/* =============================================================================
 * TwoTune Studio — production homepage cinematic showcase
 * =============================================================================
 *
 * Loaded by the public homepage (index.html) only.
 * Staff preview remains at studio-promo-preview.html + studio-promo-preview.css
 * and is not referenced here.
 *
 * Values are adapted from the approved Studio reference pack at
 *   docs/reference/twotune-studio-promo/
 * and the visually approved cinematic film in the staff preview.
 *
 * NAMESPACE
 * ---------
 * Homepage chrome uses `.tt-studio-promo*`. Cinematic product styles keep the
 * `ttp-` prefix. Custom properties stay scoped to `.ttp-root`. Nothing is
 * declared on `:root`, and there are no bare element selectors.
 * ============================================================================= */

/* -----------------------------------------------------------------------------
 * HOMEPAGE SECTION CHROME
 * Copy + CTA sit in the homepage rhythm. The cinematic stage is near-full-width
 * but not a viewport takeover (not 100vh).
 * -------------------------------------------------------------------------- */

.tt-studio-promo {
  position: relative;
  z-index: 1;
  padding: 80px 0 100px;
  overflow-x: hidden;
  background:
    radial-gradient(ellipse 64% 46% at 50% 54%, rgba(6, 8, 18, 0.16) 0%, transparent 72%),
    radial-gradient(ellipse 60% 40% at 88% 78%, rgba(158, 34, 34, 0.03) 0%, transparent 62%);
}

.tt-studio-promo::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  pointer-events: none;
  background: linear-gradient(90deg, transparent 5%, rgba(244, 239, 230, 0.15) 50%, transparent 95%);
}

.tt-studio-promo-copy {
  width: min(1400px, calc(100% - 96px));
  margin: 0 auto 36px;
}

.tt-studio-promo-copy .sec-desc {
  margin-bottom: 10px;
}

.tt-studio-promo-support {
  max-width: 42ch;
  margin: 0 0 22px;
  font-size: 0.95rem;
  line-height: 1.7;
  color: var(--t3, #afa79b);
}

.tt-studio-promo-cta {
  padding: 13px 28px;
  border-radius: 12px;
}

.tt-studio-promo-stage-wrap {
  position: relative;
  width: min(1520px, calc(100% - 48px));
  margin: 0 auto;
}

/* Atmospheric floor haze. Lives on the wrap so it is not a stage-box shadow.
   Static gradients only — no animation, no blur filter. */
.tt-studio-promo-stage-wrap::after {
  content: "";
  position: absolute;
  left: 8%;
  right: 8%;
  bottom: 0;
  height: 34%;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse 62% 58% at 50% 28%, rgba(5, 8, 18, 0.38) 0%, rgba(6, 10, 22, 0.16) 48%, transparent 76%),
    radial-gradient(ellipse 90% 86% at 50% 78%, rgba(8, 12, 26, 0.14) 0%, transparent 72%);
}

.tt-studio-promo .ttp-root {
  display: block;
  position: relative;
  z-index: 1;
}

.tt-studio-promo .ttp-stage {
  pointer-events: none;
}

/* Optional soundtrack control. Lives on the stage wrap, not inside the
 * decorative console, so product geometry and pointer-events stay untouched. */
.ttp-sound-toggle {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 12;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  margin: 0;
  padding: 0.38rem 0.72rem 0.38rem 0.55rem;
  border: 1px solid rgba(232, 200, 96, 0.22);
  border-radius: 999px;
  background: rgba(8, 10, 18, 0.42);
  color: rgba(242, 236, 226, 0.78);
  font-family: inherit;
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  line-height: 1;
  cursor: pointer;
  pointer-events: auto;
  -webkit-appearance: none;
  appearance: none;
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.28);
  transition: color 180ms ease, border-color 180ms ease, background-color 180ms ease;
}

.ttp-sound-toggle:hover {
  color: rgba(248, 243, 234, 0.94);
  border-color: rgba(232, 200, 96, 0.4);
  background: rgba(10, 12, 22, 0.55);
}

.ttp-sound-toggle:focus {
  outline: none;
}

.ttp-sound-toggle:focus-visible {
  outline: 2px solid rgba(232, 200, 96, 0.7);
  outline-offset: 3px;
}

.ttp-sound-toggle.is-on {
  color: rgba(250, 236, 196, 0.95);
  border-color: rgba(232, 200, 96, 0.48);
}

.ttp-sound-toggle-icon {
  display: grid;
  width: 15px;
  height: 15px;
  place-items: center;
}

.ttp-sound-icon {
  grid-area: 1 / 1;
  width: 15px;
  height: 15px;
}

.ttp-sound-icon--on {
  opacity: 0;
}

.ttp-sound-toggle.is-on .ttp-sound-icon--on {
  opacity: 1;
}

.ttp-sound-toggle.is-on .ttp-sound-icon--off {
  opacity: 0;
}

.ttp-sound-toggle-label {
  transform: translateY(0.5px);
}

@media (max-width: 768px) {
  .tt-studio-promo {
    padding: 72px 0 88px;
  }

  .ttp-sound-toggle {
    top: 10px;
    right: 8px;
    padding: 0.34rem 0.62rem 0.34rem 0.48rem;
    font-size: 0.62rem;
  }

  .tt-studio-promo-copy {
    width: calc(100% - 32px);
    margin-bottom: 28px;
  }

  .tt-studio-promo-stage-wrap {
    width: calc(100% - 32px);
  }

  .tt-studio-promo-stage-wrap::after {
    left: 6%;
    right: 6%;
    height: 28%;
    background:
      radial-gradient(ellipse 70% 62% at 50% 30%, rgba(5, 8, 18, 0.28) 0%, rgba(6, 10, 22, 0.1) 50%, transparent 76%),
      radial-gradient(ellipse 92% 88% at 50% 80%, rgba(8, 12, 26, 0.1) 0%, transparent 72%);
  }
}

@media (max-width: 480px) {
  .tt-studio-promo-copy,
  .tt-studio-promo-stage-wrap {
    width: calc(100% - 28px);
  }
}

/* -----------------------------------------------------------------------------
 * 0. SCOPED RESET
 * -------------------------------------------------------------------------- */

.ttp-root,
.ttp-root *,
.ttp-root *::before,
.ttp-root *::after {
  box-sizing: border-box;
}

/* -----------------------------------------------------------------------------
 * 1. TOKENS
 * Studio source reference:
 *   :root block in docs/reference/twotune-studio-promo/extracted/promo-tokens.css
 *   docs/reference/twotune-studio-promo/design-tokens.md §1-§4
 *   docs/reference/twotune-studio-promo/source-manifest.md
 * Only the tokens the promo actually uses are carried across.
 * -------------------------------------------------------------------------- */

.ttp-root {
  /* Type */
  --ttp-font-sans: "DM Sans", system-ui, sans-serif;
  --ttp-font-display: "Playfair Display", Georgia, serif;
  --ttp-font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Brand palette — tailwind.config.ts:16-29 */
  --ttp-bg: #0b0b14;
  --ttp-surface: #12141c;
  --ttp-elevated: #1a1d26;
  --ttp-gold: #e8c860;
  --ttp-gold-divider: #d4af37;
  --ttp-text: #f5f0e8;
  --ttp-muted: #9a8f7e;
  --ttp-ink: #000000;

  /* Material ladder — coated hardware, not grey blocks.
   * environment → shell → face → panel → well → raised control */
  --ttp-mat-face: #14161c;
  --ttp-mat-face-deep: #0c0d11;
  --ttp-mat-panel: #161920;
  --ttp-mat-panel-deep: #0e1015;
  --ttp-mat-well: #090a0d;
  --ttp-mat-control: #1c1f27;
  --ttp-mat-control-hi: #2a2e38;
  --ttp-mat-seam: rgba(212, 175, 55, 0.12);
  --ttp-mat-seam-soft: rgba(255, 255, 255, 0.045);
  --ttp-mat-bevel-hi: rgba(255, 255, 255, 0.07);
  --ttp-mat-bevel-lo: rgba(0, 0, 0, 0.55);

  /* Module accents — tailwind.config.ts:8-15 */
  --ttp-accent-deck: #fbbf24;   /* amber — deck + focused channel */
  --ttp-accent-lib: #22d3ee;    /* cyan  — metronome active */
  --ttp-accent-coach: #a78bfa;  /* violet — practice-part tint */

  /* Radii — tailwind.config.ts:52-61 */
  --ttp-radius: 0.75rem;
  --ttp-radius-xl: 1.125rem;
  --ttp-radius-2xl: 1.375rem;
  --ttp-radius-3xl: 1.625rem;

  /* Shadows — restrained hardware, not card stacks */
  --ttp-shadow-glow: 0 0 40px -14px rgba(212, 175, 55, 0.22);
  --ttp-shadow-card:
    inset 0 1px 0 var(--ttp-mat-bevel-hi),
    inset 0 -2px 8px rgba(0, 0, 0, 0.55),
    0 8px 22px rgba(0, 0, 0, 0.42);
  --ttp-shadow-console-depth:
    0 18px 48px rgba(0, 0, 0, 0.72),
    inset 0 0 0 1px rgba(212, 175, 55, 0.1),
    inset 0 1px 0 rgba(255, 255, 255, 0.05);
  --ttp-shadow-console-well:
    inset 0 3px 12px rgba(0, 0, 0, 0.72),
    inset 0 1px 0 rgba(255, 255, 255, 0.035);

  /* Motion — player-console.css:1245-1246 */
  --ttp-press-dur: 120ms;
  --ttp-press-ease: cubic-bezier(0.22, 0.9, 0.28, 1);

  /* Layout */
  --ttp-nameplate-w: 18rem;
  /* Native gold-edge band. Filled 6px / 8px bottom so perspective sampling
   * still resolves a continuous highlight; opacity keeps it visually thin. */
  --ttp-gold-edge: 6px;
  --ttp-gold-edge-s: 8px;
  --ttp-gold-hi: 0.48;
  --ttp-gold-mid: 0.28;
  --ttp-gold-lo: 0.22;
  --ttp-gold-side: 0.4;
  --ttp-gold-bottom: 0.36;

  /* Idle float amplitude. Driven to 0 over the last ~0.7s so completion
   * can freeze transform: none with no snap. Reduced-motion never animates. */
  --ttp-float-amp: 1;

  margin: 0;
  padding: 0;
  color: var(--ttp-text);
  font-family: var(--ttp-font-sans);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* The product subtree carries `aria-hidden` and `pointer-events: none`,
 * and every console control is a <span>. The optional Sound toggle lives
 * outside the product, on the stage wrap. */
.ttp-root .ttp-product,
.ttp-root .ttp-product * {
  cursor: default;
}

.ttp-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}


/* =============================================================================
 * 2B. CINEMATIC STAGE — PHASE 2
 * =============================================================================
 * Web-authored presentation layer. Nothing here exists in Studio; it is the
 * advertising camera, not the product. The product identity underneath is
 * unchanged.
 *
 * LAYER STACK
 *   .ttp-stage       borderless crop. Never transformed, so the lighting rig and
 *                    vignette stay locked to the frame while the camera moves.
 *     .ttp-light--*  ambient / key / floor / accent / haze washes
 *     .ttp-viewport  clipping frame, flex-centres the camera
 *       .ttp-camera  2D pan + scale-down only (scale never exceeds 1). Affine
 *                    so the JS framing maths that centres a focus target stays
 *                    exact. Magnification above 1 is a gimbal translateZ dolly,
 *                    not a 2D scale of a rasterized 3D texture.
 *         .ttp-gimbal  local perspective() + rotateX/rotateY/translateZ. Using
 *                      the perspective() FUNCTION rather than the perspective
 *                      PROPERTY on an ancestor keeps the vanishing point tied
 *                      to the product.
 *           .ttp-float   slow idle drift, independent of the shot
 *             .ttp-product  3D depth shell + flat high-detail faceplate
 *       .ttp-key-spot  masked light pool, biased toward the featured control
 *     .ttp-vignette / .ttp-blackout
 *
 * Only `transform` and `opacity` are animated on the camera path.
 * -------------------------------------------------------------------------- */

/* Homepage cinematic stage. Geometry is unchanged; chrome is not a card.
   Overflow remains for camera crops. Fill is transparent so homepage particles
   show at the feathered edge of the dark field. */
.ttp-stage {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  height: clamp(600px, 70vh, 800px);
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;

  /* Camera timing. JS rewrites these per shot; the camera and the gimbal read
   * the same pair so the dolly and the rotation stay in lockstep. */
  --ttp-cam-dur: 1600ms;
  --ttp-cam-ease: cubic-bezier(0.33, 0.02, 0.16, 1);

  --ttp-thick: 82px;
  --ttp-product-w: 1180px;

  /* Phase 4.4 — cinematic super safe area (~7.5% X / ~10% Y on desktop).
   * Percentage-based so margins scale with the responsive stage, with rem
   * floors so type never kisses the crop at small viewports. */
  --ttp-safe-x: clamp(2.85rem, 7.5%, 7.25rem);
  --ttp-safe-y: clamp(3.5rem, 10%, 6.5rem);
  --ttp-safe-x-side: clamp(2.85rem, 7.5%, 8.5rem);
}

/* --- Lighting rig ---------------------------------------------------------- */

