  :root {
    color-scheme: dark;
    --ink: #05070a;
    --glass: rgba(255, 244, 220, 0.07);
    --glass-strong: rgba(255, 244, 220, 0.09);
    --panel: #161d25;
    --line: rgba(255, 180, 90, 0.2);
    --text: #f2ebe1;
    --dim: #a9a094;
    --phosphor: #ffb45a;
    --ok: #8fd9b8;
    --bad: #ff7a7a;
    --chrome-ease: 420ms cubic-bezier(0.22, 1, 0.36, 1);
  }
  * { box-sizing: border-box; }
  html, body {
    margin: 0;
    width: 100%;
    height: 100%;
    overflow: hidden;
    background: #000;
    color: var(--text);
    font: 12px/1.4 "IBM Plex Mono", ui-monospace, monospace;
  }
  a { color: var(--phosphor); text-decoration: none; }
  a:hover { filter: brightness(1.1); }
  button, input, select, textarea { font: inherit; color: var(--text); }
  button, input, select, textarea {
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid var(--line);
    border-radius: 2px;
    padding: 4px 7px;
  }
  select, option {
    color: var(--text);
    background-color: var(--panel);
  }
  /* `hidden` must actually hide. Any rule that sets display (.field is flex, .rec-countdown
     was flex) silently outranks the UA's [hidden]{display:none}, and the failure mode is a
     control that is supposed to be gone still sitting there — it has bitten twice. */
  [hidden] { display: none !important; }

  button { cursor: pointer; }
  button:hover { border-color: rgba(255, 180, 90, 0.45); background: rgba(255, 180, 90, 0.1); }
  button:focus-visible,
  a:focus-visible,
  summary:focus-visible,
  input:focus-visible,
  select:focus-visible,
  textarea:focus-visible,
  /* The recorder's focus sink is a visually hidden textarea, so its own ring cannot be
     seen. Put the ring on the surface that visually has focus instead — without this a
     keyboard user has no idea whether their typing is going to the page. */
  .rec-screen:has(#recInput:focus-visible) {
    outline: 2px solid var(--phosphor);
    outline-offset: 2px;
  }
  button.primary {
    background: var(--phosphor);
    color: #1a1005;
    border-color: var(--phosphor);
    font-weight: 500;
  }
  button.primary:hover { filter: brightness(1.06); }
  button:disabled { opacity: .45; cursor: default; }
  button.ghost {
    background: transparent;
    border-color: transparent;
    color: var(--dim);
    padding: 4px 6px;
  }
  button.ghost:hover { color: var(--text); border-color: var(--line); }
  button.ghost.is-active { color: var(--phosphor); border-color: var(--line); background: rgba(255, 180, 90, 0.1); }
  label.field { display: flex; align-items: center; gap: 5px; color: var(--dim); white-space: nowrap; }
  .mini { font-size: 10px; color: var(--dim); }
  .grow { flex: 1 1 auto; min-width: 0; }

  /* Full-bleed stage */
  .stage-wrap {
    position: fixed;
    inset: 0;
    z-index: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #000;
    overflow: hidden;
  }
  /* AF point marker — a camera-style crosshair at the clicked focus depth, not a DoF zone. */
  .focus-reticle {
    position: absolute;
    width: 22px;
    height: 22px;
    pointer-events: none;
    z-index: 2;
    display: none;
    transform: translate(-50%, -50%);
  }
  .focus-reticle::before,
  .focus-reticle::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    background: rgba(255, 180, 90, 0.9);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.4);
  }
  .focus-reticle::before {
    width: 22px;
    height: 1px;
    transform: translate(-50%, -50%);
  }
  .focus-reticle::after {
    width: 1px;
    height: 22px;
    transform: translate(-50%, -50%);
  }
  canvas#stage {
    display: block;
    max-width: 100%;
    max-height: 100%;
    background: #000;
  }
  /*
    First-run state, centred in the stage. The canvas is 16x9 *pixels* until a source sets
    its real size, so before this existed the page was an empty black rectangle and the only
    way in was a button in the side panel.
  */
  .stage-empty {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 14px;
    padding: 24px;
    text-align: center;
    /* Sit above the canvas but below the panel and the transport bar. */
    z-index: 1;
    pointer-events: none;   /* only the button is interactive, so hover still wakes chrome */
  }
  .stage-empty h1 {
    margin: 0;
    /* vw alone overflows a narrow phone: 30 monospace characters do not fit in 390px. */
    font-size: clamp(19px, 4.4vw, 38px);
    font-weight: 500;
    letter-spacing: -0.01em;
    color: var(--text);
    max-width: 18ch;
    overflow-wrap: break-word;
    text-wrap: balance;
  }
  .stage-empty p {
    margin: 0;
    max-width: 46ch;
    color: var(--dim);
    font-size: clamp(12px, 1.3vw, 15px);
    line-height: 1.5;
  }
  .stage-empty button {
    pointer-events: auto;
    margin-top: 4px;
    padding: 11px 22px;
    font-size: 15px;
    border-radius: 8px;
  }
  .stage-empty-fine { opacity: .72; font-size: 12px !important; }
  .stage-empty-warn {
    color: #ffb45a;
    border: 1px solid rgba(255, 180, 90, 0.35);
    border-radius: 6px;
    padding: 8px 12px;
    background: rgba(255, 180, 90, 0.07);
  }
  /* Once a take exists the stage speaks for itself. */
  body[data-has-source] .stage-empty { display: none; }
  /*
    Before a source exists there is no timeline to scrub and no frame to pose, so the
    transport is a bar of dead controls — and on a phone it sits directly on top of the one
    button that matters. The focus reticle likewise marks a point on footage that is not
    there yet, and reads as a stray artifact in the middle of the copy.

    Scoped to standalone: the local Studio drives the transport from a loaded job, which
    never goes through adoptTake and so never sets data-has-source.
  */
  body[data-standalone]:not([data-has-source]) #transportChrome,
  body[data-standalone]:not([data-has-source]) .focus-reticle { display: none; }
  #liveframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
    background: #000;
  }

  /* Overlay chrome — light glass, hug content */
  .chrome {
    position: fixed;
    z-index: 2;
    backdrop-filter: blur(6px) saturate(1.25);
    -webkit-backdrop-filter: blur(6px) saturate(1.25);
    background: var(--glass);
    border: 1px solid var(--line);
    box-shadow: 0 6px 22px rgba(0, 0, 0, 0.18);
    transition:
      opacity var(--chrome-ease),
      transform var(--chrome-ease),
      visibility var(--chrome-ease);
  }
  .chrome-bottom {
    left: 50%;
    right: auto;
    bottom: 12px;
    transform: translateX(-50%);
    width: min(560px, calc(100vw - 280px));
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 7px 10px;
    border-radius: 999px;
  }
  .chrome-bottom.has-cam-keys {
    border-radius: 14px;
    width: min(640px, calc(100vw - 280px));
    padding: 8px 12px 10px;
    gap: 6px;
  }
  .transport-row {
    display: flex;
    align-items: center;
    gap: 8px;
  }
  .scrub-wrap {
    position: relative;
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
  }
  .scrub-wrap input[type=range] {
    width: 100%;
    margin: 0;
    position: relative;
    z-index: 1;
  }
  #keyMarkers {
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    height: 0;
    pointer-events: none;
    z-index: 2;
  }
  .key-marker {
    position: absolute;
    top: 0;
    width: 10px;
    height: 10px;
    margin-left: -5px;
    margin-top: -5px;
    background: var(--phosphor);
    border: 1px solid rgba(26, 16, 5, 0.85);
    transform: rotate(45deg);
    pointer-events: auto;
    cursor: grab;
    box-shadow: 0 0 0 1px rgba(255, 180, 90, 0.25);
  }
  .key-marker:hover { filter: brightness(1.12); }
  .key-marker.is-selected {
    background: #fff0d4;
    box-shadow: 0 0 0 2px rgba(255, 180, 90, 0.55);
    outline: 1px solid rgba(26, 16, 5, 0.9);
  }
  .key-marker:focus-visible {
    outline: 2px solid #fff0d4;
    outline-offset: 2px;
  }
  .key-marker.is-dragging { cursor: grabbing; }
  .frame-label {
    color: var(--dim);
    min-width: 78px;
    font-variant-numeric: tabular-nums;
    font-size: 11px;
  }
  #camKeysPanel {
    display: none;
    flex-direction: column;
    gap: 6px;
    padding-top: 2px;
    border-top: 1px solid rgba(255, 180, 90, 0.14);
  }
  .chrome-bottom.has-cam-keys #camKeysPanel { display: flex; }
  .cam-keys-row {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
  }
  .cam-keys-row button {
    padding: 3px 7px;
    font-size: 11px;
  }
  .cam-keys-row select {
    padding: 3px 5px;
    font-size: 11px;
    max-width: 132px;
  }
  .ease-graph-wrap {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-left: auto;
  }
  #easeGraph {
    display: block;
    width: 72px;
    height: 48px;
    border: 1px solid rgba(255, 180, 90, 0.22);
    border-radius: 3px;
    background: rgba(0, 0, 0, 0.35);
    flex: 0 0 auto;
  }
  .cam-moves-row {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-wrap: wrap;
    padding-top: 2px;
  }
  .cam-moves-row .moves-label { flex: 0 0 auto; margin-right: 2px; }
  #camMoveChips { display: inline-flex; gap: 4px; flex-wrap: wrap; }
  .move-chip {
    padding: 3px 8px;
    font-size: 11px;
    border-radius: 999px;
  }
  .strength-seg {
    display: inline-flex;
    margin-left: auto;
    border: 1px solid var(--line);
    border-radius: 999px;
    overflow: hidden;
  }
  .strength-seg button {
    border: 0;
    border-radius: 0;
    padding: 3px 7px;
    font-size: 10px;
    background: transparent;
    color: var(--dim);
  }
  .strength-seg button.is-active {
    background: rgba(255, 180, 90, 0.16);
    color: var(--phosphor);
  }
  .pose-chip {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 10px;
    color: var(--phosphor);
    padding: 0 2px;
  }
  /* display:flex outranks the UA's [hidden] rule — restate it or the chip never hides. */
  .pose-chip[hidden] { display: none; }
  .pose-chip button { padding: 2px 7px; font-size: 10px; }
  /* Live mode shows a snapshot, not job frames — keyframe authoring is meaningless there. */
  .cam-live-disabled { opacity: 0.45; pointer-events: none; }
  .chrome-side {
    top: 12px;
    right: 12px;
    bottom: auto;
    width: min(248px, calc(100vw - 24px));
    max-height: calc(100vh - 24px);
    overflow-y: auto;
    overflow-x: hidden;
    padding: 8px 9px 12px;
    border-radius: 8px;
    background: var(--glass-strong);
  }
  .chrome-side::-webkit-scrollbar { width: 6px; }
  .chrome-side::-webkit-scrollbar-thumb {
    background: rgba(255, 180, 90, 0.22);
    border-radius: 3px;
  }

  /* Auto-hide */
  body.chrome-hidden .chrome {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
  }
  body.chrome-hidden .chrome-bottom { transform: translate(-50%, 12px); }
  body.chrome-hidden .chrome-side { transform: translateX(14px); }
  /* During an active key session the transport is the workspace — exempt it from
     auto-hide (the side panel still fades). */
  body.chrome-hidden .chrome-bottom.has-keys {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: translateX(-50%);
  }
  body.chrome-pinned .chrome,
  body:not(.chrome-hidden) .chrome {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
  }
  body.chrome-pinned .chrome-side,
  body:not(.chrome-hidden) .chrome-side {
    transform: none;
  }
  body.chrome-pinned .chrome-bottom,
  body:not(.chrome-hidden) .chrome-bottom {
    transform: translateX(-50%);
  }

  /* Centered New-capture overlay — the guided path to a first job. */
  .capture-overlay {
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: min(420px, calc(100vw - 24px));
    padding: 14px 16px;
    border-radius: 10px;
    background: var(--glass-strong);
    z-index: 3;
    display: flex;
    flex-direction: column;
    gap: 8px;
  }
  .capture-overlay[hidden] { display: none; }
  .capture-overlay .cap-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
  .capture-overlay h2 {
    margin: 0;
    font-family: Syne, sans-serif;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
  }
  .motion-radios {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    color: var(--dim);
    margin: 4px 0;
  }
  .motion-radios label { display: flex; gap: 4px; align-items: center; }
  /* A form mid-capture must not fade away with the idle chrome. */
  body.chrome-hidden .capture-overlay:not([hidden]) {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: translate(-50%, -50%);
  }

  .wake-hint {
    position: fixed;
    left: 50%;
    bottom: 14px;
    transform: translateX(-50%);
    z-index: 1;
    color: rgba(242, 235, 225, 0.72);
    font-size: 10px;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    pointer-events: none;
    opacity: 0;
    transition: opacity 500ms ease;
  }
  body.chrome-hidden:not(.chrome-pinned) .wake-hint { opacity: 1; }
  /* No wake hint while the transport is exempt from auto-hide (active key session) —
     it would fade in directly behind the still-visible bottom bar. */
  body.chrome-hidden:has(.chrome-bottom.has-keys) .wake-hint { opacity: 0; }

  @media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
      animation-duration: 0.01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 0.01ms !important;
    }
  }

  .side-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
    margin-bottom: 8px;
  }
  .side-head .mark {
    font-family: Syne, sans-serif;
    font-size: 0.72rem;
    font-weight: 800;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text);
    text-decoration: none;
  }
  .side-head .mark span { color: var(--phosphor); }
  .side-head-tools { display: flex; gap: 2px; align-items: center; }
  .side-tools {
    display: grid;
    gap: 5px;
    margin-bottom: 8px;
    padding-bottom: 8px;
    border-bottom: 1px solid rgba(255, 180, 90, 0.12);
  }
  .side-tools .field { width: 100%; }
  .side-tools .field select { flex: 1; min-width: 0; width: 100%; }
  .live-row {
    display: flex;
    gap: 6px;
    align-items: center;
  }
  .live-row select { flex: 1; min-width: 0; }

  .group { margin: 0; }
  details.group-fold {
    margin: 0 0 2px;
    border-bottom: 1px solid rgba(255, 180, 90, 0.1);
    padding: 2px 0;
  }
  details.group-fold > summary {
    margin: 0;
    padding: 5px 0;
    font-size: 10px;
    letter-spacing: .7px;
  }
  details.group-fold[open] > summary { color: var(--text); }
  details.group-fold .group { padding: 2px 0 6px; }
  .ctl {
    display: grid;
    grid-template-columns: 72px 1fr 40px;
    align-items: center;
    gap: 5px;
    padding: 1px 0;
  }
  .ctl label { color: var(--dim); font-size: 11px; }
  .ctl input[type=range] { width: 100%; }
  .ctl .val {
    text-align: right;
    font-variant-numeric: tabular-nums;
    color: var(--text);
    font-size: 10px;
  }
  /* Plain-language knob hints: hover/focus reveal in Advanced (65 always-on lines
     would triple the panel), always-on in Simple where a dozen rows have the room.
     The hint expands BELOW the row, so the slider under the cursor never shifts. */
  .ctl .hint {
    grid-column: 1 / -1;
    display: none;
    color: var(--dim);
    font-size: 10px;
    line-height: 1.35;
    padding: 0 0 3px;
  }
  .ctl:hover .hint,
  .ctl:focus-within .hint { display: block; }
  body[data-ui-mode="simple"] .ctl .hint { display: block; }
  /* Simple mode: one rule hides every advanced-tier control, fold and card. */
  body[data-ui-mode="simple"] [data-tier="advanced"] { display: none !important; }
  .row { display: flex; gap: 6px; align-items: center; margin: 6px 0; flex-wrap: wrap; }
  .row > * { flex: 0 0 auto; }
  .row .grow { flex: 1 1 auto; }
  .card {
    background: transparent;
    border: 0;
    border-radius: 0;
    padding: 0;
    margin: 0 0 6px;
  }
  .card h2, details.card > summary {
    font-size: 10px;
    margin: 0 0 6px;
    text-transform: uppercase;
    letter-spacing: .6px;
    color: var(--dim);
    cursor: pointer;
    list-style: none;
  }
  details.card > summary::-webkit-details-marker { display: none; }
  details.card > summary::before {
    content: "▸ ";
    color: var(--phosphor);
  }
  details.card[open] > summary::before { content: "▾ "; }
  .progress {
    height: 4px;
    background: rgba(255, 255, 255, 0.05);
    border-radius: 2px;
    overflow: hidden;
    border: 1px solid rgba(255, 180, 90, 0.14);
  }
  .progress > div {
    height: 100%;
    width: 0;
    background: var(--phosphor);
    transition: width .1s linear;
  }
  .status { color: var(--dim); font-size: 11px; min-height: 14px; }
  .status a { color: var(--phosphor); }
  details summary {
    cursor: pointer;
    color: var(--dim);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .6px;
    margin-bottom: 6px;
  }
  textarea {
    width: 100%;
    height: 88px;
    resize: vertical;
    font-family: ui-monospace, Menlo, Consolas, monospace;
    font-size: 11px;
  }
  .grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; }
  #gpu { max-width: 140px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  @media (max-width: 860px) {
    /* .has-cam-keys (always on now) carries its own width — restate it here or the
       desktop min(640px, 100vw - 280px) outranks the mobile full-width layout. */
    .chrome-bottom,
    .chrome-bottom.has-cam-keys {
      width: calc(100vw - 24px);
      border-radius: 8px;
    }
    .chrome-side {
      top: auto;
      left: 12px;
      right: 12px;
      bottom: 12px;
      width: auto;
      max-height: 36vh;
    }
    .chrome-bottom { bottom: calc(36vh + 20px); }
    body.chrome-hidden .chrome-side { transform: translateY(14px); }
    body.chrome-hidden .chrome-bottom { transform: translate(-50%, 12px); }
  }

  /* ---- recorder ------------------------------------------------------------------ */
  .capture-row { display: flex; gap: 6px; }
  .capture-row button { flex: 1 1 auto; }

  .record-overlay {
    position: fixed;
    inset: 0;
    z-index: 6;
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 10px 12px 12px;
    background: rgba(6, 8, 11, 0.97);
  }
  .record-overlay[hidden] { display: none; }
  .rec-bar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
  .rec-bar .grow { flex: 1 1 auto; }
  .rec-bar input[type="url"] { min-width: 220px; }
  #recJob { width: 140px; }

  .rec-stage {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #000;
    overflow: auto;
  }
  .rec-screen { position: relative; line-height: 0; }
  /* getBoundingClientRect() returns the BORDER box, and that rect is the basis for every
     forwarded coordinate. A border or padding here is a systematic aim error, so it is a
     hard requirement rather than styling — tools/test-studio.mjs asserts it. */
  #recCanvas {
    display: block;
    border: 0;
    padding: 0;
    margin: 0;
    background: #000;
    cursor: none;
    touch-action: none;
  }
  /* Visually hidden, not display:none — a display:none element cannot take focus, and
     without focus there is no IME composition and no paste. */
  #recInput {
    position: absolute;
    left: 0; top: 0;
    width: 2px; height: 2px;
    opacity: 0;
    border: 0;
    padding: 0;
    resize: none;
    overflow: hidden;
  }
  .rec-cursor {
    position: absolute;
    left: 0; top: 0;
    width: 0; height: 0;
    pointer-events: none;
    border-left: 9px solid #fff;
    border-top: 6px solid transparent;
    border-bottom: 6px solid transparent;
    filter: drop-shadow(1px 1px 1px rgba(0, 0, 0, 0.8));
  }
  .rec-cursor[data-cur="text"] {
    width: 2px; height: 18px;
    border: 0;
    background: #fff;
    transform-origin: center;
  }
  .rec-safe {
    position: absolute;
    inset: 8% 12%;
    border: 1px dashed rgba(255, 180, 90, 0.55);
    pointer-events: none;
    display: none;
  }
  .rec-safe.on { display: block; }
  .rec-safe.on::after {
    content: "aim inside the box — the camera move crops to roughly this";
    position: absolute;
    left: 0; bottom: -20px;
    font-size: 11px;
    color: var(--dim);
  }
  /* display:flex beats the UA's [hidden]{display:none}, so hiding it needs saying out
     loud — exactly the trap .capture-overlay[hidden] already documents above. Without
     this the "1" stays burned over the middle of the take. */
  .rec-countdown[hidden] { display: none; }
  .rec-countdown {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: Syne, system-ui, sans-serif;
    font-size: 22vh;
    color: rgba(255, 180, 90, 0.85);
    background: rgba(0, 0, 0, 0.35);
    pointer-events: none;
  }
  .rec-toosmall { display: none; }
  .rec-screen.too-small .rec-toosmall {
    display: block;
    position: absolute;
    inset: auto 0 -24px;
    text-align: center;
    font-size: 12px;
    color: #ffb45a;
  }

  /* REC is a word, not just a colour — a red dot alone is invisible to a lot of people. */
  .rec-dot {
    width: 10px; height: 10px;
    border-radius: 50%;
    background: #3a4550;
  }
  .rec-word { font-size: 11px; letter-spacing: 0.12em; color: var(--dim); }
  .rec-timer { font-variant-numeric: tabular-nums; min-width: 52px; }
  .record-overlay[data-phase="recording"] .rec-dot { background: #ff4d4d; }
  .record-overlay[data-phase="recording"] .rec-word { color: #ff8080; }
  .record-overlay.link-down .rec-stage { opacity: 0.55; }
  #recBar.near-limit { background: #ff8080; }

  /* The overlay is not fully opaque, so the Studio's own panels would ghost through it
     and read as part of the recorded page. Take them out of the picture entirely while
     the recorder is open; they are already inert for input. */
  body.recording-open aside.controls,
  body.recording-open #transportChrome,
  body.recording-open .wake-hint { display: none; }

  /* The chrome auto-hide must not fade the recorder mid-take. Mirrors the
     .capture-overlay exemption above. */
  body.chrome-hidden .record-overlay:not([hidden]) {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
  }
