/* Wrap demo.
 *
 * Built to SPEC.md, "Look & feel": calm premium dark - navy rather than pure
 * black - with frosted glass where it adds depth, the brand gradient on the
 * main action and nowhere else, Outfit for headings and SF Pro for body, and
 * motion that is smooth and purposeful rather than decorative.
 *
 * Everything is in one file because the whole app is a dozen screens and a
 * second stylesheet would be filing for its own sake.
 */

/* Outfit, vendored rather than fetched: the demo has to work on bad wifi and
   on a plane, which is the same reason there is no build step. OFL, and the
   licence sits beside it, as it does for the caption fonts. */
@font-face {
  font-family: "Outfit";
  src: url("./fonts/Outfit-Variable.ttf") format("truetype-variations");
  font-weight: 100 900;
  font-display: swap;
}

:root {
  /* Navy, not black. Cool and deep enough that white text sits calmly on it,
     and dark enough that the video is still the brightest thing on screen. */
  --page: #07070c;
  --bg: #0b0b14;
  --surface: #14141f;
  --surface-high: #1d1d2b;
  --line: rgba(255, 255, 255, 0.09);
  --line-strong: rgba(255, 255, 255, 0.16);

  --text: #f4f4f8;
  --text-dim: #9a9ab0;
  --text-faint: #6b6b83;

  /* The one accent: selection, progress, the active state. */
  --accent: #6c8cff;
  --warn: #d9a441;
  --bad: #e5484d;

  /* The brand gradient. On the primary action and nothing else - the moment
     it appears twice on a screen neither one is the main action any more. */
  --brand: linear-gradient(120deg, #6c5cff 0%, #8b5cf6 45%, #d16bff 100%);
  --brand-glow: 0 10px 30px rgba(108, 92, 255, 0.35);

  /* Frosted glass, for things that float over the video or the page. */
  --glass: rgba(20, 20, 32, 0.72);
  --glass-line: rgba(255, 255, 255, 0.12);
  --blur: saturate(160%) blur(20px);

  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 18px;
  --r-xl: 26px;

  --pad: 20px;

  /* What the phone will not let us draw on: the notch, the home indicator,
     the rounded corners. Zero in a desktop browser, real numbers on an
     iPhone, and they change when the phone is turned. */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);

  /* The widest the app column gets. Wider than a phone is a desktop, and a
     desktop gets the same column rather than a stretched one. */
  --app-max: 480px;

  /* The smallest a thing you tap is allowed to be. Apple's number, and the
     one the tap-target test measures against. */
  --tap: 44px;

  /* The floating tab bar, and how much room anything scrolling leaves for it.
     Kept here because three screens need to know. */
  --tabbar-h: 62px;
  --tabbar-gap: calc(18px + var(--safe-bottom));
  --tabbar-room: calc(var(--tabbar-h) + var(--tabbar-gap) + 16px);

  /* SF Pro for body: it is what the phone reads in, and what this becomes. */
  --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro",
    "Helvetica Neue", Arial, sans-serif;
  /* Outfit for headings, with the body stack behind it so a missing font is
     a different shape rather than a broken screen. */
  --font-head: "Outfit", -apple-system, BlinkMacSystemFont, "SF Pro Display",
    "Helvetica Neue", Arial, sans-serif;

  --spring: cubic-bezier(0.32, 0.72, 0, 1);
}

/* Headings are Outfit, everywhere, without each screen having to remember. */
h1, h2, h3, .title, .stat-figure, .sheet-title, .navtab-label {
  font-family: var(--font-head);
  letter-spacing: -0.02em;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
}

* {
  box-sizing: border-box;
  -webkit-tap-highlight-color: transparent;
}

/* -- how a tap feels ----------------------------------------------------- */

/* Shandon, on his own iPhone: "buttons are finicky on the edit screen and
 * everywhere else." Three things were wrong, and all three are fixed here
 * rather than on each control, so every lane gets them without knowing.
 *
 * 1. `touch-action: manipulation`. Safari waits 300ms after a tap to see
 *    whether a second one is coming, because two taps means zoom. Every
 *    button in the app answered a third of a second late because of it.
 * 2. The pressed state is on `:active`, which fires as the finger lands, so
 *    a tap is acknowledged before the work starts.
 * 3. Hover is scoped to devices that have a pointer (further down). On a
 *    touch screen a `:hover` rule fires on tap and then *sticks* until you
 *    tap something else - a button that looks held down is exactly what
 *    "finicky" feels like.
 */
button,
[role="button"],
input,
select,
textarea,
a {
  touch-action: manipulation;
}

/* One pressed state for anything that does not draw its own. Scale rather
   than colour: it reads at any size, on any background. */
button:active:not(:disabled),
[role="button"]:active:not([aria-disabled="true"]) {
  transform: scale(0.97);
}

/* Things that are their own layout - a tab, a tile, a block on the timeline -
   must not move under the finger, so they brighten instead. */
.navtab:active,
.tile:active,
.tl-block:active,
.drop:active,
.row:active {
  transform: none;
  filter: brightness(1.3);
}

/* A control waiting on its own request: disabled, so a second tap cannot
   send the same write twice, and visibly busy so the wait is explained. */
button[aria-busy="true"] {
  opacity: 0.72;
  cursor: progress;
}

html,
body {
  margin: 0;
  height: 100%;
  /* Nothing in this app scrolls sideways. Said here as well as on the app,
     because one child that is a few pixels too wide otherwise gives the whole
     page a horizontal scrollbar - which on a phone is a screen that drifts
     when you swipe. */
  overflow-x: hidden;
}

body {
  background: var(--page);
  color: var(--text);
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
  /* The page does not bounce or rubber-band: the app is the height of the
     screen and the scrolling happens inside it. */
  overflow-y: hidden;
  overscroll-behavior: none;
}

/* -- the app, the size of the screen ----------------------------------- */

/* One column, full height, no drawn device.
 *
 * There used to be a picture of an iPhone here: a bezel, a notch and a 9:41
 * status bar, which reads well in a screenshot and is wrong on a phone. It
 * was 393px wide plus 22px of bezel, so on a 390px iPhone the right edge hung
 * off the screen and the whole page scrolled sideways.
 *
 * Height is `dvh` rather than `vh`: Safari's `vh` is the tallest the viewport
 * ever gets, so with the toolbar showing, the bottom of a `100vh` app - the
 * tab bar - sits behind it.
 */
.app {
  position: relative;
  width: 100%;
  /* On a phone this is the whole screen. On a desktop it is a centred column,
     because a timeline stretched across 1400px is nobody's editor. */
  max-width: var(--app-max);
  margin: 0 auto;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  background: var(--bg);
  /* Landscape on a notched phone puts the notch down one side. Padding here
     rather than on each screen: `.screen` is `inset: 0`, which resolves
     against this padding box, so every screen inherits the inset for free. */
  padding-left: var(--safe-left);
  padding-right: var(--safe-right);
}

/* Off a phone, the column reads as a window rather than a cropped page. */
@media (min-width: 560px) and (min-height: 600px) {
  body {
    display: grid;
    place-items: center;
  }

  .app {
    height: min(100dvh - 48px, 900px);
    border-radius: var(--r-xl);
    box-shadow:
      inset 0 0 0 1px var(--line),
      0 40px 90px -20px rgba(0, 0, 0, 0.9);
  }
}

/* -- the finger, on controls that have to stay small ------------------- */

/* A 44px target around something drawn smaller.
 *
 * Apple's minimum is about the finger, not about the icon. The two zoom
 * buttons live in the timeline's own header row and the play button sits in
 * the corner of the picture: drawn at 44px they are slabs over the video, so
 * the target grows invisibly around them instead.
 *
 * The tap-target test measures what answers a tap, not what is painted, so
 * these pass it honestly.
 */
.zoom,
.play-toggle {
  position: relative;
}

.zoom::after,
.play-toggle::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: max(100%, var(--tap));
  height: max(100%, var(--tap));
  transform: translate(-50%, -50%);
}

/* -- screen scaffolding ------------------------------------------------ */

.screen {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  /* Allowed to shrink, and clipping rather than pushing: at 360px the top bar
     could not fit its name and its export button side by side, so it grew,
     and with it the whole screen - 24px off the right edge on an iPhone SE. */
  min-width: 0;
  overflow: hidden;
  background: var(--bg);
  animation: screen-in 0.34s var(--spring);
}

.screen.back {
  animation: screen-back 0.34s var(--spring);
}

@keyframes screen-in {
  from {
    transform: translateX(24px);
    opacity: 0;
  }
}

@keyframes screen-back {
  from {
    transform: translateX(-18px);
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .screen,
  .screen.back {
    animation: none;
  }

  * {
    transition-duration: 0.01ms !important;
  }
}

.nav {
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 8px;
  padding: calc(4px + var(--safe-top)) var(--pad) 10px;
}

.nav-title {
  grid-column: 2;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.2px;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 190px;
}

.nav-left,
.nav-right {
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
}

.nav-right {
  grid-column: 3;
  justify-content: flex-end;
}

.nav-btn {
  appearance: none;
  border: 0;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: 15px;
  padding: 6px 4px;
  min-width: var(--tap);
  min-height: var(--tap);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  border-radius: var(--r-sm);
}

.nav-btn:active {
  opacity: 0.55;
}

.nav-btn.accent {
  color: var(--accent);
  font-weight: 560;
}

.nav-btn[disabled] {
  color: var(--text-faint);
  cursor: default;
  pointer-events: none;
}

.body {
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0 var(--pad) 24px;
  scrollbar-width: none;
}

.body::-webkit-scrollbar {
  display: none;
}

.body.flush {
  padding-left: 0;
  padding-right: 0;
}

/* A screen whose content fills the height rather than stacking from the top:
 * the review screen, where the chat takes whatever the player leaves. */
.body.column {
  display: flex;
  flex-direction: column;
  padding-bottom: 0;
  overflow: hidden;
}

.footer {
  flex: 0 0 auto;
  padding: 12px var(--pad) calc(20px + var(--safe-bottom));
  background: linear-gradient(to top, var(--bg) 60%, transparent);
}

/* -- type -------------------------------------------------------------- */

.title {
  margin: 4px 0 18px;
  font-size: 30px;
  font-weight: 680;
  letter-spacing: -0.7px;
}

.section {
  margin: 26px 0 10px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--text-faint);
}