.ttp-light {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* Cyclorama. A seamless studio backdrop, not flat black: a cool wall that is
 * brightest just behind the product's shoulder line and falls off into the
 * corners, over a warmer floor. This is what stops the wide shots reading as a
 * product cut out on a black page — the negative space has to be lit too. */
.ttp-light--backdrop {
  z-index: 0;
  background:
    radial-gradient(ellipse 50% 54% at 50% 42%,
      rgba(5, 6, 14, 0.97) 0%,
      rgba(6, 8, 16, 0.93) 28%,
      rgba(7, 9, 18, 0.86) 54%,
      rgba(8, 11, 22, 0.7) 72%,
      rgba(8, 12, 24, 0.28) 86%,
      rgba(8, 12, 24, 0.06) 94%,
      transparent 100%),
    radial-gradient(ellipse 70% 54% at 50% 36%, rgba(96, 86, 152, 0.14) 0%, transparent 62%),
    radial-gradient(ellipse 40% 30% at 86% 14%, rgba(150, 104, 44, 0.07) 0%, transparent 64%),
    radial-gradient(ellipse 46% 36% at 12% 86%, rgba(30, 96, 124, 0.06) 0%, transparent 66%);
  transition: filter 720ms ease-out;
}

/* Soft overhead key. The product sits inside this pool, which is what gives the
 * faceplate its top-lit falloff and separates it from the cyclorama. */
.ttp-light--key {
  z-index: 1;
  background:
    radial-gradient(ellipse 58% 52% at 50% 12%, rgba(255, 240, 214, 0.17) 0%, rgba(255, 236, 200, 0.055) 44%, rgba(255, 236, 200, 0) 72%),
    radial-gradient(ellipse 26% 20% at 50% -2%, rgba(255, 248, 232, 0.16) 0%, rgba(255, 248, 232, 0) 70%);
  transition: opacity 720ms ease-out;
}

/* Floor: a warm bounce pool directly under the product plus the heavy shadow
 * the product casts into it. Together they give the console somewhere to
 * stand. */
.ttp-light--floor {
  z-index: 2;
  background:
    radial-gradient(ellipse 44% 15% at 50% 90%, rgba(232, 200, 96, 0.1) 0%, rgba(232, 200, 96, 0) 70%),
    radial-gradient(ellipse 62% 22% at 50% 97%, rgba(120, 108, 156, 0.09) 0%, rgba(120, 108, 156, 0) 72%),
    radial-gradient(ellipse 70% 26% at 50% 108%, rgba(4, 6, 14, 0.42) 0%, rgba(4, 6, 14, 0) 74%);
  transition: opacity 720ms ease-out;
}

/* Feature-response accents. Solo lifts a low red into the stage, the metronome
 * a low cyan, gold controls a warm reflection. Never more than one dominant. */
.ttp-light--red,
.ttp-light--cyan,
.ttp-light--gold {
  z-index: 3;
  opacity: 0;
  transition: opacity 760ms ease-out;
}

.ttp-light--red {
  background:
    radial-gradient(ellipse 54% 46% at 26% 62%, rgba(220, 66, 58, 0.2) 0%, rgba(220, 66, 58, 0) 62%),
    radial-gradient(ellipse 90% 30% at 50% 102%, rgba(180, 44, 40, 0.16) 0%, rgba(180, 44, 40, 0) 70%);
}

.ttp-light--cyan {
  background:
    radial-gradient(ellipse 52% 48% at 76% 44%, rgba(34, 211, 238, 0.16) 0%, rgba(34, 211, 238, 0) 62%),
    radial-gradient(ellipse 84% 28% at 60% 102%, rgba(22, 150, 176, 0.14) 0%, rgba(22, 150, 176, 0) 70%);
}

.ttp-light--gold {
  background:
    radial-gradient(ellipse 64% 50% at 50% 58%, rgba(232, 200, 96, 0.12) 0%, rgba(232, 200, 96, 0) 64%);
}

.ttp-stage.is-lit-red .ttp-light--red { opacity: 1; }
.ttp-stage.is-lit-cyan .ttp-light--cyan { opacity: 1; }
.ttp-stage.is-lit-gold .ttp-light--gold { opacity: 1; }

/* Foreground atmosphere — a shallow depth cue in front of the product. */
.ttp-light--haze {
  z-index: 7;
  background:
    linear-gradient(180deg, rgba(6, 8, 16, 0.12) 0%, transparent 26%),
    linear-gradient(0deg, rgba(6, 8, 18, 0.2) 0%, transparent 34%);
}

.ttp-vignette {
  position: absolute;
  inset: 0;
  z-index: 8;
  pointer-events: none;
  background: radial-gradient(ellipse 68% 62% at 50% 46%, rgba(0, 0, 0, 0.2) 0%, rgba(0, 0, 0, 0.08) 42%, transparent 74%);
}

/* Safety cover for the wrap. The visible dissolve is carried by .ttp-nightfall,
 * which is already opaque by the time the state resets; this only guarantees the
 * single reset frame is covered if that transition is still settling. */
.ttp-blackout {
  position: absolute;
  inset: 0;
  z-index: 10;
  pointer-events: none;
  background: radial-gradient(ellipse 52% 56% at 50% 46%, rgba(4, 5, 12, 0.96) 0%, rgba(4, 6, 14, 0.4) 58%, transparent 100%);
  opacity: 0;
}

/* --- Camera ---------------------------------------------------------------- */

.ttp-viewport {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

/* No `will-change` here on purpose. Pinning a composited layer for a product
 * this large costs tens of megabytes of GPU texture at close-up raster scales,
 * and this treatment has to survive being embedded in the homepage. The
 * transform transitions promote on their own for their duration and re-raster
 * crisply once the camera comes to rest. */
.ttp-camera,
.ttp-gimbal {
  transform-style: preserve-3d;
  transition: transform var(--ttp-cam-dur) var(--ttp-cam-ease);
}

.ttp-camera {
  flex: 0 0 auto;
}

/* Idle float. Small enough to read as a suspended object with mass, not as a
 * bobbing UI card. */
.ttp-float {
  transform-style: preserve-3d;
  animation: none;
}

.ttp-root.is-playing:not(.is-complete):not(.is-geometry-locked) .ttp-float {
  animation: ttp-product-float 14s ease-in-out infinite;
}

@keyframes ttp-product-float {
  0%, 100% {
    transform:
      translate3d(0, calc(-5px * var(--ttp-float-amp, 1)), 0)
      rotate(calc(-0.11deg * var(--ttp-float-amp, 1)));
  }
  50% {
    transform:
      translate3d(0, calc(6px * var(--ttp-float-amp, 1)), 0)
      rotate(calc(0.11deg * var(--ttp-float-amp, 1)));
  }
}

.ttp-product {
  position: relative;
  width: var(--ttp-product-w);
  transform-style: preserve-3d;
  /* Depth walls stay in this 3D context. The faceplate is explicitly flat so
   * meters, type and SVG arcs rasterize on one front plane. */
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
}

.ttp-key-spot {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 6;
  width: 200px;
  height: 200px;
  margin: -100px 0 0 -100px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 226, 172, 0.2) 0%, rgba(255, 200, 116, 0.085) 40%, rgba(255, 190, 96, 0) 72%);
  mix-blend-mode: screen;
  opacity: 0;
  pointer-events: none;
  transition:
    transform var(--ttp-cam-dur) var(--ttp-cam-ease),
    opacity 900ms ease-out;
  will-change: transform, opacity;
}

.ttp-key-spot.is-cyan {
  background: radial-gradient(circle, rgba(150, 238, 250, 0.17) 0%, rgba(34, 211, 238, 0.07) 42%, rgba(34, 211, 238, 0) 72%);
}

.ttp-key-spot.is-red {
  background: radial-gradient(circle, rgba(255, 168, 152, 0.18) 0%, rgba(239, 68, 68, 0.075) 42%, rgba(239, 68, 68, 0) 72%);
}

/* Opening glint. Stretched flat along the faceplate's top edge, this is the one
 * thing that reads while the stage is still dark — a catchlight travelling the
 * hardware, not a lit product. Hotter and tighter in the core than the working
 * key pool so it survives being screened over near-black. */
.ttp-key-spot.is-rim {
  background: radial-gradient(circle, rgba(255, 238, 200, 0.62) 0%, rgba(255, 206, 128, 0.26) 30%, rgba(240, 176, 80, 0.06) 58%, rgba(240, 176, 80, 0) 76%);
}

/* Stage darkness. Distinct from .ttp-blackout: this one is a scheduled part of
 * the film — it holds the opening in near-black, calms the product under the end
 * card, and carries the dissolve back to the top. It sits above the product and
 * below the key light so a rim catchlight still reads through it. */
.ttp-nightfall {
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  background:
    radial-gradient(ellipse 50% 54% at 50% 44%,
      rgba(6, 6, 14, 0.96) 0%,
      rgba(5, 6, 14, 0.9) 36%,
      rgba(4, 6, 14, 0.72) 58%,
      rgba(5, 8, 18, 0.28) 78%,
      transparent 100%);
  opacity: 0;
}

/* Lockup / final Hero: keep environmental darkness at the frame edge so the
 * lockup sits in a cinematic field, but do not multiply a dark scrim through
 * the detailed faceplate. Opening nightfall stays centre-weighted above. */
.ttp-stage.ttp-shot-lockup .ttp-nightfall,
.ttp-stage.ttp-shot-front .ttp-nightfall,
.ttp-stage.is-complete .ttp-nightfall,
.ttp-stage[data-ttp-playback="completed"] .ttp-nightfall {
  background:
    radial-gradient(ellipse 62% 66% at 50% 46%,
      transparent 0%,
      transparent 46%,
      rgba(4, 6, 14, 0.22) 72%,
      rgba(4, 6, 14, 0.5) 100%);
}

/* --- Hardware thickness ----------------------------------------------------
 * A back plate at -Z plus four walls hinged off each faceplate edge. The walls
 * are inset 12px horizontally/vertically so the faceplate's 18px corner radius
 * hides their square ends. Depth is deliberately panel-like: this should read
 * as a milled rack faceplate, not as a box.
 *
 * On the wall thickness: a visible edge is only `thickness * sin(angle)` tall
 * once foreshortened, so at the sequence's restrained 12-22 degrees a "realistic"
 * 20px panel collapses to about four pixels and the product goes back to
 * reading as a flat rectangle. The walls are therefore cut at roughly 4% of the
 * faceplate width — the proportion of a real rack panel, and enough to survive
 * the foreshortening.
 * -------------------------------------------------------------------------- */

.ttp-depth {
  position: absolute;
  pointer-events: none;
  backface-visibility: hidden;
}

.ttp-depth--back {
  inset: 0;
  border-radius: var(--ttp-radius-xl);
  transform: translateZ(calc(-1 * var(--ttp-thick)));
  background: linear-gradient(180deg, #101012 0%, #08080a 52%, #040405 100%);
  box-shadow:
    0 70px 150px rgba(0, 0, 0, 0.95),
    0 0 0 1px rgba(0, 0, 0, 0.9);
}

/* Top wall catches the overhead key. Warmth is a surface bevel wash — not a
 * hairline on the hinge that would restroke the front silhouette. */
.ttp-depth--top {
  left: 12px;
  right: 12px;
  bottom: 100%;
  height: var(--ttp-thick);
  transform-origin: 50% 100%;
  transform: rotateX(90deg);
  background: linear-gradient(0deg, #2e2c28 0%, #4a4538 18%, #2c2c32 42%, #202027 64%, #101016 82%, #08080c 100%);
}

/* Bottom wall is in shade; a broad dark bevel, not a second gold frame. */
.ttp-depth--bottom {
  left: 12px;
  right: 12px;
  top: 100%;
  height: var(--ttp-thick);
  transform-origin: 50% 0;
  transform: rotateX(-90deg);
  background: linear-gradient(180deg, #1c1c20 0%, #18181c 18%, #0c0c10 46%, #030304 100%);
}

.ttp-depth--left {
  top: 12px;
  bottom: 12px;
  right: 100%;
  width: var(--ttp-thick);
  transform-origin: 100% 50%;
  transform: rotateY(-90deg);
  background: linear-gradient(90deg, #050507 0%, #14141a 48%, #26242c 78%, #322e28 100%);
}

.ttp-depth--right {
  top: 12px;
  bottom: 12px;
  left: 100%;
  width: var(--ttp-thick);
  transform-origin: 0 50%;
  transform: rotateY(90deg);
  background: linear-gradient(270deg, #050507 0%, #121218 42%, #242428 70%, #322e28 100%);
}

/* Ground contact. A gradient rather than a blur filter — `filter` would flatten
 * the preserve-3d subtree and cost a full-size offscreen buffer every frame. */
.ttp-contact {
  position: absolute;
  left: -9%;
  right: -9%;
  bottom: -13%;
  height: 26%;
  pointer-events: none;
  /* Lifted to 1 on the wide shots, where the product needs somewhere to stand;
   * on the macros the shadow is off-frame anyway. */
  opacity: 0.78;
  transition: opacity 900ms ease-out;
  transform: translateZ(calc(-1 * var(--ttp-thick) - 24px));
  background:
    radial-gradient(46% 62% at 50% 0%, rgba(0, 0, 0, 0.95) 0%, rgba(0, 0, 0, 0.6) 44%, rgba(0, 0, 0, 0) 78%),
    radial-gradient(72% 100% at 50% 0%, rgba(0, 0, 0, 0.66) 0%, rgba(0, 0, 0, 0.22) 46%, rgba(0, 0, 0, 0) 80%);
}

/* --- Faceplate surface lighting -------------------------------------------- */

/* The faceplate's own response to the overhead key: a warm wash falling from
 * the top-left shoulder and a cool shade pooling in the lower-right. No
 * hairline here — the metallic perimeter is the faceplate's same-plane band. */
.ttp-plate-rim {
  position: absolute;
  inset: 0;
  z-index: 4;
  border-radius: var(--ttp-radius-xl);
  pointer-events: none;
  opacity: 0.84;
  transition: opacity 900ms ease-out;
  background:
    linear-gradient(158deg, rgba(255, 244, 216, 0.1) 0%, rgba(255, 244, 216, 0.028) 26%, rgba(255, 244, 216, 0) 46%),
    radial-gradient(ellipse 78% 58% at 22% -6%, rgba(255, 238, 205, 0.075) 0%, rgba(255, 238, 205, 0) 62%),
    radial-gradient(ellipse 70% 60% at 96% 104%, rgba(0, 0, 0, 0.42) 0%, rgba(0, 0, 0, 0) 64%);
}

/* One-pass reveal sweep, restarted by JS at the top of the hero shot. */
.ttp-sheen {
  position: absolute;
  inset: 0;
  z-index: 5;
  border-radius: var(--ttp-radius-xl);
  overflow: hidden;
  pointer-events: none;
  opacity: 0;
}

.ttp-sheen::before {
  content: "";
  position: absolute;
  top: -30%;
  bottom: -30%;
  left: -60%;
  width: 45%;
  transform: translateX(-160%) rotate(9deg);
  background: linear-gradient(
    90deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 248, 228, 0.07) 38%,
    rgba(255, 232, 176, 0.13) 52%,
    rgba(255, 255, 255, 0) 100%
  );
}

.ttp-sheen.is-sweeping {
  opacity: 1;
  animation: ttp-sheen-fade 2600ms ease-out 1 forwards;
}

.ttp-sheen.is-sweeping::before {
  animation: ttp-sheen-sweep 2600ms cubic-bezier(0.3, 0.05, 0.2, 1) 1 forwards;
}

@keyframes ttp-sheen-sweep {
  from { transform: translateX(-160%) rotate(9deg); }
  to   { transform: translateX(430%) rotate(9deg); }
}

@keyframes ttp-sheen-fade {
  0%   { opacity: 0; }
  18%  { opacity: 1; }
  82%  { opacity: 1; }
  100% { opacity: 0; }
}

/* --- Shot states -----------------------------------------------------------
 * The driver sets exactly one `ttp-shot-*` class on the stage. These rules
 * carry only the environment: light level, atmosphere and how tightly the
 * frame is closed down. Camera pose, the key-light pool and every product
 * state are set from JS.
 * -------------------------------------------------------------------------- */

.ttp-light--key,
.ttp-light--backdrop,
.ttp-light--floor,
.ttp-vignette {
  transition: opacity 900ms ease-out;
}

/* Shot 0 is the film opening: the rig is all but off. What little is on is the
 * cyclorama's own falloff, which keeps a silhouette rather than a void.
 * Phase 4.4: tiny key/floor lift for front-plane separation — still under-lit. */
.ttp-stage.ttp-shot-intro .ttp-light--key {
  opacity: 0.4;
}

.ttp-stage.ttp-shot-intro .ttp-light--floor {
  opacity: 0.38;
}

/* Parked homepage wait: same intro pose, slightly more readable ambience.
 * Static gradients only — no motion. One-shot opacity handoff when playback
 * begins, so the film opening is not a black flash. */
.ttp-stage::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  opacity: 0;
  transition: opacity 720ms ease-out;
  background:
    radial-gradient(ellipse 54% 40% at 46% 34%, rgba(232, 200, 96, 0.08) 0%, rgba(232, 200, 96, 0) 68%),
    radial-gradient(ellipse 42% 20% at 50% 90%, rgba(232, 200, 96, 0.055) 0%, rgba(120, 108, 156, 0.04) 46%, transparent 74%);
}

.ttp-stage[data-ttp-playback="not-started"]::after {
  opacity: 1;
}

.ttp-stage[data-ttp-playback="not-started"] .ttp-camera,
.ttp-stage[data-ttp-playback="not-started"] .ttp-gimbal {
  transition: none;
}

.ttp-stage[data-ttp-playback="not-started"].ttp-shot-intro .ttp-light--key {
  opacity: 0.7;
}

.ttp-stage[data-ttp-playback="not-started"].ttp-shot-intro .ttp-light--floor {
  opacity: 0.58;
}

.ttp-stage[data-ttp-playback="not-started"].ttp-shot-intro .ttp-light--backdrop {
  opacity: 1;
  filter: brightness(1.12);
}

.ttp-stage[data-ttp-playback="not-started"].ttp-shot-intro .ttp-vignette {
  opacity: 0.86;
}

/* The interface comes up out of the hardware, not with it. Holding the console
 * back while the faceplate, its walls and its gold edge are already there
 * is what makes the opening a reveal instead of a dimmed screenshot — and it is
 * the only honest way to show "a premium object is about to appear" when the
 * object's own surface is a lit UI. Driven as a scalar from the demo clock so
 * the ramp is part of the film, and dropped entirely once the reveal is over so
 * the console is not left inside a compositing layer for the other nine shots. */
.ttp-product.is-revealing .ttp-console {
  opacity: var(--ttp-reveal, 1);
}

/* Opening catchlight on the milled thickness — a bevel wash across the wall
 * face. Peak warmth sits on the wall, not on the front-edge join. */
.ttp-stage.ttp-shot-intro .ttp-depth--top {
  background: linear-gradient(0deg, #3a3428 0%, #a89058 16%, #6a5c40 32%, #2a2824 54%, #17171c 76%, #08080c 100%);
}

.ttp-stage.ttp-shot-intro .ttp-depth--right {
  background: linear-gradient(270deg, #050507 0%, #121218 36%, #3a3428 62%, #6e5c3c 84%, #4a4030 100%);
}

.ttp-depth--top,
.ttp-depth--right,
.ttp-plate-rim {
  transition:
    background 1100ms ease-out,
    opacity 900ms ease-out;
}

/* Shot 1 opens restrained: the stage is barely lit and the reveal sheen is
 * what first describes the faceplate. */
.ttp-stage.ttp-shot-hero .ttp-light--key {
  opacity: 0.62;
}

.ttp-stage.ttp-shot-intro .ttp-vignette,
.ttp-stage.ttp-shot-hero .ttp-vignette,
.ttp-stage.ttp-shot-final .ttp-vignette,
.ttp-stage.ttp-shot-lockup .ttp-vignette,
.ttp-stage.ttp-shot-front .ttp-vignette {
  opacity: 1;
}

/* Wide shots carry the product's silhouette, so its edges have to survive the
 * dark set: the perimeter catchlight and the contact shadow are both lifted for
 * the four full-product shots and left alone on the macros, where the same
 * values would read as a halo. */
.ttp-stage.ttp-shot-intro .ttp-plate-rim,
.ttp-stage.ttp-shot-hero .ttp-plate-rim,
.ttp-stage.ttp-shot-final .ttp-plate-rim,
.ttp-stage.ttp-shot-lockup .ttp-plate-rim,
.ttp-stage.ttp-shot-front .ttp-plate-rim {
  opacity: 1;
}

.ttp-stage.ttp-shot-final .ttp-contact,
.ttp-stage.ttp-shot-lockup .ttp-contact,
.ttp-stage.ttp-shot-front .ttp-contact {
  opacity: 1;
}

/* Close-ups open the frame up a little — a tight vignette on a macro shot just
 * reads as a dirty lens. */
.ttp-stage.ttp-shot-volume .ttp-vignette,
.ttp-stage.ttp-shot-solo .ttp-vignette,
.ttp-stage.ttp-shot-mute .ttp-vignette,
.ttp-stage.ttp-shot-metronome .ttp-vignette {
  opacity: 0.68;
}

.ttp-stage.ttp-shot-volume .ttp-light--key,
.ttp-stage.ttp-shot-metronome .ttp-light--key {
  opacity: 1.15;
}

/* -----------------------------------------------------------------------------
 * 2b. SUPERS — opening titles, mid-sequence lines, closing brand lockup
 *
 * Advertising supers, not page copy: no cards, no rules, no boxes, nothing that
 * reads as an interface. Every one of them is driven by opacity plus a few
 * pixels of translate from the demo clock, so the layer costs two composited
 * properties and never reflows the stage under the camera.
 *
 * The brand marks are the repository's approved files, used unmodified:
 *   opening  assets/brand/twotune-logo-light.svg   (full lockup, as site footers)
 *   closing  assets/brand/twotune-icon-light.svg   (icon mark)
 *
 * Layout rule for the wide tiers: the type lives in the negative space the
 * camera leaves free, and the product is biased away from it by the pose's own
 * `ax` — so nothing is ever printed over a control. Portrait cannot spare a
 * column, so there the type stacks above the product instead.
 * -------------------------------------------------------------------------- */

.ttp-supers {
  position: absolute;
  inset: 0;
  z-index: 9;
  pointer-events: none;
  /* Supers are lit type on a dark set: they should feel like part of the print,
   * not like a layer switched on over it. */
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

/* --- Opening titles -------------------------------------------------------- */

/* Centred inside its own column rather than flush left: the wordmark is drawn
 * centred in its viewBox, so ranging the type left of it would leave the logo
 * visibly indented against the words underneath. */
.ttp-titles {
  position: absolute;
  left: var(--ttp-safe-x-side);
  top: 50%;
  width: min(30rem, 33vw);
  transform: translateY(-50%);
  text-align: center;
  opacity: 0;
}

/* Each super animates through `--ttp-y` rather than through `transform`
 * directly, so the driver never has to know whether the tier's base transform
 * also carries a centring translate. */
.ttp-supers [data-ttp-super] {
  transform: translateY(var(--ttp-y, 12px));
}

/* Quiet, confident, and deliberately nowhere near header scale. */
.ttp-title-logo {
  display: block;
  width: clamp(148px, 14.5vw, 236px);
  height: auto;
  margin: 0 auto;
  opacity: 0;
  transform: translateY(var(--ttp-y, 14px)) scale(var(--ttp-s, 0.99));
  /* Keep the mark a vector at every opacity — no blur, no filter. */
  filter: none;
}

.ttp-title-name {
  margin: clamp(1.5rem, 2.6vw, 2.4rem) 0 0;
  font-family: var(--ttp-font-sans);
  font-size: clamp(1.5rem, 2.15vw, 2.35rem);
  font-weight: 600;
  letter-spacing: 0.055em;
  line-height: 1.12;
  color: #f2f2f2;
  opacity: 0;
  transform: translateY(var(--ttp-y, 12px));
  text-shadow: 0 2px 26px rgba(0, 0, 0, 0.75);
}

.ttp-title-line {
  margin: 0.85rem 0 0;
  font-family: var(--ttp-font-sans);
  font-size: clamp(0.95rem, 1.12vw, 1.2rem);
  font-weight: 400;
  letter-spacing: 0.035em;
  line-height: 1.45;
  color: rgba(238, 232, 222, 0.76);
  opacity: 0;
  transform: translateY(var(--ttp-y, 10px));
  text-shadow: 0 2px 22px rgba(0, 0, 0, 0.8);
}

/* --- Mid-sequence lines ---------------------------------------------------- */

/* One slot, bottom left, well clear of the subject in all three shots that use
 * it. Small on purpose: the meters are the argument, the line is the caption.
 * Phase 4.4: inset via --ttp-safe-* so copy never sits on the stage crop. */
.ttp-superline {
  position: absolute;
  left: var(--ttp-safe-x);
  bottom: var(--ttp-safe-y);
  max-width: min(26rem, 46vw);
  font-family: var(--ttp-font-sans);
  font-size: clamp(1.05rem, 1.45vw, 1.6rem);
  font-weight: 500;
  letter-spacing: 0.05em;
  line-height: 1.3;
  color: #f4f1ea;
  opacity: 0;
  transform: translateY(var(--ttp-y, 10px));
  text-shadow:
    0 2px 18px rgba(0, 0, 0, 0.9),
    0 0 44px rgba(0, 0, 0, 0.7);
}

/* A single hairline of gold ahead of the line — the one piece of decoration in
 * the type, borrowed from the faceplate's own edge. */
.ttp-superline span,
.ttp-metro-title-block {
  display: block;
  padding-left: 1.05rem;
  border-left: 1px solid rgba(212, 175, 55, 0.55);
}

/* The close crops leave no dead stage to caption into, so each line carries its
 * own pool of shade. Soft and far enough past the text on every side to read as
 * the light falling off behind it rather than as a plate. */
.ttp-superline::before {
  content: "";
  position: absolute;
  inset: -280% -34%;
  z-index: -1;
  background: radial-gradient(ellipse at center,
    rgba(2, 2, 6, 0.66) 0%,
    rgba(2, 2, 6, 0.4) 38%,
    rgba(2, 2, 6, 0.14) 58%,
    rgba(2, 2, 6, 0) 76%);
}

/* --- Closing brand lockup -------------------------------------------------- */

.ttp-endcard {
  position: absolute;
  left: 50%;
  top: 50%;
  width: min(34rem, 78vw);
  transform: translate(-50%, -50%);
  text-align: center;
  opacity: 0;
}

/* Not a card — a shadow pad. The end card lands over a live console, and
 * without something to sit against the lockup reads as type dropped on top of
 * an interface. This is soft enough and far enough past the text on every side
 * that it registers as the stage light going down behind the brand, which is
 * exactly what it is. It fades with the lockup, so the other nine shots never
 * see it. */
.ttp-endcard::before {
  content: "";
  position: absolute;
  inset: -150% -55%;
  z-index: -1;
  background: radial-gradient(ellipse at center,
    rgba(2, 2, 6, 0.72) 0%,
    rgba(2, 2, 6, 0.5) 34%,
    rgba(2, 2, 6, 0.2) 56%,
    rgba(2, 2, 6, 0) 74%);
}

.ttp-endcard-icon {
  display: block;
  width: clamp(56px, 5.4vw, 88px);
  height: auto;
  margin: 0 auto;
  opacity: 0;
  transform: translateY(var(--ttp-y, 10px)) scale(var(--ttp-s, 0.99));
}

.ttp-endcard-name {
  margin: clamp(1.1rem, 1.8vw, 1.7rem) 0 0;
  font-family: var(--ttp-font-sans);
  font-size: clamp(1.35rem, 1.95vw, 2.15rem);
  font-weight: 600;
  letter-spacing: 0.075em;
  line-height: 1.15;
  color: #f2f2f2;
  opacity: 0;
  transform: translateY(var(--ttp-y, 10px));
  text-shadow: 0 2px 30px rgba(0, 0, 0, 0.8);
}

/* Held back and brought in late — the beat between the name and the line is
 * what makes the ending feel like an ending. */
.ttp-endcard-line {
  margin: clamp(0.7rem, 1.1vw, 1rem) 0 0;
  font-family: var(--ttp-font-sans);
  font-size: clamp(0.9rem, 1.05vw, 1.12rem);
  font-weight: 400;
  letter-spacing: 0.06em;
  line-height: 1.5;
  color: rgba(236, 230, 220, 0.74);
  opacity: 0;
  transform: translateY(var(--ttp-y, 8px));
  text-shadow: 0 2px 22px rgba(0, 0, 0, 0.85);
}

/* --- Metronome title -------------------------------------------------------
 * Same graphic family as the mid-sequence supers: a caption in the negative
 * space, never a card, never over the LCD. On the wide tiers the metronome is
 * biased right, so this sits in the open stage on the left. Portrait stacks it
 * at the bottom like the other feature lines. */
.ttp-metro-title {
  position: absolute;
  left: var(--ttp-safe-x-side);
  top: 50%;
  width: min(22rem, 32vw);
  transform: translateY(-50%);
  pointer-events: none;
  /* Wrapper owns the super's visibility so the gold rule cannot outlive the copy. */
  opacity: 0;
}

.ttp-metro-title::before {
  content: "";
  position: absolute;
  inset: -120% -40%;
  z-index: -1;
  background: radial-gradient(ellipse at center,
    rgba(2, 2, 6, 0.55) 0%,
    rgba(2, 2, 6, 0.28) 42%,
    rgba(2, 2, 6, 0) 72%);
}

.ttp-metro-title-name,
.ttp-metro-title-line {
  margin: 0;
  font-family: var(--ttp-font-sans);
  color: #f4f1ea;
  text-shadow:
    0 2px 18px rgba(0, 0, 0, 0.9),
    0 0 44px rgba(0, 0, 0, 0.7);
}

.ttp-metro-title-name {
  opacity: 1;
  font-size: clamp(1.35rem, 1.85vw, 2.05rem);
  font-weight: 600;
  letter-spacing: 0.06em;
  line-height: 1.15;
  transform: translateY(var(--ttp-y, 12px));
}

.ttp-metro-title-line {
  opacity: 0;
  margin-top: 0.7rem;
  font-size: clamp(0.95rem, 1.15vw, 1.22rem);
  font-weight: 400;
  letter-spacing: 0.045em;
  line-height: 1.4;
  color: rgba(238, 232, 222, 0.78);
  transform: translateY(var(--ttp-y, 10px));
}

/* -----------------------------------------------------------------------------
 * 3. FACEPLATE + CONSOLE SHELL
 * Studio source reference:
 *   .tt-console-faceplate  (player-console.css:141-154)
 *   docs/reference/twotune-studio-promo/source-manifest.md §2
 * -------------------------------------------------------------------------- */

.ttp-faceplate {
  position: relative;
  z-index: 1;
  transform-style: flat;
  border-radius: var(--ttp-radius-xl);
  border: 0;
  /* Same-plane metallic band painted as faceplate background (a filled
   * 6px / 8px-bottom gradient strip per edge), not a CSS stroke. Restraint
   * comes from opacity, not from fading the band to a hairline. */
  background-image:
    linear-gradient(180deg,
      rgb(255 236 190 / var(--ttp-gold-hi)) 0%,
      rgb(196 158 78 / var(--ttp-gold-mid)) 55%,
      rgb(140 110 58 / var(--ttp-gold-lo)) 100%),
    linear-gradient(0deg,
      rgb(196 158 78 / var(--ttp-gold-bottom)) 0%,
      rgb(120 92 42 / var(--ttp-gold-lo)) 100%),
    linear-gradient(90deg,
      rgb(176 140 70 / var(--ttp-gold-side)) 0%,
      rgb(120 92 42 / var(--ttp-gold-lo)) 100%),
    linear-gradient(270deg,
      rgb(232 204 120 / var(--ttp-gold-side)) 0%,
      rgb(140 110 58 / var(--ttp-gold-lo)) 100%),
    linear-gradient(168deg, rgba(255, 255, 255, 0.035) 0%, transparent 48%),
    linear-gradient(180deg, #181a20 0%, var(--ttp-mat-face) 42%, var(--ttp-mat-face-deep) 100%);
  background-size:
    100% var(--ttp-gold-edge),
    100% var(--ttp-gold-edge-s),
    var(--ttp-gold-edge) calc(100% - var(--ttp-gold-edge) - var(--ttp-gold-edge-s)),
    var(--ttp-gold-edge) calc(100% - var(--ttp-gold-edge) - var(--ttp-gold-edge-s)),
    100% 100%,
    100% 100%;
  background-position:
    0 0,
    0 100%,
    0 var(--ttp-gold-edge),
    100% var(--ttp-gold-edge),
    0 0,
    0 0;
  background-repeat: no-repeat;
  box-shadow:
    0 32px 96px rgba(0, 0, 0, 0.9),
    0 2px 0 rgba(255, 255, 255, 0.025),
    inset 0 1px 0 rgba(255, 255, 255, 0.04),
    inset 0 -4px 14px rgba(0, 0, 0, 0.42);
  padding: 1rem;
}

/* Opening nightfall is heavy; lift the same band so it still reads as metal.
 * Phase 4.4: slightly stronger deck bevel only — no gold-edge width/alpha change. */
.ttp-stage.ttp-shot-intro .ttp-faceplate {
  --ttp-gold-hi: 0.82;
  --ttp-gold-mid: 0.52;
  --ttp-gold-lo: 0.4;
  --ttp-gold-side: 0.72;
  --ttp-gold-bottom: 0.7;
  box-shadow:
    0 32px 96px rgba(0, 0, 0, 0.9),
    0 2px 0 rgba(255, 255, 255, 0.04),
    inset 0 1px 0 rgba(255, 255, 255, 0.075),
    inset 0 -4px 14px rgba(0, 0, 0, 0.36);
}

.ttp-console {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 1rem;
  align-items: start;
  transform-style: flat;
}

.ttp-deck-col {
  min-width: 0;
  border-radius: var(--ttp-radius);
  border: 1px solid rgba(212, 175, 55, 0.16);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.028) 0%, transparent 28%),
    linear-gradient(180deg, var(--ttp-mat-panel) 0%, var(--ttp-mat-panel-deep) 100%);
  box-shadow:
    inset 0 1px 0 var(--ttp-mat-bevel-hi),
    inset 0 -2px 10px rgba(0, 0, 0, 0.5);
  overflow: hidden;
}

/* Centred in the console row rather than top-aligned, so the shorter metronome
 * column does not leave the bottom-right of the faceplate visibly empty in the
 * wide hero shots. */
.ttp-metro-col {
  display: flex;
  justify-content: center;
  align-self: center;
}

/* -----------------------------------------------------------------------------
 * 4. PRESSABLE BUTTON SYSTEM
 * Studio source reference:
 *   .tt-pressable + --gold / --cyan / --violet / --pill / focus ring
 *   (player-console.css:1243-1395)
 *   docs/reference/twotune-studio-promo/extracted/promo-tokens.css §4-§8
 * -------------------------------------------------------------------------- */

.ttp-press {
  position: relative;
  overflow: hidden;
  border: 1px solid rgba(70, 74, 84, 0.55);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.06) 0%, transparent 38%),
    linear-gradient(180deg, var(--ttp-mat-control-hi) 0%, var(--ttp-mat-control) 48%, #12141a 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    inset 0 -4px 10px rgba(0, 0, 0, 0.48),
    0 2px 6px rgba(0, 0, 0, 0.45);
  transition:
    transform var(--ttp-press-dur) var(--ttp-press-ease),
    box-shadow 160ms var(--ttp-press-ease),
    border-color 160ms var(--ttp-press-ease),
    filter 160ms var(--ttp-press-ease);
}

.ttp-press::before {
  content: "";
  position: absolute;
  inset: 1px 1px auto;
  height: 36%;
  border-radius: inherit;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0));
  pointer-events: none;
}

/* PHASE 2: no hover / active / focus states.
 * Every control is a subject inside an autoplay advertisement, so it must never
 * offer an operable affordance. The product subtree is `pointer-events: none`
 * and `aria-hidden`; these states could not fire anyway, and are removed so the
 * stylesheet cannot suggest otherwise.
 * The PRESSED look is still reachable: the demo driver adds `.is-pressed` for a
 * few frames when the sequence actuates a control, so the viewer sees the
 * button travel exactly as Studio renders it under a real press. */
.ttp-press.is-pressed {
  transform: translateY(1px);
  box-shadow:
    inset 0 2px 0 rgba(255, 255, 255, 0.05),
    inset 0 -2px 6px rgba(0, 0, 0, 0.5),
    0 1px 3px rgba(0, 0, 0, 0.5);
}

.ttp-press.is-pressed::before {
  opacity: 0.45;
}

.ttp-press--gold {
  border-color: rgba(182, 146, 60, 0.55);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.18) 0%, transparent 40%),
    linear-gradient(180deg, #e8d48a 0%, #d4af4a 42%, #9a6e1e 78%, #4a320c 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.28),
    inset 0 -5px 10px rgba(0, 0, 0, 0.3),
    0 2px 8px rgba(0, 0, 0, 0.45),
    0 0 10px rgba(232, 200, 96, 0.1);
}

.ttp-press--cyan {
  border-color: rgba(56, 162, 180, 0.55);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    inset 0 -4px 10px rgba(0, 0, 0, 0.48),
    0 2px 6px rgba(0, 0, 0, 0.45),
    0 0 10px rgba(34, 211, 238, 0.08);
}

.ttp-press--violet {
  border-color: rgba(145, 96, 230, 0.55);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    inset 0 -4px 10px rgba(0, 0, 0, 0.48),
    0 2px 6px rgba(0, 0, 0, 0.45),
    0 0 10px rgba(145, 96, 230, 0.08);
}

.ttp-press--pill {
  border-radius: 9999px;
}

/* -----------------------------------------------------------------------------
 * 5. MAIN PLAYER DECK
 * Studio source reference:
 *   MainPlayerDeck.tsx:161-218 (panel, eyebrow, title, artist, metadata)
 *   docs/reference/twotune-studio-promo/multitrack-reference.md §4.2
 * -------------------------------------------------------------------------- */

.ttp-deck-section {
  border-bottom: 1px solid var(--ttp-mat-seam);
  padding: 0.75rem 1.25rem;
}

.ttp-deck-panel {
  border-radius: var(--ttp-radius-2xl);
  border: 1px solid rgba(212, 175, 55, 0.14);
  background:
    linear-gradient(180deg, rgba(255, 248, 230, 0.03) 0%, transparent 36%),
    linear-gradient(180deg, rgba(28, 22, 14, 0.35) 0%, rgba(14, 16, 22, 0.55) 55%, transparent 100%);
  padding: 1rem;
  box-shadow: var(--ttp-shadow-console-well);
}

.ttp-eyebrow {
  margin: 0;
  font-family: var(--ttp-font-sans);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--ttp-gold-divider);
}