.section:first-child {
  margin-top: 8px;
}

.hint {
  margin: 8px 0 0;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--text-faint);
}

.empty {
  padding: 56px 24px;
  text-align: center;
  color: var(--text-faint);
  font-size: 14px;
  line-height: 1.5;
}

.empty strong {
  display: block;
  color: var(--text-dim);
  font-size: 16px;
  font-weight: 600;
  margin-bottom: 6px;
}

/* -- buttons ----------------------------------------------------------- */

.btn {
  appearance: none;
  width: 100%;
  border: 0;
  border-radius: 14px;
  padding: 15px 18px;
  font: inherit;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.2px;
  /* The brand gradient lives here and nowhere else. `.btn` is the main action
     on a screen; everything else is `.btn.ghost` or `.btn.quiet`. */
  background: var(--brand);
  box-shadow: var(--brand-glow);
  color: #fff;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  transition: transform 0.14s var(--spring), opacity 0.14s ease;
}

.btn:active {
  transform: scale(0.985);
}

.btn:disabled {
  background: var(--surface-high);
  box-shadow: none;
  color: var(--text-faint);
}

.btn:active {
  transform: scale(0.975);
}

.btn[disabled] {
  background: var(--surface-high);
  color: var(--text-faint);
  cursor: default;
  pointer-events: none;
}

/* Not the main action, so not the gradient - and not its glow either. The
   glow is what makes the main action read as the main action, and a quiet
   button wearing it was two main actions on one screen. */
.btn.quiet {
  background: var(--surface-high);
  box-shadow: none;
  color: var(--text);
}

.btn.ghost {
  background: none;
  box-shadow: none;
  color: var(--text-dim);
  border: 1px solid var(--line-strong);
}

.btn.danger {
  background: none;
  color: var(--bad);
}

/* -- project rows ------------------------------------------------------ */

.rows {
  display: flex;
  flex-direction: column;
}

.row {
  appearance: none;
  width: 100%;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 0;
  cursor: pointer;
  border-bottom: 1px solid var(--line);
}

.row:active {
  opacity: 0.6;
}

.row-thumb {
  flex: 0 0 auto;
  width: 46px;
  height: 62px;
  border-radius: 9px;
  background: var(--surface-high);
  overflow: hidden;
  position: relative;
  display: grid;
  place-items: center;
  color: var(--text-faint);
}

.row-thumb video,
.row-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.row-main {
  flex: 1 1 auto;
  min-width: 0;
}

.row-name {
  font-size: 15.5px;
  font-weight: 560;
  letter-spacing: -0.2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.row-meta {
  margin-top: 3px;
  font-size: 12.5px;
  color: var(--text-faint);
  display: flex;
  align-items: center;
  gap: 6px;
}

.row-chevron {
  flex: 0 0 auto;
  color: var(--text-faint);
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px;
  border-radius: 99px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.2px;
  background: var(--surface-high);
  color: var(--text-dim);
}

.pill.ready {
  color: var(--accent);
  background: rgba(61, 125, 255, 0.14);
}

.pill.processing {
  color: var(--warn);
  background: rgba(217, 164, 65, 0.14);
}

.pill.error {
  color: var(--bad);
  background: rgba(229, 72, 77, 0.14);
}

.pill.demo {
  color: #000;
  background: var(--text);
}

/* -- misc -------------------------------------------------------------- */

.banner {
  margin: 12px 0 0;
  padding: 12px 14px;
  border-radius: var(--r-md);
  background: var(--surface);
  border: 1px solid var(--line);
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-dim);
}

.banner code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  color: var(--text);
  background: var(--surface-high);
  padding: 1px 5px;
  border-radius: 5px;
}

.banner.bad {
  border-color: rgba(229, 72, 77, 0.4);
  color: #f3b0b2;
}

.spin {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  border: 2px solid var(--line-strong);
  border-top-color: var(--text);
  animation: spin 0.7s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* -- clips and drop zones ---------------------------------------------- */

.clips {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.clip {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 9px 11px;
  border-radius: var(--r-md);
  background: var(--surface);
  border: 1px solid var(--line);
}

.clip.dragged {
  opacity: 0.35;
}

.clip-order {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 11px;
  font-weight: 650;
  background: var(--surface-high);
  color: var(--text-dim);
}

.clip-order.dim {
  background: none;
  color: var(--text-faint);
}

.clip-thumb {
  flex: 0 0 auto;
  width: 34px;
  height: 46px;
  border-radius: 7px;
  overflow: hidden;
  background: var(--surface-high);
}

.clip-thumb video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.clip-main {
  flex: 1 1 auto;
  min-width: 0;
}

.clip-name {
  font-size: 14px;
  font-weight: 540;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.clip-meta {
  margin-top: 2px;
  font-size: 11.5px;
  color: var(--text-faint);
}

.clip-grip {
  flex: 0 0 auto;
  color: var(--text-faint);
  cursor: grab;
}

.clip-remove {
  flex: 0 0 auto;
  appearance: none;
  border: 0;
  background: none;
  color: var(--text-faint);
  width: var(--tap);
  height: var(--tap);
  display: grid;
  place-items: center;
  cursor: pointer;
  border-radius: 10px;
}

@media (hover: hover) {
  .clip-remove:hover {
    color: var(--bad);
  }
}

.upload-bar {
  margin-top: 7px;
  height: 3px;
  border-radius: 2px;
  background: var(--surface-high);
  overflow: hidden;
}

.upload-bar-fill {
  display: block;
  height: 100%;
  width: 0%;
  background: var(--accent);
  transition: width 0.2s linear;
}

.drop {
  appearance: none;
  width: 100%;
  display: flex;
  align-items: center;
  gap: 11px;
  text-align: left;
  padding: 12px;
  border-radius: var(--r-md);
  border: 1px dashed var(--line-strong);
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}

.drop.over,
@media (hover: hover) {
  .drop:hover {
    border-color: var(--accent);
    background: rgba(61, 125, 255, 0.07);
  }
}

.drop-plus {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--surface-high);
  color: var(--text-dim);
}

.drop-main {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.drop-label {
  font-size: 14px;
  font-weight: 560;
}

.drop-hint {
  font-size: 11.5px;
  color: var(--text-faint);
  margin-top: 1px;
}

.camera-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 26px 20px;
  border-radius: var(--r-md);
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--text-faint);
}

.camera-icon {
  color: var(--text-dim);
}

.camera-label {
  font-size: 14px;
  font-weight: 560;
  color: var(--text-dim);
}

.camera-note {
  font-size: 11.5px;
}

/* -- the style screen --------------------------------------------------- */

/* Horizontally scrolling row of choices. Bleeds to both edges so it reads as
 * something that carries on rather than something that stopped. */
.reel {
  display: flex;
  gap: 9px;
  overflow-x: auto;
  padding: 2px var(--pad) 4px;
  margin: 0 calc(var(--pad) * -1);
  scrollbar-width: none;
  scroll-snap-type: x proximity;
}

.reel::-webkit-scrollbar {
  display: none;
}

.card {
  flex: 0 0 auto;
  width: 178px;
  text-align: left;
  padding: 12px 13px;
  border-radius: var(--r-md);
  background: var(--surface);
  border: 1px solid var(--line);
  color: inherit;
  font: inherit;
  cursor: pointer;
  scroll-snap-align: start;
  transition: border-color 0.15s ease, background 0.15s ease;
}

.card.chosen {
  border-color: var(--accent);
  background: rgba(61, 125, 255, 0.09);
}

.card-name {
  font-size: 14px;
  font-weight: 600;
}

.card-note {
  margin-top: 3px;
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--text-dim);
}

.card-turns {
  margin-top: 7px;
  font-size: 10.5px;
  line-height: 1.35;
  color: var(--text-faint);
}

.preset {
  flex: 0 0 auto;
  width: 124px;
  height: 86px;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border-radius: var(--r-md);
  background: #08080a;
  border: 1px solid var(--line);
  color: inherit;
  font: inherit;
  cursor: pointer;
  scroll-snap-align: start;
  overflow: hidden;
}

.preset.chosen {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}

.preset-sample {
  font-size: 15px;
  font-weight: 800;
  letter-spacing: -0.2px;
  line-height: 1;
}

.preset-accent {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
}

.preset-name {
  font-size: 10.5px;
  color: var(--text-faint);
}

.steps {
  display: flex;
  flex-direction: column;
  gap: 1px;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--line);
}

.step {
  background: var(--surface);
  padding: 11px 13px;
}

.step-head {
  display: flex;
  align-items: center;
  gap: 12px;
}

.step-main {
  flex: 1 1 auto;
  min-width: 0;
}

.step-label {
  font-size: 14.5px;
  font-weight: 540;
  letter-spacing: -0.1px;
}

.step-detail {
  margin-top: 2px;
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--text-faint);
}