.ttp-deck-title {
  margin: 0.15rem 0 0;
  font-family: var(--ttp-font-display);
  font-size: 1.85rem;
  font-weight: 500;
  line-height: 1.16;
  letter-spacing: -0.015em;
  color: var(--ttp-text);
}

.ttp-deck-artist {
  margin: 0.2rem 0 0;
  font-size: 14px;
  color: var(--ttp-muted);
}

.ttp-deck-meta {
  margin: 0.35rem 0 0;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--ttp-mat-seam);
  font-size: 11px;
  color: var(--ttp-muted);
}

.ttp-deck-meta .ttp-bpm {
  font-family: var(--ttp-font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--ttp-gold);
}

.ttp-deck-meta .ttp-sep {
  color: rgba(212, 175, 55, 0.55);
  margin: 0 0.4rem;
}

/* -----------------------------------------------------------------------------
 * 6. PRACTICE PRESET CHIPS
 * Studio source reference:
 *   PRACTICE_MODES + chip row (MainPlayerDeck.tsx:66-70, 227-252)
 *   Selected chip = tt-pressable--gold + text-twotune-ink
 * -------------------------------------------------------------------------- */

.ttp-preset-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.5rem;
  margin-top: 0.625rem;
}

.ttp-preset {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0;
  border-radius: var(--ttp-radius-xl);
  padding: 0.5rem 0.875rem;
  text-align: center;  color: #f4f4f5;
  font-family: inherit;
}

.ttp-preset-label {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.015em;
}

.ttp-preset-sub {
  margin: 0;
  font-size: 10px;
  line-height: 1.2;
  color: #a1a1aa;
}

.ttp-preset.is-selected {
  color: var(--ttp-ink);
}

.ttp-preset.is-selected .ttp-preset-sub {
  color: rgba(0, 0, 0, 0.75);
}

/* -----------------------------------------------------------------------------
 * 7. TRANSPORT + TIMELINE
 * Studio source reference:
 *   TransportControls.tsx:24-40 (hero sphere, CSS-only glyphs)
 *   ProgressBar.tsx:70-117 (timeline card)
 *   .tt-console-slider / -rail (player-console.css:1479-1607)
 * -------------------------------------------------------------------------- */

.ttp-transport-row {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  gap: 1rem;
  margin-top: 0.75rem;
}

.ttp-transport {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.75rem;
}

.ttp-transport-label {
  font-family: var(--ttp-font-sans);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--ttp-muted);
}

.ttp-play-hero {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 5.25rem;
  height: 5.25rem;
  border-radius: 9999px;
  color: var(--ttp-ink);  padding: 0;
}

.ttp-glyph-pause {
  display: block;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 1px;
  border-left: 4px solid var(--ttp-ink);
  border-right: 4px solid var(--ttp-ink);
}

.ttp-glyph-play {
  display: block;
  width: 0;
  height: 0;
  margin-left: 0.375rem;
  border-top: 11px solid transparent;
  border-bottom: 11px solid transparent;
  border-left: 18px solid var(--ttp-ink);
}

.ttp-timeline-col {
  display: flex;
  flex: 1 1 auto;
  min-width: 0;
  flex-direction: column;
  gap: 0.75rem;
}

.ttp-timeline-card {
  border: 1px solid rgba(113, 113, 122, 0.5);
  border-radius: var(--ttp-radius-2xl);
  background-image: linear-gradient(to bottom, rgba(24, 24, 27, 0.55), #070708);
  padding: 1.25rem 1.5rem;
  box-shadow:
    inset 0 2px 14px rgba(0, 0, 0, 0.55),
    0 4px 14px rgba(0, 0, 0, 0.35);
}

.ttp-timeline-label {
  margin: 0 0 0.875rem;
  padding-left: 0.25rem;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: #a1a1aa;
}

.ttp-slider-rail {
  display: flex;
  align-items: center;
  border-radius: 9999px;
  padding: 10px 12px;
  background: linear-gradient(180deg, #060606 0%, #101012 45%, #0a0a0c 100%);
  border: 1px solid rgba(85, 85, 98, 0.55);
  box-shadow:
    inset 0 4px 16px rgba(0, 0, 0, 0.82),
    inset 0 1px 0 rgba(255, 255, 255, 0.05),
    0 2px 6px rgba(0, 0, 0, 0.55),
    0 1px 0 rgba(255, 255, 255, 0.03);
  transition: box-shadow 260ms ease-out;
}

/* PROMO-ONLY EMBELLISHMENT.
 * Studio draws NO A/B markers or loop region on the timeline
 * (capability-boundary.md, demo-sequence.md 9.0-11.0s). This is a brief
 * transient glow on loop wrap so the promo reads as a loop. It is deliberately
 * momentary and leaves no persistent marker, so it cannot be mistaken for
 * shipping UI. */
.ttp-slider-rail.is-loop-wrap {
  box-shadow:
    inset 0 4px 16px rgba(0, 0, 0, 0.82),
    inset 0 1px 0 rgba(255, 255, 255, 0.05),
    0 2px 6px rgba(0, 0, 0, 0.55),
    0 0 22px rgba(232, 200, 96, 0.32);
  transition: box-shadow 90ms ease-out;
}

/* Display-only readout. Studio's timeline IS a draggable range input; here the
 * playhead is driven by the demo clock alone, so PHASE 2 renders it from plain
 * elements instead of a native <input type="range">. That keeps the track and
 * the gold thumb vector-crisp when the camera dollies past 1:1 during the A/B
 * loop shot, which a UA-painted control is not guaranteed to do. */
.ttp-slider {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  align-self: center;
  height: 22px;
  --ttp-trk-h: 12px;
  --ttp-thumb: 22px;
}

.ttp-slider-track {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: var(--ttp-trk-h);
  margin-top: calc(var(--ttp-trk-h) / -2);
  border-radius: 9999px;
  background: linear-gradient(180deg, #020202 0%, #121215 38%, #28282f 62%, #16161a 100%);
  border: 1px solid rgba(130, 130, 145, 0.55);
  box-shadow:
    inset 0 5px 14px rgba(0, 0, 0, 0.95),
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    0 1px 0 rgba(255, 255, 255, 0.04);
}

.ttp-slider-thumb {
  position: absolute;
  top: 50%;
  left: calc(var(--ttp-thumb) / 2);
  width: var(--ttp-thumb);
  height: var(--ttp-thumb);
  margin: calc(var(--ttp-thumb) / -2) 0 0 calc(var(--ttp-thumb) / -2);
  border-radius: 50%;
  background: linear-gradient(155deg, #fffef5 0%, #f2e088 18%, #e8c860 48%, #a67c1a 82%, #4a3208 100%);
  border: 1px solid rgba(0, 0, 0, 0.45);
  box-shadow:
    0 3px 6px rgba(0, 0, 0, 0.65),
    0 0 16px rgba(232, 200, 96, 0.2),
    inset 0 3px 5px rgba(255, 255, 255, 0.42),
    inset 0 -4px 6px rgba(0, 0, 0, 0.38);
  transform: translate3d(var(--ttp-playhead, 0px), 0, 0);
}

.ttp-timecode-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 0.875rem;
  font-family: var(--ttp-font-mono);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: #d4d4d8;
}

/* -----------------------------------------------------------------------------
 * 8. READINESS CARD
 * Studio source reference:
 *   MainPlayerDeck.tsx:302-342, readinessStatusLabel 51-64
 *   interaction-states.md §20 (Ready)
 * -------------------------------------------------------------------------- */

.ttp-readiness {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  margin-top: 0.75rem;
  border-radius: var(--ttp-radius-2xl);
  border: 1px solid rgba(245, 158, 11, 0.25);
  background: rgba(69, 26, 3, 0.15);
  padding: 0.5rem 1rem;
  box-shadow: inset 0 1px 0 rgba(232, 200, 96, 0.08);
  transition:
    opacity 320ms ease-out,
    transform 320ms var(--ttp-press-ease);
}

/* PHASE 2: the card keeps its box in flow and fades instead of unmounting.
 * A height change here would reflow the whole product mid-shot and invalidate
 * the camera's cached framing offsets. */
.ttp-readiness.is-gone {
  opacity: 0;
  transform: translateY(-3px);
}

.ttp-readiness-dot {
  flex-shrink: 0;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 9999px;
  background: #34d399;
  box-shadow: 0 0 8px rgba(52, 211, 153, 0.55);
}

.ttp-readiness-copy {
  margin: 0;
  font-size: 12px;
  color: rgba(254, 243, 199, 0.9);
}

.ttp-readiness-hint {
  color: rgba(254, 243, 199, 0.6);
}

/* -----------------------------------------------------------------------------
 * 9. UTILITY ROW — Loop A-B / Metronome / Reset mix
 * Studio source reference:
 *   MainPlayerDeck.tsx:344-383, abLoopButtonLabel 82-86
 *   Loop phases: off -> a_set (amber outline) -> on (gold fill)
 * -------------------------------------------------------------------------- */

.ttp-utility-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px solid rgba(212, 175, 55, 0.1);
}

.ttp-btn-utility {
  display: inline-flex;
  min-height: 2.5rem;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
  border-radius: var(--ttp-radius-xl);
  padding: 0.625rem 1rem;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  line-height: 1;
  letter-spacing: 0.14em;
  color: #f4f4f5;}

.ttp-btn-utility.is-loop-armed {
  border-color: rgba(245, 158, 11, 0.7);
  color: #fde68a;
}

.ttp-btn-utility.is-on-gold {
  color: var(--ttp-ink);
}

.ttp-btn-utility.is-on-cyan {
  color: #ecfeff;
}

/* -----------------------------------------------------------------------------
 * 10. MIXER SECTION
 * Studio source reference: TrackConsole.tsx:30-90
 * -------------------------------------------------------------------------- */

.ttp-mixer {
  padding: 1rem 1.25rem;
}

.ttp-mixer-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.625rem;
}

.ttp-mixer-title {
  margin: 0.1rem 0 0;
  font-family: var(--ttp-font-display);
  font-size: 20px;
  font-weight: 500;
  color: var(--ttp-text);
}

.ttp-mixer-sub {
  margin: 0.125rem 0 0;
  font-size: 11px;
  color: var(--ttp-muted);
}

.ttp-mixer-count {
  margin: 0;
  flex-shrink: 0;
  font-family: var(--ttp-font-mono);
  font-size: 10px;
  color: var(--ttp-muted);
}

.ttp-mixer-rows {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding-right: 0.25rem;
  padding-bottom: 0.75rem;
}

/* -----------------------------------------------------------------------------
 * 11. CHANNEL STRIP
 * Studio source reference:
 *   ttUi.channelCard / ttUi.channelFocused (ui-classes.ts:49-52)
 *   ChannelStrip.tsx:256, 276
 * Focused channel is the amber module accent (#fbbf24). Non-soloed strips are
 * NEVER dimmed — only their meters fall (multitrack-reference.md §7).
 * -------------------------------------------------------------------------- */

.ttp-channel {
  border: 1px solid rgba(212, 175, 55, 0.1);
  border-radius: var(--ttp-radius-2xl);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.03) 0%, transparent 30%),
    linear-gradient(180deg, var(--ttp-mat-panel) 0%, var(--ttp-mat-panel-deep) 100%);
  box-shadow: var(--ttp-shadow-card);
  padding: 0.625rem 1rem;
  flex-shrink: 0;
  transition: border-color 180ms var(--ttp-press-ease), box-shadow 180ms var(--ttp-press-ease);
}

.ttp-channel.is-focused {
  border-width: 1px;
  border-color: rgba(251, 191, 36, 0.42);
  background:
    linear-gradient(180deg, rgba(251, 191, 36, 0.06) 0%, transparent 34%),
    linear-gradient(180deg, #1c1e26 0%, var(--ttp-mat-panel-deep) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 236, 190, 0.08),
    inset 0 -2px 8px rgba(0, 0, 0, 0.5),
    0 0 0 1px rgba(251, 191, 36, 0.12),
    var(--ttp-shadow-glow);
  padding: 0.625rem 1rem;
}

.ttp-channel-grid {
  display: grid;
  width: 100%;
  min-width: 0;
  grid-template-columns: 2.5rem minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  column-gap: 1rem;
  row-gap: 0.625rem;
}

.ttp-col-badge {
  display: flex;
  align-items: center;
  justify-content: center;
}

.ttp-col-body {
  min-width: 0;
}

/* Track index badge — player-console.css:1007-1051.
 * `--master` renders FULL MIX when track.order === 1 (TrackConsole.tsx:83). */
.ttp-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.7rem;
  height: 1.9rem;
  padding: 0 0.5rem;
  border-radius: 9999px;
  border: 1px solid rgba(232, 200, 96, 0.35);
  background: linear-gradient(180deg, rgba(36, 39, 46, 0.96) 0%, rgba(16, 18, 22, 0.94) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.07),
    inset 0 -2px 4px rgba(0, 0, 0, 0.45),
    0 1px 4px rgba(0, 0, 0, 0.32);
  font-family: var(--ttp-font-mono);
  font-size: 1.22rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.03em;
  white-space: nowrap;
  color: rgba(232, 200, 96, 0.94);
  text-shadow: 0 0 8px rgba(232, 200, 96, 0.25);
}

.ttp-badge--master {
  min-width: 5rem;
  padding: 0 0.7rem;
  font-size: 0.84rem;
  letter-spacing: 0.06em;
}

/* Track nameplate — ChannelStrip.tsx:305-311. Deliberately not a button. */
.ttp-nameplate {
  display: flex;
  align-items: center;
  min-width: 0;
  width: var(--ttp-nameplate-w);
  max-width: 100%;
  border: 1px solid rgba(245, 158, 11, 0.1);
  border-radius: 2px;
  background: rgba(5, 5, 5, 0.75);
  padding: 1px 0.5rem;
  box-shadow:
    inset 0 1px 4px rgba(0, 0, 0, 0.85),
    inset 0 1px 0 rgba(255, 255, 255, 0.04);
}

.ttp-nameplate-text {
  display: block;
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: left;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.015em;
  color: rgba(245, 240, 232, 0.95);
}

/* -----------------------------------------------------------------------------
 * 12. 72-SEGMENT LED METER
 * Studio source reference:
 *   ChannelStrip.tsx:29-33 (DB_LEFT -48, DB_RIGHT +9, DB_ZERO_POS 0.72,
 *   LED_COUNT 72), :116-143 (colour ramp), :314-382 (housing / well / needle)
 *   docs/reference/twotune-studio-promo/multitrack-reference.md §6
 *
 * The dB scale is ASYMMETRIC: 0 dB sits at 72% of the width, leaving 28%
 * headroom. Per-segment colours are assigned by JS from the documented ramp
 * formula into --ttp-led-on / --ttp-led-glow, matching ledOnColor() exactly.
 * -------------------------------------------------------------------------- */

/* PHASE 2: `--ttp-spill` / `--ttp-spill-c` are written by the demo driver from
 * the channel's current envelope and its topmost lit segment colour, so each
 * meter throws its own light onto the surrounding panel. Both are quantised in
 * JS, so this box-shadow repaints a few times a second, not 60. */
.ttp-meter-housing {
  position: relative;
  border: 1px solid rgba(55, 58, 66, 0.55);
  border-radius: var(--ttp-radius-xl);
  background: var(--ttp-mat-well);
  padding: 0.125rem 0.5rem 0.25rem;
  box-shadow: var(--ttp-shadow-console-well);
  margin-top: 0.375rem;
}

.ttp-meter-housing::after {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  pointer-events: none;
  box-shadow: 0 0 14px 1px var(--ttp-spill-c, rgba(120, 220, 140, 0.28));
  opacity: var(--ttp-spill, 0);
}

.ttp-meter-scale {
  position: relative;
  height: 0.875rem;
  width: 100%;
  margin-bottom: 0.125rem;
  padding: 0 0.125rem;
  font-family: var(--ttp-font-mono);
  font-size: 8.5px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  color: rgba(168, 172, 180, 0.72);
}

.ttp-meter-scale-inf {
  position: absolute;
  left: 0.25rem;
  top: 0;
  font-size: 7.5px;
  color: rgba(120, 124, 132, 0.75);
}

.ttp-meter-scale-tick {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
}

.ttp-meter-scale-tick.is-right {
  transform: translateX(-100%);
}

.ttp-meter-well {
  position: relative;
  width: 100%;
  border-radius: 5px;
  background: rgba(0, 0, 0, 0.72);
  padding: 0.25rem 0;
  box-shadow:
    inset 0 1px 2px rgba(0, 0, 0, 0.7),
    inset 0 0 0 1px rgba(48, 52, 60, 0.45);
}

.ttp-meter-gridline {
  pointer-events: none;
  position: absolute;
  top: 0.25rem;
  bottom: 0.25rem;
  width: 1px;
  background: rgba(90, 94, 104, 0.28);
}

.ttp-meter-gridline.is-zero {
  background: rgba(212, 175, 55, 0.38);
}

.ttp-meter-peak {
  pointer-events: none;
  position: absolute;
  top: 0.125rem;
  bottom: 0.125rem;
  z-index: 10;
  width: 1.5px;
  border-radius: 9999px;
  background: rgba(232, 200, 96, 0.92);
  box-shadow: 0 0 4px rgba(232, 200, 96, 0.28);
  transform: translateX(-50%);
  opacity: 0.9;
}

.ttp-meter-leds {
  display: flex;
  height: 11px;
  width: 100%;
  align-items: stretch;
  gap: 1px;
  padding: 0 0.375rem;
}

.ttp-led {
  min-width: 0;
  flex: 1 1 0%;
  border-radius: 1px;
  border: 1px solid rgba(0, 0, 0, 0.35);
  background-color: hsl(220 10% 16%);
  opacity: 0.38;
  box-shadow: inset 0 -1px 0 hsl(0 0% 0% / 0.5);
  transition:
    opacity 0.04s ease-out,
    background-color 0.05s ease-out;
}

.ttp-led.is-on {
  background-color: var(--ttp-led-on);
  opacity: 1;
  box-shadow:
    inset 0 1px 0 hsl(0 0% 100% / 0.16),
    0 0 2.5px var(--ttp-led-glow);
}

/* Muted channel: Studio gates the glow on `on && !mix.muted`
 * (ChannelStrip.tsx:373-374) so a lit segment keeps the unlit shadow. */
.ttp-meter.is-muted .ttp-led {
  opacity: 0.18;
}

.ttp-meter.is-muted .ttp-led.is-on {
  opacity: 0.28;
  box-shadow: inset 0 -1px 0 hsl(0 0% 0% / 0.45);
}

.ttp-meter.is-muted .ttp-meter-peak {
  opacity: 0.15;
}

/* -----------------------------------------------------------------------------
 * 13. SOLO / MUTE COLUMN
 * Studio source reference:
 *   ChannelStrip.tsx:390-441 (order is Solo then Mute, DAW convention)
 *   Solo ON drops .tt-pressable entirely and uses the red ramp (:419)
 *   Mute ON keeps .tt-pressable and adds --gold
 *   .tt-strip-status-led (player-console.css:943-1005)
 * -------------------------------------------------------------------------- */

.ttp-sm-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
}

.ttp-sm-leds,
.ttp-sm-buttons {
  display: flex;
  align-items: center;
  gap: 0.375rem;
}

.ttp-sm-btn {
  display: flex;
  width: 2.5rem;
  height: 2.25rem;
  align-items: center;
  justify-content: center;
  border-radius: var(--ttp-radius-xl);
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.025em;
  color: #f4f4f5;  padding: 0;
}