.step-options {
  margin-top: 12px;
  padding-top: 11px;
  border-top: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.control {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.control-label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 11.5px;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  color: var(--text-faint);
}

.control-value {
  font-variant-numeric: tabular-nums;
  text-transform: none;
  letter-spacing: 0;
  color: var(--text-dim);
}

.segments {
  display: flex;
  gap: 2px;
  padding: 2px;
  border-radius: 9px;
  background: var(--bg);
}

.segment {
  flex: 1 1 0;
  appearance: none;
  border: 0;
  border-radius: 7px;
  padding: 6px 4px;
  font: inherit;
  font-size: 12.5px;
  font-weight: 520;
  background: none;
  color: var(--text-dim);
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.segment.chosen {
  background: var(--surface-high);
  color: var(--text);
}

.picker {
  appearance: none;
  width: 100%;
  border-radius: 9px;
  border: 1px solid var(--line);
  background: var(--bg);
  color: var(--text);
  font: inherit;
  font-size: 13px;
  padding: 8px 10px;
}

.slider {
  appearance: none;
  width: 100%;
  height: 22px;
  background: none;
  cursor: pointer;
}

.slider::-webkit-slider-runnable-track {
  height: 3px;
  border-radius: 2px;
  background: var(--surface-high);
}

.slider::-webkit-slider-thumb {
  appearance: none;
  width: 16px;
  height: 16px;
  margin-top: -6.5px;
  border-radius: 50%;
  background: var(--text);
}

.switch {
  flex: 0 0 auto;
  appearance: none;
  width: 44px;
  height: 26px;
  padding: 2px;
  border: 0;
  border-radius: 99px;
  background: var(--surface-high);
  cursor: pointer;
  display: flex;
  transition: background 0.2s var(--spring);
}

.switch.on {
  background: var(--accent);
}

.switch-knob {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: #fff;
  transition: transform 0.2s var(--spring);
}

.switch.on .switch-knob {
  transform: translateX(18px);
}

/* Cards in a reel stretch to the tallest, so their text is clamped to keep
 * them a sensible height rather than letting one long description set it. */
.card-note {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.preset-name {
  max-width: 108px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: center;
}

/* -- processing --------------------------------------------------------- */

/* Replaced by the stacked, centred head below: the title and the clock sat
   side by side, so a two-word stage name wrapped down the left of the
   screen while a sentence sat beside it. */

.elapsed {
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  color: var(--text-faint);
}

.stages {
  display: flex;
  flex-direction: column;
}

.stage {
  display: flex;
  align-items: flex-start;
  gap: 13px;
  padding: 14px 0;
  border-bottom: 1px solid var(--line);
}

.stage.pending {
  opacity: 0.4;
}

.stage.skipped {
  opacity: 0.45;
}

.mark {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  margin-top: 1px;
  border-radius: 50%;
  border: 1.5px solid var(--line-strong);
  display: grid;
  place-items: center;
  font-size: 12px;
  color: var(--text-faint);
}

.mark.done {
  border-color: var(--accent);
  background: var(--accent);
  color: #fff;
}

.mark.running {
  border-color: transparent;
}

.mark.skipped {
  border-style: dashed;
}

.stage-main {
  flex: 1 1 auto;
  min-width: 0;
}

.stage-label {
  font-size: 15px;
  font-weight: 540;
  letter-spacing: -0.1px;
}

.stage-detail {
  margin-top: 2px;
  font-size: 12px;
  color: var(--text-faint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.stage-bar {
  margin-top: 8px;
  height: 3px;
  border-radius: 2px;
  background: var(--surface-high);
  overflow: hidden;
}

.stage-bar-fill {
  display: block;
  height: 100%;
  background: var(--accent);
  transition: width 0.3s linear;
}

.stage-time {
  flex: 0 0 auto;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--text-faint);
  margin-top: 2px;
}

/* -- review -------------------------------------------------------------- */

.player-wrap {
  position: relative;
  flex: 0 0 auto;
  height: 42%;
  background: #000;
}

/* Letterboxed inside its box rather than sized by its own aspect ratio: a
 * 9:16 clip and a 16:9 one have to leave the chat the same room. */
.player {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: contain;
  background: #000;
}

.before-toggle {
  position: absolute;
  top: 10px;
  left: 10px;
  appearance: none;
  border: 0;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 10px;
  border-radius: 99px;
  font: inherit;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.2px;
  /* Glass, per the design direction: the controls float over the video. */
  background: rgba(20, 20, 22, 0.62);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14);
  color: var(--text);
  cursor: pointer;
}

.before-toggle.on {
  color: var(--warn);
}

.stale {
  /* A footnote with a button, not a warning. It says the last render is older
     than the edit, which is worth knowing and is not an error. */
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 0 var(--pad) 6px;
  padding: 7px 8px 7px 12px;
  border-radius: 99px;
  background: rgba(255, 212, 109, 0.09);
  box-shadow: inset 0 0 0 1px rgba(255, 212, 109, 0.2);
  font-size: 11.5px;
  color: var(--warn);
}


.stale span {
  flex: 1 1 auto;
}

.stale-go {
  appearance: none;
  border: 0;
  border-radius: 99px;
  padding: 5px 13px;
  font: inherit;
  font-size: 12px;
  font-weight: 620;
  background: var(--warn);
  color: #1a1400;
  cursor: pointer;
}

.chat {
  display: flex;
  flex-direction: column;
  min-height: 0;
  flex: 1 1 auto;
}

.chat-log {
  flex: 1 1 auto;
  min-height: 120px;
  overflow-y: auto;
  padding: 14px var(--pad) 6px;
  display: flex;
  flex-direction: column;
  gap: 9px;
  scrollbar-width: none;
}

.chat-log::-webkit-scrollbar {
  display: none;
}

.said {
  max-width: 84%;
  padding: 9px 12px;
  border-radius: 15px;
  font-size: 13.5px;
  line-height: 1.4;
}

.said.wrap {
  align-self: flex-start;
  background: var(--surface);
  border-bottom-left-radius: 5px;
}

.said.me {
  align-self: flex-end;
  background: var(--accent);
  color: #fff;
  border-bottom-right-radius: 5px;
}

.said.bad {
  color: #f3b0b2;
  background: rgba(229, 72, 77, 0.13);
}

.said.thinking {
  padding: 11px 14px;
}

.said-note {
  margin-top: 5px;
  font-size: 10.5px;
  letter-spacing: 0.2px;
  color: var(--text-faint);
}

.chips {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  padding: 6px var(--pad);
  scrollbar-width: none;
}

.chips::-webkit-scrollbar {
  display: none;
}

.chips.inline {
  padding: 8px 0 0;
  margin: 0;
}

.chip {
  flex: 0 0 auto;
  appearance: none;
  border: 1px solid var(--line-strong);
  border-radius: 99px;
  padding: 5px 11px;
  font: inherit;
  font-size: 12px;
  background: none;
  color: var(--text-dim);
  cursor: pointer;
  white-space: nowrap;
}

@media (hover: hover) {
  .chip:hover {
    border-color: var(--accent);
    color: var(--text);
  }
}

.chat-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px var(--pad) 2px;
}

.chat-input {
  flex: 1 1 auto;
  min-width: 0;
  appearance: none;
  border: 1px solid var(--line-strong);
  border-radius: 99px;
  padding: 11px 16px;
  font: inherit;
  font-size: 14px;
  background: var(--surface);
  color: var(--text);
}

.chat-input:focus {
  outline: none;
  border-color: var(--accent);
}

.chat-send {
  flex: 0 0 auto;
  appearance: none;
  border: 0;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--text);
  color: #000;
  cursor: pointer;
}

/* -- layers -------------------------------------------------------------- */

.timeline {
  margin: 4px 0 18px;
}

.ruler {
  position: relative;
  height: 15px;
  margin-left: 66px;
  border-bottom: 1px solid var(--line);
}

.tick {
  position: absolute;
  top: 0;
  font-size: 9.5px;
  color: var(--text-faint);
  border-left: 1px solid var(--line);
  padding-left: 3px;
  line-height: 1;
}

.track {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 0;
}

.track-name {
  flex: 0 0 auto;
  width: 58px;
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 10.5px;
  letter-spacing: 0.2px;
  color: var(--text-faint);
}

.track.empty .track-name {
  opacity: 0.5;
}

.track-lane {
  position: relative;
  flex: 1 1 auto;
  height: 30px;
  border-radius: 6px;
  background: var(--surface);
  overflow: hidden;
}

.lane-empty {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 10.5px;
  color: var(--text-faint);
}

.block {
  position: absolute;
  top: 3px;
  bottom: 3px;
  appearance: none;
  border: 0;
  border-radius: 4px;
  padding: 0 5px;
  font: inherit;
  overflow: hidden;
  cursor: pointer;
  text-align: left;
  background: var(--surface-high);
  color: var(--text-dim);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07);
}

.block-video {
  background: #23313f;
  color: #b9d2e8;
}

.block-broll {
  background: #2c2540;
  color: #cbbde8;
}

.block-captions {
  background: #1f3330;
  color: #a9d7c9;
}

.block-text {
  background: #3a2f21;
  color: #e3c89b;
}

.block-music {
  background: #2a2333;
  color: #c6b2d9;
}

.block.chosen {
  box-shadow: inset 0 0 0 1.5px var(--accent);
  color: var(--text);
}

.block.warn {
  box-shadow: inset 0 0 0 1.5px var(--warn);
}

.block-label {
  display: block;
  font-size: 10px;
  line-height: 24px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.panel {
  border-top: 1px solid var(--line);
  padding-top: 14px;
  display: flex;
  flex-direction: column;
  gap: 13px;
}

.panel-empty {
  margin: 20px 0;
  text-align: center;
  font-size: 13px;
  color: var(--text-faint);
}

.panel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.panel-title {
  font-size: 16px;
  font-weight: 620;
  letter-spacing: -0.2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.panel-when {
  flex: 0 0 auto;
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
  color: var(--text-faint);
}

.panel-note {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--text-dim);
}

.control-group {
  font-size: 11px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--text-faint);
  border-top: 1px solid var(--line);
  padding-top: 12px;
}

.btn.small {
  padding: 9px 14px;
  font-size: 13.5px;
  border-radius: 10px;
}

/* One line instead of a panel of dead controls. */
.coming {
  margin: 2px 0 0;
  font-size: 11.5px;
  color: var(--text-faint);
}

/* -- export -------------------------------------------------------------- */

.headline {
  padding: 18px 0 22px;
  border-bottom: 1px solid var(--line);
}

.headline-number {
  font-size: 52px;
  font-weight: 700;
  letter-spacing: -2px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.headline-label {
  margin-top: 7px;
  font-size: 13.5px;
  color: var(--text-dim);
}

.figures {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  margin-top: 1px;
  background: var(--line);
  border-bottom: 1px solid var(--line);
}

.figure {
  background: var(--bg);
  padding: 14px 4px;
}

.figure-value {
  font-size: 19px;
  font-weight: 620;
  letter-spacing: -0.4px;
  font-variant-numeric: tabular-nums;
}

.figure-label {
  margin-top: 2px;
  font-size: 10.5px;
  line-height: 1.3;
  color: var(--text-faint);
}

.applied {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.applied li {
  position: relative;
  padding-left: 16px;
  font-size: 13.5px;
  color: var(--text-dim);
}

.applied li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 7px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent);
}