.ttp-sm-btn.is-solo-on {
  background-image: linear-gradient(180deg, #e88980 0%, #c93a3a 52%, #6b1515 100%);
  color: #140606;
  border: 1px solid rgba(252, 165, 165, 0.28);
  box-shadow:
    0 0 10px rgba(248, 113, 113, 0.28),
    inset 0 1px 0 rgba(255, 220, 210, 0.25),
    inset 0 -3px 8px rgba(0, 0, 0, 0.35);
}

.ttp-sm-btn.is-solo-on::before {
  content: none;
}

.ttp-sm-btn.is-mute-on {
  color: var(--ttp-ink);
}

.ttp-pulse-red {
  animation: ttp-red-pulse 1850ms ease-in-out infinite;
}

@keyframes ttp-red-pulse {
  0%,
  100% {
    box-shadow:
      0 0 8px rgba(239, 68, 68, 0.16),
      inset 0 1px 0 rgba(255, 220, 210, 0.2),
      inset 0 -3px 8px rgba(0, 0, 0, 0.35);
  }
  50% {
    box-shadow:
      0 0 14px rgba(248, 113, 113, 0.32),
      inset 0 1px 0 rgba(255, 220, 210, 0.25),
      inset 0 -3px 8px rgba(0, 0, 0, 0.35);
  }
}

.ttp-led-status {
  position: relative;
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 9999px;
  background: radial-gradient(circle at 32% 30%, #59616d 0%, #353b44 58%, #252b33 100%);
  border: 1px solid rgba(17, 20, 24, 0.9);
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.1),
    0 0 0 1px rgba(0, 0, 0, 0.35);
}

.ttp-led-status::before,
.ttp-led-status::after {
  content: "";
  position: absolute;
  border-radius: 9999px;
  pointer-events: none;
}

.ttp-led-status::before {
  inset: 0.1rem;
  background: radial-gradient(circle at 35% 30%, rgba(244, 248, 255, 0.28) 0%, rgba(82, 90, 106, 0.28) 42%, rgba(28, 32, 40, 0.9) 100%);
}

.ttp-led-status::after {
  inset: -0.2rem;
  opacity: 0;
  transform: scale(0.86);
}

.ttp-led-status.is-mute-on {
  background: radial-gradient(circle at 34% 32%, #fff6d9 0%, #f6d36f 42%, #d3a43a 74%, #7a5615 100%);
  border-color: rgba(120, 90, 20, 0.9);
  box-shadow:
    0 0 8px rgba(245, 204, 94, 0.46),
    0 0 14px rgba(232, 200, 96, 0.3),
    inset 0 1px 1px rgba(255, 246, 209, 0.42);
}

.ttp-led-status.is-mute-on::before {
  background: radial-gradient(circle at 35% 30%, #fffdf5 0%, #ffe9b7 22%, #f7cf69 52%, #c5962c 82%, #7c5a17 100%);
}

.ttp-led-status.is-solo-on {
  background: radial-gradient(circle at 34% 32%, #ffe0db 0%, #ff8b7f 38%, #e74937 70%, #8f2218 100%);
  border-color: rgba(122, 25, 20, 0.9);
  box-shadow:
    0 0 8px rgba(248, 113, 113, 0.5),
    0 0 16px rgba(239, 68, 68, 0.33),
    inset 0 1px 1px rgba(255, 239, 236, 0.42);
}

.ttp-led-status.is-solo-on::before {
  background: radial-gradient(circle at 35% 30%, #fff8f4 0%, #ffd5cf 22%, #ff8c80 52%, #d74231 82%, #8f1f16 100%);
}

.ttp-led-status.is-solo-on::after {
  background: radial-gradient(circle, rgba(248, 113, 113, 0.56) 0%, rgba(239, 68, 68, 0.26) 48%, rgba(239, 68, 68, 0.04) 74%, rgba(239, 68, 68, 0) 100%);
  animation: ttp-led-halo-breathe 1350ms ease-in-out infinite;
}

@keyframes ttp-led-halo-breathe {
  0%,
  100% {
    opacity: 0.42;
    transform: scale(0.86);
  }
  50% {
    opacity: 0.95;
    transform: scale(1.08);
  }
}

/* -----------------------------------------------------------------------------
 * 14. ROTARY KNOBS — Vol / Low / Mid / High
 * Studio source reference:
 *   StemRotaryKnob.tsx:22-28, 43-47, 120, 151-169
 *   .tt-stem-knob-* (player-console.css:1145-1241)
 *
 * Geometry: viewBox 0 0 72 72, centre 36,36, r 30, stroke 3.2,
 * sweep -150deg..+150deg, ARC_LEN 157.0796,
 * dialDeg = -150 + value * 300, dashoffset = ARC_LEN * (1 - value).
 * Volume is a ROTARY KNOB. Studio has no linear fader anywhere.
 * -------------------------------------------------------------------------- */

.ttp-knob-row {
  display: flex;
  width: 100%;
  align-items: center;
}

.ttp-knob-strip {
  display: flex;
  width: 100%;
  flex-wrap: nowrap;
  align-items: flex-start;
  justify-content: space-between;
  column-gap: 1rem;
  row-gap: 0.5rem;
}

.ttp-knob-cell {
  display: flex;
  flex: 1 1 0;
  min-width: 0;
  justify-content: center;
}

.ttp-knob {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.125rem;
}

.ttp-knob-label {
  margin: 0;
  font-size: 7px;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: rgba(220, 224, 230, 0.48);
  text-transform: uppercase;
}

.ttp-knob-well {
  position: relative;
  width: 3.35rem;
  height: 3.35rem;
  border-radius: 50%;
  background:
    radial-gradient(circle at 48% 28%, rgba(255, 255, 255, 0.05) 0%, transparent 42%),
    radial-gradient(circle at 50% 55%, #26282e 0%, #14161b 58%, #07080a 100%);
  box-shadow:
    inset 0 5px 14px rgba(0, 0, 0, 0.88),
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    0 2px 6px rgba(0, 0, 0, 0.5);
  border: 1px solid rgba(0, 0, 0, 0.62);
  padding: 0;
  transition: box-shadow 420ms var(--ttp-press-ease);
}

/* PHASE 2 macro shot: while the camera is on the Vol knob the well gains a
 * warm rim and the cap a stronger catchlight, so it reads as a machined part
 * rather than a flat circle at 3x. Lighting only — no geometry change. */
.ttp-knob-well.is-macro {
  box-shadow:
    inset 0 5px 14px rgba(0, 0, 0, 0.88),
    inset 0 1px 0 rgba(255, 255, 255, 0.1),
    0 2px 6px rgba(0, 0, 0, 0.5),
    0 0 18px rgba(232, 200, 96, 0.12);
}

.ttp-knob-well.is-macro .ttp-knob-cap {
  box-shadow:
    0 3px 10px rgba(0, 0, 0, 0.55),
    inset 0 1px 2px rgba(255, 255, 255, 0.16),
    inset 0 -3px 6px rgba(0, 0, 0, 0.5);
}

.ttp-knob-ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.ttp-knob-arc {
  transition: stroke-dashoffset 0.12s ease-out;
}

.ttp-knob-cap {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 2.15rem;
  height: 2.15rem;
  margin-left: -1.075rem;
  margin-top: -1.075rem;
  border-radius: 50%;
  background:
    radial-gradient(circle at 32% 26%, rgba(255, 255, 255, 0.14) 0%, transparent 40%),
    linear-gradient(155deg, #4a4d54 0%, #2e3138 48%, #1a1c21 100%);
  box-shadow:
    0 2px 7px rgba(0, 0, 0, 0.55),
    inset 0 1px 1px rgba(255, 255, 255, 0.1),
    inset 0 -2px 5px rgba(0, 0, 0, 0.48);
  border: 1px solid rgba(0, 0, 0, 0.5);
  transform-origin: 50% 50%;
  pointer-events: none;
  transition: transform 0.12s ease-out;
}

.ttp-knob-dot {
  position: absolute;
  left: 50%;
  top: 3px;
  width: 4px;
  height: 4px;
  margin-left: -2px;
  border-radius: 50%;
  background: #eceef2;
  box-shadow:
    0 0 2px rgba(255, 255, 255, 0.28),
    inset 0 -1px 1px rgba(0, 0, 0, 0.3);
}

.ttp-knob-readout {
  font-family: var(--ttp-font-mono);
  font-size: 8.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: rgba(200, 208, 220, 0.72);
  line-height: 1;
}

/* -----------------------------------------------------------------------------
 * 15. HARDWARE METRONOME — chassis
 * Studio source reference:
 *   HardwareMetronomeVisual.tsx:152-275
 *   .tt-hw-chassis (player-console.css:174-206)
 *   docs/reference/twotune-studio-promo/metronome-reference.md §5
 * -------------------------------------------------------------------------- */

/* Studio sizes the widget `w-max` because it floats free. Here the column is
 * fixed at the expanded panel's width so collapsing does not reflow the mixer,
 * and so the compact chassis still resolves its 6.5rem max-width. */
.ttp-metro-shell {
  position: relative;
  width: 18.5rem;
  max-width: 304px;
}

.ttp-hw-chassis {
  width: 100%;
  max-width: 17.5rem;
  margin: 0 auto;
  padding: 0.65rem 0.7rem 0.75rem;
  border-radius: 0.65rem;
  background:
    linear-gradient(165deg, rgba(255, 255, 255, 0.045) 0%, transparent 44%),
    linear-gradient(180deg, #2c2e34 0%, #1e2026 40%, #14161b 100%);
  border: 1px solid rgba(0, 0, 0, 0.7);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    inset 0 -3px 10px rgba(0, 0, 0, 0.48),
    0 10px 24px rgba(0, 0, 0, 0.5),
    0 1px 3px rgba(0, 0, 0, 0.35);
}

.ttp-hw-chassis--compact {
  max-width: 6.5rem;
  padding: 0.35rem 0.4rem 0.4rem;
}

.ttp-hw-face {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}

.ttp-hw-chassis--compact .ttp-hw-face {
  gap: 0;
}

/* --- Amber LCD. Four stacked stops plus three radial washes; do not flatten
 *     to a solid fill (metronome-reference.md §5). --- */

.ttp-hw-lcd {
  position: relative;
  border-radius: 0.45rem;
  padding: 2px;
  background:
    linear-gradient(152deg, #2a2c30 0%, #1a1c20 48%, #101214 100%);
  box-shadow:
    inset 0 3px 12px rgba(0, 0, 0, 0.88),
    inset 0 1px 0 rgba(255, 255, 255, 0.05),
    inset 0 -1px 0 rgba(0, 0, 0, 0.5),
    0 1px 0 rgba(255, 255, 255, 0.025),
    0 3px 7px rgba(0, 0, 0, 0.4);
}

.ttp-hw-lcd::after {
  content: "";
  position: absolute;
  inset: 3px;
  border-radius: 0.34rem;
  pointer-events: none;
  box-shadow:
    inset 12px 0 18px rgba(0, 0, 0, 0.08),
    inset -12px 0 18px rgba(0, 0, 0, 0.08);
}

.ttp-hw-lcd-inner {
  position: relative;
  border-radius: 0.38rem;
  padding: 0.45rem 0.5rem 0.4rem;
  background:
    radial-gradient(110% 80% at 50% -20%, rgba(255, 241, 208, 0.16) 0%, rgba(255, 241, 208, 0) 58%),
    linear-gradient(180deg, #e09a55 0%, #c97a36 38%, #b05f24 72%, #944a16 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 243, 223, 0.22),
    inset 0 -2px 5px rgba(78, 31, 8, 0.28),
    inset 0 0 16px rgba(120, 66, 20, 0.1);
  filter: saturate(0.93) contrast(1.015) brightness(0.99);
}

/* Scanline treatment + glare blobs */
.ttp-hw-lcd-inner::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background:
    repeating-linear-gradient(
      180deg,
      rgba(255, 255, 255, 0.01) 0px,
      rgba(255, 255, 255, 0.01) 1px,
      rgba(0, 0, 0, 0.014) 2px,
      rgba(0, 0, 0, 0.014) 5px
    ),
    radial-gradient(circle at 28% 36%, rgba(255, 255, 255, 0.055) 0%, rgba(255, 255, 255, 0) 34%);
  opacity: 1;
  mix-blend-mode: multiply;
  pointer-events: none;
}

/* Vignette + inner rim */
.ttp-hw-lcd-inner::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow:
    inset 0 0 0 1px rgba(69, 28, 8, 0.2),
    inset 0 -10px 14px rgba(74, 26, 7, 0.14),
    inset 0 10px 12px rgba(255, 246, 229, 0.035);
  pointer-events: none;
}

/* LCD ambient states. Both animations are decoration only — they carry no
 * timing information (metronome-reference.md §8). */
.ttp-hw-chassis--active .ttp-hw-lcd-inner {
  animation: ttp-hw-backlight-drift 4.8s ease-in-out infinite;
}

.ttp-hw-chassis--active .ttp-hw-lcd-inner::before {
  animation: ttp-hw-glass-sweep 7.4s ease-in-out infinite;
}

.ttp-hw-chassis--idle .ttp-hw-lcd-inner {
  filter: saturate(0.9) contrast(1.01) brightness(0.97);
}

@keyframes ttp-hw-backlight-drift {
  0%,
  100% {
    filter: saturate(1) brightness(1);
  }
  50% {
    filter: saturate(1.03) brightness(1.03);
  }
}

@keyframes ttp-hw-glass-sweep {
  0%,
  100% {
    opacity: 0.88;
    transform: translateX(0);
  }
  50% {
    opacity: 1;
    transform: translateX(0.7%);
  }
}

/* --- LCD content rows --- */

.ttp-hw-lcd-row--tempo {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.35rem;
  margin-bottom: 0.2rem;
}

.ttp-hw-lcd-label {
  font-family: var(--ttp-font-sans);
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: rgba(0, 0, 0, 0.58);
  text-shadow: none;
  white-space: nowrap;
}

/* JetBrains Mono numeric display — the only LCD text with a shadow. */
.ttp-hw-lcd-bpm {
  font-family: var(--ttp-font-mono);
  font-size: 2.15rem;
  font-weight: 800;
  line-height: 0.95;
  letter-spacing: 0.06em;
  color: #120b06;
  text-shadow:
    0 1px 0 rgba(255, 246, 230, 0.18),
    0 -1px 0 rgba(0, 0, 0, 0.22),
    0 0 0.7px rgba(0, 0, 0, 0.3);
}

.ttp-hw-lcd--compact .ttp-hw-lcd-inner {
  padding: 0.35rem 0.4rem 0.3rem;
}

.ttp-hw-lcd--compact .ttp-hw-lcd-bpm {
  font-size: 1.35rem;
}

/* The 6.5rem compact face cannot hold the TEMPO caption alongside a 1.35rem
 * readout without wrapping, so the caption is dropped and the number centred —
 * the same reduction the compact face already applies to the sound list. */
.ttp-hw-lcd--compact .ttp-hw-lcd-row--tempo {
  justify-content: center;
  margin-bottom: 0.1rem;
}

.ttp-hw-lcd--compact .ttp-hw-lcd-label {
  display: none;
}

.ttp-hw-lcd--compact .ttp-hw-sound-list {
  display: none;
}

.ttp-hw-lcd--compact .ttp-hw-lcd-row--mid {
  justify-content: center;
}

.ttp-hw-lcd--compact .ttp-hw-beat-row {
  gap: 0.25rem;
  padding-top: 0.1rem;
}

.ttp-hw-lcd--compact .ttp-hw-beat-dot {
  width: 6px;
  height: 6px;
}

.ttp-hw-lcd-row--mid {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 0.35rem;
  margin-bottom: 0.25rem;
}

.ttp-hw-lcd-rhythm-block {
  display: flex;
  flex-direction: column;
  gap: 0.08rem;
  min-width: 0;
}

.ttp-hw-lcd-rhythm {
  display: flex;
  align-items: center;
  gap: 0.2rem;
  font-family: var(--ttp-font-sans);
  font-size: 11px;
  font-weight: 800;
  color: #0a0a0a;
  text-shadow: none;
}

.ttp-hw-lcd-note {
  font-size: 14px;
  line-height: 1;
  opacity: 0.85;
}

.ttp-hw-lcd-ts {
  font-family: var(--ttp-font-mono);
  font-size: 11px;
  letter-spacing: 0.02em;
  text-shadow: none;
}

.ttp-hw-sound-list {
  list-style: none;
  margin: 0;
  padding: 0;
  text-align: right;
  font-family: var(--ttp-font-sans);
  font-size: 7px;
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: 1.35;
}

.ttp-hw-sound-line {
  color: rgba(0, 0, 0, 0.42);
  text-shadow: none;
}

.ttp-hw-sound-line--on {
  color: #070707;
}

/* --- Beat LEDs. Ink rings on the amber panel, not glowing lights. --- */

.ttp-hw-beat-row {
  display: flex;
  justify-content: center;
  gap: 0.35rem;
  padding-top: 0.15rem;
}

.ttp-hw-beat-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 2px solid #0a0a0a;
  background: transparent;
  opacity: 0.45;
}

.ttp-hw-beat-dot--accent {
  background: #0a0a0a;
  opacity: 0.85;
}

.ttp-hw-beat-dot.is-lit {
  opacity: 1;
  transform: scale(1.12);
  background: rgba(10, 10, 10, 0.72);
  border-color: #050505;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.2);
}

.ttp-hw-beat-dot--accent.is-lit {
  background: #0a0a0a;
  border-color: #050505;
}

/* --- Plastic key pad --- */

.ttp-hw-keys {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  border-radius: 0.5rem;
  padding: 0.28rem 0.35rem;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.03) 0%, rgba(0, 0, 0, 0.22) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.05),
    inset 0 -2px 8px rgba(0, 0, 0, 0.32);
}

.ttp-hw-keys-row {
  display: flex;
  gap: 0.4rem;
  justify-content: center;
  align-items: center;
}

.ttp-hw-key {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.35rem;
  height: 2rem;
  border-radius: 0.3rem;
  border: 1px solid rgba(0, 0, 0, 0.55);
  background: linear-gradient(180deg, #3e4148 0%, #272a30 50%, #1a1c21 100%);
  color: #f0f1f3;
  font-family: inherit;
  font-size: 10px;
  font-weight: 700;
  box-shadow:
    0 2px 4px rgba(0, 0, 0, 0.42),
    inset 0 1px 0 rgba(255, 255, 255, 0.09),
    inset 0 -2px 4px rgba(0, 0, 0, 0.38);
  transition:
    filter 0.12s ease,
    transform 0.08s ease;
}

.ttp-hw-key:hover:not(:disabled) {
  filter: brightness(1.08);
}

.ttp-hw-key:active:not(:disabled) {
  transform: translateY(1px);
  box-shadow:
    0 1px 3px rgba(0, 0, 0, 0.5),
    inset 0 2px 6px rgba(0, 0, 0, 0.35);
}

.ttp-hw-key.is-on {
  background: linear-gradient(180deg, #e8d48a 0%, #c9a84a 50%, #8a6520 100%);
  color: #1f1607;
  border-color: rgba(89, 65, 20, 0.65);
  box-shadow:
    0 2px 4px rgba(0, 0, 0, 0.42),
    inset 0 1px 0 rgba(255, 248, 207, 0.42),
    inset 0 -2px 4px rgba(88, 61, 14, 0.38);
}

.ttp-hw-key--wide {
  min-width: 3.75rem;
  font-size: 8px;
  letter-spacing: 0.08em;
}

.ttp-hw-key--status {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  min-width: 3.75rem;
  height: 2rem;
  border-radius: 0.3rem;
  border: 1px solid rgba(0, 0, 0, 0.5);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.04) 0%, rgba(0, 0, 0, 0.2) 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}

.ttp-hw-pause-icon {
  display: block;
  font-size: 8px;
  letter-spacing: 0.02em;
  line-height: 1;
  opacity: 0.95;
}

/* --- LIVE status LED --- */

.ttp-hw-status-led {
  position: relative;
  width: 0.46rem;
  height: 0.46rem;
  border-radius: 9999px;
  background: radial-gradient(circle at 30% 30%, #5d636f 0%, #353a43 60%, #232831 100%);
  border: 1px solid rgba(18, 20, 24, 0.85);
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.12),
    0 0 0 1px rgba(0, 0, 0, 0.4);
}

.ttp-hw-status-led::before,
.ttp-hw-status-led::after {
  content: "";
  position: absolute;
  border-radius: 9999px;
  pointer-events: none;
}

.ttp-hw-status-led::before {
  inset: 0.11rem;
  background: radial-gradient(circle at 35% 30%, rgba(245, 248, 255, 0.32) 0%, rgba(76, 84, 97, 0.35) 42%, rgba(26, 30, 38, 0.92) 100%);
}

.ttp-hw-status-led::after {
  inset: -0.2rem;
  opacity: 0;
  transform: scale(0.86);
}

.ttp-hw-status-led.is-on {
  background: radial-gradient(circle at 34% 32%, #ffe0db 0%, #ff8b7f 38%, #e74937 70%, #8f2218 100%);
  border-color: rgba(122, 25, 20, 0.9);
  box-shadow:
    0 0 8px rgba(248, 113, 113, 0.52),
    0 0 16px rgba(239, 68, 68, 0.34),
    inset 0 1px 1px rgba(255, 239, 236, 0.45);
}

.ttp-hw-status-led.is-on::before {
  inset: 0.1rem;
  background: radial-gradient(circle at 35% 30%, #fff8f4 0%, #ffd5cf 22%, #ff8c80 52%, #d74231 82%, #8f1f16 100%);
}

.ttp-hw-status-led.is-on::after {
  background: radial-gradient(circle, rgba(248, 113, 113, 0.58) 0%, rgba(239, 68, 68, 0.28) 48%, rgba(239, 68, 68, 0.04) 74%, rgba(239, 68, 68, 0) 100%);
  animation: ttp-led-halo-breathe 1600ms ease-in-out infinite;
}

.ttp-hw-status-label {
  font-family: var(--ttp-font-mono);
  font-size: 7px;
  letter-spacing: 0.08em;
  color: rgba(214, 218, 226, 0.86);
  line-height: 1;
}

/* --- Recessed tempo dial. 30-240 BPM across a 300deg sweep;
 *     dialDeg = -150 + ((bpm - 30) / 210) * 300. 120 BPM = -21.429deg. --- */

.ttp-hw-dial-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
  margin-top: 0.1rem;
}

.ttp-hw-dial-label {
  margin: 0;
  font-family: var(--ttp-font-sans);
  font-size: 7px;
  font-weight: 700;
  letter-spacing: 0.2em;
  color: rgba(255, 255, 255, 0.35);
}

.ttp-hw-dial-well {
  position: relative;
  width: 5.5rem;
  height: 5.5rem;
  border-radius: 50%;
  background:
    radial-gradient(circle at 48% 28%, rgba(255, 255, 255, 0.05) 0%, transparent 42%),
    radial-gradient(circle at 50% 55%, #2a2c32 0%, #16181d 58%, #08090b 100%);
  box-shadow:
    inset 0 5px 16px rgba(0, 0, 0, 0.88),
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    0 3px 8px rgba(0, 0, 0, 0.48);
  border: 1px solid rgba(0, 0, 0, 0.62);
}

.ttp-hw-dial-knob {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 3.65rem;
  height: 3.65rem;
  margin-left: -1.825rem;
  margin-top: -1.825rem;
  border-radius: 50%;
  background:
    radial-gradient(circle at 32% 26%, rgba(255, 255, 255, 0.14) 0%, transparent 40%),
    linear-gradient(155deg, #4a4d54 0%, #2e3138 48%, #1a1c21 100%);
  box-shadow:
    0 3px 9px rgba(0, 0, 0, 0.55),
    inset 0 1px 2px rgba(255, 255, 255, 0.1),
    inset 0 -3px 6px rgba(0, 0, 0, 0.48);
  border: 1px solid rgba(0, 0, 0, 0.5);
  transform-origin: 50% 50%;
  pointer-events: none;
}

.ttp-hw-dial-dot {
  position: absolute;
  left: 50%;
  top: 5px;
  width: 7px;
  height: 7px;
  margin-left: -3.5px;
  border-radius: 50%;
  background: #fafafa;
  box-shadow:
    0 0 6px rgba(255, 255, 255, 0.5),
    inset 0 -1px 2px rgba(0, 0, 0, 0.25);
}

/* -----------------------------------------------------------------------------
 * 16. METRONOME WIDGET CHROME — expanded panel
 * Studio source reference: FloatingMetronomeWidget.tsx:343-591
 *
 * Promo simplification: Studio portals this widget to document.body as a
 * draggable `position: fixed` card at z-[200] that starts collapsed. The promo
 * places it in a static column and keeps it expanded, so the console and the
 * metronome read in one frame and the product layout never moves under the
 * camera. Studio's 168px collapsed card is therefore not reproduced.
 * -------------------------------------------------------------------------- */

/* Expanded panel. Border re-tints with the practice mode; the chassis never
 * tints (metronome-reference.md §5). */
.ttp-metro-panel {
  width: 100%;
  border-radius: var(--ttp-radius-3xl);
  border: 1px solid rgba(6, 182, 212, 0.28);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.03) 0%, transparent 28%),
    linear-gradient(180deg, var(--ttp-mat-panel) 0%, var(--ttp-mat-panel-deep) 100%);
  padding: 1.25rem 1.25rem 2rem;
  box-shadow: var(--ttp-shadow-console-depth);
  transition: border-color 220ms var(--ttp-press-ease);
}

.ttp-metro-panel.is-mode-violet {
  border-color: rgba(139, 92, 246, 0.32);
}

.ttp-metro-panel.is-mode-amber {
  border-color: rgba(212, 175, 55, 0.3);
}

.ttp-metro-close {
  position: absolute;
  right: 0.75rem;
  top: 0.75rem;
  z-index: 3;
  flex-shrink: 0;
  border-radius: 9999px;
  padding: 0.375rem 0.75rem;
  font-family: inherit;
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  line-height: 1;
  letter-spacing: 0.05em;
  color: #f4f4f5;}

.ttp-metro-hw-slot {
  margin-bottom: 0.75rem;
  padding-top: 2.25rem;
}

.ttp-metro-stepper-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  margin-bottom: 1rem;
}

.ttp-metro-step {
  display: flex;
  min-height: 2.75rem;
  min-width: 2.75rem;
  align-items: center;
  justify-content: center;
  border-radius: var(--ttp-radius-xl);
  padding: 0.5rem 0;
  font-family: var(--ttp-font-mono);
  font-size: 18px;
  line-height: 1;
  color: #f4f4f5;
}

.ttp-metro-bpm-big {
  margin: 0;
  min-width: 7rem;
  text-align: center;
  font-family: var(--ttp-font-mono);
  font-size: 24px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.015em;
  color: #fafafa;
}

.ttp-metro-bpm-unit {
  margin-left: 0.5rem;
  font-family: var(--ttp-font-sans);
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: #d4d4d8;
}

.ttp-metro-startstop {
  display: inline-flex;
  width: 100%;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
  border-radius: 9999px;
  padding: 0.75rem 1.5rem;
  margin-bottom: 0.75rem;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  line-height: 1;
  letter-spacing: 0.12em;
  color: var(--ttp-text);}

.ttp-metro-startstop.is-active {
  color: var(--ttp-ink);
}

.ttp-metro-volume {
  margin-bottom: 1rem;
  padding: 0 0.125rem;
}

.ttp-metro-volume-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}

.ttp-metro-field-label {
  font-family: var(--ttp-font-sans);
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: #a1a1aa;
}

.ttp-metro-volume-value {
  font-family: var(--ttp-font-mono);
  font-size: 10px;
  font-variant-numeric: tabular-nums;
  color: rgba(165, 243, 252, 0.9);
}

.ttp-metro-rail {
  display: flex;
  align-items: center;
  border-radius: 9999px;
  padding: 7px 10px;
  background: linear-gradient(180deg, #060606 0%, #101012 45%, #0a0a0c 100%);
  border: 1px solid rgba(85, 85, 98, 0.55);
  box-shadow:
    inset 0 4px 16px rgba(0, 0, 0, 0.82),
    inset 0 1px 0 rgba(255, 255, 255, 0.05),
    0 2px 6px rgba(0, 0, 0, 0.55);
}

/* Static 70% readout, rendered from elements for the same crispness reason as
 * the transport timeline. */
.ttp-metro-volume-slider {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  height: 16px;
  --ttp-metro-trk: 9px;
  --ttp-metro-thumb: 15px;
}

.ttp-metro-volume-track {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: var(--ttp-metro-trk);
  margin-top: calc(var(--ttp-metro-trk) / -2);
  border-radius: 9999px;
  background: linear-gradient(180deg, #020202 0%, #121215 38%, #28282f 62%, #16161a 100%);
  border: 1px solid rgba(130, 130, 145, 0.5);
  box-shadow:
    inset 0 4px 12px rgba(0, 0, 0, 0.9),
    inset 0 1px 0 rgba(255, 255, 255, 0.06);
}

.ttp-metro-volume-thumb {
  position: absolute;
  top: 50%;
  left: 70%;
  height: var(--ttp-metro-thumb);
  width: var(--ttp-metro-thumb);
  margin: calc(var(--ttp-metro-thumb) / -2) 0 0 calc(var(--ttp-metro-thumb) / -2);
  border-radius: 9999px;
  background: linear-gradient(155deg, #fffef5 0%, #f2e088 18%, #e8c860 48%, #a67c1a 82%, #4a3208 100%);
  border: 1px solid rgba(0, 0, 0, 0.45);
  box-shadow:
    0 2px 5px rgba(0, 0, 0, 0.6),
    0 0 12px rgba(34, 211, 238, 0.12),
    inset 0 2px 4px rgba(255, 255, 255, 0.4),
    inset 0 -3px 5px rgba(0, 0, 0, 0.35);
}

.ttp-metro-beat {
  margin-bottom: 0.75rem;
}

.ttp-metro-beat-label {
  margin: 0 0 0.375rem;
  font-family: var(--ttp-font-sans);
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ttp-muted);
}

.ttp-metro-ts-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.375rem;
}

.ttp-metro-ts {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--ttp-radius-xl);
  padding: 0.5rem 0;
  font-family: var(--ttp-font-mono);
  font-size: 11px;
  font-weight: 600;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: #d4d4d8;
  text-align: center;
}

.ttp-metro-ts.is-on-cyan {
  color: #ecfeff;
}

.ttp-metro-ts.is-on-violet {
  color: #f5f3ff;
}

/* Accent pattern is derived from the time signature, never stored
 * (metronome-reference.md §10) — the promo renders it from one source too. */
.ttp-metro-accent {
  margin: 0.5rem 0 0;
  font-family: var(--ttp-font-mono);
  font-size: 9px;
  line-height: 1.625;
  color: rgba(154, 143, 126, 0.85);
}

.ttp-metro-accent-key {
  color: rgba(232, 200, 96, 0.9);
}

.ttp-metro-accent-legend {
  margin-left: 0.25rem;
  font-family: var(--ttp-font-sans);
  font-size: 8px;
  font-weight: 400;
  text-transform: none;
  color: rgba(154, 143, 126, 0.55);
}

.ttp-metro-tap {
  display: inline-flex;
  width: 100%;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
  border-radius: 9999px;
  padding: 0.75rem 1.5rem;
  margin-bottom: 0.75rem;
  font-family: inherit;
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  line-height: 1;
  letter-spacing: 0.14em;
  color: var(--ttp-text);
}

.ttp-metro-reset {
  display: inline-flex;
  width: 100%;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
  border-radius: 9999px;
  padding: 0.5rem 1rem;
  margin-bottom: 0.75rem;
  font-family: inherit;
  font-size: 11px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.06em;
  color: var(--ttp-gold);
}

.ttp-metro-footer {
  margin: 0.5rem 0 0;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  padding: 1rem 0 0.25rem;
  text-align: center;
  font-family: var(--ttp-font-display);
  font-size: 9px;
  letter-spacing: 0.18em;
  color: rgba(232, 200, 96, 0.55);
}

/* -----------------------------------------------------------------------------
 * 17. RESPONSIVE
 * Studio source reference: multitrack-reference.md §10, metronome-reference.md §11
 *
 * The promo does not reproduce Studio's full three-column responsive shell.
 * Breakpoints are aligned to this site's existing homepage set
 * (1320 / 1100 / 900 / 768 / 480) rather than the reference pack's single
 * 640px breakpoint, so a future homepage integration inherits one scale.
 * -------------------------------------------------------------------------- */

/* --- Cinematic tiers -------------------------------------------------------
 * The product is laid out at a FIXED design width per tier and the camera fits
 * it to the stage. Composition is therefore identical at 1920 and at 1280 —
 * only the fit scale differs — instead of the layout reflowing under the
 * camera. Mobile gets its own width, its own depth, and its own pose table in
 * the driver; it is not the desktop composition squeezed into 390px.
 * -------------------------------------------------------------------------- */

@media (min-width: 1440px) {
  .ttp-stage {
    --ttp-product-w: 1280px;
    --ttp-thick: 90px;
  }
}

@media (max-width: 1320px) {
  .ttp-root {
    --ttp-nameplate-w: 15rem;
  }

  .ttp-channel-grid {
    column-gap: 0.75rem;
  }

  .ttp-knob-strip {
    column-gap: 0.5rem;
  }
}

@media (max-width: 1100px) {
  /* Tablet: single column. Full mixer readability is retained — the metronome
   * moves below the console rather than shrinking the channel strips.
   * Perspective depth and camera travel are reduced by the driver's tablet
   * pose table; the hardware thickness drops with them. */
  .ttp-stage {
    --ttp-product-w: 880px;
    --ttp-thick: 54px;
    --ttp-safe-x: clamp(2.5rem, 7%, 5.5rem);
    --ttp-safe-y: clamp(2.85rem, 9%, 5rem);
    --ttp-safe-x-side: clamp(2.5rem, 7%, 6rem);
  }

  .ttp-root {
    --ttp-gold-edge: 3px;
    --ttp-gold-edge-s: 4px;
  }

  /* Portrait has no free column beside the product, so the opening titles stop
   * being a side panel and become a centred title card in the band of stage
   * above the console — which is where the driver's portrait poses push the
   * product down to make room. */
  .ttp-titles {
    left: 50%;
    top: clamp(4.5rem, 13vh, 10rem);
    width: min(30rem, 84vw);
    transform: translateX(-50%);
    text-align: center;
  }

  .ttp-title-logo {
    width: clamp(150px, 34vw, 250px);
  }

  .ttp-superline {
    left: 50%;
    right: auto;
    bottom: var(--ttp-safe-y);
    width: min(30rem, 86vw);
    max-width: none;
    transform: translateX(-50%) translateY(var(--ttp-y, 10px));
    text-align: center;
  }

  /* Centred type does not take a left rule without looking lopsided. */
  .ttp-superline span,
  .ttp-metro-title-block {
    padding-left: 0;
    border-left: 0;
  }

  /* Portrait frames are filled edge to edge by the product, so both the supers
   * and the lockup need a deeper pool of shade behind them than the wides do. */
  .ttp-superline::before {
    inset: -300% -22%;
  }

  .ttp-endcard::before {
    inset: -170% -78%;
    background: radial-gradient(ellipse at center,
      rgba(2, 2, 6, 0.9) 0%,
      rgba(2, 2, 6, 0.74) 30%,
      rgba(2, 2, 6, 0.36) 54%,
      rgba(2, 2, 6, 0) 76%);
  }

  /* Portrait metronome fills the column, so the title leaves the side panel
   * and sits in the same bottom band as the other feature supers. */
  .ttp-metro-title {
    left: 50%;
    top: auto;
    bottom: var(--ttp-safe-y);
    width: min(30rem, 86vw);
    transform: translateX(-50%);
    text-align: center;
  }

  .ttp-console {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Stacked layout: the metronome sits under the console rather than beside it.
   * Centring it keeps the closing portrait frame balanced — left-aligned, the
   * narrow chassis leaves a large empty plate to its right. */
  .ttp-metro-col {
    justify-content: center;
  }

  .ttp-root {
    --ttp-nameplate-w: 13rem;
  }

  .ttp-channel-grid {
    grid-template-columns: 2.25rem minmax(0, 1fr) auto;
  }

  .ttp-knob-row {
    grid-column: 2 / -1;
  }

  .ttp-deck-title {
    font-size: 1.5rem;
  }
}

@media (max-width: 900px) {
  .ttp-transport-row {
    flex-direction: column;
    align-items: stretch;
  }

  .ttp-transport {
    align-items: center;
  }

  .ttp-preset-row {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (max-width: 768px) {
  /* Mobile promo layout. Five full channel strips will not read side by side,
   * so each strip stacks: badge + nameplate, then meter, then S/M + Vol.
   * PRESENTATION SIMPLIFICATION: the Low / Mid / High EQ knobs are hidden.
   * The real Studio channel strip keeps all four knobs at every width and
   * wraps them two-up instead (multitrack-reference.md §10). */
  .ttp-stage {
    --ttp-product-w: min(400px, calc(100vw - 18px));
    --ttp-thick: 26px;
    /* Tighter than desktop, still clear of the crop. */
    --ttp-safe-x: clamp(1.35rem, 6%, 2.75rem);
    --ttp-safe-y: clamp(2rem, 8%, 3.5rem);
    --ttp-safe-x-side: clamp(1.35rem, 6%, 2.75rem);
  }

  /* Mobile framing is a close crop. Keep a center dark field for readability
   * without restoring a rectangular rim. */
  .ttp-vignette {
    background: radial-gradient(ellipse 62% 58% at 50% 46%, rgba(0, 0, 0, 0.28) 0%, rgba(0, 0, 0, 0.1) 46%, transparent 76%);
  }

  .ttp-light--haze {
    background:
      linear-gradient(180deg, rgba(6, 8, 16, 0.1) 0%, transparent 22%),
      linear-gradient(0deg, rgba(6, 8, 18, 0.16) 0%, transparent 28%);
  }

  .ttp-light--backdrop {
    background:
      radial-gradient(ellipse 56% 58% at 50% 44%,
        rgba(5, 6, 14, 0.96) 0%,
        rgba(6, 8, 16, 0.9) 32%,
        rgba(7, 9, 18, 0.72) 58%,
        rgba(8, 11, 22, 0.32) 78%,
        transparent 100%),
      radial-gradient(ellipse 70% 54% at 50% 36%, rgba(96, 86, 152, 0.12) 0%, transparent 62%);
  }

  .ttp-metro-shell {
    width: 100%;
    max-width: 100%;
  }

  .ttp-faceplate {
    padding: 0.5rem;
    border-radius: var(--ttp-radius);
  }

  .ttp-root {
    --ttp-gold-edge: 2px;
    --ttp-gold-edge-s: 3px;
  }

  .ttp-depth--back,
  .ttp-plate-rim,
  .ttp-sheen {
    border-radius: var(--ttp-radius);
  }

  .ttp-deck-section,
  .ttp-mixer {
    padding: 0.75rem;
  }

  .ttp-deck-panel {
    padding: 0.75rem;
  }

  .ttp-root {
    --ttp-nameplate-w: 100%;
  }

  .ttp-channel-grid {
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: 0.625rem;
    row-gap: 0.5rem;
  }

  .ttp-col-body {
    grid-column: 2;
  }

  .ttp-sm-col {
    grid-column: 1 / -1;
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
    gap: 0.75rem;
  }

  .ttp-knob-row {
    grid-column: 1 / -1;
    justify-content: flex-end;
  }

  .ttp-knob-strip {
    justify-content: flex-end;
    column-gap: 0.75rem;
  }

  .ttp-knob-cell.ttp-knob-cell--eq {
    display: none;
  }

  .ttp-knob-cell {
    flex: 0 0 auto;
  }

  .ttp-play-hero {
    width: 4.5rem;
    height: 4.5rem;
  }

  .ttp-timeline-card {
    padding: 1rem;
  }

  .ttp-deck-title {
    font-size: 1.3rem;
  }

  .ttp-btn-utility {
    flex: 1 1 auto;
    letter-spacing: 0.08em;
    padding: 0.625rem 0.75rem;
  }
}

@media (max-width: 480px) {
  .ttp-meter-scale {
    font-size: 7px;
  }

  .ttp-badge {
    font-size: 1rem;
    min-width: 2.25rem;
  }

  .ttp-badge--master {
    font-size: 0.7rem;
    min-width: 4.25rem;
  }
}

/* -----------------------------------------------------------------------------
 * 18. REDUCED MOTION
 * Studio disables the marquee, both LCD ambient animations and the knob arc
 * transition under prefers-reduced-motion (demo-sequence.md rule 8,
 * player-console.css:358-363). The promo additionally freezes the meter
 * oscillation, the Solo pulse, the LED halo breathe and the beat LED cycle —
 * the JS never starts its animation loop and renders a single static frame.
 * -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .ttp-root .ttp-pulse-red,
  .ttp-root .ttp-led-status.is-solo-on::after,
  .ttp-root .ttp-hw-status-led.is-on::after,
  .ttp-root .ttp-hw-chassis--active .ttp-hw-lcd-inner,
  .ttp-root .ttp-hw-chassis--active .ttp-hw-lcd-inner::before,
  .ttp-root .ttp-float,
  .ttp-root .ttp-sheen,
  .ttp-root .ttp-sheen::before {
    animation: none;
  }

  .ttp-root .ttp-led-status.is-solo-on::after,
  .ttp-root .ttp-hw-status-led.is-on::after {
    opacity: 0.7;
    transform: scale(1);
  }

  .ttp-root .ttp-knob-arc,
  .ttp-root .ttp-knob-cap,
  .ttp-root .ttp-knob-well,
  .ttp-root .ttp-led,
  .ttp-root .ttp-channel,
  .ttp-root .ttp-slider-rail,
  .ttp-root .ttp-metro-panel,
  .ttp-root .ttp-readiness,
  .ttp-root .ttp-key-spot,
  .ttp-root .ttp-light--red,
  .ttp-root .ttp-light--cyan,
  .ttp-root .ttp-light--gold,
  .ttp-root .ttp-camera,
  .ttp-root .ttp-gimbal,
  .ttp-root .ttp-press {
    transition: none;
  }

  /* No camera sequence. The driver never starts its loop and renders one
   * static front-facing hero composition instead; the float animation, the
   * reveal sheen and every accent cross-fade above are already disabled, so
   * the frame is genuinely still. */
  .ttp-root .ttp-float {
    transform: none;
  }

  .ttp-root .ttp-sheen {
    opacity: 0;
  }

  .ttp-sound-toggle {
    display: none;
  }
}

@media (max-width: 1100px) {
  .ttp-stage {
    height: clamp(540px, 58vh, 700px);
  }
}

@media (max-width: 768px) {
  .ttp-stage {
    height: 560px;
    border-radius: 0;
  }
}

@media (max-width: 480px) {
  .ttp-stage {
    height: 540px;
    border-radius: 0;
  }
}

/* Final front lock: product geometry is frozen before transport stop / meter
 * release. Float animation is fully off (not merely amplitude 0) so the
 * preserve-3d layer cannot subpixel-jitter. Press travel is disabled so the
 * Pause→Play state change cannot dip the transport 1px. */
.ttp-root.is-geometry-locked .ttp-float {
  animation: none !important;
  transform: none !important;
}

.ttp-root.is-geometry-locked .ttp-camera,
.ttp-root.is-geometry-locked .ttp-gimbal,
.ttp-root.is-geometry-locked .ttp-press,
.ttp-root.is-geometry-locked .ttp-key-spot,
.ttp-root.is-geometry-locked .ttp-light--key,
.ttp-root.is-geometry-locked .ttp-light--floor,
.ttp-root.is-geometry-locked .ttp-contact,
.ttp-root.is-geometry-locked .ttp-plate-rim {
  transition: none;
}

.ttp-root.is-geometry-locked .ttp-press.is-pressed {
  transform: none;
}

.ttp-root.is-geometry-locked .ttp-pulse-red,
.ttp-root.is-geometry-locked .ttp-led-status.is-solo-on::after,
.ttp-root.is-geometry-locked .ttp-hw-status-led.is-on::after,
.ttp-root.is-geometry-locked .ttp-hw-chassis--active .ttp-hw-lcd-inner,
.ttp-root.is-geometry-locked .ttp-hw-chassis--active .ttp-hw-lcd-inner::before,
.ttp-root.is-geometry-locked .ttp-readiness {
  animation: none !important;
}

.ttp-root.is-geometry-locked .ttp-readiness {
  opacity: 0;
  transform: none;
}
.ttp-root.is-complete .ttp-float,
.ttp-root.is-complete .ttp-sheen,
.ttp-root.is-complete .ttp-sheen::before,
.ttp-root.is-complete .ttp-pulse-red,
.ttp-root.is-complete .ttp-led-status.is-solo-on::after,
.ttp-root.is-complete .ttp-hw-status-led.is-on::after,
.ttp-root.is-complete .ttp-hw-chassis--active .ttp-hw-lcd-inner,
.ttp-root.is-complete .ttp-hw-chassis--active .ttp-hw-lcd-inner::before {
  animation: none;
}

.ttp-root.is-complete *,
.ttp-root.is-complete *::before,
.ttp-root.is-complete *::after {
  animation: none !important;
}

.ttp-root.is-complete .ttp-camera,
.ttp-root.is-complete .ttp-gimbal,
.ttp-root.is-complete .ttp-key-spot,
.ttp-root.is-complete .ttp-light--red,
.ttp-root.is-complete .ttp-light--cyan,
.ttp-root.is-complete .ttp-light--gold,
.ttp-root.is-complete .ttp-light--key,
.ttp-root.is-complete .ttp-light--floor,
.ttp-root.is-complete .ttp-press,
.ttp-root.is-complete .ttp-contact,
.ttp-root.is-complete .ttp-depth--top,
.ttp-root.is-complete .ttp-depth--right,
.ttp-root.is-complete .ttp-plate-rim {
  transition: none;
}

.ttp-root.is-complete .ttp-float {
  transform: none;
}

.ttp-root.is-complete .ttp-sheen {
  opacity: 0;
}

.ttp-root.is-complete .ttp-key-spot {
  will-change: auto;
}

/* Finished poster lighting. Applied from the front shot so freezeHero does
 * not pop key/floor opacity when data-ttp-playback becomes completed. */
.ttp-stage.ttp-shot-front .ttp-light--key,
.ttp-stage[data-ttp-playback="completed"] .ttp-light--key {
  opacity: 0.78;
}

.ttp-stage.ttp-shot-front .ttp-light--floor,
.ttp-stage[data-ttp-playback="completed"] .ttp-light--floor {
  opacity: 0.6;
}

.ttp-stage[data-ttp-playback="completed"] .ttp-contact {
  opacity: 1;
}

.ttp-stage[data-ttp-playback="completed"] .ttp-plate-rim {
  opacity: 1;
}

.ttp-stage[data-ttp-playback="completed"] .ttp-endcard-icon {
  opacity: 1;
}

.ttp-stage[data-ttp-playback="completed"] .ttp-endcard-name {
  color: #f6f3ec;
  text-shadow:
    0 2px 28px rgba(0, 0, 0, 0.88),
    0 0 36px rgba(232, 200, 96, 0.12);
}

.ttp-stage[data-ttp-playback="completed"] .ttp-endcard-line {
  color: rgba(242, 236, 226, 0.84);
  text-shadow: 0 2px 22px rgba(0, 0, 0, 0.88);
}