.applied.warn li::before {
  background: var(--warn);
}

.file {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px;
  border-radius: var(--r-md);
  background: var(--surface);
  border: 1px solid var(--line);
}

.file-main {
  min-width: 0;
}

.file-name {
  font-size: 13.5px;
  font-weight: 540;
  word-break: break-all;
}

.file-meta {
  margin-top: 3px;
  font-size: 11.5px;
  color: var(--text-faint);
}

a.btn {
  text-decoration: none;
}

.drop-wrap {
  display: contents;
}

/* -- sheets, hooks, layer editing --------------------------------------- */

.sheet {
  position: absolute;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: flex-end;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(3px);
  animation: sheet-in 0.26s var(--spring);
}

@keyframes sheet-in {
  from { opacity: 0; }
}

.sheet-card {
  width: 100%;
  max-height: 78%;
  overflow-y: auto;
  padding: 14px var(--pad) calc(34px + var(--safe-bottom));
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  background: #17171a;
  border-top: 1px solid var(--line-strong);
  scrollbar-width: none;
}

.sheet-card::-webkit-scrollbar { display: none; }

.sheet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}

.sheet-title {
  font-size: 18px;
  font-weight: 650;
  letter-spacing: -0.3px;
}

.hooks {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.hook {
  appearance: none;
  text-align: left;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  color: inherit;
  font: inherit;
  padding: 11px 13px;
  cursor: pointer;
}

.hook.chosen {
  border-color: var(--accent);
  background: rgba(61, 125, 255, 0.09);
}

.hook-angle {
  font-size: 10px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--text-faint);
}

.hook-text {
  margin-top: 4px;
  font-size: 14.5px;
  font-weight: 560;
  line-height: 1.3;
}

.hook-why {
  margin-top: 5px;
  font-size: 11px;
  color: var(--text-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.text-edit {
  width: 100%;
  resize: vertical;
  border-radius: 9px;
  border: 1px solid var(--line);
  background: var(--bg);
  color: var(--text);
  font: inherit;
  font-size: 13.5px;
  line-height: 1.35;
  padding: 9px 10px;
}

.text-edit:focus {
  outline: none;
  border-color: var(--accent);
}

.control-row {
  display: flex;
  gap: 8px;
}

.control-row .btn {
  flex: 1 1 0;
}

.lane-add {
  position: absolute;
  inset: 0;
  appearance: none;
  border: 0;
  background: none;
  color: var(--text-faint);
  font: inherit;
  font-size: 10.5px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  cursor: pointer;
  border-radius: 6px;
}

@media (hover: hover) {
  .lane-add:hover {
    color: var(--text);
    background: rgba(255, 255, 255, 0.04);
  }
}

.row-wrap {
  display: flex;
  align-items: center;
  border-bottom: 1px solid var(--line);
}

.row-wrap .row {
  border-bottom: 0;
  flex: 1 1 auto;
  min-width: 0;
}

.row-delete {
  flex: 0 0 auto;
  appearance: none;
  border: 0;
  background: none;
  color: var(--text-faint);
  padding: 10px 2px 10px 10px;
  cursor: pointer;
  border-radius: 6px;
}

@media (hover: hover) {
  .row-delete:hover {
    color: var(--bad);
  }
}

.btn.danger-solid {
  background: var(--bad);
  color: #fff;
}

/* A layer changed since the last render: it is in the edit, not yet in the
 * file being watched. */
.block.pending {
  box-shadow: inset 0 0 0 1.5px var(--warn);
  opacity: 0.85;
}

/* -- projects grid ------------------------------------------------------- */

.grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px 11px;
}

.tile-wrap {
  position: relative;
  display: flex;
  flex-direction: column;
}

.tile {
  appearance: none;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  padding: 0;
  cursor: pointer;
  width: 100%;
}

.tile-shot {
  position: relative;
  aspect-ratio: 3 / 4;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--surface-high);
  display: grid;
  place-items: center;
  color: var(--text-faint);
}

.tile-shot video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.tile.picked .tile-shot {
  box-shadow: inset 0 0 0 2.5px var(--accent);
}

.tile-time,
.tile-tag {
  position: absolute;
  padding: 2px 6px;
  border-radius: 5px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.2px;
  background: rgba(0, 0, 0, 0.62);
  backdrop-filter: blur(8px);
  color: #fff;
}

.tile-time {
  right: 6px;
  bottom: 6px;
  font-variant-numeric: tabular-nums;
}

.tile-tag {
  left: 6px;
  top: 6px;
}

.tile-tag.demo {
  background: var(--text);
  color: #000;
}

.tile-tag.processing { background: var(--warn); color: #1a1400; }
.tile-tag.error { background: var(--bad); }

.tick {
  position: absolute;
  right: 6px;
  top: 6px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, 0.7);
  background: rgba(0, 0, 0, 0.35);
  display: grid;
  place-items: center;
  color: #fff;
}

.tick.on {
  background: var(--accent);
  border-color: var(--accent);
}

.tile-name {
  margin-top: 7px;
  font-size: 13.5px;
  font-weight: 560;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tile-meta {
  margin-top: 2px;
  font-size: 11px;
  color: var(--text-faint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The tile's "..." button. Always visible, never on hover: a phone has no
   hover, and the menu behind this is the only way to delete without holding
   a finger down on a tile for half a second. */
.tile-wrap {
  position: relative;
}

.tile-action {
  appearance: none;
  border: 0;
  position: absolute;
  right: 4px;
  bottom: 36px;
  width: var(--tap);
  height: var(--tap);
  border-radius: 12px;
  display: grid;
  place-items: center;
  background: rgba(10, 10, 12, 0.82);
  backdrop-filter: blur(10px);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14);
  color: var(--text);
  cursor: pointer;
}

@media (hover: hover) {
  .tile-action:hover,
  .tile-action:focus-visible {
    background: rgba(20, 20, 24, 0.95);
  }
}

/* Grab handles on the ends of the selected clip.

   Wide enough for a finger (44px is the guideline; 22 either side of the edge
   gets there once both clips' handles are counted) but drawn narrow, so the
   timeline still reads as clips rather than as a row of grips. */
.tl-edge {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 22px;
  z-index: 4;
  cursor: ew-resize;
  touch-action: none;
  display: grid;
  place-items: center;
}

/* Inside the clip rather than straddling its edge. Half of a straddling
   handle sits outside the block, where the lane clips it and the press lands
   on whatever is behind. */
.tl-edge.start { left: 0; }
.tl-edge.end { right: 0; }

.tl-edge::after {
  content: "";
  width: 4px;
  height: 58%;
  border-radius: 99px;
  background: var(--text);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.45);
}

.tl-edge:active::after {
  background: var(--accent);
}

/* Redo is undo's arrow the other way round. One icon, mirrored, so the pair
   reads as a pair. */
.nav-btn.flipped svg {
  transform: scaleX(-1);
}

.nav-btn:disabled {
  opacity: 0.32;
  pointer-events: none;
}

/* A heading inside a sheet, for when one sheet covers more than one thing. */
.sheet-sub {
  margin: 18px 0 6px;
  font-size: 11.5px;
  font-weight: 640;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.sheet-sub:first-child { margin-top: 0; }

/* A label and its switch side by side. `.control` stacks by default, and
   setting only the alignment left this stacked and centred - the direction is
   the one property that had to be said. */
.control.row {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

/* Room under a sheet's explanation, so it does not sit on the next label. */
.sheet .hint {
  margin-bottom: 10px;
}

/* A short list of things to pick one of, each with a line saying what it
   does. Used where a slider would invite a value nobody meant. */
.choices {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.choice {
  appearance: none;
  width: 100%;
  padding: 11px 14px;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: none;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.choice.on {
  border-color: var(--accent);
  background: rgba(61, 125, 255, 0.12);
}

.choice-title {
  font-size: 14px;
  font-weight: 600;
}

.choice-note {
  font-size: 12px;
  color: var(--text-faint);
}

/* The line under a control saying what it does. Small and quiet: it is there
   to be read once, not every time. */
.control-note {
  flex-basis: 100%;
  margin: 2px 0 0;
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--text-faint);
}

/* About how long is left. Quieter than the clock counting up, because the
   clock is a fact and this is a guess - and it says so when it runs over
   rather than sitting on "almost there" for a minute. */
.remaining {
  margin-top: 2px;
  font-size: 12.5px;
  color: var(--text-faint);
}

.remaining.over {
  color: #ffd46d;
}

/* -- the editor's top bar and player row ---------------------------------- */

/* SPEC "Editor layout": back, the project's name, what shape it is, a way to
   report a problem, and Export. Export lives up here because the bottom of
   the screen is the toolbar now. */
.topbar {
  flex: 0 0 auto;
  min-width: 0;
  padding-top: calc(10px + var(--safe-top));
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px var(--pad);
}

.top-btn {
  appearance: none;
  border: 0;
  background: none;
  color: var(--text-dim);
  /* Its own width, kept: as a flex item it was squeezed to 41px at 360 by the
     name beside it, and a tap target is not a thing that gives way. The name
     truncates instead - it is the only part of that row that can. */
  flex: 0 0 auto;
  width: var(--tap);
  height: var(--tap);
  /* No negative margin: at 44px it would slide this button's target under the
     one beside it, and the tap would do the other thing. */
  margin: 0;
  display: grid;
  place-items: center;
  cursor: pointer;
}

@media (hover: hover) { .top-btn:hover { color: var(--text); } }

.top-name {
  appearance: none;
  border: 0;
  background: none;
  color: var(--text);
  font: inherit;
  font-family: var(--font-head);
  font-size: 15.5px;
  font-weight: 600;
  letter-spacing: -0.02em;
  display: flex;
  align-items: center;
  gap: 3px;
  min-width: 0;
  min-height: var(--tap);
  padding: 0;
  cursor: pointer;
}

.top-name span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.aspect-chip {
  flex: 0 0 auto;
  margin-left: auto;
  padding: 3px 8px;
  border-radius: 99px;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-dim);
  box-shadow: inset 0 0 0 1px var(--line-strong);
}

.top-export {
  appearance: none;
  border: 0;
  flex: 0 0 auto;
  padding: 7px 14px;
  min-height: var(--tap);
  border-radius: 99px;
  background: var(--brand);
  box-shadow: var(--brand-glow);
  color: #fff;
  font: inherit;
  font-size: 13.5px;
  font-weight: 640;
  cursor: pointer;
}

.top-export:active { transform: scale(0.97); }

/* Everything that acts on what you are watching, in one row under it. */
/* Back on one side, the actions on the other, both the same width, so the
   name is centred rather than pushed along by whatever sits beside it.
   Reference item 5: "back, project name centered, one accent action". */
.editor-top > .top-name {
  flex: 0 1 auto;
  min-width: 0;
}

.editor-top > [data-back] { flex: 1 1 0; justify-content: flex-start; }

.editor-top > .top-actions {
  flex: 1 1 0;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 4px;
  min-width: 0;
}

.player-row {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 6px var(--pad) 2px;
}

.row-gap { flex: 1 1 auto; }

/* The two halves either side of Play. Equal width, so Play is centred
   whatever each of them holds. `min-width: 0` or a long side pushes it off
   centre again, which is the thing this replaced. */
.row-side {
  flex: 1 1 0;
  /* Never below the buttons' own width. `min-width: 0` let the two halves
     squeeze their contents to balance, which took the transport buttons from
     44px to 26 - under the tap minimum, to centre a play button. Centring is
     worth less than being able to hit the thing. */
  min-width: min-content;
  display: flex;
  align-items: center;
  gap: 2px;
}

.row-side.end { justify-content: flex-end; }

.row-btn {
  appearance: none;
  border: 0;
  background: none;
  color: var(--text-dim);
  width: var(--tap);
  height: var(--tap);
  border-radius: 12px;
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: color 0.15s ease, background 0.15s ease;
}

@media (hover: hover) { .row-btn:hover:not(:disabled) { color: var(--text); background: var(--surface); } }
.row-btn:disabled { opacity: 0.3; pointer-events: none; }
.row-btn.play { color: var(--text); }
.row-btn.note { color: var(--text-dim); }

/* Fullscreen: the player takes the whole phone and the chrome gets out of
   the way, per SPEC "clean playback". */
/* Scoped to the editor so it beats `.editor-body .ba-box`, which sets the
   player to a share of the column and otherwise wins on being later. */
.editor-body .ba-box.fullscreen {
  position: absolute;
  inset: 0;
  z-index: 80;
  max-height: none;
  height: 100%;
  margin: 0;
  border-radius: 0;
}

/* The way out of fullscreen, on the player - because the player is covering
   the button that put it there. */
.full-close {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 5;
  appearance: none;
  border: 0;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--glass);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  box-shadow: inset 0 0 0 1px var(--glass-line);
  color: var(--text);
  cursor: pointer;
}

/* -- the timeline's waveform ---------------------------------------------- */

/* Under the thumbnails, not instead of them: the picture says what the clip
   is and the shape says where the words are. */
.tl-wave {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 42%;
  pointer-events: none;
  opacity: 0.85;
}

/* A dark band behind it, so the shape reads against a bright thumbnail
   instead of disappearing into it. */
.tl-block.tl-video::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 42%;
  background: linear-gradient(transparent, rgba(0, 0, 0, 0.55));
  pointer-events: none;
}

.tl-wave path { fill: rgba(255, 255, 255, 0.9); }

.tl-block.chosen .tl-wave path { fill: #fff; }

/* -- edit notes ----------------------------------------------------------- */

/* Marks on the running time, above the lanes: a note is about a moment in
   the video, not about a layer of it. */
.tl-pins {
  position: relative;
  height: 0;
  z-index: 3;
}

.tl-pin {
  position: absolute;
  top: -20px;
  transform: translateX(-50%);
  appearance: none;
  border: 0;
  width: 20px;
  height: 20px;
  border-radius: 6px;
  display: grid;
  place-items: center;
  background: var(--brand);
  color: #fff;
  cursor: pointer;
}

/* How many notes are waiting, on the button that opens them. */
.row-btn .note-count {
  position: absolute;
  top: 1px;
  right: 1px;
  min-width: 14px;
  height: 14px;
  padding: 0 3px;
  border-radius: 99px;
  background: var(--brand);
  color: #fff;
  font-size: 9.5px;
  font-weight: 700;
  line-height: 14px;
  text-align: center;
}

.row-btn { position: relative; }
.row-btn .note-count:empty { display: none; }
.row-btn[data-count]:not([data-count="0"]) { color: var(--text); }

.note-field {
  width: 100%;
  resize: none;
  border-radius: var(--r-md);
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 15px;
  padding: 11px 13px;
}

.note-field:focus {
  outline: none;
  border-color: var(--accent);
}

.note-actions {
  display: flex;
  gap: 8px;
  margin-top: 12px;
  align-items: center;
}

.note-actions .btn { flex: 1 1 auto; width: auto; }
.note-actions .btn.ghost.small { flex: 0 0 auto; width: auto; padding: 11px 13px; }

.notes-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 46vh;
  overflow-y: auto;
}

.note-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: var(--r-md);
  background: var(--surface);
}

.note-at {
  appearance: none;
  border: 0;
  background: none;
  color: var(--accent);
  font: inherit;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  font-weight: 640;
  padding: 0;
  cursor: pointer;
  flex: 0 0 auto;
}

.note-text {
  flex: 1 1 auto;
  font-size: 13.5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.note-pin { color: var(--text-faint); display: grid; place-items: center; }

.note-drop {
  appearance: none;
  border: 0;
  background: none;
  color: var(--text-faint);
  padding: 4px;
  margin: -4px;
  cursor: pointer;
  flex: 0 0 auto;
}

@media (hover: hover) { .note-drop:hover { color: var(--bad); } }

/* While picking a spot on the frame, the player says so. */
.ba-box.picking {
  cursor: crosshair;
  box-shadow: inset 0 0 0 2px var(--accent);
}

/* -- the chat bar --------------------------------------------------------- */

/* Pinned above the toolbar, per SPEC "AI chat & edit notes". Glass, because
   it sits between the timeline and the tools and should read as floating over
   both rather than as another row of either. */
.chatbar {
  flex: 0 0 auto;
  appearance: none;
  border: 0;
  margin: 8px var(--pad) 4px;
  padding: 11px 14px;
  min-height: var(--tap);
  border-radius: 999px;
  display: flex;
  align-items: center;
  gap: 9px;
  background: var(--glass);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  box-shadow: inset 0 0 0 1px var(--glass-line);
  color: var(--text-dim);
  font: inherit;
  font-size: 14px;
  text-align: left;
  cursor: pointer;
  transition: box-shadow 0.18s ease;
}

@media (hover: hover) { .chatbar:hover { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.24); } }

.chatbar-text { flex: 1 1 auto; }

.chatbar-mic {
  display: grid;
  place-items: center;
  color: var(--text-faint);
}

/* A reply is one line, and a way to take it back sits under it. */
.said-line { line-height: 1.4; }

.said-undo {
  appearance: none;
  border: 0;
  margin-top: 8px;
  padding: 5px 10px;
  border-radius: 99px;
  background: var(--surface-high);
  color: var(--text);
  font: inherit;
  font-size: 12px;
  font-weight: 560;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  cursor: pointer;
}

.said-undo:disabled { opacity: 0.4; pointer-events: none; }

/* When a request is unclear the agent asks one question and the answers are
   tappable, rather than making somebody guess the phrasing. */
.said-options {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}

.chat-allowance {
  margin: 6px 0 0;
  font-size: 11.5px;
  color: var(--warn);
}

.chat-allowance:empty { display: none; }

/* -- the toolbar's two modes ---------------------------------------------- */

.tool-back {
  min-width: 38px;
  color: var(--text);
}

/* A tool the engine cannot do yet. Dimmed rather than disabled, because it
   still opens a sheet that says what it will do. */
.tool.is-soon { opacity: 0.45; }

/* -- the tab bar ---------------------------------------------------------- */

/* A floating glass pill with Create raised out of it (SPEC "Navigation").
   It floats over the screen rather than sitting under it, so a list can run
   to the bottom edge and scroll behind it. */
.tabbar {
  position: absolute;
  left: 14px;
  right: 14px;
  /* Above the home indicator, not under it. On a phone with no indicator the
     inset is zero and this is the 18px it always was. */
  bottom: var(--tabbar-gap);
  z-index: 40;
  height: var(--tabbar-h);
  display: flex;
  align-items: center;
  justify-content: space-around;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--glass);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  box-shadow:
    inset 0 0 0 1px var(--glass-line),
    0 18px 40px rgba(0, 0, 0, 0.55);
}

.navtab {
  appearance: none;
  border: 0;
  background: none;
  flex: 1 1 0;
  height: 100%;
  padding: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  color: var(--text-faint);
  cursor: pointer;
  transition: color 0.18s ease;
}

.navtab.on { color: var(--text); }

.navtab-label {
  font-size: 10px;
  font-weight: 560;
  letter-spacing: 0.01em;
}

/* Create stands proud of the pill: the one control that makes something. */
.navtab-center {
  flex: 0 0 auto;
  width: 56px;
  height: 56px;
  margin-top: -20px;
  border-radius: 20px;
  background: var(--brand);
  box-shadow: var(--brand-glow);
  color: #fff;
}

.navtab-center:active { transform: scale(0.94); }

/* Room for the bar under anything that scrolls, so the last row is reachable
   rather than sitting behind the glass.

   `flush` is a class on the body, not on the screen - written the other way
   round it excluded nothing, and the editor carried 96px of dead space that
   pushed its toolbar into the middle of the phone. */
.body:not(.flush) { padding-bottom: var(--tabbar-room); }

.screen:has(.footer) .body:not(.flush) { padding-bottom: 12px; }

.footer { padding-bottom: var(--tabbar-room); }

/* -- placeholder tabs ------------------------------------------------------ */

.soon-list {
  margin-top: 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.soon-row {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  color: var(--text-dim);
}

.soon-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--text-faint);
  flex: 0 0 auto;
}

.lead {
  margin: 2px 0 0;
  font-size: 14.5px;
  color: var(--text-dim);
}

.continue {
  margin-bottom: 10px;
}

.continue-row {
  appearance: none;
  width: 100%;
  border: 0;
  border-radius: var(--r-md);
  padding: 14px;
  margin-bottom: 8px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  display: flex;
  align-items: center;
  justify-content: space-between;
  cursor: pointer;
}

.continue-name { font-weight: 560; }

/* -- toast -------------------------------------------------------------- */

/* Sits above the footer button rather than over it, so Undo and the main
   action are never the same pixel. */
.toast {
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: calc(66px + var(--tabbar-gap));
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-radius: 13px;
  overflow: hidden;
  background: rgba(28, 28, 32, 0.97);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12), 0 10px 30px rgba(0, 0, 0, 0.5);
  animation: toast-in 0.18s ease;
}

@keyframes toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

.toast-text {
  flex: 1;
  font-size: 13.5px;
  color: var(--text);
}

.toast-action {
  appearance: none;
  border: 0;
  background: none;
  padding: 4px 6px;
  margin: -4px -2px;
  font: inherit;
  font-size: 13.5px;
  font-weight: 640;
  color: var(--accent);
  cursor: pointer;
}

/* How long is left, without a number counting down at anybody. */
.toast-bar {
  position: absolute;
  left: 0;
  bottom: 0;
  height: 2px;
  width: 100%;
  background: var(--accent);
  transform-origin: left;
  animation-name: toast-run;
  animation-timing-function: linear;
  animation-fill-mode: forwards;
}

@keyframes toast-run {
  from { transform: scaleX(1); }
  to { transform: scaleX(0); }
}

@media (prefers-reduced-motion: reduce) {
  .toast { animation: none; }
  .toast-bar { animation: none; opacity: 0.35; }
}

.btn.ghost.danger-text {
  color: var(--bad);
}

.footer-stack {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* -- create ------------------------------------------------------------- */

.tabs {
  display: flex;
  gap: 2px;
  padding: 3px;
  margin-bottom: 16px;
  border-radius: 11px;
  background: var(--surface);
}

.tab {
  flex: 1 1 0;
  appearance: none;
  border: 0;
  border-radius: 9px;
  padding: 8px 6px;
  font: inherit;
  font-size: 13px;
  font-weight: 540;
  background: none;
  color: var(--text-dim);
  cursor: pointer;
}

.tab.chosen {
  background: var(--surface-high);
  color: var(--text);
}

.create-body {
  display: block;
}

.chat.in-create {
  display: flex;
  flex-direction: column;
  min-height: 340px;
}

.chat.in-create .chat-log {
  min-height: 200px;
  padding-left: 0;
  padding-right: 0;
}

.chat.in-create .chips,
.chat.in-create .chat-row {
  padding-left: 0;
  padding-right: 0;
}

.free-to-go {
  margin-top: 22px;
  padding: 13px 14px;
  border-radius: var(--r-md);
  background: var(--surface);
  border: 1px solid var(--line);
}

.free-title {
  font-size: 13.5px;
  font-weight: 600;
}

.free-note {
  margin-top: 4px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--text-faint);
}

/* -- editor: preview, timeline, toolbar ---------------------------------- */

.preview {
  position: relative;
  flex: 0 0 auto;
  height: 38%;
  background: #000;
}

.preview .player {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

/* The layers, drawn over the video at the same coordinates the plan uses, so
 * dragging one is dragging the thing the renderer will place. */
.stage-layers {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* The frame around a layer on the preview.
 *
 * Only the selected one is drawn. Every layer outlined at once put a dashed
 * rectangle and a name tag over the video before anybody had asked to move
 * anything, which is the first thing Shandon saw when he opened the editor.
 */
.layer-box {
  position: absolute;
  pointer-events: auto;
  cursor: grab;
  border: 1px dashed transparent;
  border-radius: 3px;
  touch-action: none;
}

.layer-box.chosen {
  border: 1.5px solid var(--accent);
  background: rgba(61, 125, 255, 0.08);
  cursor: move;
}

/* These are what still drew a dashed rectangle over the video when nothing
   was selected: a per-track colour, set on every layer whether or not it was
   the one being held. They belong to the selected box only. */
.layer-box.chosen.layer-text { border-color: rgba(227, 200, 155, 0.9); }
.layer-box.chosen.layer-broll { border-color: rgba(203, 189, 232, 0.9); }

.layer-tag {
  display: none;
  position: absolute;
  left: 0;
  top: -16px;
  font-size: 9px;
  letter-spacing: 0.2px;
  padding: 1px 4px;
  border-radius: 3px;
  background: rgba(0, 0, 0, 0.6);
  color: var(--text-dim);
  white-space: nowrap;
}

.handle {
  position: absolute;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.5);
  touch-action: none;
}

.handle.se { right: -8px; bottom: -8px; cursor: nwse-resize; }
.handle.rot { left: 50%; top: -22px; margin-left: -7px; cursor: grab; background: var(--text); }

.play-toggle {
  position: absolute;
  left: 10px;
  bottom: 10px;
  appearance: none;
  border: 0;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: rgba(20, 20, 22, 0.65);
  backdrop-filter: blur(12px);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.16);
  color: var(--text);
  cursor: pointer;
}

.tl-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px var(--pad) 4px;
}

.tl-clock {
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
}

/* 22px apart, so the 44px targets these two carry sit side by side instead of
   on top of each other. */
.tl-zoom { display: flex; gap: 22px; }

.zoom {
  appearance: none;
  border: 1px solid var(--line-strong);
  background: none;
  color: var(--text-dim);
  width: 26px;
  height: 24px;
  border-radius: 7px;
  font: inherit;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
}

.tl-scroll {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  /* Up and down only. Sideways is the transform's job now, so a strip that
     is wider than the screen cannot also be dragged out of step with the
     playhead. */
  overflow-x: hidden;
  overflow-y: auto;
  padding: 0 var(--pad) 6px;
  scrollbar-width: none;
}

.tl-scroll::-webkit-scrollbar { display: none; }

.tl-inner { position: relative; height: 100%; }

.tl-ruler {
  position: relative;
  height: 14px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 4px;
}

.tl-tick {
  position: absolute;
  top: 0;
  font-size: 9px;
  color: var(--text-faint);
  border-left: 1px solid var(--line);
  padding-left: 3px;
  line-height: 1;
}

.tl-track {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 3px 0;
}

.tl-name {
  flex: 0 0 auto;
  width: 52px;
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 9.5px;
  color: var(--text-faint);
}

.tl-track.empty .tl-name { opacity: 0.5; }

.tl-lane {
  position: relative;
  flex: 1 1 auto;
  height: 32px;
  border-radius: 5px;
  background: var(--surface);
  overflow: hidden;
}

/* The video lane is the filmstrip, and a filmstrip has to be tall enough to
   show a face and a few words. The other lanes stay slim: they carry one
   thing each and do not need the room. */
.tl-track.tl-video-track .tl-lane,
.tl-track:first-child .tl-lane {
  height: 58px;
}

.tl-film {
  position: absolute;
  inset: 0;
  background-size: 100% 100%;
  background-repeat: no-repeat;
  opacity: 0.55;
  /* Thumbnails, not a control. It covers the whole lane, so without this it
     is what a press lands on - which is how the trim handles came to be
     unreachable by an actual finger while responding perfectly to a
     synthetic event aimed straight at them. */
  pointer-events: none;
}

.tl-empty {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 9.5px;
  color: var(--text-faint);
}

/* A pinch has to reach the timeline rather than be eaten as a page zoom, and
   a scrub has to not also drag-scroll the row under it. */
.tl-scroll {
  touch-action: pan-x;
}

/* The ruler is the scrub surface, so it needs to be worth aiming at. */
.tl-ruler {
  cursor: ew-resize;
  min-height: 22px;
}

.tl-block {
  position: absolute;
  top: 3px;
  bottom: 3px;
  appearance: none;
  border: 0;
  border-radius: 4px;
  padding: 0 4px;
  overflow: hidden;
  text-align: left;
  cursor: pointer;
  background: var(--surface-high);
  color: var(--text-dim);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07);
}

.tl-video { background: #23313f; color: #b9d2e8; }
.tl-broll { background: #2c2540; color: #cbbde8; }
.tl-captions { background: #1f3330; color: #a9d7c9; }
.tl-text { background: #3a2f21; color: #e3c89b; }
.tl-music { background: #2a2333; color: #c6b2d9; }

.tl-block.chosen { box-shadow: inset 0 0 0 1.5px var(--accent); color: var(--text); }
.tl-block.pending { box-shadow: inset 0 0 0 1.5px var(--warn); }

.tl-label {
  display: block;
  font-size: 9.5px;
  line-height: 26px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The frame the strip scrolls inside, with the playhead fixed down its
   middle (reference, section 5). The line does not move; the video does. */
.tl-frame {
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.playhead {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--playhead, 50%);
  width: 2px;
  background: var(--bad);
  pointer-events: none;
  z-index: 5;
}

/* The strip itself, moved under the line. Every lane and the ruler shift by
   the same amount, so they stay in step; the track names do not, because
   they are outside the lane. */
.tl-frame .tl-inner {
  transform: translateX(var(--shift, 0px));
  will-change: transform;
}

.editor-panel {
  flex: 0 0 auto;
  padding: 8px var(--pad) 4px;
  border-top: 1px solid var(--line);
  min-height: 56px;
}

.toolbar {
  display: flex;
  gap: 2px;
  overflow-x: auto;
  scrollbar-width: none;
}

.toolbar::-webkit-scrollbar { display: none; }

.tool {
  flex: 0 0 auto;
  appearance: none;
  border: 0;
  background: none;
  color: var(--text-dim);
  font: inherit;
  font-size: 9.5px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  min-width: var(--tap);
  min-height: var(--tap);
  padding: 7px 10px;
  border-radius: 9px;
  cursor: pointer;
}

@media (hover: hover) { .tool:hover:not([disabled]) { background: var(--surface); color: var(--text); } }
.tool[disabled] { opacity: 0.32; cursor: default; }

.ready-title {
  font-size: 22px;
  font-weight: 680;
  letter-spacing: -0.5px;
  margin-bottom: 14px;
}

.ready-figures {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--line);
  border-radius: var(--r-md);
  overflow: hidden;
}

.ready-figures .figure { background: #17171a; padding: 11px 6px; text-align: center; }
.ready-figures .figure-value { font-size: 16px; }

.ready-note {
  margin: 12px 0 16px;
  font-size: 13px;
  color: var(--text-dim);
}

.layout-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin-bottom: 14px;
}

.layout {
  appearance: none;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--text-dim);
  font: inherit;
  font-size: 9.5px;
  padding: 8px 4px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}

@media (hover: hover) { .layout:hover { border-color: var(--accent); color: var(--text); } }

.layout-shape {
  width: 30px;
  height: 40px;
  border: 1px solid var(--line-strong);
  border-radius: 3px;
  position: relative;
  overflow: hidden;
}

.layout-shape::after {
  content: "";
  position: absolute;
  background: var(--accent);
  opacity: 0.75;
}

.shape-full::after { inset: 0; }
.shape-pip-top-left::after { left: 3px; top: 3px; width: 11px; height: 11px; }
.shape-pip-top-right::after { right: 3px; top: 3px; width: 11px; height: 11px; }
.shape-pip-bottom-left::after { left: 3px; bottom: 3px; width: 11px; height: 11px; }
.shape-pip-bottom-right::after { right: 3px; bottom: 3px; width: 11px; height: 11px; }
.shape-split-top::after { left: 0; right: 0; top: 0; height: 50%; }
.shape-split-bottom::after { left: 0; right: 0; bottom: 0; height: 50%; }
.shape-split-left::after { top: 0; bottom: 0; left: 0; width: 50%; }
.shape-split-right::after { top: 0; bottom: 0; right: 0; width: 50%; }

.nudge { display: flex; gap: 4px; margin-bottom: 12px; }
.nudge .segment { background: var(--surface); }

.chat.in-sheet { display: flex; flex-direction: column; }
.chat.in-sheet .chat-log { min-height: 150px; max-height: 220px; padding: 0 0 6px; }
.chat.in-sheet .chips, .chat.in-sheet .chat-row { padding-left: 0; padding-right: 0; }

/* A proxy still being made. Better than a black rectangle, which is what a
 * browser shows for an HEVC file it cannot open. */
.thumb-working {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  color: var(--text-faint);
}

/* -- the editor: one screen, player pinned, toolbar pinned --------------- */

/* A column that fills what is left of the phone, with only the middle of it
   scrolling. Letting the whole thing scroll put the toolbar below the fold at
   390x844, and the toolbar is how anything gets edited. */
.editor-body {
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* Full width, capped height, video letterboxed inside - not a 9:16 box.
   A 9:16 box on a 9:16 phone leaves nothing for the timeline and the toolbar,
   and shrinking it to fit made the picture 170px wide with gutters either
   side. A black stage with the video centred in it is what every phone editor
   does, and it is the same picture, larger. */
.editor-body .ba-box {
  /* A share of the column rather than "whatever is left": as a flexible item
     it lost every argument with the timeline and sat at its 150px minimum.
     About half the screen, which is what the reference gives it. */
  flex: 0 0 auto;
  height: 46%;
  aspect-ratio: auto;
  min-height: 150px;
  max-height: 50vh;
}

/* No browser control bar under it here, so the toggle sits in the corner
   rather than hovering above where the scrubber used to be. */
.editor-body .ba-toggle {
  bottom: 10px;
}

/* What you are actually watching, said on the player itself.
   Top left, because both bottom corners already have a control in them, and
   a chip rather than a sentence because the player is 213px tall on a phone.
   Laid out in the flow it sat behind the videos, which are absolute. */
/* What the live preview is not showing.
 *
 * True and worth saying - the cut plays without its captions - but it was a
 * bright yellow banner across the top of the video, which is a warning's
 * weight for a footnote. Quiet, small, and out of the middle. */
.ba-note {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 3;
  max-width: calc(100% - 16px);
  padding: 3px 8px;
  border-radius: 99px;
  font-size: 9.5px;
  font-weight: 560;
  letter-spacing: 0.01em;
  opacity: 0.75;
  color: var(--text-dim);
  background: rgba(10, 10, 12, 0.82);
  backdrop-filter: blur(10px);
  box-shadow: inset 0 0 0 1px var(--line);
  pointer-events: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.editor-scrollers {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: none;
}

.editor-scrollers::-webkit-scrollbar { display: none; }

.editor-body .toolbar {
  flex: 0 0 auto;
  padding: 6px var(--pad) var(--safe-bottom);
}

.editor-body .tl-head {
  flex: 0 0 auto;
}

.editor-body .cmp-note {
  margin: 0;
  flex: 1 1 auto;
  text-align: center;
}

.ba-box {
  position: relative;
  margin: 0 var(--pad);
  border-radius: var(--r-md);
  overflow: hidden;
  background: #000;
  aspect-ratio: 9 / 16;
  max-height: 52vh;
}

.ba-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #000;
}

/* Hidden, not unloaded. Both keep their buffer so a swap is instant. */
.ba-video.hidden {
  opacity: 0;
  pointer-events: none;
}

.ba-toggle {
  position: absolute;
  right: 10px;
  /* Clear of the player's own control bar, which is about 48px tall and sits
   * under it. Overlapping meant the pill and the scrubber fought for taps. */
  bottom: 62px;
  z-index: 2;
  appearance: none;
  border: 0;
  border-radius: 99px;
  padding: 8px 14px;
  min-height: var(--tap);
  font: inherit;
  font-size: 13px;
  font-weight: 640;
  letter-spacing: 0.2px;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  cursor: pointer;
  background: rgba(14, 14, 16, 0.78);
  backdrop-filter: blur(14px) saturate(140%);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18), 0 4px 14px rgba(0, 0, 0, 0.5);
  color: var(--text);
  transition: background 0.18s ease, color 0.18s ease;
}

.ba-toggle .ba-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
}

/* Watching the original: the button says so loudly, because the one thing
 * that must never happen is not knowing which you are looking at. */
.ba-toggle.original {
  background: var(--warn);
  color: #1a1400;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2), 0 4px 14px rgba(0, 0, 0, 0.5);
}

.ba-toggle.original .ba-dot { background: #1a1400; }

.cmp-note {
  margin: 9px var(--pad) 0;
  font-size: 12px;
  color: var(--text-faint);
}


/* -- the More panel: everything advanced, closed by default -------------- */

.more-toggle {
  appearance: none;
  width: 100%;
  margin-top: 22px;
  padding: 11px 14px;
  min-height: var(--tap);
  border-radius: var(--r-md);
  border: 1px solid var(--line-strong);
  background: none;
  color: var(--text-dim);
  font: inherit;
  font-size: 13.5px;
  font-weight: 540;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  cursor: pointer;
}

@media (hover: hover) { .more-toggle:hover { color: var(--text); border-color: var(--accent); } }

.more-panel {
  margin-top: 4px;
  animation: more-in 0.24s var(--spring);
}

@keyframes more-in {
  from { opacity: 0; transform: translateY(-4px); }
}

.banner-icon {
  color: var(--bad);
  margin-right: 6px;
  vertical-align: -2px;
}

/* -- the shared kit ----------------------------------------------------- */

/* Parts every lane builds from (features/kit.js). Anything drawn by a feature
   comes from here, so six lanes ship one app rather than six. */

/* A control and its plain-words line, side by side with its switch. */
.control-main {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.control-main .control-note {
  flex-basis: auto;
  margin: 0;
}

/* Something went wrong, and what to do about it. */
.banner-text {
  flex: 1 1 auto;
  min-width: 0;
}

.banner[data-error="1"] {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--text);
}

.banner-action {
  appearance: none;
  border: 0;
  flex: 0 0 auto;
  min-height: var(--tap);
  padding: 0 14px;
  border-radius: 99px;
  background: rgba(255, 255, 255, 0.1);
  box-shadow: inset 0 0 0 1px var(--line-strong);
  color: var(--text);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

.banner-action:active { background: rgba(255, 255, 255, 0.16); }

/* A line to type into. 16px, and not a pixel less: iOS zooms the whole page
   in when a field it focuses has smaller type, and the zoom never comes back
   on its own. */
.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 14px;
}

.field-label {
  font-size: 12.5px;
  font-weight: 560;
  color: var(--text-dim);
}

.input {
  appearance: none;
  width: 100%;
  min-height: var(--tap);
  padding: 11px 14px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 16px;
}

.input::placeholder { color: var(--text-faint); }

.input:focus {
  outline: none;
  border-color: var(--accent);
}

/* -- You ---------------------------------------------------------------- */

.you-card {
  margin-top: 18px;
  padding: 16px 18px;
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line);
}

.you-name {
  font-family: var(--font-head);
  font-size: 19px;
  font-weight: 640;
  letter-spacing: -0.02em;
}

.you-meta {
  margin-top: 2px;
  font-size: 13px;
  color: var(--text-dim);
}

/* What is left today, as two numbers. A bar two thirds full is a puzzle; "3
   edits left today" is a fact you can act on. */
.you-limits {
  display: flex;
  gap: 10px;
}

.you-limit {
  flex: 1 1 0;
  padding: 14px;
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line);
}

.you-figure {
  display: block;
  font-family: var(--font-head);
  font-size: 26px;
  font-weight: 680;
  letter-spacing: -0.03em;
}

.you-note {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  line-height: 1.3;
  color: var(--text-dim);
}

/* -- an upload that can fail --------------------------------------------- */

.upload-percent {
  flex: 0 0 auto;
  min-width: 38px;
  text-align: right;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
}

.clip.failed {
  border-color: rgba(229, 72, 77, 0.4);
}

.clip-order.bad {
  color: var(--bad);
}

/* Why it did not go up, beside the file it happened to. */
.clip-problem {
  margin-top: 2px;
  font-size: 12px;
  line-height: 1.35;
  color: var(--text-dim);
}

.clip-retry {
  appearance: none;
  border: 0;
  flex: 0 0 auto;
  min-height: var(--tap);
  padding: 0 14px;
  border-radius: 99px;
  background: rgba(255, 255, 255, 0.1);
  box-shadow: inset 0 0 0 1px var(--line-strong);
  color: var(--text);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

.clip-retry:active { background: rgba(255, 255, 255, 0.18); }

/* Waiting behind somebody else's edit. The position matters more than the
   spinner: "2nd in line" is a wait a person can sit through. */
.queued {
  margin-top: 8px;
  padding: 10px 14px;
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line);
  font-size: 13px;
  color: var(--text-dim);
}

/* -- the editor, to the reference layout --------------------------------- */

/* Where you are, out of how long the cut is. Tabular figures so the numbers
   do not jump about as they count. */
.tl-time {
  flex: 0 0 auto;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
}

.tl-time .tl-clock {
  font-weight: 640;
  color: var(--text);
}

.tl-total {
  color: var(--text-faint);
}

/* Play is the one control on this row anybody aims for, so it is bigger than
   the rest and sits in the middle where a thumb lands without looking. */
.row-btn.play.big {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  color: var(--text);
  background: rgba(255, 255, 255, 0.08);
  box-shadow: inset 0 0 0 1px var(--line-strong);
}

.row-btn.play.big:active:not(:disabled) {
  background: rgba(255, 255, 255, 0.16);
}

/* The words on a clip: as many as fit, clipped cleanly, never wrapped. It is
   how you find the bit you are looking for at a glance. */
.tl-block .tl-label {
  font-size: 9.5px;
  line-height: 1.15;
  font-weight: 560;
  letter-spacing: 0.01em;
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 2px 4px 0;
  color: rgba(255, 255, 255, 0.92);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9);
}

/* How long the clip is, in its bottom corner, out of the way of the words. */
.tl-length {
  position: absolute;
  right: 3px;
  bottom: 2px;
  font-size: 8.5px;
  font-variant-numeric: tabular-nums;
  color: rgba(255, 255, 255, 0.75);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9);
  pointer-events: none;
}

/* A tool that cannot be used right now dims rather than disappearing: a
   toolbar that changes length as you tap around it is a toolbar you cannot
   learn (reference, section 5). */
.tool[disabled] {
  opacity: 0.32;
}

/* Delete means something only when something is selected, and then it says so
   in the one colour that means "this takes something away". */
.tool.danger:not([disabled]) {
  color: var(--bad);
}

/* -- processing, to the reference layout --------------------------------- */

.processing-head {
  margin-top: 24px;
  text-align: center;
}

.processing-head .title {
  font-size: 26px;
}

/* "You can leave, we will tell you." The one thing worth knowing while a
   machine works, and the reason nobody has to sit and watch it. */
.processing-sub {
  margin: 6px 0 0;
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--text-dim);
}

/* The clip, with how far it has got drawn around it.
 *
 * The percentage sits on the thing being worked on rather than in a bar
 * somewhere else, so it is obvious what is happening to what. */
.ring {
  position: relative;
  width: 190px;
  aspect-ratio: 9 / 16;
  max-height: 46vh;
  margin: 26px auto 0;
  border-radius: 18px;
  overflow: hidden;
  background: var(--surface);
}

.ring-shot {
  position: absolute;
  inset: 0;
  filter: brightness(0.5);
}

.ring-shot video,
.ring-shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The steps are two words and a dot, not two cards. */
.step {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: none;
  padding: 0;
}

/* The ring itself: one conic sweep, no SVG and no animation frame. It moves
   when the engine says it has moved and at no other time. */
.ring-arc {
  position: absolute;
  inset: 0;
  border-radius: 18px;
  padding: 3px;
  background: conic-gradient(var(--accent) var(--done, 0%), rgba(255, 255, 255, 0.12) 0);
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  mask-composite: exclude;
  transition: background 0.4s linear;
}

.ring-percent {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-family: var(--font-head);
  font-size: 34px;
  font-weight: 680;
  letter-spacing: -0.03em;
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.8);
}

/* Two steps, because the engine really does two passes. */
.stepper {
  display: flex;
  justify-content: center;
  gap: 18px;
  margin-top: 18px;
  font-size: 12px;
  color: var(--text-faint);
}

.step {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.step-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--line-strong);
}

.step.done {
  color: var(--text-dim);
}

.step.done .step-dot {
  background: var(--accent);
}

.processing-foot {
  margin-top: 22px;
  text-align: center;
}

/* -- the export sheet ----------------------------------------------------- */

.export-head {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 14px;
}

.export-shot {
  flex: 0 0 auto;
  width: 54px;
  height: 72px;
  border-radius: 10px;
  overflow: hidden;
  background: var(--surface-high);
  display: grid;
  place-items: center;
  color: var(--text-faint);
}

.export-shot video,
.export-shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.export-name {
  font-family: var(--font-head);
  font-size: 17px;
  font-weight: 640;
  letter-spacing: -0.02em;
}

.export-meta {
  margin-top: 2px;
  font-size: 13px;
  color: var(--text-dim);
}

/* What is about to be made, one fact a line. Read-only for now: V1 exports
   1080p and nothing else, and a dropdown with one option in it is a promise
   of a choice that does not exist. */
.export-rows {
  margin: 16px 0 18px;
}

.export-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 11px 2px;
  border-bottom: 1px solid var(--line);
  font-size: 14px;
}

.export-row:last-child {
  border-bottom: 0;
}

/* Pushed to the right so the value stays in the same column as every other
   row's, with the note tucked just inside it. */
.export-note {
  margin-left: auto;
  font-size: 12px;
  color: var(--text-faint);
}

.export-label {
  color: var(--text-dim);
}

.export-value {
  font-weight: 620;
  font-variant-numeric: tabular-nums;
}

/* The line that says the video is older than the edit. */
.warn-hint {
  color: var(--warn);
}

.export-action {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* A row of pills that runs off the side of the screen: filters, folders,
   caption styles. The row scrolls; the pills do not shrink. */
.pill-row {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  scrollbar-width: none;
  padding: 2px var(--pad);
  margin: 0 calc(var(--pad) * -1);
}

.pill-row::-webkit-scrollbar { display: none; }

.pill {
  appearance: none;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--tap);
  padding: 0 15px;
  border: 0;
  border-radius: 99px;
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line);
  color: var(--text-dim);
  font: inherit;
  font-size: 13.5px;
  font-weight: 560;
  white-space: nowrap;
  cursor: pointer;
}

.pill.on {
  background: var(--surface-high);
  box-shadow: inset 0 0 0 1px var(--line-strong);
  color: var(--text);
}

/* A nav-bar button that is currently on. */
.nav-btn.on {
  color: var(--accent);
  font-weight: 620;
}

/* -- caption looks -------------------------------------------------------- */

/* Each one drawn in its own style, so the choice is made by looking. */
.cap-styles {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  scrollbar-width: none;
  padding: 2px var(--pad) 6px;
  margin: 0 calc(var(--pad) * -1);
}

.cap-styles::-webkit-scrollbar { display: none; }

.cap-style {
  appearance: none;
  flex: 0 0 auto;
  width: 108px;
  min-height: var(--tap);
  padding: 12px 10px 10px;
  border: 0;
  border-radius: var(--r-md);
  background: #000;
  box-shadow: inset 0 0 0 1px var(--line);
  cursor: pointer;
  text-align: center;
}

.cap-style.on {
  box-shadow: inset 0 0 0 2px var(--accent);
}

.cap-sample {
  display: block;
  font-size: 13px;
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.01em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cap-name {
  display: block;
  margin-top: 8px;
  font-size: 10.5px;
  color: var(--text-faint);
}

/* -- adding another clip -------------------------------------------------- */

/* The "+" at the end of the strip, on the lane it would join. */
.tl-add-wrap {
  position: absolute;
  right: -46px;
  top: 0;
  bottom: 0;
  display: grid;
  place-items: center;
}

.tl-add {
  appearance: none;
  border: 0;
  width: 40px;
  height: 40px;
  border-radius: 12px;
  display: grid;
  place-items: center;
  background: var(--surface-high);
  box-shadow: inset 0 0 0 1px var(--line-strong);
  color: var(--text);
  cursor: pointer;
}

/* The editor, dimmed, while the cut is made again with the new clip in it.
   A timeline that freezes with no explanation is what this replaces. */
.adding {
  position: absolute;
  inset: 0;
  z-index: 70;
  display: grid;
  place-items: center;
  padding: var(--pad);
  background: rgba(7, 7, 12, 0.72);
  backdrop-filter: blur(6px);
}

.adding-card {
  width: 100%;
  max-width: 300px;
  padding: 22px 20px;
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line-strong), 0 20px 50px rgba(0, 0, 0, 0.6);
  text-align: center;
}

.adding-title {
  margin-top: 12px;
  font-family: var(--font-head);
  font-size: 17px;
  font-weight: 640;
}

.adding-note {
  margin-top: 4px;
  font-size: 13px;
  line-height: 1.4;
  color: var(--text-dim);
}

.adding-warn {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  font-size: 12px;
  line-height: 1.4;
  color: var(--warn);
}

/* -- the live cut preview ------------------------------------------------ */

.preview.live-preview { background: #000; }

.live { position: absolute; inset: 0; display: flex; flex-direction: column; }

.live-box { position: relative; flex: 1 1 auto; min-height: 0; background: #000; }

.live-video {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
  background: #000;
}

.live-controls {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 6px 10px;
  background: rgba(0, 0, 0, 0.5);
}

.live-play {
  appearance: none;
  border: 0;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: rgba(255, 255, 255, 0.92);
  color: #000;
  cursor: pointer;
}

.live-play.playing { background: var(--accent); color: #fff; }

.live-scrub {
  flex: 1 1 auto;
  appearance: none;
  height: 18px;
  background: none;
  cursor: pointer;
}

.live-scrub::-webkit-slider-runnable-track {
  height: 3px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.22);
}

.live-scrub::-webkit-slider-thumb {
  appearance: none;
  width: 12px;
  height: 12px;
  margin-top: -4.5px;
  border-radius: 50%;
  background: #fff;
}

.live-time {
  flex: 0 0 auto;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
}

/* The tag naming a layer comes back with the box that holds it. */
.layer-box.chosen .layer-tag {
  display: inline-flex;
}
