/* KitchenDrop operator portal. Depends on brand.css.
   Built phone-first — this gets used standing at the pass, not at a desk. */

:root {
  /* The width of the work on a desktop, before the view's own padding. Every
     view is this wide and centred, so a form, a card, a section heading and
     the drops grid all share one left and one right edge no matter how big
     the monitor is. Wider than this and a single-line input starts reading as
     a mistake; narrower and a row of drop cards stops fitting three across. */
  --col: 880px;
}

/* ---------- Which agent a thing came from ----------
   Anything carrying data-intent picks up that agent's colour and wash here,
   once, and every component downstream just reads --intent. Each agent's
   colour used to be written out again in every component that showed one,
   which is how the pitch pills and the mix meters ended up disagreeing about
   Reach -- and how two of them ended up as raw hexes that went unreadable the
   moment the theme flipped. */

[data-intent="reach"] {
  --intent: var(--intent-reach);
  --intent-wash: var(--intent-reach-wash);
}

[data-intent="craving"] {
  --intent: var(--intent-craving);
  --intent-wash: var(--intent-craving-wash);
}

[data-intent="trust"] {
  --intent: var(--intent-trust);
  --intent-wash: var(--intent-trust-wash);
}

[data-intent="booking_order"] {
  --intent: var(--intent-booking_order);
  --intent-wash: var(--intent-booking_order-wash);
}

body {
  display: flex;
  justify-content: center;
  min-height: 100vh;
  background: var(--surface-2);
}

.app {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 520px;
  min-height: 100vh;
  padding-bottom: calc(var(--tabbar-h, 72px) + 20px);
  background: var(--bg);
  border-inline: 1px solid var(--line);
}

/* ---------- App bar ---------- */

.app-bar {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  background: var(--veil);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
}

.app-bar .kd-logo {
  font-size: 1rem;
  margin-right: auto;
}

.app-bar-tools {
  display: flex;
  align-items: center;
  gap: 8px;
}

.btn-sm {
  padding: 0.45em 0.75em;
  font-size: 0.8125rem;
}

/* Which restaurant you're working on is context, not a form field. It reads as
   one quiet line under the app bar so the first real thing on the page is the
   thing you came to do. */
.place-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  border-bottom: 1px solid var(--line-soft);
  background: var(--surface);
}

.place-bar-icon {
  width: 17px;
  height: 17px;
  flex: none;
  color: var(--fg-3);
}

.place-select {
  flex: 1;
  min-width: 0;
  border: 0;
  background: transparent;
  padding: 2px 0;
  font: inherit;
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--fg-1);
  cursor: pointer;
  appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23585f6d' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat: no-repeat;
  background-position: right 0 center;
  background-size: 15px;
  padding-right: 20px;
  text-overflow: ellipsis;
}

.place-select:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 3px;
  border-radius: 4px;
}

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

/* ---------- Views ---------- */

.view {
  display: none;
  padding: 16px;
}

.view.is-active {
  display: block;
  animation: kd-view 0.18s var(--ease);
}

@keyframes kd-view {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: none; }
}

/* ---------- Send card ---------- */




/* ---------- Cards & forms ---------- */

.card {
  padding: 18px;
  margin-bottom: 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--shadow-1);
}

.card-head {
  margin-bottom: 18px;
}

.card-head h2 {
  font-family: var(--sans);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -0.012em;
}

.card-head p {
  max-width: 62ch;
  margin-top: 4px;
  font-size: 0.8125rem;
  color: var(--fg-3);
  line-height: 1.5;
}

.switch-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 0;
  border-top: 1px solid var(--line-soft);
}

.switch-row b {
  display: block;
  font-size: 0.875rem;
  font-weight: 600;
}

.switch-row span {
  display: block;
  margin-top: 2px;
  font-size: 0.8125rem;
  color: var(--fg-3);
  line-height: 1.45;
}

.switch-row:last-child {
  padding-bottom: 0;
}

/* A quiet "optional" tag inside a field label. */
/* Two short fields that belong together read better on one line than stacked. */
.field-pair {
  display: grid;
  gap: 0 12px;
  grid-template-columns: 1fr 1fr;
}

@media (max-width: 400px) {
  .field-pair { grid-template-columns: 1fr; }
}

.label-optional {
  margin-left: 5px;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--fg-4);
  text-transform: none;
  letter-spacing: 0;
}

/* ---------- Dropzone ---------- */

/* Both selectors carry the same weight on purpose. A bare `.dropzone` loses to
   `.field label` in brand.css, which forces display:block and collapses the
   icon, the title and the hint onto one line — so every context a dropzone
   lives in has to be named rather than relying on the class alone. */
.field .dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 26px 16px;
  border: 1.5px dashed var(--line-strong);
  border-radius: var(--r-md);
  background: var(--surface-2);
  cursor: pointer;
  text-align: center;
  transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease);
}

.dropzone:hover,
.dropzone.is-hot {
  border-color: var(--brand);
  background: var(--brand-wash);
}

.dropzone svg {
  width: 22px;
  height: 22px;
  margin-bottom: 5px;
  color: var(--fg-3);
}

.field .dropzone b {
  margin: 0;
  color: var(--fg);
  font-size: 0.875rem;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.field .dropzone span {
  font-size: 0.8125rem;
  color: var(--fg-3);
}

/* Picked files, listed under the dropzone so photos/videos are clearly visible with thumbnails */
.file-list {
  list-style: none;
  margin: 12px 0 0;
  padding: 0 2px 0 0;
  display: grid;
  gap: 8px;
  max-height: 240px;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--line-strong) transparent;
}
.file-list::-webkit-scrollbar {
  width: 5px;
}
.file-list::-webkit-scrollbar-thumb {
  background: var(--line-strong);
  border-radius: 4px;
}
.file-list li,
.file-list .file-item {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 13px;
  color: var(--fg-2);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  padding: 8px 12px;
  position: relative;
  overflow: hidden;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.file-list li:hover,
.file-list .file-item:hover {
  border-color: var(--line-strong);
  background: var(--surface);
}
.file-list-badge {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  border-radius: var(--r-pill);
  background: var(--brand-ink);
  color: var(--on-brand);
  font-size: 11px;
  font-weight: 700;
  display: grid;
  place-items: center;
}
/* A drop is a running order, so the rows can be dragged into one. The handle is
   a real button: the same reorder has to work from a keyboard, and native
   drag-and-drop never fires on touch. */
.file-drag-handle {
  flex: 0 0 auto;
  width: 24px;
  height: 32px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  color: var(--fg-3);
  cursor: grab;
  display: grid;
  place-items: center;
  padding: 0;
  margin-left: -4px;
  touch-action: none;
  transition: color 0.15s ease, background 0.15s ease;
}
.file-drag-handle:hover {
  color: var(--fg);
  background: var(--surface-3);
}
.file-drag-handle:focus-visible {
  outline: none;
  border-color: var(--brand);
  color: var(--brand-ink);
}
.file-drag-handle:active {
  cursor: grabbing;
}
.file-drag-handle svg {
  width: 15px;
  height: 15px;
  display: block;
}
.file-list .file-item.is-dragging {
  border-color: var(--brand);
  background: var(--brand-wash);
  box-shadow: var(--shadow-2);
}

/* Wraps the thumb so a clip's length can sit on top of its own frame. */
.file-thumb-wrap {
  position: relative;
  flex: 0 0 48px;
  width: 48px;
  height: 48px;
}
.file-thumb-wrap .file-list-thumb,
.file-thumb-wrap .file-list-video-icon {
  flex: none;
  width: 100%;
  height: 100%;
}
.file-thumb-duration {
  position: absolute;
  right: 2px;
  bottom: 2px;
  padding: 1px 4px;
  border-radius: 4px;
  background: rgba(11, 16, 32, 0.78);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.02em;
  line-height: 1.4;
}

/* What the shots add up to, said before the owner sends rather than after the
   render comes back a different length than they pictured. */
.shot-summary {
  margin: 10px 2px 0;
  font-size: 12px;
  font-weight: 500;
  color: var(--fg-3);
}
/* Said before sending, when the attached shots will not all survive the cut. */
.shot-summary.is-warning {
  color: var(--warn);
  font-weight: 600;
}


/* The pre-send check under the format picker. Three tones, one box. */

.file-list-thumb {
  flex: 0 0 48px;
  width: 48px;
  height: 48px;
  border-radius: var(--r-sm);
  object-fit: cover;
  background: var(--surface-3);
  border: 1px solid var(--line-strong);
  display: block;
  box-shadow: var(--shadow-1);
}
.file-list-video-icon {
  flex: 0 0 48px;
  width: 48px;
  height: 48px;
  border-radius: var(--r-sm);
  background: var(--surface-3);
  border: 1px solid var(--line-strong);
  display: grid;
  place-items: center;
  color: var(--brand-ink);
  box-shadow: var(--shadow-1);
}
.file-list-info {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1;
  gap: 2px;
}
.file-list-name {
  font-weight: 600;
  color: var(--fg);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
}
.file-list-meta {
  font-size: 11px;
  color: var(--fg-3);
  font-weight: 500;
}
.file-remove-btn {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  border-radius: 6px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--fg-3);
  cursor: pointer;
  display: grid;
  place-items: center;
  padding: 0;
  margin-left: auto;
  transition: background-color 0.15s var(--ease), border-color 0.15s var(--ease),
    color 0.15s var(--ease);
}
.file-remove-btn:hover {
  background: var(--bad-wash);
  color: var(--bad);
  border-color: rgba(178, 59, 44, 0.2);
}
.file-remove-btn svg {
  width: 15px;
  height: 15px;
  display: block;
}

.dropzone.has-file {
  border-style: solid;
  border-color: var(--brand);
  background: var(--brand-wash);
}

.dropzone.has-file svg {
  color: var(--brand-ink);
}

/* ---------- Feed ---------- */

/* A row, not a column. Cards keep the size a drop actually is and the row runs
   past the right edge, which is what says there is more without spending a
   screen saying it. */
/* A grid, not a row.
   This was a horizontal carousel: on a 1280px screen it showed three and a half
   drops out of nine, with the bottom half of the page empty underneath, and it
   needed arrows, edge fades and scroll-position bookkeeping to make being a row
   bearable. A grid needs none of that, shows all of them, and scrolls the way
   every other page does. */
.feed {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(232px, 1fr));
  gap: 16px;
  /* Vertical room for the card shadow, which a clipped overflow would cut. */
  padding: 4px;
  margin: 0 -4px;
}

/* Two up on a phone. One 340px-wide card per row is a screen per drop — worse
   than the row this replaced, which at least let you swipe. Narrow enough that
   the action labels shorten, which .drop-actions-minor already handles. */
@media (max-width: 560px) {
  .feed {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
  }

  /* Two folds, two action rows, a caption and its hashtags all stack in a
     column 139px wide, so every row of chrome costs real depth. */
  .drop-body .vo { margin-top: 6px; }
  .drop-body .vo summary { padding-top: 6px; padding-bottom: 6px; }

  /* One line of hashtags, not two. Two was already a truncation — the second
     line only ever bought one more tag, for a fifth of the body's height.
     Scoped through .drop-body to outrank the base rule further down. */
  .drop-body .tags { -webkit-line-clamp: 1; }

  /* A flex line is collected from each item's content width, so a label wider
     than what the tick left over jumped to a line of its own and left the tick
     sitting alone. A zero basis puts the label on the tick's line and lets it
     wrap inside itself; the link takes the line under them both. */
  .drop-body .stamp-text { flex: 1 1 0; text-align: center; }
  .drop-body .stamp-link { flex: 1 0 100%; margin-left: 0; text-align: center; }
}


/* Empty states and the loading skeleton are messages about the grid, not items
   in it, so they take the full width rather than sitting in one cell. */
.feed > :not(.drop):not(.feed-more) { grid-column: 1 / -1; }

.drop {
  display: flex;
  /* Was `flex: 0 0 260px` for the carousel; the grid track sets the width now,
     so a card fills its column instead of being a fixed slab in a row. */
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: var(--shadow-2);
  overflow: hidden;
}

/* The card opens on the drop itself. State, dish and provenance are laid over
   the picture rather than stacked above it in a bar, so what the owner is
   judging is the first thing on screen and every card is the same shape. */
.drop-media {
  position: relative;
  flex: none;
  width: 100%;
  aspect-ratio: 4 / 5;
  background: #0a0e0b;
  display: grid;
  place-items: center;
  overflow: hidden;
}

.drop-media.is-still { background: var(--surface-2); }

.drop-media video,
.drop-media img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}

/* Fills the stage a still of another shape would leave bare. The frame itself
   stays whole on top of it: cropping to fit would hide the part of the picture
   the owner is being asked to stand behind. */
.drop-backdrop {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  object-fit: cover;
  filter: blur(26px) saturate(1.25);
  /* Past the edges, so the blur samples picture rather than its own falloff. */
  transform: scale(1.18);
}

.drop-shot { position: relative; }

/* ---- The overlay ----
   Inert as a whole. The stage under it is one large play target, and a lid of
   transparent boxes over that would swallow the click. Only remove opts back
   in to pointer events. */

.drop-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
  transition: opacity 0.2s var(--ease);
}

/* The edit, on the picture. Hidden until the pointer is on the card so a grid
   of drops stays a grid of drops; the Edit button in the row below is what
   touch uses, where there is no hover to show this. */
.drop-edit {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) scale(0.96);
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 9px 16px;
  border: none;
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--fg);
  font: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  box-shadow: var(--shadow-3);
  opacity: 0;
  cursor: pointer;
  transition: opacity 0.16s var(--ease), transform 0.16s var(--ease);
}

.drop-media:hover .drop-edit,
.drop-edit:focus-visible {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

@media (hover: none) {
  .drop-edit { display: none; }
}

/* Over a photograph the wash backgrounds have nothing to sit on, so the chip
   keeps a dark base for legibility and takes its state from a tint laid over
   that base — enough hue to tell the states apart down a row of cards, not so
   much that it stops being readable against a bright picture. */
.drop-overlay .pill {
  position: absolute;
  top: 9px;
  left: 9px;
  max-width: calc(100% - 60px);
  padding: 0.28em 0.62em;
  border-color: var(--edge, rgba(255, 255, 255, 0.18));
  background: linear-gradient(rgba(10, 14, 24, 0.62), rgba(10, 14, 24, 0.62)),
    var(--tint, transparent);
  color: var(--ink, #fff);
  box-shadow: 0 1px 10px rgba(0, 0, 0, 0.3);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

.drop-overlay .pill::before {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--dot, #cbd5e1);
  box-shadow: 0 0 0 3px var(--halo, transparent);
}

.drop-overlay .pill-live::before { animation: kd-pulse 1.6s var(--ease) infinite; }

.drop-overlay .pill-good {
  --dot: #4ade80;
  --tint: rgba(34, 197, 94, 0.34);
  --edge: rgba(134, 239, 172, 0.5);
  --ink: #d7f8e3;
}

.drop-overlay .pill-warn {
  --dot: #fb923c;
  --tint: rgba(249, 115, 22, 0.34);
  --edge: rgba(253, 186, 116, 0.5);
  --ink: #ffe6cf;
}

.drop-overlay .pill-bad {
  --dot: #f87171;
  --tint: rgba(239, 68, 68, 0.36);
  --edge: rgba(252, 165, 165, 0.5);
  --ink: #ffdedb;
}

.drop-overlay .pill-violet {
  --dot: #c4b5fd;
  --tint: rgba(139, 92, 246, 0.34);
  --edge: rgba(196, 181, 253, 0.5);
  --ink: #e9e0ff;
}

/* The one state that is a request rather than a report: it is the only thing
   on this screen the owner has to do something about, so it drops the dark
   base entirely and reads as a solid marker down the row. */
.drop-overlay .pill-gold {
  --dot: #7a5300;
  --halo: rgba(122, 83, 0, 0.16);
  border-color: rgba(255, 255, 255, 0.42);
  background: linear-gradient(180deg, #ffd873, #f7bf3c);
  color: #4a3400;
  font-weight: 700;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.35);
}

.drop-capbar {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  padding: 26px 12px 10px;
  background: linear-gradient(
    to top,
    rgba(8, 11, 18, 0.88) 0%,
    rgba(8, 11, 18, 0.55) 46%,
    rgba(8, 11, 18, 0) 100%
  );
  color: #fff;
}

/* The pipeline and the stopped panel are centred columns and need the floor
   they stand on; the capbar's gradient is also cut for photographs, and over a
   pale panel it reads as a stray dark band. */
.drop-media.is-pipeline .drop-capbar,
.drop-media.is-stalled .drop-capbar { display: none; }

.drop-title {
  margin: 0;
  font-size: 0.9375rem;
  font-weight: 650;
  line-height: 1.25;
  letter-spacing: -0.01em;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.55);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.drop-facts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 5px;
  font-size: 0.75rem;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.84);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}

.drop-facts span + span::before {
  content: "";
  display: inline-block;
  width: 1px;
  height: 0.85em;
  margin: 0 8px;
  vertical-align: -0.1em;
  background: rgba(255, 255, 255, 0.34);
}

@media (prefers-reduced-motion: reduce) {
  .drop-overlay,
  .drop-remove { transition: none; }
}

/* ---- The opener ----
   A reel's first frame is often dark and always still, which reads as a broken
   image rather than as something you can start. One disc over the whole stage
   says otherwise. The stage no longer plays in place — it opens the drop in the
   media sheet — so the affordance stays put instead of clearing out to free the
   controls underneath it. */

.drop-open {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  width: 100%;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  transition: background-color 0.2s var(--ease);
}

/* Only a clip needs lifting off its frame; a still is its own invitation. */
.drop-open.is-video {
  background: linear-gradient(180deg, rgba(0, 0, 0, 0.04), rgba(0, 0, 0, 0.16));
}

.drop-open:hover { background-color: rgba(0, 0, 0, 0.14); }

.drop-play-disc {
  display: grid;
  place-items: center;
  width: 58px;
  height: 58px;
  padding-left: 4px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.94);
  color: #16203a;
  box-shadow: var(--shadow-2);
  transition: transform 0.16s var(--ease);
}

.drop-play-disc svg {
  width: 24px;
  height: 24px;
}

.drop-open:hover .drop-play-disc,
.drop-open:focus-visible .drop-play-disc {
  transform: scale(1.07);
}

.drop-open:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: -4px;
}

@media (prefers-reduced-motion: reduce) {
  .drop-open,
  .drop-play-disc {
    transition: none;
  }
}

.drop-body {
  display: flex;
  flex: 1;
  flex-direction: column;
  padding: 12px;
}

/* The height a stretched card gains goes above the buttons, so a row of cards
   ends on one line rather than wherever each card's own copy ran out. Only the
   last block takes the slack — a failed drop carries both a reason and a retry,
   and pinning each would push them apart instead of down. */
.drop-body > .drop-actions:last-child,
.drop-body > .stamp:last-child,
.drop-body > .failure:last-child { margin-top: auto; }

/* Three lines, always — not at most three. A caption that ran to two would
   otherwise start its hashtags a line higher than the card beside it, and the
   whole point of a row is that the eye can read across it. */
.caption {
  display: -webkit-box;
  min-height: calc(3em * 1.55);
  font-size: 0.875rem;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow: hidden;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
}

/* Only appears where the clamp actually cut something. It opens the drop in
   the sheet rather than growing the card: expanding one card in a row where
   every card shares a height would stretch all of them to read one. */
.caption-more {
  align-self: flex-end;
  margin-top: 3px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--fg-3);
  font-size: 0.8125rem;
  font-weight: 600;
  cursor: pointer;
}

.caption-more:hover { color: var(--brand-strong); }
.caption-more.is-hidden { visibility: hidden; }

/* Every card in the row is as tall as the tallest, so one drop that came back
   with seven hashtags sets the height for all of them. Two lines here, and the
   rest stay in the copy itself — the caption is never cut, because that is the
   text being approved. */
/* One line, always — reserved whether or not this drop has tags. The caption
   above already holds three lines for the same reason: a card without tags used
   to pull everything under it up by a line, so no two cards in the row agreed
   on where the caption ended and the actions began. */
.tags {
  display: -webkit-box;
  min-height: 1.3em;
  margin-top: 6px;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--brand-strong);
  overflow: hidden;
  overflow-wrap: anywhere;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.caption-empty { color: var(--fg-3); }

/* The script matters when you're deciding, not while you're scrolling, so it
   stays folded until asked for. */
.vo {
  margin-top: 10px;
  border-top: 1px solid var(--line-soft);
}

/* The voiceover and the activity log, side by side while both are shut. Two
   full-width bars for two things you open occasionally is a row of chrome per
   card, and the card is 165px wide on a phone. Opening one gives it the whole
   width back, so the script and the log still read as paragraphs. */
.drop-folds {
  display: flex;
  flex-wrap: wrap;
  column-gap: 10px;
}

/* Full width each on a phone, where "Voiceover" plus its icon and chevron is
   already most of a 165px card and two of them would squeeze both to nothing.
   They only pair up once there is room for the pair. */
.drop-folds > .vo { flex: 1 1 100%; min-width: 0; }

@media (min-width: 561px) {
  .drop-folds > .vo { flex-basis: 0; }
  .drop-folds > .vo[open] { flex-basis: 100%; }
  .drop-folds > .vo summary { padding-right: 0; }
}

/* The disc says "click to play"; while hover is already playing it, it is in
   the way of the frame being judged. */
.drop-media.is-playing .drop-play-disc { opacity: 0; }

.drop-compare {
  position: absolute;
  top: 8px;
  right: 44px;
  z-index: 2;
  pointer-events: auto;
  padding: 6px 10px;
  border: 0;
  border-radius: var(--r-pill);
  background: rgba(10, 14, 24, 0.5);
  color: rgba(255, 255, 255, 0.88);
  font-size: 0.75rem;
  font-weight: 600;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  touch-action: none;
}

.drop-media.is-original .drop-compare { background: var(--brand); }

.picks {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  margin: 8px 0 2px;
}

.pick-thumb {
  width: 52px;
  height: 52px;
  padding: 0;
  border: 2px solid transparent;
  border-radius: var(--r-sm);
  overflow: hidden;
  background: var(--surface-2);
  cursor: pointer;
}

.pick-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

.pick-thumb.is-on { border-color: var(--brand); cursor: default; }

.picks-hint { font-size: 0.75rem; color: var(--fg-3); }

.take-video {
  display: block;
  width: 100%;
  max-height: 260px;
  margin: 8px 0;
  border-radius: var(--r-sm);
  background: #0d1117;
}

.take .btn { margin-top: 6px; }

.vo[open] {
  border-radius: var(--r-sm);
  border-top-color: transparent;
  background: var(--surface-2);
}

.vo summary {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 9px 2px;
  list-style: none;
  cursor: pointer;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--fg-3);
}

.vo[open] summary { padding: 9px 11px; }

.vo summary::-webkit-details-marker { display: none; }
.vo summary:hover { color: var(--fg-2); }

.vo-chevron {
  margin-left: auto;
  transition: transform 0.18s var(--ease);
}

.vo[open] .vo-chevron { transform: rotate(180deg); }

/* The activity fold. A timestamp then what happened — the times line up down
   the left so the gaps between them are readable at a glance. */
.drop-log {
  margin: 0;
  padding: 0 11px 11px;
  list-style: none;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--fg-3);
}

.drop-log li {
  display: flex;
  gap: 8px;
  padding: 3px 0;
  border-top: 1px solid var(--line-soft);
}

.drop-log li:first-child { border-top: 0; }

.drop-log b {
  flex: none;
  width: 10.5em;
  font-weight: 600;
  color: var(--fg-2);
}

.vo p {
  padding: 0 11px 11px;
  margin-top: -2px;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--fg-2);
}

.drop-notes {
  margin-top: 10px;
  font-size: 0.8125rem;
  color: var(--fg-3);
}

.drop-notes b {
  color: var(--fg-2);
  font-weight: 600;
}

.drop-notes.is-warning {
  padding-left: 8px;
  border-left: 2px solid #fb923c;
  color: var(--fg-2);
}

/* The notes fold. Their count is what belongs on a card being scanned; the
   prose behind it is what belongs to a card being decided on. A warning in
   there colours the row, so nothing that needs looking at is folded away
   silently. */
.notes-fold summary { font-weight: 600; }
.notes-fold.is-warning summary { color: var(--warn); }
.notes-fold.is-warning[open] { background: var(--warn-wash); }

.notes-body { padding: 0 11px 10px; }
.notes-body > .drop-notes:first-child { margin-top: 0; }

/* One loud button per drop. Scheduling and re-rolling are alternatives to it,
   not rivals, so they sit underneath at half the volume. */
/* `minmax(0, 1fr)`, not the default `auto`: a grid column sizes to its widest
   item's min-content, and three nowrap labels in the row below came to 230px
   inside a 139px card. The column took that width, `.btn-block` filled it, and
   "Post now" ran out under the card's own overflow clip. */
.drop-actions {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 8px;
  margin-top: 14px;
}

/* One row, always, whether a drop carries two of these or three: the primary
   button above sits on whatever this row leaves it, so a row that grew a line
   would drop "Post now" out of step with the card beside it. The labels are
   short enough to hold a third of a card without breaking, and each keeps its
   full phrasing in a title. */
/* It wraps rather than being clipped. Two up on a phone the row is 139px wide
   and "Edit · Schedule · Re-roll 0/2" is not, so the choice was never one line
   or two — it was a second line or a third action nobody can read. */
.drop-actions-minor {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  min-width: 0;
}

/* Sized to their labels, not to an equal share: thirds of a narrow card give
   "Re-roll 0/2" the same room as "Edit" and clip it. Each takes what its text
   needs and they split what is left over. */
.drop-actions-minor .btn {
  flex: 1 1 auto;
  min-width: 0;
  padding: 0.52em 0.35em;
  gap: 0.32em;
  font-size: 0.75rem;
  white-space: nowrap;
}

/* The icon is the part that survives a narrow card; the label may ellipsise. */
.drop-actions-minor .btn svg { flex: none; }

.stamp {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 7px;
  margin-top: 14px;
  padding: 11px;
  border-radius: var(--r-sm);
  background: var(--good-wash);
  color: var(--good);
  font-size: 0.875rem;
  font-weight: 600;
}

/* Two up on a phone this row is 139px wide, and it used to squeeze its own
   tick to nothing and break "View post" over three lines. The tick and the
   link keep their width; the label is the part that gives, wrapping inside
   itself rather than sending the tick to a line of its own. */
.stamp svg { flex: none; }
.stamp-text { min-width: 0; }

/* "Scheduled" is not the same news as "posted", and a card that says both in
   the same green makes the owner read the words to tell them apart. */
.stamp-plan {
  background: var(--brand-wash);
  color: var(--brand-ink);
}

.stamp-wait {
  background: var(--gold-wash);
  color: var(--gold);
}

.stamp-bad {
  background: var(--bad-wash);
  color: var(--bad);
}

/* Stand-in for copy that is still being written, sized to the three lines and
   the tag row the caption will occupy. */
.copy-skeleton {
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding-top: 3px;
}

.copy-skeleton span {
  height: 9px;
  border-radius: 4px;
  background: linear-gradient(
    90deg,
    var(--surface-2) 0%,
    var(--line) 42%,
    var(--surface-2) 84%
  );
  background-size: 240% 100%;
  animation: kd-shimmer 1.9s linear infinite;
}

.copy-skeleton span:nth-child(2) { width: 92%; }
.copy-skeleton span:nth-child(3) { width: 64%; }

.copy-skeleton .sk-tags {
  width: 46%;
  height: 8px;
  margin-top: 7px;
}

@keyframes kd-shimmer {
  from { background-position: 160% 0; }
  to   { background-position: -60% 0; }
}

/* Quieter than the rest: it reports that nothing is wrong, not that anything
   happened. The card's news is still the stage above it. */
.stamp-live {
  background: var(--surface-2);
  color: var(--fg-3);
  font-weight: 500;
}

.stamp-spin {
  width: 12px;
  height: 12px;
  flex: none;
  border-radius: 50%;
  border: 2px solid var(--line-strong);
  border-top-color: var(--brand);
  animation: kd-spin 0.9s linear infinite;
}

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

@media (prefers-reduced-motion: reduce) {
  .stamp-spin,
  .drop-media.is-pipeline::before,
  .copy-skeleton span,
  .pipe-step.now i { animation: none; }
}

.stamp-link {
  color: var(--good);
  text-decoration: underline;
  margin-left: 6px;
  font-weight: 700;
  white-space: nowrap;
  transition: opacity 0.15s;
}

.stamp-link:hover {
  opacity: 0.8;
}

.failure {
  margin-top: 14px;
  padding: 11px 12px;
  border-radius: var(--r-sm);
  background: var(--bad-wash);
  color: var(--bad);
  font-size: 0.8125rem;
  line-height: 1.5;
}

.failure b {
  display: block;
  margin-bottom: 2px;
}

/* Two lines of the provider's own words. Printed whole, a 400 from Instagram
   ran four hundred pixels down a card 165px wide — and dragged the card beside
   it to the same height, since a grid row is as tall as its tallest cell. */
.failure-why {
  display: -webkit-box;
  overflow: hidden;
  overflow-wrap: anywhere;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.failure.is-open .failure-why {
  display: block;
  -webkit-line-clamp: unset;
}

.failure-more {
  display: block;
  margin-top: 4px;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 700;
  text-decoration: underline;
  cursor: pointer;
}

/* ---------- Pipeline progress ---------- */

/* A drop mid-render is the one card that cannot be acted on, so the stage
   answers the two questions worth asking about it: what is happening now, and
   is it still moving. A dark panel three cards wide is a lot of nothing, so a
   slow sweep keeps it alive between six-second polls. */
.drop-media.is-pipeline {
  background:
    radial-gradient(120% 80% at 50% 0%, rgba(221, 90, 31, 0.16), transparent 62%),
    #0d1117;
}

.drop-media.is-pipeline::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    115deg,
    transparent 38%,
    rgba(255, 255, 255, 0.045) 50%,
    transparent 62%
  );
  background-size: 260% 100%;
  animation: kd-sweep 3.4s linear infinite;
  pointer-events: none;
}

@keyframes kd-sweep {
  from { background-position: 160% 0; }
  to   { background-position: -60% 0; }
}

/* The owner's upload under the steps: present, but not competing with them. */
.pipe-source {
  opacity: 0.38;
  filter: blur(3px) saturate(0.85);
  transform: scale(1.06);
}

.drop-hook {
  display: flex;
  gap: 8px;
  align-items: baseline;
  margin-bottom: 6px;
  font-size: 0.9375rem;
  font-weight: 650;
  line-height: 1.35;
  letter-spacing: -0.01em;
}

.drop-hook > span:first-child {
  flex: none;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--brand-ink);
}

/* Two lines of it. A hook is a line of on-screen text, but nothing enforces
   that, and a long one pushed the caption it introduces off the card. */
.drop-hook-text {
  display: -webkit-box;
  min-width: 0;
  overflow: hidden;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.vo-audio {
  display: block;
  width: calc(100% - 22px);
  height: 32px;
  margin: 2px 11px 8px;
}

.pipeline {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 230px;
  padding: 18px;
}

.pipe-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 14px;
}

.pipe-head b {
  font-size: 0.9375rem;
  font-weight: 620;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: #f4f6fa;
}

.pipe-count {
  flex: none;
  font-size: 0.6875rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: rgba(238, 241, 247, 0.42);
}

/* The rail is what makes four dots read as one run rather than four unrelated
   lines: it is drawn behind the markers and lit as far as the work has got. */
.pipe-steps {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 11px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.pipe-steps::before {
  content: "";
  position: absolute;
  top: 9px;
  bottom: 9px;
  left: 6px;
  width: 1.5px;
  border-radius: 1px;
  background: rgba(238, 241, 247, 0.14);
}

.pipe-step {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.8125rem;
  line-height: 1.3;
  color: rgba(238, 241, 247, 0.38);
}

.pipe-step i {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 13px;
  height: 13px;
  flex: none;
  border-radius: 50%;
  background: #171d27;
  box-shadow: inset 0 0 0 1.5px rgba(238, 241, 247, 0.2);
}

.pipe-step i svg {
  width: 8px;
  height: 8px;
}

.pipe-step.done {
  color: rgba(238, 241, 247, 0.6);
}

.pipe-step.done i {
  background: var(--good);
  color: #06210f;
  box-shadow: none;
}

.pipe-step.now {
  color: #eef1f7;
  font-weight: 560;
}

.pipe-step.now i {
  background: var(--brand);
  box-shadow: 0 0 0 4px rgba(221, 90, 31, 0.2);
  animation: kd-throb 1.6s var(--ease) infinite;
}

@keyframes kd-throb {
  0%, 100% { box-shadow: 0 0 0 3px rgba(221, 90, 31, 0.28); }
  50%      { box-shadow: 0 0 0 7px rgba(221, 90, 31, 0.05); }
}

/* Two up on a phone the stage is 163x203 and this panel was 282 tall: the
   current step's name spilled out over the top edge and "Ready for you" was
   cut off the bottom, on the one card the owner is actually watching. The head
   names the step the list below already lights, so at this size the list is
   the whole panel. */
@media (max-width: 560px) {
  .pipeline { padding: 10px; }
  .pipe-head { display: none; }
  .pipe-steps { gap: 8px; }
  .pipe-step { font-size: 0.75rem; gap: 8px; }
  .pipe-foot {
    flex-wrap: wrap;
    margin-top: 10px;
    padding-top: 8px;
    font-size: 0.6875rem;
  }
}

/* Elapsed and remaining, because a step name alone cannot tell the owner
   whether four minutes on "Rendering video" is normal or wedged. */
.pipe-foot {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  margin-top: 14px;
  padding-top: 11px;
  border-top: 1px solid rgba(238, 241, 247, 0.1);
  font-size: 0.6875rem;
  font-variant-numeric: tabular-nums;
  color: rgba(238, 241, 247, 0.44);
}

.pipe-slow { color: #f0b47a; }

/* Progress without a word of it: readable from across the grid, and the part
   that visibly moves when the poll comes back. */
.pipe-bar {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  height: 3px;
  background: rgba(238, 241, 247, 0.1);
}

.pipe-bar span {
  display: block;
  height: 100%;
  border-radius: 0 2px 2px 0;
  background: linear-gradient(90deg, var(--brand), #ffb37a);
  box-shadow: 0 0 12px rgba(221, 90, 31, 0.55);
  transition: width 0.6s var(--ease);
}

/* ---------- Stopped, with nothing rendered ----------
   Deliberately still. The pipeline animates, and animation reads as progress;
   a drop the allowance already killed must not borrow that. */

.drop-media.is-stalled { background: var(--surface-2); }

.stalled {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  max-width: 210px;
  padding: 18px;
  text-align: center;
}

.stalled-icon {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  margin-bottom: 3px;
  border-radius: 50%;
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--fg-3);
}

.stalled-icon svg { width: 18px; height: 18px; }

.stalled b {
  font-size: 0.875rem;
  font-weight: 620;
  color: var(--fg-1);
}

.stalled p {
  margin: 0;
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--fg-3);
}

/* ---------- Empty & loading ---------- */

.empty {
  padding: 34px 24px 30px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-md);
  background: var(--surface);
  text-align: center;
}

.empty-art {
  width: 84px;
  height: 84px;
  margin: 0 auto 16px;
  border-radius: 50%;
  object-fit: cover;
  filter: grayscale(0.35);
  box-shadow: var(--shadow-2);
}

.empty h3 {
  font-family: var(--sans);
  font-size: 1rem;
  font-weight: 600;
  margin-bottom: 5px;
}

.empty p {
  /* 32ch broke this sentence into five short lines down the middle of a panel
     three times that wide, which reads as a column that failed to fill rather
     than as a centred paragraph. */
  max-width: 46ch;
  margin: 0 auto 18px;
  font-size: 0.875rem;
  color: var(--fg-3);
  line-height: 1.55;
  text-wrap: balance;
}

.skeleton {
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  overflow: hidden;
}

.skeleton-media {
  aspect-ratio: 9 / 16;
  max-height: 300px;
}

.skeleton-line {
  height: 11px;
  margin: 12px 14px;
  border-radius: 4px;
}

.skeleton-line.short {
  width: 45%;
}

.skeleton-media,
.skeleton-line {
  background: linear-gradient(90deg, var(--surface-2) 25%, var(--surface-3) 37%, var(--surface-2) 63%);
  background-size: 400% 100%;
  animation: kd-shimmer 1.3s ease-in-out infinite;
}

@keyframes kd-shimmer {
  from { background-position: 100% 0; }
  to { background-position: 0 0; }
}

/* ---------- Social list ---------- */

.social-list {
  margin-bottom: 12px;
}

.social-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 0;
  border-bottom: 1px solid var(--line-soft);
}

.social-row:last-child {
  border-bottom: none;
}

.social-row svg,
.social-row img {
  width: 19px;
  height: 19px;
  flex: none;
  color: var(--fg-2);
}

/* An unlinked row ends in a Connect button where a linked one ends in a pill. */
.social-row .btn {
  margin-left: auto;
}

.social-row b {
  display: block;
  font-size: 0.875rem;
  font-weight: 600;
}

.social-row span {
  display: block;
  font-size: 0.8125rem;
  color: var(--fg-3);
}

.social-row .pill {
  margin-left: auto;
}

.none-yet {
  padding: 4px 0 12px;
  font-size: 0.875rem;
  color: var(--fg-3);
  line-height: 1.5;
}

/* When this sentence is the whole body of a section it has to look like an
   empty state, not like a paragraph whose card failed to render — Queue, Post
   log, Library and the two Memory grids all opened as one grey line floating
   in the page. Scoped to :only-child so the same class stays a quiet inline
   note wherever it sits underneath real content. */
.none-yet:only-child,
#formatEmpty {
  /* Several of the containers it lands in are flex rows, where a block-level
     panel is only as wide as its sentence and reads as a stray tooltip. */
  width: 100%;
  flex: 1 1 100%;
  padding: 26px 20px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-md);
  background: var(--surface);
  text-align: center;
  text-wrap: balance;
}

/* The pickers it lands in are grids, so it has to claim the whole row rather
   than sit in the first cell as a one-column panel. */
.voice-picker > .none-yet,
.intent-mix-grid > .none-yet,
/* ---------- Instagram connect ---------- */

.connect-note {
  padding: 4px 0 14px;
  font-size: 0.875rem;
  color: var(--fg-3);
  line-height: 1.5;
}

.connect-note b {
  color: var(--fg-2);
  font-weight: 600;
}

.connect-status {
  margin-top: 12px;
  font-size: 0.875rem;
  color: var(--fg-3);
  line-height: 1.5;
  text-align: center;
}


.connect-status a {
  color: inherit;
  text-decoration: underline;
}

/* ---------- Sheet actions ---------- */

.sheet-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 9px;
}

/* ---------- Tab bar ---------- */

.tab-bar {
  position: fixed;
  bottom: 0;
  z-index: 50;
  display: flex;
  flex-wrap: nowrap;
  width: 100%;
  max-width: 520px;
  padding: 8px 0 max(10px, env(safe-area-inset-bottom));
  background: var(--veil);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-top: 1px solid var(--line);
}

.tab {
  position: relative;
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 5px 2px;
  border: none;
  background: none;
  color: var(--fg-3);
  /* Four destinations and More across a 375px phone leaves ~72px each, which
     fits "Schedule" at a readable size. Still allowed to ellipsis rather than
     wrap, because a two-line label makes the bar jump height. */
  font-size: 0.75rem;
  font-weight: 500;
  cursor: pointer;
  transition: color 0.15s var(--ease);
}

.tab span {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tab svg {
  width: 20px;
  height: 20px;
}

.tab.is-active {
  color: var(--brand-ink);
}

/* How many queued posts are still waiting on a yes. The queue is one tab of
   seven, so without this the only way to learn something needs approving is to
   go and look. On the phone bar it rides the icon; on the rail there is room
   for it at the end of the row. */
.tab-badge {
  position: absolute;
  top: 1px;
  left: 50%;
  margin-left: 4px;
  min-width: 16px;
  padding: 0 4px;
  border-radius: var(--r-pill);
  background: var(--brand-ink);
  color: var(--on-brand);
  font-size: 0.625rem;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
}

.tab-badge[hidden] {
  display: none;
}

/* ---------- Drops sub-nav ----------
   Two subsections of one tab, so they belong to the nav rather than to the
   page. On the phone bar there is no room to nest, so they take a row above
   the seven tabs; on the rail they indent under Drops as a nested list.

   Phone: a segmented control on a sunken track, deliberately not the outlined
   chip used for the feed filters a few pixels below it. Two rows of identical
   chips doing unrelated jobs is the sort of thing that makes people stop
   trusting what a control does. */

.tab-subnav {
  display: flex;
  gap: 2px;
  order: -1;
  width: calc(100% - 24px);
  margin: 0 12px 9px;
  padding: 3px;
  border-radius: var(--r-pill);
  background: var(--surface-3);
}

/* Contextual sections sit under the restaurant selector instead of inside the
   primary taskbar. The taskbar therefore keeps one fixed row on phones and a
   fixed list on desktops; opening a subsection no longer moves its siblings. */
.workspace-subnavs {
  flex: none;
  padding: 10px 16px 0;
  background: var(--bg);
}

.workspace-subnavs:empty { display: none; }

.workspace-subnavs .tab-subnav {
  order: 0;
  width: 100%;
  margin: 0;
}

.tab-subnav[hidden] { display: none; }

/* Four or five sub-tabs with their full names do not fit a phone at even
   shares; "Needs your yes" came out "Needs your ye". Each keeps its whole
   name and the strip scrolls sideways, kept on the lit one by syncNav. */
@media (max-width: 899px) {
  .workspace-subnavs .tab-subnav {
    overflow-x: auto;
    scrollbar-width: none;
  }
  .workspace-subnavs .tab-subnav::-webkit-scrollbar { display: none; }
  .workspace-subnavs .subtab {
    flex: 1 0 auto;
    overflow: visible;
  }
}

.subtab {
  flex: 1;
  min-width: 0;
  font: inherit;
  font-size: 0.75rem;
  font-weight: 550;
  padding: 6px 10px;
  border: 0;
  border-radius: var(--r-pill);
  background: none;
  color: var(--fg-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  transition: background-color 0.15s var(--ease), color 0.15s var(--ease),
              box-shadow 0.15s var(--ease);
}

.subtab.is-active {
  background: var(--surface);
  color: var(--fg);
  font-weight: 650;
  box-shadow: var(--shadow-1);
}

.subtab:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

.subtab-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 17px;
  height: 17px;
  padding: 0 5px;
  border-radius: var(--r-pill);
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1;
  background: var(--surface-2);
  color: var(--fg-2);
}

.subtab.is-active .subtab-badge {
  background: var(--brand-wash);
  color: var(--brand-ink);
}

.subtab-badge.pill-live {
  background: var(--warn-wash);
  color: var(--warn);
}

.subtab-badge[hidden] {
  display: none;
}

@media (min-width: 560px) and (max-width: 899px) {
  .app {
    box-shadow: var(--shadow-2);
  }
}

/* ---------- Desktop: the same app, laid out for a screen ----------
   Below 900px this stays what it was built as — a phone app with its thumbs at
   the bottom of the screen, used standing at the pass. Above it, the bottom bar
   becomes a left rail and the column opens up, because at a desk seven tabs
   crushed into a strip is a waste of a monitor. Nothing moves in the markup
   between the two; only where the nav sits and how wide the work gets. */
@media (min-width: 900px) {
  body { background: var(--bg); }

  /* Fills the screen. A centred column left a few inches of dead background
     down each side of a wide monitor, which reads as the page having failed to
     load rather than as a margin. The rail sits flush left and the work runs
     from it, the way an app on a desktop is expected to. */
  .app {
    max-width: none;
    padding-bottom: 0;
    border-inline: 0;
  }

  .app-bar { padding-inline: 24px; }

  /* The rail is only one viewport tall — it is sticky, not a column — so on
     any view longer than the screen its own background ran out and left a seam
     across the page. The strip is painted here instead, on the element that is
     as tall as the content, and the rail sits on top of it. */
  .dashboard-section {
    display: flex;
    align-items: flex-start;
    min-height: calc(100vh - var(--bar-h, 59px));
    background: linear-gradient(
      to right,
      var(--surface-2) 0 236px,
      var(--line) 236px 237px,
      transparent 237px
    );
  }

  .tab-bar {
    position: sticky;
    top: var(--bar-h, 59px);
    z-index: 30;
    flex: none;
    flex-direction: column;
    /* The phone bar wraps its row of tabs; a column that wraps puts whatever
       does not fit the window's height in a second column, past the rail's
       edge. The rail scrolls instead (below). */
    flex-wrap: nowrap;
    gap: 2px;
    width: 236px;
    max-width: none;
    height: calc(100vh - var(--bar-h, 59px));
    padding: 16px 12px;
    background: var(--surface-2);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border-top: 0;
    border-right: 1px solid var(--line);
    /* Seven destinations plus an open subnav is taller than a laptop window
       with devtools open, and the rail is a fixed 100vh — the bottom items
       simply could not be reached. The page's own scroll does not help: the
       rail is sticky and scrolls with nothing. */
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    scrollbar-color: var(--line-strong) transparent;
  }

  .tab-bar::-webkit-scrollbar { width: 8px; }
  .tab-bar::-webkit-scrollbar-thumb {
    border: 2px solid transparent;
    border-radius: var(--r-pill);
    background: var(--line-strong);
    background-clip: content-box;
  }
  .tab-bar::-webkit-scrollbar-track { background: transparent; }

  .tab {
    flex: none;
    flex-direction: row;
    justify-content: flex-start;
    gap: 11px;
    padding: 9px 12px;
    border-radius: var(--r-sm);
    font-size: 0.875rem;
    font-weight: 500;
  }

  .tab span {
    max-width: none;
    overflow: visible;
  }

  .tab svg { width: 18px; height: 18px; }

  .tab-badge {
    position: static;
    margin-left: auto;
  }

  /* Indented to where the tab labels start, so the nesting is read as nesting
     rather than as two more top-level destinations. */
  .tab-subnav {
    flex-direction: column;
    gap: 0;
    order: 0;
    width: auto;
    margin: 4px 0 6px 21px;
    padding: 0;
    border-radius: 0;
    background: none;
  }

  /* The guide line is built out of the items themselves — each owns a segment
     of it, and the active one lights its own. The filled pill this replaced sat
     directly under the parent tab's filled pill, so the rail read as two cards
     stacked rather than as a heading with children. */
  .subtab {
    flex: none;
    text-align: left;
    padding: 7px 10px 7px 15px;
    border-left: 2px solid var(--line);
    border-radius: 0;
    background: none;
    color: var(--fg-3);
    font-size: 0.8125rem;
    font-weight: 500;
    display: flex;
    align-items: center;
    justify-content: space-between;
  }

  /* A wash, not the filled pill: the row needs a visible target — nothing but
     a 2px line moved before — without restaging as a second card under the
     parent tab's. */
  .subtab:hover {
    background: var(--surface-3);
    border-left-color: var(--line-strong);
    color: var(--fg);
  }

  .subtab.is-active {
    background: var(--brand-wash);
    border-left-color: var(--brand);
    color: var(--brand-ink);
    font-weight: 600;
    box-shadow: none;
  }

  .subtab:hover,
  .subtab.is-active {
    border-radius: 0 var(--r-sm) var(--r-sm) 0;
  }

  .subtab:focus-visible {
    outline-offset: -2px;
  }

  .tab:hover { background: var(--surface-3); color: var(--fg); }

  .tab.is-active {
    background: var(--surface);
    color: var(--brand-ink);
    font-weight: 600;
    box-shadow: var(--shadow-1);
  }

  .workspace {
    flex: 1;
    min-width: 0;
  }

  /* The strip spans the window, but the name inside it lines up with the left
     edge of the work below rather than sitting alone against the rail while
     the column starts a few hundred pixels further in. */
  .place-bar {
    padding-block: 12px;
    padding-inline: max(32px, calc((100% - var(--col)) / 2));
  }

  /* Which restaurant you are on is a label, not a field. Left stretching on
     flex:1 the select ran the whole window and parked its chevron a foot from
     the name on a wide monitor, reading as a broken input rather than as the
     one line of context it is. */
  .place-select { flex: 0 1 auto; }

  .workspace-subnavs {
    padding-block: 12px 0;
    padding-inline: max(32px, calc((100% - var(--col)) / 2));
  }

  /* The rail's nested-list treatment is intentionally not used here. These
     are page-level section choices and remain a stable horizontal strip. */
  .workspace-subnavs .tab-subnav {
    flex-direction: row;
    gap: 2px;
    width: 100%;
    margin: 0;
    padding: 3px;
    border-radius: var(--r-pill);
    background: var(--surface-3);
  }

  .workspace-subnavs .subtab {
    flex: 1;
    justify-content: center;
    gap: 6px;
    padding: 7px 10px;
    border: 0;
    border-radius: var(--r-pill);
    background: none;
    color: var(--fg-2);
    font-size: 0.8125rem;
    font-weight: 550;
    text-align: center;
  }

  .workspace-subnavs .subtab:hover {
    border-radius: var(--r-pill);
    background: var(--surface-2);
    color: var(--fg);
  }

  .workspace-subnavs .subtab.is-active {
    border-radius: var(--r-pill);
    background: var(--surface);
    color: var(--fg);
    font-weight: 650;
    box-shadow: var(--shadow-1);
  }

  /* One column, centred, for every view. Capping the children instead pinned
     the work against the rail and left the rest of the monitor empty to its
     right — 840px of bare background at 1920, which reads as a page that
     failed to load rather than as a margin. Centring the column spends the
     same space as two even margins, and the column itself keeps the measure
     forms and prose need. Everything on a view now shares one left and one
     right edge: header, cards, feed and composer all line up. */
  .view {
    /* The workspace is a flex column, and an auto-margined item in one
       shrinks to its content: Schedule's four sections came out four
       different widths, and the page jumped as you moved between them. */
    width: 100%;
    max-width: calc(var(--col) + 64px);
    margin-inline: auto;
    padding: 24px 32px 72px;
  }
}


/* ---------- Password reset ----------
   A link, not a button: it sits under the primary action and must not read as
   a second one competing with it. */

.auth-forgot {
  display: block;
  width: 100%;
  margin-top: 12px;
  text-align: center;
  font-size: 0.875rem;
}

.auth-step-note {
  margin: 0 0 16px;
  text-align: center;
}

.reset-actions {
  display: flex;
  justify-content: center;
  gap: 16px;
  margin-top: 14px;
  font-size: 0.875rem;
  flex-wrap: wrap;
}

/* ---------- First run ----------
   Three rows, and then it is gone. Deliberately not a card like everything
   else on the page: it is scaffolding, and scaffolding that looks permanent
   is the kind people learn to scroll past. */

.setup-card {
  margin-bottom: 16px;
  padding: 13px 14px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-md);
  background: var(--surface-2);
}

.setup-card[hidden] { display: none; }

/* ---------- Today ---------- */

.today-card {
  margin-bottom: 16px;
  padding: 15px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: linear-gradient(135deg, var(--surface-2), var(--surface));
}

.today-card[hidden] { display: none; }

.today-head {
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 12px;
}

.today-kicker {
  display: block;
  margin-bottom: 3px;
  color: var(--brand-ink);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

/* A card's title, set like every other card's (.card-head h2) and the setup
   card beside it, not in the display face the page heading uses. */
.today-head h2 { margin: 0; font-family: var(--sans); font-size: 1rem; font-weight: 600; letter-spacing: -0.012em; }
.today-note { color: var(--fg-3); font-size: 0.75rem; white-space: nowrap; }

.today-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 8px;
}

.today-stat {
  min-width: 0;
  padding: 11px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--fg);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.15s var(--ease), transform 0.15s var(--ease), background-color 0.15s var(--ease);
}

.today-stat:hover { border-color: var(--line-strong); transform: translateY(-1px); }
.today-stat:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.today-stat.has-work { border-color: color-mix(in srgb, var(--brand) 42%, var(--line)); }
.today-stat.is-alert { border-color: var(--bad); background: var(--bad-wash); }
.today-stat-ideas.has-work {
  border-color: color-mix(in srgb, var(--gold) 55%, var(--line));
  background: var(--gold-wash);
}

.today-stat b {
  display: block;
  margin-bottom: 2px;
  font-family: "Fraunces", serif;
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1;
}

.today-stat span {
  display: block;
  overflow: hidden;
  color: var(--fg-3);
  font-size: 0.75rem;
  line-height: 1.3;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@media (max-width: 560px) {
  .today-note { display: none; }
  .today-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .today-stat:last-child:nth-child(odd) { grid-column: 1 / -1; }
}

.setup-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}

.setup-head b { font-size: 1rem; font-weight: 600; letter-spacing: -0.012em; }

.setup-head span { font-size: 0.8125rem; color: var(--fg-3); }

.setup-steps { display: grid; gap: 6px; }

.setup-step {
  display: grid;
  grid-template-columns: 22px 1fr auto;
  align-items: center;
  gap: 11px;
  width: 100%;
  padding: 10px 11px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--fg);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease);
}

.setup-step:hover:not(:disabled) { border-color: var(--brand); }

.setup-step:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

/* A done step is quieted by its colour and the strike, not by opacity: at
   0.62 its sentence fell to 2.8:1, under AA (rule 14). */
.setup-step:disabled { cursor: default; }
.setup-step:disabled .setup-text b { color: var(--fg-3); }

.setup-tick {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--surface-3);
  color: var(--fg-2);
  font-size: 0.75rem;
  font-weight: 700;
}

.setup-tick svg { width: 12px; height: 12px; }

.setup-step.is-done .setup-tick { background: var(--good-wash); color: var(--good); }

.setup-text b {
  display: block;
  /* The row's own colour is the muted explanation; the step name is not. */
  color: var(--fg);
  font-size: 0.875rem;
  font-weight: 650;
}

.setup-text {
  display: block;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--fg-3);
}

.setup-step.is-done .setup-text b { text-decoration: line-through; }

.setup-go { color: var(--brand-ink); font-weight: 700; }

/* The card only names what is blocking a post. The tour is the rest of the
   app, so the way to it belongs under the blockers rather than beside them. */
.setup-tour {
  margin-top: 10px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--brand-ink);
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 600;
  cursor: pointer;
}

.setup-tour:hover { text-decoration: underline; }

.setup-tour:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }

/* Two ways out of an empty state sit on one centred line, not stacked. */
.empty .btn + .btn { margin-left: 8px; }

/* ---------- Show me around ----------
   Was a centred dialog per step, because a bubble pinned to a tab the owner
   cannot see on a 390px phone points at nothing. The tour walks to the step
   before it draws it now — the tab and the subsection are already open — so
   the bubble can sit beside the button, section or subsection it is about, and
   everything else goes dark. */

.tour-layer {
  /* One value for the dark: the ring throws it as a shadow, and the bubble
     falls back to it as a flat background when there is nothing to ring. */
  --tour-dim: rgba(9, 11, 16, 0.58);
  position: fixed;
  inset: 0;
  z-index: 60;
}

.tour-layer[hidden] { display: none; }

/* With nothing to ring — an anchor on a tab whose list has not landed yet —
   the dim has to come from somewhere, and the bubble goes to the middle. */
.tour-layer.is-loose { background: var(--tour-dim); }

/* The hole and the dim are one element: a ring on the target, and a shadow
   wider than any screen doing everything outside it. Nothing else has to be
   kept in line with the target, and the ring cannot be clicked through to the
   thing it is drawn around — the step's own buttons are the way on. */
.tour-ring {
  position: absolute;
  border-radius: var(--r-sm);
  box-shadow: 0 0 0 9999px var(--tour-dim), 0 0 0 2px var(--brand);
  pointer-events: none;
  transition: top 0.18s ease, left 0.18s ease, width 0.18s ease, height 0.18s ease;
}

.tour-ring[hidden] { display: none; }

.tour-bubble {
  position: absolute;
  /* Narrower than the dialog it replaces: it now sits next to something rather
     than instead of it, and a card as wide as the phone reads as one again. */
  width: min(340px, calc(100vw - 24px));
  padding: 13px 14px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--shadow-3);
  /* The same move as the ring, so a step that hops from the bar at the bottom
     of a phone to a card at the top reads as one thing travelling. */
  transition: top 0.18s ease, left 0.18s ease;
}

/* A ring and a bubble that slide across the screen together is the whole
   read of one step moving to the next; without the motion they should just
   be where the step is, not somewhere on the way to it. */
@media (prefers-reduced-motion: reduce) {
  .tour-ring,
  .tour-bubble { transition: none; }
}

/* No anchor, no side to be on. */
.tour-bubble.is-centred {
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

/* A bubble clamped to the edge of a phone is rarely centred on what it is
   about, so the arrow is placed on the target rather than on the bubble. */
.tour-arrow {
  position: absolute;
  width: 11px;
  height: 11px;
  margin-left: -6px;
  background: var(--surface);
  border: 1px solid var(--line);
  transform: rotate(45deg);
}

.tour-bubble.is-below .tour-arrow {
  top: -6px;
  border-right: 0;
  border-bottom: 0;
}

.tour-bubble.is-above .tour-arrow {
  bottom: -6px;
  border-left: 0;
  border-top: 0;
}

.tour-bubble.is-centred .tour-arrow { display: none; }

.tour-head {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin-bottom: 5px;
}

.tour-head > div { flex: 1; }

.tour-head h3 {
  margin: 0;
  font-size: 1rem;
  line-height: 1.3;
}

#tourBody {
  margin: 0;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--fg-2);
}

.tour-kicker {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 3px;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg-4);
}

/* Reopening the tour on a step the owner has since finished should say so,
   or the bubble reads as a thing still to do. */
.tour-done {
  padding: 2px 7px;
  border-radius: var(--r-pill);
  background: var(--good-wash);
  color: var(--good);
  letter-spacing: 0.04em;
}

.tour-dots {
  display: flex;
  gap: 5px;
  margin: 11px 0 0;
  padding: 0;
  list-style: none;
}

/* Bars, not dots: seven circles across a phone read as a loading spinner laid
   flat, and a bar can show the one you are on by filling rather than growing. */
.tour-dot {
  flex: 1;
  height: 3px;
  border-radius: var(--r-pill);
  background: var(--surface-3);
}

.tour-dot.is-done { background: var(--good); }

.tour-dot.is-at { background: var(--brand); }

.tour-panel {
  margin-top: 11px;
  padding: 10px 11px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-sm);
  background: var(--surface-2);
}

.tour-panel[hidden] { display: none; }

.tour-points {
  display: grid;
  gap: 7px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.tour-points li {
  padding-left: 16px;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--fg-2);
  /* A dash rather than a bullet glyph: these are notes on one idea, not a
     ranked list, and the disc markers sat off the panel's left padding. */
  background: linear-gradient(var(--fg-4), var(--fg-4)) 0 0.72em / 7px 1px no-repeat;
}

/* Four real formats off the catalogue. The hook under the name is the point:
   it is what the shape sounds like, which the name alone never says. */
.tour-formats {
  display: grid;
  gap: 9px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.tour-formats b {
  display: block;
  font-size: 0.8125rem;
  font-weight: 650;
  color: var(--fg);
}

.tour-formats span {
  display: block;
  margin-top: 1px;
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--fg-3);
  font-style: italic;
}

.tour-note,
.tour-wait {
  margin: 9px 0 0;
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--fg-3);
}

.tour-wait { margin: 0; }

/* Only the step that leaves the app has one. */
.tour-go { margin-top: 12px; }

.tour-go[hidden] { display: none; }

/* Out of the tour on the left, through it on the right. Back and Next are a
   pair and stay one, which a row that spreads all three apart would break. */
.tour-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 12px;
}

.tour-walk {
  display: flex;
  gap: 7px;
}

.tour-skip { font-size: 0.8125rem; }

/* ---------- Five sections, on every width ----------
   Today, Posts, Plan, Restaurant and Settings fit a phone bar as they are, so
   the phone and the desktop rail show the same five, with no More behind
   them. Appearance, the tour and the admin tools open from the avatar. */

button.user-avatar {
  border: 0;
  padding: 0;
  cursor: pointer;
}

button.user-avatar:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

.more-list {
  display: grid;
  gap: 6px;
}

.more-row {
  display: grid;
  grid-template-columns: 22px 1fr;
  align-items: center;
  gap: 13px;
  width: 100%;
  padding: 13px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--fg);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease);
}

.more-row:hover { border-color: var(--line-strong); background: var(--surface-2); }

.more-row:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

.more-row svg { width: 22px; height: 22px; color: var(--fg-2); }
.more-row .more-icon {
  flex: none;
  width: 28px;
  height: 28px;
  object-fit: contain;
  transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.more-row:hover .more-icon { transform: translateY(-2px) rotate(-8deg) scale(1.1); }
.more-row:active .more-icon { transform: scale(0.88); transition-duration: 0.08s; }
@media (prefers-reduced-motion: reduce) { .more-row .more-icon { transition: none; } .more-row:hover .more-icon { transform: none; } }

.more-row b {
  display: block;
  color: var(--fg);
  font-size: 0.9375rem;
  font-weight: 650;
}

.more-row span {
  display: block;
  font-size: 0.8125rem;
  line-height: 1.4;
  color: var(--fg-3);
}

.more-admin {
  display: grid;
  gap: 6px;
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

.more-admin[hidden] { display: none; }

.more-admin-title {
  margin: 0 0 2px;
  color: var(--fg-3);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.more-mode-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--fg-2);
  font-size: 0.8125rem;
  font-weight: 600;
}

.more-mode-row .mode-toggle-pill { margin: 0; }

.more-row .more-admin-icon {
  color: var(--fg-2);
  font-size: 1rem;
  line-height: 1;
  text-align: center;
}

/* ---------- Intel: before the first scan ----------
   Seven cards each printing a variant of "run an AI Web Scan" is one sentence
   set seven times, above a page with a Scan button already in its header.
   Until a scan has run, the page is that sentence and that button. */

/* Descendants, not children: the cards moved into subsections, and the empty
   state has to keep covering them. The photo library and the profile are the
   owner's own, not the web's, so a scan has nothing to do with them. */
#viewRestaurant.is-unscanned .card:not(.own-card):not(#sectionLibrary .card):not(#sectionProfile .card),
#viewRestaurant.is-unscanned > .claim-banner,
#viewRestaurant.is-unscanned > .claim-verified-note {
  display: none;
}

#viewRestaurant:not(.is-unscanned) > .intel-first-run {
  display: none;
}

/* Your restaurant: the owner's own photos and clips, look-only. */
/* The director's scenes on the plan card. */
.drop-notes .plan-scenes {
  margin: 6px 0 0;
  padding-left: 20px;
}

.drop-notes .plan-scenes li {
  margin: 2px 0;
}

/* Film your rooms once: the three standing shots, ticked off as they land.
   Ticks borrow the setup checklist's, so done looks the same everywhere. */
.own-rooms {
  margin-bottom: 16px;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
}

.own-rooms-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  font-size: 0.9375rem;
}

.own-rooms > p {
  margin: 6px 0 10px;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--fg-3);
}

.own-rooms-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.own-room {
  display: grid;
  grid-template-columns: 22px 1fr auto;
  align-items: start;
  gap: 11px;
  padding: 9px 0;
  border-top: 1px solid var(--line);
}

.own-room .setup-tick { margin-top: 1px; }
.own-room.is-done .setup-tick { background: var(--good-wash); color: var(--good); }

.own-room-text {
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--fg-3);
}

.own-room-text b {
  display: block;
  color: var(--fg);
  font-size: 0.875rem;
  font-weight: 650;
}

.own-room.is-done .own-room-text b { color: var(--fg-3); }

.own-room-tip {
  display: block;
  margin-top: 3px;
  color: var(--fg-2);
}

/* The second-read row: a count and a button, above the groups. */
.own-reinspect {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
  font-size: 0.875rem;
  color: var(--ink-2, inherit);
}

.own-source + .own-source {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

.own-source h3 {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 14px 0 0;
  font-family: var(--sans);
  font-size: 0.9375rem;
  font-weight: 600;
}

.own-card h4 {
  margin: 16px 0 8px;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--fg-3);
}

.own-card .library-grid { margin: 0 0 8px; }

/* Centred by hand: the body is a flex column, and Safari lets that leak
   into a modal dialog's placement, which put the picture hard against the
   left edge. */
.own-lightbox {
  position: fixed;
  inset: 0;
  margin: auto;
  width: fit-content;
  height: fit-content;
  padding: 0;
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  max-width: 92vw;
  max-height: 92vh;
  cursor: zoom-out;
}

.own-lightbox::backdrop {
  background: rgba(0, 0, 0, 0.7);
}

.own-lightbox img {
  display: block;
  max-width: 92vw;
  max-height: 92vh;
  object-fit: contain;
  border-radius: var(--r-sm);
}

/* Over the picture, at its edges. The dialog is fit-content around the image,
   so these sit on the slide rather than floating in the backdrop. */
.lightbox-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
}
.lightbox-arrow:hover { background: rgba(0, 0, 0, 0.8); }
.lightbox-arrow.is-prev { left: 10px; }
.lightbox-arrow.is-next { right: 10px; }

.lightbox-count {
  position: absolute;
  left: 50%;
  bottom: 10px;
  transform: translateX(-50%);
  padding: 3px 10px;
  border-radius: var(--r-pill);
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
}

/* Clips on the same column grid as the photos, only taller, so a shelf of
   both reads as one wall rather than two sizes of thing. */
.own-clips {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));
  gap: 10px;
  margin: 0 0 8px;
}

.own-clips video {
  width: 100%;
  aspect-ratio: 9 / 16;
  object-fit: cover;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface-2);
}

.own-more {
  margin: 2px 0 10px;
}

.staff-role {
  color: var(--fg-3);
  font-size: 0.8125rem;
}

.intel-first-run .btn-quiet {
  margin-top: 10px;
}

/* ---------- Voiceover picker ----------
   A wall of cards, not a column of rows: the markup is a flat list of options
   with heading paragraphs between them, and the grid is what makes it a
   gallery. Done in CSS alone on purpose — selection, preview playback and the
   clone/persona switch are all wired to this DOM.

   The play control is the card's subject, so it gets the size and the brand,
   and the rest of the card stays one hit target for choosing the voice. */

.voice-picker {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 8px;
  margin-top: 7px;
}

.sound-summary {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px 24px;
  margin-bottom: 14px;
  padding: 14px 16px;
  border: 1px solid color-mix(in srgb, var(--brand) 30%, var(--line));
  border-radius: var(--r-md);
  background: var(--brand-wash);
}

.sound-summary-head span,
.sound-summary-facts small {
  display: block;
  color: var(--fg-3);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.sound-summary-head b {
  display: block;
  margin-top: 2px;
  color: var(--fg);
  font-size: 1rem;
}

.sound-summary-facts {
  display: flex;
  align-items: center;
  gap: 22px;
  color: var(--fg-2);
  font-size: 0.8125rem;
}

.sound-summary-facts small { margin-bottom: 2px; }

.audio-preview-status {
  margin: -4px 0 14px;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  color: var(--fg-2);
  font-size: 0.8125rem;
}
.audio-preview-status.is-loading::before,
.audio-preview-status.is-playing::before {
  content: "";
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-right: 8px;
  border-radius: 50%;
  background: var(--brand);
  animation: voice-pulse 1s ease-in-out infinite;
}
.audio-preview-status.is-playing::before { animation: none; }
.audio-preview-status.is-error { border-color: var(--bad); color: var(--bad); }

@media (max-width: 560px) {
  .sound-summary { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .sound-summary-facts { justify-content: space-between; }
}

/* The pace pills and the try-out line sit above the grid, full width. */
.voice-filters { margin-top: 8px; margin-bottom: 10px; }
.voice-filters[hidden] { display: none; }

#voiceWho:not(:empty) { margin-bottom: 18px; padding-bottom: 16px; border-bottom: 1px solid var(--line-soft); }
#voiceWho .voice-own { margin-top: 0; }

.voice-try { margin-top: 18px; }
.voice-try .input { margin-bottom: 4px; }

/* The folded tail of the ranked list. A link, not a card. */
.voice-more {
  grid-column: 1 / -1;
  justify-self: start;
  padding: 6px 0;
  border: 0;
  background: none;
  color: var(--brand-ink);
  font: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  cursor: pointer;
}
.voice-more:hover { text-decoration: underline; }
.voice-more-count {
  display: inline-block;
  margin-left: 7px;
  color: var(--fg-3);
  font-size: 0.75rem;
  font-weight: 500;
}

/* Pace and accent, in the corner where the check lives until it is chosen. */
.voice-option .voice-tags { display: block; margin-top: 6px; }

.voice-option .voice-tag,
.voice-tag {
  display: inline-block;
  margin-right: 5px;
  padding: 2px 7px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  color: var(--fg-3);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.voice-option.is-on .voice-tag { background: var(--brand-wash); color: var(--brand-ink); }

/* Headings and the narrator switch are dividers, not cards. */
.voice-picker > .voice-group,
.voice-picker > .voice-own,
.voice-picker > .narrate-switch {
  grid-column: 1 / -1;
}

/* A library row: the orb is artwork, the copy describes the voice, and the
   preview is a separate labelled action. */
.voice-option {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr) auto;
  grid-template-areas: "tile text actions";
  align-items: center;
  gap: 12px;
  padding: 10px 12px 10px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  text-align: left;
  cursor: pointer;
  transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease),
              box-shadow 0.15s var(--ease);
}

.voice-option > .voice-text  { grid-area: text; }
.voice-option > .voice-tile  { grid-area: tile; }
.voice-option > .voice-actions { grid-area: actions; }

/* One thing moves on hover. Lifting the card and darkening its border at the
   same time reads as two states on a grid this dense. */
.voice-option:hover {
  box-shadow: var(--shadow-1);
}

/* `.voice-option span` below sets every span in a row to block; the badge is
   the one span that must stay inline or it stretches into a full-width bar. */
.voice-option .voice-badge,
.voice-badge {
  display: inline-block;
  width: auto;
  margin-top: 0;
  margin-left: 7px;
  padding: 1px 7px;
  border-radius: var(--r-pill);
  background: var(--brand-wash);
  color: var(--brand-strong);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  vertical-align: 1px;
}

.voice-why {
  display: block;
  margin-top: 3px;
  font-size: 0.75rem;
  color: var(--fg-2);
  line-height: 1.45;
}

/* The server writes reasons mid-sentence ("your vibe profile describes…");
   shown on their own they should read as sentences. */
.voice-why::first-letter {
  text-transform: uppercase;
}

.voice-group {
  margin: 12px 2px 1px;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--fg-3);
}

.voice-picker > .voice-group:first-child {
  margin-top: 4px;
}

/* Whose voice speaks, not one of the styles to pick between. It used to carry
   the identical border and wash as `.is-on` below, so with a persona selected
   two rows lit up brand-orange and the picker read as two live selections.
   A neutral surface with a brand edge keeps it tied to the brand while making
   it plainly a different kind of thing from the cards underneath. */
.voice-own {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 11px 12px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--brand);
  border-radius: var(--r-sm);
  background: var(--surface-2);
}

.voice-own .voice-text {
  flex: 1;
  min-width: 0;
}

.voice-own b {
  display: block;
  font-size: 0.875rem;
  font-weight: 600;
}

.voice-own > .voice-text > span {
  display: block;
  margin-top: 1px;
  font-size: 0.8125rem;
  color: var(--fg-3);
  line-height: 1.45;
}

/* Parked: still enrolled, not speaking. Dimmed rather than hidden, because the
   way back has to stay visible. */
.voice-own.is-idle {
  border-left-color: var(--line-strong);
}

.voice-own.is-idle .voice-badge {
  background: var(--surface-3);
  color: var(--fg-3);
}

.voice-own.is-idle b,
.voice-own.is-idle .voice-play {
  opacity: 0.75;
}

/* ---------- Narrator switch ---------- */

.narrate-switch {
  display: grid;
  gap: 7px;
  margin: 9px 0 2px;
}

.narrate-label {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--fg-3);
}

.narrate-opts {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 5px;
  padding: 4px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface-2);
}

.narrate-opt {
  padding: 8px 6px;
  border: none;
  border-radius: calc(var(--r-sm) - 4px);
  background: transparent;
  color: var(--fg-2);
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.3;
  cursor: pointer;
  transition: background-color 0.15s var(--ease), color 0.15s var(--ease);
}

.narrate-opt:hover {
  color: var(--fg-1);
}

.narrate-opt.is-on {
  background: var(--surface);
  color: var(--brand-strong);
  box-shadow: var(--shadow-1);
}

[data-theme="dark"] .narrate-opt.is-on {
  color: var(--brand-ink);
}

.narrate-means {
  display: block;
  width: 100%;
  color: var(--fg-2);
  font-size: 0.8125rem;
  line-height: 1.45;
}


.voice-option.is-off {
  opacity: 0.55;
}

.voice-note {
  display: block;
  margin-top: 3px;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--warn);
}

.voice-option.is-on {
  border-color: var(--brand);
  background: var(--brand-wash);
}

/* A column, so the tag row and the reason under it can be pushed to the
   bottom of the card. Left flowing, they sat wherever the description above
   happened to end, and a row of three cards showed its pace pills at three
   different heights — the grid stretches the cards to the same height, so the
   only thing that made the row look ragged was the content inside them. */
.voice-option .voice-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.voice-option .voice-text > span:not([class]) {
  flex: 1 0 auto;
}

.voice-option b {
  display: block;
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.25;
}

.voice-option span {
  display: block;
  margin-top: 1px;
  font-size: 0.8125rem;
  color: var(--fg-3);
  line-height: 1.45;
}

/* The tile holds the identity artwork only. Preview is kept separate so the
   orb never hides the play affordance or looks like a second control. */
.voice-tile {
  position: relative;
  width: 56px;
  height: 56px;
  display: grid;
  place-items: center;
  border-radius: 14px;
  background: var(--surface-2);
}
.voice-tile .voice-orb { width: 38px; height: 38px; }

.voice-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 5px;
}

.voice-option .voice-actions .voice-play {
  display: inline-flex;
  width: auto;
  min-width: 88px;
  height: 34px;
  gap: 6px;
  padding: 0 11px;
  border-color: color-mix(in srgb, var(--brand) 45%, var(--line));
  background: var(--brand-wash);
  color: var(--brand-strong);
  font: inherit;
  font-size: 0.75rem;
  font-weight: 700;
}

.voice-option .voice-actions .voice-play:hover {
  border-color: var(--brand);
  background: color-mix(in srgb, var(--brand-wash) 72%, var(--surface));
  color: var(--brand-ink);
}

.voice-option .voice-actions .voice-play.is-playing {
  background: var(--brand-ink);
  color: var(--on-brand);
}

.voice-option .voice-play-copy,
.voice-option .voice-play-copy > span {
  display: inline;
  margin: 0;
  color: inherit;
  font: inherit;
  line-height: 1;
}

.voice-play-copy-stop { display: none !important; }
.voice-play.is-playing .voice-play-copy-idle { display: none !important; }
.voice-play.is-playing .voice-play-copy-stop { display: inline !important; }

.voice-option .voice-selected {
  display: none;
  margin: 0 2px 0 0;
  color: var(--brand-ink);
  font-size: 0.625rem;
  font-weight: 700;
  line-height: 1;
  text-transform: uppercase;
}

.voice-option.is-on .voice-selected { display: block; }

/* On a phone the cards carry a name and a play button, so they go two up.
   `auto-fill` with a 150px floor was one column short of fitting inside the
   card's own padding at 375px, which quietly turned sixteen narrators into a
   screen and a half of full-width rows. Two columns, stated. */
@media (max-width: 560px) {
  .voice-picker {
    grid-template-columns: 1fr;
    gap: 6px;
  }
  .voice-option {
    grid-template-columns: 48px minmax(0, 1fr) auto;
    padding: 8px 10px 8px 8px;
    gap: 10px;
  }
  .voice-tile { width: 48px; height: 48px; border-radius: 12px; }
  .voice-tile .voice-orb { width: 32px; height: 32px; }
  .voice-option .voice-actions .voice-play { min-width: 80px; padding-inline: 9px; }
  /* The blurb and the ranking reason are sentences; they do not fit a
     half-width card. The pace tags and the "needs a key" note are short and
     are the two things you would otherwise have to guess at, so they stay. */
  .voice-option .voice-text > span:not([class]),
  .voice-option .voice-why { display: none; }
  /* Two tags have to sit on one line inside a half-width card, or the row
     they wrap onto costs more height than the tags are worth. */
  .voice-option .voice-tags { margin-top: 5px; }
  .voice-option .voice-tag {
    margin-right: 4px;
    padding: 2px 6px;
    font-size: 0.625rem;
    letter-spacing: 0.02em;
  }
  .voice-group { margin-top: 10px; }
}

/* The play control sits inside the option row, so it stops the click from
   also selecting the voice — hearing one should not commit you to it. */
.voice-play {
  flex: none;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface-2);
  color: var(--fg-2);
  cursor: pointer;
  transition: color 0.15s var(--ease), border-color 0.15s var(--ease);
}

.voice-play:hover {
  border-color: var(--brand);
  color: var(--brand-ink);
}

.voice-play svg {
  width: 13px;
  height: 13px;
}

/* Play at rest, stop while playing — the button says what tapping it does. */
.voice-play .ico-stop {
  display: none;
}

.voice-play.is-playing {
  border-color: var(--brand);
  background: var(--brand-ink);
  color: var(--on-brand);
}

.voice-play.is-playing .ico-play {
  display: none;
}

.voice-play.is-playing .ico-stop {
  display: block;
}

.voice-play.is-loading {
  color: var(--fg-4);
  cursor: progress;
}

.voice-play.is-loading svg {
  animation: voice-pulse 1s ease-in-out infinite;
}

@keyframes voice-pulse {
  0%, 100% { opacity: 0.3; }
  50%      { opacity: 1; }
}

/* A narrator who could not read, and the stand-in who did. */
.vo-standin {
  margin: 8px 0 0;
  padding: 7px 9px;
  border-radius: 7px;
  background: var(--warn-wash);
  color: var(--warn);
  font-size: 0.75rem;
  line-height: 1.4;
}
.vo-lang {
  margin-left: 6px;
  padding: 1px 8px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  color: var(--fg-2);
  font-size: 0.6875rem;
  font-weight: 600;
}
.vo-standin-mark {
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: var(--r-pill);
  background: var(--warn-wash);
  color: var(--warn);
  font-size: 0.6875rem;
  font-weight: 600;
}

/* The reel's language: a chip with a globe, the way the voice library offers
   its Language filter. */
.lang-field { margin-bottom: 14px; }
.lang-select { position: relative; display: inline-block; min-width: 240px; max-width: 100%; }
.lang-select svg {
  position: absolute;
  left: 12px;
  top: 50%;
  width: 17px;
  height: 17px;
  transform: translateY(-50%);
  color: var(--fg-2);
  pointer-events: none;
}
.lang-select select.input {
  padding-left: 38px;
  border-radius: var(--r-pill);
  font-weight: 600;
}

/* ---------- The voice library: search, shelves, collections ----------
   Modelled on a voice library rather than a settings list: find someone by
   what they sound like, browse a shelf, or start from a handpicked collection. */
.voice-search { margin: 10px 0 2px; max-width: 520px; }
.voice-search .input { border-radius: var(--r-pill); }

.voice-tag.is-social,
.voice-option .voice-tag.is-social {
  /* Dark enough ends that the white label clears AA at this size. */
  background: linear-gradient(120deg, #D6204A, #4B1FB8);
  color: #fff;
}

.voice-colls-title {
  margin: 4px 0 8px;
  font-size: 0.9375rem;
  font-weight: 700;
}
.voice-colls {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(250px, 1fr);
  gap: 10px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: 6px;
  margin-bottom: 14px;
  scrollbar-width: thin;
}
.voice-coll {
  scroll-snap-align: start;
  position: relative;
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr);
  align-items: center;
  gap: 12px;
  min-height: 88px;
  padding: 10px 44px 10px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface-2);
  color: var(--fg);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.voice-coll:hover { box-shadow: var(--shadow-2); }
.voice-coll:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.voice-coll.is-on { border-color: var(--brand); background: var(--brand-wash); }
.voice-coll-art {
  width: 64px;
  height: 64px;
  display: grid;
  place-items: center;
  border-radius: 14px;
  color: #fff;
  background:
    radial-gradient(circle at 30% 25%, rgba(255, 255, 255, 0.45), transparent 45%),
    linear-gradient(140deg, var(--c1), var(--c2));
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.15);
}
.voice-coll-art svg { width: 28px; height: 28px; }
.voice-coll-text { display: grid; gap: 2px; min-width: 0; }
.voice-coll-text b { font-family: var(--display); font-size: 1rem; font-weight: 600; line-height: 1.2; }
.voice-coll-text span { color: var(--fg-3); font-size: 0.75rem; line-height: 1.35; }
.voice-coll-go {
  position: absolute;
  right: 10px;
  bottom: 10px;
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--fg);
  color: var(--surface);
}
.voice-coll-go svg { width: 13px; height: 13px; }

@media (max-width: 560px) {
  .voice-colls { grid-auto-columns: 82%; }
}

/* ---------- Voice clone ---------- */

.clone-state {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  padding: 13px;
  margin-bottom: 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface-2);
}

.clone-state.is-ready {
  border-color: transparent;
  background: var(--brand-wash);
}

.clone-state.is-bad {
  border-color: transparent;
  background: var(--bad-wash);
}

.clone-state svg {
  width: 18px;
  height: 18px;
  margin-top: 2px;
  flex: none;
  color: var(--fg-3);
}

.clone-state.is-ready svg { color: var(--brand-ink); }
.clone-state.is-bad svg { color: var(--bad); }

.clone-state b {
  display: block;
  font-size: 0.875rem;
  font-weight: 600;
}

.clone-state span {
  display: block;
  margin-top: 2px;
  font-size: 0.8125rem;
  color: var(--fg-2);
  line-height: 1.5;
}

.clone-actions {
  display: flex;
  gap: 8px;
}

.clone-actions .btn {
  flex: 1;
}

/* Script the owner reads while recording */
.script {
  max-height: 190px;
  overflow-y: auto;
  padding: 13px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  font-size: 0.875rem;
  line-height: 1.6;
}

.script p + p {
  margin-top: 0.8em;
  color: var(--fg-2);
}

.script-consent {
  font-weight: 500;
  padding-left: 10px;
  border-left: 2px solid var(--brand);
}

.consent-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin-bottom: 16px;
  font-size: 0.875rem;
  line-height: 1.5;
  cursor: pointer;
}

.consent-row input {
  width: 17px;
  height: 17px;
  margin-top: 2px;
  flex: none;
  accent-color: var(--brand);
  cursor: pointer;
}

/* Recorder */
.recorder {
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 14px;
  margin-bottom: 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
}

.rec-btn {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  flex: none;
  border: none;
  border-radius: 50%;
  background: var(--bad);
  cursor: pointer;
  transition: background-color 0.15s var(--ease);
}

.rec-btn:disabled {
  background: var(--surface-3);
  color: var(--fg-4);
  cursor: not-allowed;
}

.rec-dot {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fff;
  transition: border-radius 0.18s var(--ease), width 0.18s var(--ease),
    height 0.18s var(--ease);
}

/* Recording: the dot becomes a stop square and the button pulses. */
.recorder.is-live .rec-dot {
  width: 14px;
  height: 14px;
  border-radius: 3px;
}

.recorder.is-live .rec-btn {
  animation: kd-rec 1.5s var(--ease) infinite;
}

@keyframes kd-rec {
  0%, 100% { box-shadow: 0 0 0 0 rgba(178, 59, 44, 0.5); }
  60% { box-shadow: 0 0 0 10px rgba(178, 59, 44, 0); }
}

.rec-meta {
  flex: 1;
}

.rec-meta b {
  display: block;
  font-family: var(--mono);
  font-size: 1.0625rem;
  font-weight: 500;
}

.rec-meta span {
  display: block;
  font-size: 0.8125rem;
  color: var(--fg-3);
}

.rec-level {
  width: 4px;
  height: 40px;
  flex: none;
  border-radius: var(--r-pill);
  background: var(--surface-3);
  overflow: hidden;
  display: flex;
  align-items: flex-end;
}

.rec-level i {
  display: block;
  width: 100%;
  height: 0%;
  border-radius: inherit;
  background: var(--brand);
  transition: height 0.08s linear;
}

/* ==========================================================================
   Authentication Gate & OTP Styles
   ========================================================================== */

.auth-gate {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 32px 16px 48px;
  animation: kd-view 0.24s var(--ease);
}

.auth-card {
  width: 100%;
  max-width: 440px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 28px 22px;
  box-shadow: var(--shadow-2);
}

.auth-loading-card { text-align: center; }

.auth-loader {
  width: 30px;
  height: 30px;
  display: inline-block;
  margin-bottom: 14px;
  border: 3px solid var(--line-strong);
  border-top-color: var(--brand);
  border-radius: 50%;
  animation: auth-spin 0.8s linear infinite;
}

.auth-loading-card.is-error .auth-loader { display: none; }
@keyframes auth-spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .auth-loader { animation: none; border-top-color: var(--line-strong); }
}

.auth-header {
  text-align: center;
  margin-bottom: 22px;
}

.auth-icon-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--brand-wash);
  color: var(--brand-ink);
  margin-bottom: 12px;
}

.auth-header h2 {
  font-family: var(--display);
  font-size: 1.5rem;
  font-weight: 600;
  color: var(--fg);
  margin-bottom: 6px;
  letter-spacing: -0.02em;
}

.auth-sub {
  font-size: 0.875rem;
  color: var(--fg-3);
  line-height: 1.45;
  max-width: 320px;
  margin-inline: auto;
}

.password-input-wrap {
  position: relative;
}

.password-input-wrap .input {
  width: 100%;
  padding-right: 64px;
}

.password-visibility {
  position: absolute;
  top: 50%;
  right: 10px;
  transform: translateY(-50%);
  min-width: 44px;
  min-height: 32px;
  padding: 4px 6px;
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--fg-3);
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 650;
  cursor: pointer;
}

.password-visibility:hover,
.password-visibility:focus-visible {
  background: var(--surface-2);
  color: var(--fg);
}

/* Channel Pills */
.channel-pills {
  display: flex;
  gap: 6px;
  background: var(--surface-2);
  padding: 4px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line-soft);
  margin-bottom: 20px;
}

.channel-pill {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px 10px;
  font-size: 0.8125rem;
  font-weight: 600;
  border: none;
  background: transparent;
  color: var(--fg-3);
  border-radius: var(--r-pill);
  cursor: pointer;
  transition: background-color 0.15s var(--ease), border-color 0.15s var(--ease),
    color 0.15s var(--ease);
}

.channel-pill:hover {
  color: var(--fg);
}

.channel-pill.is-active {
  background: var(--surface);
  color: var(--brand-ink);
  box-shadow: var(--shadow-1);
}

/* Sent Banner */
.auth-sent-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 14px;
  background: var(--brand-wash);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  margin-bottom: 18px;
  font-size: 0.8125rem;
}

.banner-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  color: var(--fg-2);
}

.banner-dest {
  font-family: var(--mono);
  color: var(--fg);
  font-size: 0.9375rem;
}

.btn-link {
  padding: 0;
  border: 0;
  background: none;
  color: var(--brand-ink);
  font: inherit;
  font-weight: 600;
  text-decoration: underline;
  cursor: pointer;
}

.btn-link:hover:not(:disabled) {
  text-decoration: underline;
}

.btn-link:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* 6-Digit OTP Group */
.otp-inputs {
  display: flex;
  gap: 8px;
  justify-content: space-between;
  margin-top: 4px;
}

.otp-digit {
  width: 100%;
  height: 52px;
  text-align: center;
  font-family: var(--mono);
  font-size: 1.375rem;
  font-weight: 600;
  background: var(--field);
  border: 1.5px solid var(--line);
  border-radius: var(--r-sm);
  color: var(--fg);
  transition: background-color 0.15s var(--ease), border-color 0.15s var(--ease),
    color 0.15s var(--ease);
  caret-color: var(--brand);
}

.otp-digit:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-wash);
}

/* Resend Row & Footer */
.resend-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin-top: 14px;
  font-size: 0.8125rem;
  color: var(--fg-3);
}

.auth-footer {
  margin-top: 24px;
  padding-top: 18px;
  border-top: 1px solid var(--line-soft);
  text-align: center;
  font-size: 0.8125rem;
  color: var(--fg-3);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 4px 8px;
}

.auth-link {
  color: var(--brand-ink);
  font-weight: 600;
  text-decoration: none;
}

.auth-link:hover {
  text-decoration: underline;
}

/* Asking for an invite code, inside the code field on the create-account form. */
.invite-ask {
  display: grid;
  gap: 8px;
  margin-top: 10px;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface-2);
}

.invite-ask label {
  margin: 0;
}

.invite-ask .hint {
  margin: 0;
}

.invite-ask .btn {
  justify-self: start;
}

.hint-inline {
  font-weight: 400;
  color: var(--fg-3);
}

.invite-ask-done {
  color: var(--good);
}

/* Superadmin Mode Toggle Pill */
.mode-toggle-pill {
  display: inline-flex;
  align-items: center;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  padding: 2px;
  gap: 2px;
  margin-right: 6px;
  box-shadow: var(--shadow-1);
}

.mode-btn {
  background: transparent;
  border: none;
  border-radius: var(--r-pill);
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--fg-3);
  padding: 3px 8px;
  cursor: pointer;
  transition: background-color 0.15s var(--ease), border-color 0.15s var(--ease),
    color 0.15s var(--ease);
}

.mode-btn:hover {
  color: var(--fg);
}

.mode-btn.active {
  background: var(--surface);
  color: var(--brand-strong);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
}

.nav-trends-btn,
.nav-creator-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.8125rem;
  font-weight: 700;
  color: var(--brand-strong);
  background: var(--brand-wash);
  border: 1px solid rgba(221, 90, 31, 0.25);
  border-radius: var(--r-pill);
  padding: 4px 10px;
  text-decoration: none;
  margin-right: 6px;
  transition: background-color 0.15s var(--ease), border-color 0.15s var(--ease),
    color 0.15s var(--ease);
}

.nav-trends-btn:hover,
.nav-creator-btn:hover {
  background: var(--brand-ink);
  color: var(--on-brand);
}

/* User Pill in App Bar */
.user-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 4px 6px 4px 4px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  font-size: 0.8125rem;
  color: var(--fg-2);
  margin-right: 4px;
  box-shadow: var(--shadow-1);
}

.user-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--grad-brand);
  color: var(--on-brand);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), 0 1px 2px rgba(140, 55, 20, 0.25);
}

.user-dest {
  font-family: var(--mono);
  font-weight: 500;
  max-width: 120px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.btn-logout {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  background: transparent;
  border: none;
  padding: 0;
  margin-left: 1px;
  color: var(--fg-4);
  cursor: pointer;
  border-radius: 50%;
  transition: color 0.15s ease, background-color 0.15s ease;
}

.btn-logout:hover {
  color: var(--bad);
  background: var(--bad-wash);
}

/* Button Spinner */
.btn-spinner {
  display: inline-block;
  width: 14px;
  height: 14px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  opacity: 0.75;
  border-radius: 50%;
  animation: kd-spin 0.6s linear infinite;
  margin-left: 6px;
  vertical-align: middle;
}

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

/* ---------- Auth mode tabs ---------- */

/* The reset steps are neither tab, so the strip steps back — and `display:
   flex` beats the hidden attribute unless it is said out loud. */
.auth-tabs[hidden] { display: none; }

.auth-tabs {
  display: flex;
  gap: 4px;
  padding: 4px;
  margin-bottom: 20px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
}

.auth-tab {
  flex: 1;
  padding: 0.55em 0.8em;
  border: none;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--fg-3);
  font-size: 0.875rem;
  font-weight: 600;
  cursor: pointer;
  transition: background-color 0.15s var(--ease), color 0.15s var(--ease);
}

.auth-tab:hover {
  color: var(--fg);
}

.auth-tab.is-active {
  background: var(--surface);
  color: var(--brand-ink);
  box-shadow: var(--shadow-1);
}

/* ---------- Verification checklist ---------- */

.verify-list {
  list-style: none;
  margin-bottom: 20px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  overflow: hidden;
}

.verify-row {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--line-soft);
  background: var(--surface);
}

.verify-row:last-child {
  border-bottom: none;
}

.verify-row.is-done {
  background: var(--brand-wash);
}

.verify-mark {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  flex: none;
  color: var(--fg-4);
}

.verify-row.is-done .verify-mark {
  color: var(--brand-ink);
}

.verify-mark svg {
  width: 100%;
  height: 100%;
}

.verify-row b {
  display: block;
  font-size: 0.875rem;
  font-weight: 600;
}

.verify-row span:not(.verify-mark):not(.pill) {
  display: block;
  font-size: 0.8125rem;
  color: var(--fg-3);
  overflow-wrap: anywhere;
}

.verify-row .pill {
  margin-left: auto;
}

.verify-row > div {
  min-width: 0;
}

/* A long email must not push the theme toggle off the bar. Flex items default
   to min-width:auto, so without these the pill refuses to shrink below its
   text and the controls to its right get pushed out of the container. */
.app-bar .user-pill {
  min-width: 0;
  flex: 0 1 auto;
}

/* The logo keeps its size; the tools give way. Squeezed any other way, the
   wordmark clipped to "Kitch" and every pill wrapped its icon over its label
   at any width between a phone and a wide desktop. When the tools don't fit
   they scroll sideways in their own strip, and the page stays the window's
   width. */
.app-bar .kd-logo {
  flex: none;
}

.app-bar-tools {
  min-width: 0;
  flex: 1 1 auto;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  white-space: nowrap;
  /* Room for the focus rings the strip would otherwise clip. */
  padding: 2px;
  margin: -2px;
}
.app-bar-tools::-webkit-scrollbar { display: none; }
.app-bar-tools > * { flex: none; }
/* Held to the right while it fits. Not justify-content: flex-end, which
   pushes the overflow off the left edge, where no scroll can reach it. */
.app-bar-tools::before { content: ""; margin-left: auto; }

.app-bar .user-pill {
  max-width: none;
  overflow: hidden;
}

.app-bar .user-dest {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Never shrink the controls themselves — only the label between them. */
.app-bar .theme-btn,
.app-bar .btn,
.app-bar .btn-logout,
.app-bar .user-avatar,
.app-bar .kd-logo img {
  flex: none;
}

/* On a phone there isn't room for the wordmark, the email and the buttons.
   Shrinking lets the wordmark paint under the pill, so drop the text outright:
   the mark still says who we are, and the email lives on in the Profile tab. */
@media (max-width: 540px) {
  .app-bar {
    gap: 8px;
    padding-inline: 12px;
  }

  .app-bar .kd-logo b,
  .app-bar .user-dest {
    display: none;
  }

  /* Labelled copies live in More; the icon-only duplicates made this toolbar
     harder to scan and easier to mis-tap during a demo. */
  .app-bar #btnTour,
  .app-bar #themeBtn { display: none; }

  /* A phone header is a toolbar, not a carousel. The old overflow strip left
     the final action half painted on first load and made it look broken. Keep
     the plan legible, compact the secondary action to its shop-plus icon, and
     fit the complete row in the viewport. */
  .app-bar-tools {
    gap: 6px;
    overflow-x: visible;
    margin: 0;
    padding: 0;
  }

  .app-bar .user-pill {
    gap: 4px;
    margin-right: 0;
  }

  .app-bar .nav-plan-btn {
    margin-right: 0;
    padding-inline: 8px;
    font-size: 0.75rem;
  }

  #navAddRestaurant {
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
  }

  #navAddRestaurant svg {
    width: 17px;
    height: 17px;
  }

  #navAddRestaurant span {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
}

/* Admin destinations make the phone header wider than the viewport. They
   live in More at phone/tablet widths, alongside the other occasional tools,
   while the header keeps only account and appearance actions. */
@media (max-width: 899px) {
  .app-bar #superadminModeToggle,
  .app-bar #navTrendsBtn,
  .app-bar #navResearchBtn,
  .app-bar #navInvitesBtn { display: none !important; }
}

/* The tour is always available during onboarding. On the narrowest phones its
   persistent shortcut is the one optional control; removing it keeps account,
   theme, plan and add-location actions fully visible instead of reintroducing
   sideways scrolling. */
@media (max-width: 360px) {
  .app-bar #btnTour { display: none; }
}


.auth-footer .auth-link {
  white-space: nowrap;
}

/* =============================================================================
   Intelligence & Deals Styles
   ============================================================================= */

.card-head-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 14px;
}

.card-head-row .card-head {
  margin-bottom: 0;
}

.intel-hero-card {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 20px 22px;
  margin-bottom: 12px;
  border-radius: var(--r-lg);
  background:
    radial-gradient(120% 140% at 100% 0%, var(--brand-wash) 0%, transparent 55%),
    var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-1);
}

@media (min-width: 480px) {
  .intel-hero-card {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}

.intel-status-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 8px;
}

/* Claimed is settled, not busy: the dot goes green like the badge beside it. */
.agent-pulse-dot.is-good { background: var(--good); }
.agent-pulse-dot.is-good::after { border-color: var(--good); }

.agent-pulse-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--brand);
  position: relative;
}

.agent-pulse-dot.is-active::after {
  content: '';
  position: absolute;
  top: -3px;
  left: -3px;
  right: -3px;
  bottom: -3px;
  border-radius: 50%;
  border: 1.5px solid var(--brand);
  animation: pulse-ring 2s infinite ease-out;
}

.agent-pulse-dot.is-scanning {
  background: var(--warn);
}

.agent-pulse-dot.is-scanning::after {
  content: '';
  position: absolute;
  top: -4px;
  left: -4px;
  right: -4px;
  bottom: -4px;
  border-radius: 50%;
  border: 2px solid var(--warn);
  animation: pulse-ring 1s infinite ease-out;
}

@keyframes pulse-ring {
  0% { transform: scale(0.7); opacity: 1; }
  100% { transform: scale(2.2); opacity: 0; }
}

.intel-badge {
  font-size: 0.75rem;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: var(--r-lg);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.intel-last-scan {
  font-size: 0.75rem;
  color: var(--fg-3);
  margin-left: 4px;
}

.intel-hero-content h2 {
  font-size: 1.125rem;
  font-weight: 600;
  margin: 0 0 4px;
  color: var(--fg-1);
}

.intel-hero-content p {
  font-size: 0.8125rem;
  color: var(--fg-2);
  margin: 0;
  line-height: 1.4;
}

.intel-empty-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-md);
  color: var(--fg-3);
  font-size: 0.8125rem;
  line-height: 1.45;
}

.intel-empty-row svg { flex: none; color: var(--fg-4); }

/* Links and offers sit in one card each, rows divided by hairlines, the way
   the queue and the feeds are -- not a stack of grey boxes. */
.booking-list, .deals-list {
  display: flex;
  flex-direction: column;
}

.booking-list:has(> .booking-item-row),
.deals-list:has(> .deal-card-item) {
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  overflow: hidden;
}

.booking-item-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 13px 16px;
  transition: background-color 0.12s var(--ease);
}

.booking-item-row + .booking-item-row { border-top: 1px solid var(--line-soft); }
.booking-item-row:hover { background: var(--surface-2); }

.booking-meta {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  min-width: 0;
}

.booking-link-text {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-width: 0;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--fg-1);
  text-decoration: none;
  overflow-wrap: anywhere;
}

.booking-link-text:hover { color: var(--brand-strong); }
.booking-link-text svg { flex: none; color: var(--fg-3); }

.plat-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px 3px 8px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  border: 1px solid var(--line-soft);
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--fg-2);
}

.plat-badge::before {
  content: "";
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: 50%;
  background: var(--dot, var(--fg-4));
}

.badge-resy { --dot: #ea580c; }
.badge-opentable { --dot: #dc2626; }

.pill-xs {
  font-size: 0.6875rem;
  padding: 1px 6px;
}

.btn-xs {
  padding: 4px 9px;
  font-size: 0.75rem;
}

.booking-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: none;
}

.btn-icon-subtle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 6px;
  border: none;
  background: transparent;
  color: var(--fg-3);
  cursor: pointer;
  transition: background-color 0.15s var(--ease), border-color 0.15s var(--ease),
    color 0.15s var(--ease);
}

.btn-icon-subtle:hover {
  background: var(--bad-wash);
  color: var(--bad);
}

/* Deal rows. The type is the one colour on a row, so a list of them sorts
   into happy hours, specials and events at a glance. */
.deal-card-item {
  --deal: var(--navy-strong);
  --deal-wash: var(--navy-wash);
  display: grid;
  gap: 6px;
  padding: 14px 16px;
  transition: background-color 0.12s var(--ease);
}

.deal-card-item + .deal-card-item { border-top: 1px solid var(--line-soft); }
.deal-card-item:hover { background: var(--surface-2); }
.deal-card-item[data-type="happy_hour"] { --deal: var(--brand-strong); --deal-wash: var(--brand-wash); }
.deal-card-item[data-type="special"],
.deal-card-item[data-type="lunch_special"] { --deal: var(--good); --deal-wash: var(--good-wash); }
.deal-card-item[data-type="event"] { --deal: var(--violet); --deal-wash: var(--violet-wash); }

/* Switched off is still on the list, just set back from the live ones --
   everything but the switch, which has to stay readable to be switched on. */
.deal-card-item.is-inactive-deal > :not(.deal-card-top),
.deal-card-item.is-inactive-deal .deal-title-group { opacity: 0.5; }

.deal-card-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.deal-title-group {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  min-width: 0;
}

.deal-title-group b {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--fg-1);
}

.deal-type-pill {
  padding: 2px 9px;
  border-radius: var(--r-pill);
  background: var(--deal-wash);
  color: var(--deal);
  font-size: 0.6875rem;
  font-weight: 700;
}

.deal-toggle-group {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: none;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--fg-3);
}

.deal-schedule-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--fg-2);
}

.deal-schedule-tag svg { flex: none; color: var(--fg-3); }

.deal-desc {
  margin: 0;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--fg-2);
}

.deal-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 2px;
}

.deal-buttons {
  display: flex;
  align-items: center;
  gap: 6px;
}

.deal-source-link {
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--fg-3);
  text-decoration: none;
}

.deal-source-link:hover { color: var(--brand-strong); }

/* Profile details: a definition list, label left and value right, on one
   card -- not five grey boxes of different sizes. */
.intel-details-grid {
  display: grid;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  overflow: hidden;
}

.intel-grid-row {
  display: grid;
  grid-template-columns: 170px minmax(0, 1fr);
  align-items: baseline;
  gap: 16px;
  padding: 13px 16px;
  font-size: 0.875rem;
  color: var(--fg-1);
}

.intel-grid-row + .intel-grid-row { border-top: 1px solid var(--line-soft); }

.intel-label {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--fg-3);
}

.intel-summary-p {
  margin: 0;
  font-size: 0.875rem;
  color: var(--fg-1);
  line-height: 1.5;
}

.intel-price-val {
  color: var(--fg-1);
  font-size: 0.9375rem;
  letter-spacing: 0.04em;
}

.intel-web-link {
  color: var(--brand-strong);
  font-weight: 500;
  text-decoration: none;
  overflow-wrap: anywhere;
}

.intel-web-link:hover { text-decoration: underline; }

.intel-chips-wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.intel-chip {
  padding: 3px 10px;
  border-radius: var(--r-pill);
  background: var(--brand-wash);
  color: var(--brand-strong);
  font-size: 0.8125rem;
  font-weight: 500;
}

@media (max-width: 560px) {
  .intel-grid-row { grid-template-columns: minmax(0, 1fr); gap: 4px; }
}

/* Reviews and Customer Sentiment */
.intel-reviews-wrap {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

/* The summary leads, set large, as the one line to take away. */
.intel-reviews-summary {
  margin: 0;
  padding: 2px 0 2px 16px;
  border-left: 3px solid var(--brand);
  font-family: var(--display);
  font-size: 1.0625rem;
  line-height: 1.5;
  color: var(--fg-1);
}

.intel-mini-title {
  display: block;
  margin-bottom: 10px;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--fg-3);
}

.intel-praises-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 8px;
}

.praise-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-sm);
  background: var(--surface);
  font-size: 0.875rem;
  color: var(--fg-1);
}

.praise-item svg {
  flex: none;
  box-sizing: content-box;
  padding: 4px;
  border-radius: 50%;
  background: var(--good-wash);
}

.intel-quotes-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 12px;
}

.review-quote-card {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 12px;
  padding: 22px 16px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
}

.review-quote-card::before {
  content: "\201C";
  position: absolute;
  top: 4px;
  left: 12px;
  font-family: var(--display);
  font-size: 2.4rem;
  line-height: 1;
  color: var(--brand-ink);
  opacity: 0.35;
}

.quote-text {
  position: relative;
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.55;
  color: var(--fg-1);
}

.quote-source {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--fg-3);
}

/* Vibe and Overview */
.intel-vibe-wrap {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.vibe-section {
  display: flex;
  flex-direction: column;
}

.vibe-text {
  margin: 0;
  max-width: 70ch;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--fg-1);
}

.vibe-tags-wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.vibe-tag-pill {
  padding: 4px 11px;
  border-radius: var(--r-pill);
  background: var(--brand-wash);
  color: var(--brand-strong);
  font-size: 0.75rem;
  font-weight: 600;
}

/* Danger Zone Styles */
/* Destructive controls need distance, not just a red border. Save sat flush
   against the card that deletes the restaurant — nothing but a card edge
   between "keep my changes" and "erase this place" — so the danger zone is
   pushed below a rule and out of the reach of a mis-aimed click. */
.danger-card {
  border-color: color-mix(in srgb, var(--bad) 35%, var(--line)) !important;
  margin-top: 56px;
  position: relative;
}

.danger-card::before {
  content: "";
  position: absolute;
  top: -28px;
  left: 0;
  right: 0;
  border-top: 1px solid var(--line);
}

.danger-title {
  color: var(--bad) !important;
}

.danger-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 0 4px;
}

.danger-p {
  margin: 4px 0 0;
  font-size: 0.8125rem;
  color: var(--fg-3);
  line-height: 1.4;
}

.btn-danger {
  /* Set through --btn-fg like every other variant rather than an !important
     colour. The !important could only be answered with another !important, and
     the disabled treatment then hung on :disabled invalidating cleanly through
     two competing important declarations. This just wins on specificity. */
  --btn-fg: #ffffff;
  background: var(--grad-danger);
  border: 1px solid rgba(120, 30, 20, 0.5);
  font-weight: 600;
  box-shadow: 0 1px 2px rgba(120, 30, 20, 0.16), 0 4px 12px -6px rgba(120, 30, 20, 0.28);
}

.btn-danger:hover {
  background: var(--grad-danger-hover);
}

.btn-danger:active {
  background: var(--grad-danger);
  box-shadow: 0 1px 2px rgba(120, 30, 20, 0.16);
}




/* Account Profile Modal */
.account-info-box {
  padding: 14px;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  border: 1px solid var(--line);
}

.account-email-row {
  display: flex;
  align-items: center;
  gap: 12px;
}

.account-plan-box {
  margin-top: 14px;
  padding: 14px;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  border: 1px solid var(--line);
}

.account-plan-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

.account-plan-head .plan-title {
  margin: 2px 0 0;
}

/* The composer sets its two meters side by side under a wide box; in here they
   are a two-line summary of the plan above them, so they stack. */
.account-plan-usage {
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
  margin: 12px 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--line);
}

.account-plan-usage .usage-meter { justify-content: space-between; }
.account-plan-usage .usage-bar { flex: 1; width: auto; }

.user-avatar-lg {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--grad-brand);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--on-brand);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), 0 2px 5px -1px rgba(140, 55, 20, 0.38);
}

.account-verified-tag {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 600;
  padding: 2px 7px;
  border-radius: 4px;
  background: var(--surface-3);
  color: var(--fg-3);
  margin-top: 3px;
}

.account-verified-tag.is-verified {
  background: var(--good-wash);
  color: var(--good);
}

.danger-box {
  margin-top: 40px;
  padding: 14px;
  border-radius: var(--r-sm);
  border: 1px solid var(--bad);
  background: var(--bad-wash);
}

.danger-box b {
  color: var(--bad);
  font-size: 0.875rem;
  display: block;
}

.danger-box p {
  margin: 4px 0 8px;
  font-size: 0.8125rem;
  color: var(--fg-2);
  line-height: 1.4;
}

.modal-sm {
  max-width: 440px !important;
}

/* =============================================================================
   Usage Metrics & Activity Dashboard Styles
   ============================================================================= */

/* This grid always lives inside the phone-width `.app` shell (max-width:
   520px), never the browser viewport, so breakpoints keyed to window width
   don't track its real available space — on any normal desktop browser the
   window clears typical breakpoints while the shell itself stays ~488px.
   `minmax(0, 1fr)` overrides Grid's default content-based minimum column
   width, so a long dynamic string can't force a column wider than its fair
   share and push a card out past the shell's edge (see the plan quota line
   that used to live in a 4th card here — moved to Account settings). */
.metrics-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
  margin-bottom: 20px;
}

.metric-card {
  display: flex;
  align-items: center;
  gap: 14px;
  min-width: 0;
  padding: 16px;
  background: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.metric-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

.metric-icon-wrap {
  width: 44px;
  height: 44px;
  border-radius: var(--r-md);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

/* One treatment for all four — the number is the story, not the icon. */
.icon-reels,
.icon-posts,
.icon-published {
  background: var(--brand-wash);
  color: var(--brand-ink);
}

.metric-meta {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.metric-label {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--fg-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.metric-value {
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--fg-1);
  line-height: 1.2;
  margin: 2px 0;
}

.metric-sub {
  font-size: 0.75rem;
  color: var(--fg-2);
  overflow-wrap: anywhere;
}

/* Three columns used to squeeze each card to ~100px and wrap the labels a
   letter per line, so they were stacked instead — and three stacked cards ate
   the whole first screen of Activity to say three zeros. What cost the width
   was the 44px icon chip, which left the label ~55px to wrap in. The icons
   were never the point (they all carry the same wash, above), so on a
   phone they go and the row stays a row: at 375px that leaves each column
   ~107px, enough for "Image posts" on one line. */
@media (max-width: 620px) {
  .metrics-grid {
    gap: 8px;
  }

  .metric-card {
    gap: 0;
    padding: 11px 12px;
  }

  .metric-icon-wrap {
    display: none;
  }

  .metric-meta {
    flex: 1;
  }

  /* The number leads; the label under it says what it counts. */
  .metric-value {
    order: -1;
    font-size: 1.375rem;
    margin: 0 0 1px;
  }

  .metric-label {
    font-size: 0.6875rem;
    letter-spacing: 0.05em;
    overflow-wrap: anywhere;
  }

  .metric-sub {
    font-size: 0.6875rem;
  }
}

/* Activity Timeline Feed */
.activity-filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 16px;
}

.activity-timeline {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.activity-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  transition: background 0.15s ease;
}

.activity-row:hover {
  background: var(--surface-3);
}

.activity-media-wrap {
  position: relative;
  width: 54px;
  height: 54px;
  border-radius: var(--r-sm);
  overflow: hidden;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  background: var(--surface-3);
}

/* Icon and artwork share the one cell — the artwork covers the icon while it
   loads, and if it fails the icon is simply there underneath. */
.activity-media-wrap > * {
  grid-area: 1 / 1;
}

/* Openable rows only: the tile is a button there, and has to shed the browser's
   own button chrome to stay the same tile it is on a row with nothing to open. */
button.activity-media-wrap {
  padding: 0;
  border: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
}

button.activity-media-wrap img {
  transition: transform 0.16s var(--ease);
}

button.activity-media-wrap:hover img,
button.activity-media-wrap:focus-visible img {
  transform: scale(1.07);
}

button.activity-media-wrap:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  button.activity-media-wrap img { transition: none; }
}

.activity-media-wrap img {
  width: 54px;
  height: 54px;
  object-fit: cover;
}

/* Items with no artwork get a tinted type icon, matching their badge, rather
   than a stock photo pretending to be their food. */
.activity-media-wrap > svg {
  width: 22px;
  height: 22px;
}

.tile-reel    { background: var(--brand-wash); color: var(--brand-ink); }
.tile-post    { background: var(--navy-wash);  color: var(--navy); }
.tile-publish { background: var(--good-wash);  color: var(--good); }
.tile-scan    { background: var(--surface-3);  color: var(--fg-3); }

.play-indicator {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  background: rgba(0, 0, 0, 0.35);
}

.play-indicator svg {
  width: 16px;
  height: 16px;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.4));
}

.activity-content-wrap {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.activity-top-line {
  display: flex;
  align-items: center;
  gap: 8px;
}

.activity-type-badge {
  font-size: 0.6875rem;
  font-weight: 600;
  padding: 2px 7px;
  border-radius: 4px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  white-space: nowrap;
}

.badge-reel {
  background: var(--brand-wash);
  color: var(--brand-ink);
}

.badge-post {
  background: var(--navy-wash);
  color: var(--navy);
}

.badge-publish {
  background: var(--good-wash);
  color: var(--good);
}

.badge-scan {
  background: var(--surface-3);
  color: var(--fg-2);
}

.activity-time {
  font-size: 0.75rem;
  color: var(--fg-3);
}

.activity-title {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--fg-1);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Two lines, then an ellipsis: on a phone a single-line caption cuts off
   after three or four words, which reads as broken rather than tidy. */
.activity-caption {
  margin: 0;
  font-size: 0.8125rem;
  line-height: 1.4;
  color: var(--fg-2);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.activity-action-col {
  flex-shrink: 0;
}

.activity-empty {
  display: grid;
  justify-items: center;
  gap: 10px;
  padding: 28px 18px;
  border: 1.5px dashed var(--line-strong);
  border-radius: var(--r-md);
  text-align: center;
}

.activity-empty svg {
  width: 26px;
  height: 26px;
  color: var(--fg-4);
}

.activity-empty p {
  margin: 0;
  max-width: 34ch;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--fg-3);
}

/* Plan Card & Quota Meters */
.plan-head-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
}

.plan-title {
  font-family: var(--sans);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -0.012em;
  margin: 4px 0 4px;
}

.plan-sub {
  margin: 0;
  font-size: 0.8125rem;
  color: var(--fg-3);
  line-height: 1.5;
  max-width: 48ch;
}

.quota-bars-grid {
  display: grid;
  /* Two meters or three (the made-for-you one is hidden when a plan has none):
     each as wide as the row shares out, never narrower than a label. */
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 18px;
  margin-top: 18px;
}

@media (max-width: 680px) {
  .quota-bars-grid {
    grid-template-columns: 1fr;
  }
}

.quota-box {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  padding: 14px;
}

.quota-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
  font-size: 0.875rem;
}

.quota-head span {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--brand-ink);
}

.progress-bar-bg {
  width: 100%;
  height: 8px;
  background: var(--surface-3);
  border-radius: 4px;
  overflow: hidden;
}

.progress-bar-fill {
  height: 100%;
  background: var(--grad-brand);
  border-radius: 4px;
  transition: width 0.3s ease;
}

.progress-bar-fill.fill-posts {
  background: var(--grad-navy);
}

/* The same three states the composer's usage strip uses, on the same
   thresholds, so a meter that is orange under the button is orange here too.
   Colour beats reading the count, which is the point of having a bar at all. */
.quota-box.is-low { border-color: var(--warn); }
.quota-box.is-low .quota-head span { color: var(--warn); }
.quota-box.is-low .progress-bar-fill,
.quota-box.is-low .progress-bar-fill.fill-posts { background: var(--warn); }

.quota-box.is-out { border-color: var(--bad); background: var(--bad-wash); }
.quota-box.is-out .quota-head span { color: var(--bad); }
.quota-box.is-out .progress-bar-fill,
.quota-box.is-out .progress-bar-fill.fill-posts { background: var(--bad); }
.quota-box.is-out .quota-hint { color: var(--bad); font-weight: 600; }

/* Full and flat. There is nothing to draw down, and the bar is only still here
   so the card keeps its shape next to the metered one beside it. */
.quota-box.is-unlimited .quota-head span { color: var(--fg-3); }
.quota-box.is-unlimited .progress-bar-fill,
.quota-box.is-unlimited .progress-bar-fill.fill-posts { background: var(--line-strong); }

.quota-hint {
  display: block;
  font-size: 0.75rem;
  color: var(--fg-3);
  margin-top: 6px;
}

.syndication-channels-row {
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
}

.syndication-label {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--fg-2);
}

/* Platform chips: one neutral chrome, the platform's own logo on a fixed-
   white badge so it stays legible in dark mode (TikTok's mark is pure black).
   (These class names also exist in landing.css; the two files never load
   on the same page.) */
.social-pills-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.social-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px 3px 4px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--fg-2);
  font-size: 0.75rem;
  font-weight: 500;
  white-space: nowrap;
}

.social-pill img {
  width: 15px;
  height: 15px;
  flex: none;
  padding: 3px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.06);
}





/* =============================================================================
   Schedule: library grid, queue rows, posting-window picker
   ============================================================================= */

/* ---- Library ---- */

.lib-dropzone {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 0 0 16px;
  padding: 16px 18px;
  border: 1.5px dashed var(--line-strong);
  border-radius: var(--r-md);
  background: var(--surface);
  cursor: pointer;
  transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease);
}

.lib-drop-icon {
  display: grid;
  place-items: center;
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 12px;
  background: var(--brand-wash);
  color: var(--brand-strong);
}

.lib-drop-icon svg { width: 19px; height: 19px; }
.lib-drop-text { display: grid; gap: 2px; min-width: 0; }
.lib-drop-text b { font-size: 0.9375rem; font-weight: 600; color: var(--fg); }
.lib-drop-text span { font-size: 0.8125rem; color: var(--fg-3); }

.lib-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 0 2px 10px;
  font-size: 0.8125rem;
}

.lib-toolbar[hidden] { display: none; }
.lib-picked { font-weight: 600; color: var(--fg-2); }

.library-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));
  gap: 10px;
  margin: 0 0 18px;
}

.lib-empty {
  grid-column: 1 / -1;
  margin: 0;
  padding: 18px;
  border: 1px dashed var(--line);
  border-radius: var(--r-md);
  font-size: 0.8125rem;
  color: var(--fg-3);
  text-align: center;
}

.lib-tile {
  position: relative;
  aspect-ratio: 1;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface-2);
  overflow: hidden;
  cursor: pointer;
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease), transform 0.08s var(--ease);
}

.lib-tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.2s var(--ease);
}

.lib-tile video { width: 100%; height: 100%; object-fit: cover; }
.media-set-aside { margin-top: 20px; color: var(--fg-2); }
.media-set-aside summary { cursor: pointer; font-weight: 600; }
.media-set-aside > p { margin: 10px 0; font-size: 0.875rem; }
.media-set-aside ul { list-style: none; margin: 0; padding: 0; }
.media-set-aside li { display: flex; gap: 12px; align-items: center; padding: 12px 0; border-top: 1px solid var(--line); }
.media-set-aside li > .lib-tile,
.media-set-aside li > video { flex: 0 0 76px; width: 76px; height: 76px; object-fit: cover; border-radius: 10px; }
.media-set-aside li > div { min-width: 0; }
.media-set-aside li p { margin: 4px 0; font-size: 0.875rem; overflow-wrap: anywhere; }
.media-set-aside li a { font-size: 0.875rem; }
.compose-idea { padding: 12px 16px; border-bottom: 1px solid var(--line); color: var(--fg-2); }
.compose-idea b { font-size: 0.8125rem; }
.compose-idea p { margin: 4px 0 0; font-size: 0.875rem; overflow-wrap: anywhere; }

.lib-tile:hover img { transform: scale(1.03); }
.lib-tile:active { transform: scale(0.97); }

.lib-tile.is-on {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-wash), 0 0 0 1px var(--brand);
}

/* Selection tick, only painted once the tile is chosen. */
.lib-check {
  position: absolute;
  top: 7px;
  right: 7px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.95);
  background: rgba(0, 0, 0, 0.28);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
  transition: background-color 0.15s var(--ease);
}

.lib-tile.is-on .lib-check {
  background: var(--brand);
  border-color: #fff;
}

.lib-tile.is-on .lib-check::after {
  content: "";
  position: absolute;
  inset: 0;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E") center / 12px no-repeat;
}

/* The two things a picked batch can become, side by side. */
.lib-actions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 14px;
}

.lib-action-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 0;
  padding: 16px 18px;
}

.lib-action-text { display: grid; gap: 3px; flex: 1; }
.lib-action-text b { font-size: 0.9375rem; font-weight: 600; color: var(--fg); }
.lib-action-text .hint { margin: 0; font-size: 0.8125rem; line-height: 1.5; }
.lib-action-card > .btn { align-self: flex-start; min-width: 150px; }

.lib-pack-row { display: flex; gap: 8px; }
.lib-pack-row .input { flex: 1; min-width: 0; }
.lib-pack-row .btn { flex: none; }

.lib-pack-result {
  margin: 0;
  padding: 10px 12px;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--fg-2);
}

.lib-pack-result[hidden] { display: none; }
.lib-clip-thumb { width: 72px; height: 128px; object-fit: cover; border-radius: 8px; vertical-align: middle; margin-right: 8px; }
.lib-backdrop-thumb { width: 44px; height: 44px; object-fit: cover; border-radius: 8px; vertical-align: middle; margin-right: 8px; }

@media (max-width: 460px) {
  .lib-pack-row { flex-direction: column; }
  .lib-action-card > .btn { align-self: stretch; }
  .library-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
}

/* ---- Queue ---- */

/* The status filter is the same switch the rest of the portal uses. */
.sched-filters {
  display: grid;
  width: fit-content;
  max-width: 100%;
  margin: 0 0 16px;
  overflow-x: auto;
  scrollbar-width: none;
}

.sched-filters::-webkit-scrollbar { display: none; }
.sched-filters[hidden] { display: none; }
.sched-filters .seg-btn { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; padding: 7px 16px; }
.sched-filters .seg-n { font-family: var(--mono); font-size: 0.6875rem; color: var(--fg-3); }
.sched-filters .seg-btn.is-on .seg-n { color: inherit; opacity: 0.75; }

/* One list, one card: rows divided by hairlines, the way Activity is. */
#scheduleList.schedule-list {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  overflow: hidden;
}

#scheduleList.schedule-list:has(> .sched-empty),
#scheduleList.schedule-list:has(> .none-yet) {
  border: 0;
  background: none;
  overflow: visible;
}

.schedule-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.sched-row {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 14px 16px 14px 19px;
  transition: background-color 0.12s var(--ease);
}

.sched-row + .sched-row { border-top: 1px solid var(--line-soft); }
.sched-row:hover { background: var(--surface-2); }

/* The state, as a stripe down the row's leading edge. A queue is read as a
   column: the pill on the right answers "what is this one waiting on", but
   only the stripe answers it for twelve rows at once. */
.sched-row[data-state]::before {
  content: "";
  position: absolute;
  inset: 12px auto 12px 0;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--edge, var(--line));
}

.sched-row[data-state="draft"]     { --edge: var(--gold); }
.sched-row[data-state="approved"]  { --edge: var(--good); }
.sched-row[data-state="posting"]   { --edge: var(--warn); }
.sched-row[data-state="failed"]    { --edge: var(--bad); }
.sched-row[data-state="posted"]    { --edge: var(--good); }
.sched-row[data-state="cancelled"] { --edge: var(--line-strong); }

/* Landed on from a feed card's "See in queue". The colour is the answer to
   "which of these is the one I was just looking at" — it fades once read. */
.sched-row.is-found {
  background: var(--brand-wash);
  box-shadow: inset 0 0 0 2px var(--brand);
}

.sched-thumb {
  position: relative;
  width: 56px;
  height: 70px;
  flex: none;
  padding: 0;
  border: 0;
  border-radius: 10px;
  overflow: hidden;
  background: var(--surface-3);
}

button.sched-thumb {
  cursor: pointer;
}

button.sched-thumb:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

/* Centred rather than tucked in a corner: it is the thing you press, not a
   label saying the file happens to be a video. */
.sched-play {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  padding-left: 1px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.58);
  color: #fff;
  font-size: 8px;
  line-height: 1;
  transition: background-color 0.15s var(--ease);
}

button.sched-thumb:hover .sched-play {
  background: var(--brand);
}

.sched-empty {
  display: grid;
  justify-items: center;
  gap: 8px;
  padding: 36px 20px;
  border: 1.5px dashed var(--line-strong);
  border-radius: var(--r-lg);
  background: var(--surface);
  text-align: center;
}

.sched-empty-icon {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  margin-bottom: 4px;
  border-radius: 14px;
  background: var(--brand-wash);
  color: var(--brand-strong);
}

.sched-empty-icon svg { width: 22px; height: 22px; }
.sched-empty b { font-size: 1rem; font-weight: 600; color: var(--fg); }
.sched-empty p { margin: 0; max-width: 40ch; font-size: 0.8125rem; line-height: 1.5; color: var(--fg-3); }
.sched-empty-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-top: 8px; }

.sched-remaining {
  margin: 0;
  padding: 10px 16px;
  border-top: 1px solid var(--line-soft);
  background: var(--surface-2);
  font-size: 0.8125rem;
  color: var(--fg-3);
}

/* ---- Media preview ---- */

/* Wider than a form sheet: this one exists to be looked at, so the clip gets
   the room a 4:5 frame needs before the page around it starts to matter. */
.sheet-media { max-width: 620px; }

/* A question is a couple of lines and two buttons. At the full sheet width it
   reads as a form with the fields missing. */
.sheet-narrow { max-width: 372px; }

/* No head/body gap on a question: the body IS the question, and 1.2rem of air
   between it and the buttons makes a two-line dialog feel half empty. */
#askSheet .sheet-head { margin-bottom: 1rem; }
#askSheet .sheet-head p { margin-top: 6px; }

/* ---------- Asking in the page (the enrolment link) ----------
   That page has no modal machinery, and a staff phone opened straight from a
   text message is the wrong place to introduce one. The button gives way to
   the question instead. */

.drop-confirm {
  margin-top: 10px;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--bad-wash);
}

.drop-confirm[hidden] { display: none; }

.drop-confirm b {
  display: block;
  font-size: 0.9375rem;
  color: var(--bad);
}

.drop-confirm p {
  margin: 5px 0 12px;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--fg-2);
}

.drop-confirm-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

.media-preview video,
.media-preview img {
  display: block;
  width: 100%;
  max-height: 72vh;
  object-fit: contain;
  border-radius: var(--r-sm);
  background: #000;
}

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

.sched-time {
  font: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--fg);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 3px 8px;
  max-width: 100%;
  cursor: pointer;
  transition: border-color 0.15s var(--ease);
}

.sched-time:hover { border-color: var(--line-strong); }
.sched-time:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }

.sched-meta .sched-error {
  color: var(--bad);
  font-weight: 500;
}

/* "Wed, Sep 3, 11:30" is the fact; "in 2 days" is the answer. Both, because
   the first is what you edit and the second is what you were asking. */
.sched-meta b > .sched-when {
  flex: none;
  padding: 2px 8px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--fg-2);
  white-space: nowrap;
}

/* A slot already gone by is the one thing on this screen worth interrupting
   for — either the cron is behind or the post is waiting on a yes it will
   never now get in time. */
.sched-meta b > .sched-when.is-late {
  background: var(--bad-wash);
  color: var(--bad);
}

.sched-meta {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* The slot time must stay on one line — it's the thing being scanned. */
.sched-meta b {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  min-width: 0;
  font-size: 0.875rem;
  font-weight: 600;
}

.sched-meta b > .sched-time { flex: none; max-width: 100%; }

.sched-meta span {
  font-size: 0.8125rem;
  color: var(--fg-3);
}

.sched-meta .sched-caption {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  line-height: 1.45;
  color: var(--fg-2);
}

/* The lifecycle line: queued/approved/posted times. Quieter than the caption —
   it's there to be checked, not read every time. */
.sched-meta .sched-log {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  font-size: 0.75rem;
  color: var(--fg-4);
}

.sched-meta .sched-kind {
  padding: 1px 7px;
  border-radius: var(--r-pill);
  background: var(--surface-3);
  font-size: 0.6875rem;
  font-weight: 600;
  color: var(--fg-2);
}

.sched-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: none;
  padding-top: 2px;
}

/* On a phone, thumb + time + buttons on one line leaves the date control about
   108px, which is enough to clip the year off it. The buttons drop to their own
   line instead — the row is taller, and the time is readable. */
@media (max-width: 560px) {
  .sched-row {
    flex-wrap: wrap;
    padding: 12px 12px 12px 15px;
  }

  .sched-thumb { width: 48px; height: 60px; }

  .sched-meta {
    flex: 1 1 calc(100% - 64px);
  }

  .sched-actions {
    width: 100%;
    justify-content: flex-end;
  }
}

/* ---- Day picker ---- */

/* A week is seven columns, not a wrapping row. Left to flex-wrap it broke
   five-and-two on a phone, which reads as a list that ran out of room rather
   than as Monday to Sunday, and the two orphans sat under a gap where Sat and
   Sun ought to be. Capped so the chips don't stretch into slabs on a desktop. */
.day-picker {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 6px;
  max-width: 430px;
}

.day-chip {
  padding: 9px 4px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
  color: var(--fg-3);
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 500;
  text-align: center;
  text-decoration: line-through;
  text-decoration-color: var(--fg-4);
  cursor: pointer;
  transition: background-color 0.15s var(--ease), color 0.15s var(--ease),
    border-color 0.15s var(--ease);
}

.day-chip:hover { border-color: var(--line-strong); }

/* Seven filled orange pills is the loudest thing on a page whose actual
   action is a Save button — and every account starts with all seven on, so
   the default state shouted. The wash reads as clearly chosen against an off
   day, which is also struck through so the two never depend on colour alone. */
.day-chip.is-on {
  background: var(--brand-wash);
  border-color: var(--brand);
  color: var(--brand-strong);
  font-weight: 650;
  text-decoration: none;
}

/* ---- Posting times ---- */

.times-card { padding: 4px 22px 22px; }

.times-group {
  display: grid;
  gap: 12px;
  padding: 18px 0;
}

.times-group + .times-group { border-top: 1px solid var(--line-soft); }
.times-group .field { margin: 0; }
.times-group .switch-row { padding: 0; border-top: 0; }

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

.times-group-head b { font-size: 0.9375rem; font-weight: 600; color: var(--fg); }
.times-group-head span { font-size: 0.75rem; color: var(--fg-3); }

.times-suggest {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  justify-self: start;
  color: var(--brand-strong);
}

.times-card > #btnSaveSchedule { margin-top: 4px; }

@media (max-width: 460px) {
  .times-card { padding: 2px 16px 16px; }
}

/* Quieter than the mode switch above it: photo-or-generated is a setting
   within Image post, not a peer of the choice between video and image. */
.seg-quiet {
  max-width: 320px;
  margin-bottom: 16px;
  background: transparent;
  border-color: transparent;
  padding: 0;
  gap: 6px;
}

.seg-quiet .seg-btn {
  border: 1px solid var(--line);
  font-size: 0.8125rem;
}

.seg-quiet .seg-btn.is-on {
  border-color: var(--brand);
  background: var(--brand-wash);
  color: var(--brand-ink);
}

.seg-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
}

.seg-btn svg { flex: none; }



/* Two selects that read as one control: the second narrows to the first. */
.field-pair-tight {
  gap: 8px;
  margin-bottom: 6px;
}

/* Arriving from "Use this", the format is a decision already taken, so it is

.chosen-format[hidden] { display: none; }




/* Same 9:13 as the gallery card, small enough to sit beside the words rather

.chosen-thumb[hidden] { display: none; }


.chosen-thumb[data-intent="craving"] { background: var(--grad-brand); }
.chosen-thumb[data-intent="trust"] { background: var(--grad-good); }
.chosen-thumb[data-intent="booking_order"] { background: var(--grad-violet); }

/* The fallback when a format has no example clip: the frame it opens on. */





/* ---------------- The composer ----------------
   One box, the shape every AI tool now takes a request in: the words, what
   is attached above them, the tools underneath, one button that sends. The
   two-column form it replaced (dropzone | paragraph, label, textarea, hint,
   button, three footnotes) asked the owner to read before they could type. */

/* Fills the column like everything else on the view. Its own cap left the
   composer 120px short of the section heading directly above it, so the one
   thing you came to type sat inside a ragged right edge. */
.composer { max-width: 100%; }

.prompt-box {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px 12px 10px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: var(--shadow-2);
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}

.prompt-box:focus-within {
  border-color: var(--brand);
  box-shadow: var(--shadow-2), 0 0 0 3px var(--brand-wash);
}

/* The words. No border of their own: the box is the field. Grows with what
   is typed (field-sizing where the browser has it; two lines elsewhere). */
.prompt-text {
  width: 100%;
  min-height: 56px;
  max-height: 40vh;
  padding: 6px 4px;
  border: 0;
  background: transparent;
  color: var(--fg);
  font-size: 1rem;
  line-height: 1.5;
  resize: none;
  field-sizing: content;
}

.prompt-text:focus { outline: none; }
.prompt-text::placeholder { color: var(--fg-4); }

/* Under the words: attach, what to make, send. */
.compose-tools {
  --tool-h: 38px;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.compose-tools .dropzone {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: var(--tool-h);
  padding: 0 12px 0 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface-2);
  color: var(--fg-2);
  font-size: 0.8125rem;
  line-height: 1;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease), color 0.15s var(--ease);
}

.compose-tools .dropzone b { font-weight: inherit; color: inherit; font-size: inherit; }
.compose-tools .dropzone svg { width: 16px; height: 16px; margin: 0; color: inherit; }
.compose-tools .dropzone:hover,
.compose-tools .dropzone.has-file { color: var(--brand-ink); }
.compose-tools .dropzone:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

/* Video or image, as a small switch in the toolbar rather than a bar above
   the whole form: it is a setting on the request, not a page. */
.compose-tools .seg-mini {
  height: var(--tool-h);
  margin: 0;
  padding: 3px;
  gap: 2px;
  box-sizing: border-box;
}

.compose-tools .seg-mini .seg-btn {
  padding: 0 11px;
  font-size: 0.8125rem;
  gap: 6px;
}

.compose-send {
  height: var(--tool-h);
  margin-left: auto;
  padding: 0 0.8em 0 1.05em;
  border-radius: var(--r-pill);
  gap: 0.4em;
}

.compose-send:disabled { opacity: 0.45; }

/* Docked in the thread the box is a reply field, shaped like the one in every
   chat app: rounder, and sent with a round arrow. The words on the button
   ("Send", "Working on it…") are what the thread itself already says, so
   there they are for the screen reader only. */
#viewChat .prompt-box { border-radius: var(--r-xl); padding: 12px 12px 10px 16px; }
#viewChat .prompt-text { min-height: 28px; }
#viewChat .compose-send {
  width: var(--tool-h);
  padding: 0;
  justify-content: center;
  border-radius: 50%;
}
#viewChat .compose-send svg { width: 18px; height: 18px; }
#viewChat #btnComposeText {
  position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}
#viewChat .compose-send[data-busy] svg { display: none; }
#viewChat .compose-send[data-busy]::after {
  content: "";
  width: 14px;
  height: 14px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: kd-spin 0.8s linear infinite;
}

/* While the agent works the button is its Stop: a square, the mark every
   player and every chat app uses for it. Pressed, it spins until the agent
   has actually stopped -- it stops between steps, not in the middle of one. */
#viewChat .compose-send[data-stop]:not([data-stopping])::after {
  width: 11px;
  height: 11px;
  border: 0;
  border-radius: 2px;
  background: currentColor;
  animation: none;
}
#viewChat .compose-send[data-stop]:not(:disabled) { opacity: 1; cursor: pointer; }
.chat-stopping { font-size: 0.8125rem; color: var(--fg-3); }

/* Dropped anywhere on the box. The veil says so while a file is over it. */
.drop-veil {
  position: absolute;
  inset: 0;
  display: none;
  place-items: center;
  border-radius: inherit;
  border: 2px dashed var(--brand);
  background: var(--brand-wash);
  color: var(--brand-ink);
  font-weight: 700;
  pointer-events: none;
}

.prompt-box.is-hot .drop-veil { display: grid; }

/* Attached shots as a storyboard in the order they play: tall tiles in the
   reel's own proportion, the shot number on a gradient at the foot, a dashed
   tile at the end to add the next one. The row list this replaced showed one
   48px thumb beside a filename; a reel is judged by its pictures. */
.prompt-box .file-list {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 0;
  padding: 2px 0 0;
  max-height: none;
  overflow: visible;
}

.prompt-box .file-item,
.prompt-box .file-add {
  position: relative;
  width: 76px;
  height: 118px;
  padding: 0;
  border-radius: var(--r-sm);
  overflow: hidden;
  display: block;
}
.prompt-box .file-item {
  background: var(--surface-3);
  box-shadow: inset 0 0 0 1px rgba(22, 32, 58, 0.08), var(--shadow-1);
  transition: transform 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.prompt-box .file-item:hover {
  background: var(--surface-3);
  border-color: transparent;
  transform: translateY(-2px);
  box-shadow: inset 0 0 0 1px rgba(22, 32, 58, 0.08), var(--shadow-2);
}
/* A foot of shade so the number and the length read on any picture. */
.prompt-box .file-item::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 44%;
  background: linear-gradient(to top, rgba(11, 16, 32, 0.6), rgba(11, 16, 32, 0));
  pointer-events: none;
  z-index: 1;
}

.prompt-box .file-thumb-wrap { position: static; width: 100%; height: 100%; }
.prompt-box .file-list-thumb,
.prompt-box .file-list-video-icon { width: 100%; height: 100%; border: 0; border-radius: 0; box-shadow: none; }
.prompt-box .file-thumb-duration {
  right: 6px;
  bottom: 7px;
  padding: 0;
  background: none;
  font-size: 10px;
  font-weight: 600;
  z-index: 2;
}

/* The handle is the whole tile: drag it anywhere. The number and the remove
   sit on top of it. */
.prompt-box .file-drag-handle {
  position: absolute;
  inset: 0;
  width: auto;
  height: auto;
  margin: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: transparent;
  z-index: 1;
  cursor: grab;
}
.prompt-box .file-drag-handle:hover { background: transparent; }
.prompt-box .file-drag-handle:focus-visible { box-shadow: inset 0 0 0 2px var(--brand); }

.prompt-box .file-list-badge {
  position: absolute;
  top: auto;
  bottom: 6px;
  left: 6px;
  width: 20px;
  height: 20px;
  border-radius: var(--r-pill);
  background: #fff;
  color: #16203a;
  font-size: 11px;
  z-index: 2;
  pointer-events: none;
}

.prompt-box .file-list-info { display: none; }

.prompt-box .file-remove-btn {
  position: absolute;
  top: 5px;
  right: 5px;
  width: 22px;
  height: 22px;
  margin: 0;
  border-radius: var(--r-pill);
  background: rgba(11, 16, 32, 0.65);
  color: #fff;
  z-index: 2;
  opacity: 0;
  transition: opacity 0.12s var(--ease);
}
.prompt-box .file-remove-btn svg { width: 12px; height: 12px; }
.prompt-box .file-item:hover .file-remove-btn,
.prompt-box .file-item:focus-within .file-remove-btn { opacity: 1; }
@media (hover: none) { .prompt-box .file-remove-btn { opacity: 1; } }
.prompt-box .file-remove-btn:hover { background: var(--bad); border-color: transparent; }

.prompt-box .file-item.is-dragging {
  transform: scale(1.04);
  box-shadow: 0 0 0 2px var(--brand), var(--shadow-2);
}

/* The next shot goes here: a label for the same hidden input the toolbar
   button opens, so the strip grows from its own end. */
.prompt-box .file-add {
  border: 1.5px dashed var(--line-strong);
  background: transparent;
  color: var(--fg-3);
  transition: border-color 0.15s var(--ease), color 0.15s var(--ease), background-color 0.15s var(--ease);
}
.prompt-box .file-add label {
  display: grid;
  place-items: center;
  align-content: center;
  gap: 4px;
  width: 100%;
  height: 100%;
  font-size: 11px;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
}
.prompt-box .file-add:hover { border-color: var(--brand); color: var(--brand-ink); background: var(--brand-wash); }
.prompt-box .file-add svg { width: 18px; height: 18px; }

/* What the shots add up to, as a quiet line under the strip. */
.prompt-box .shot-summary { margin: 2px 2px 0; }

@media (max-width: 560px) {
  .prompt-box .file-item,
  .prompt-box .file-add { width: 64px; height: 100px; }
}

/* The chosen format, as a chip on top of the box: a 9:13 thumb, the name,
   a way out. */
.compose-pick {
  display: inline-flex;
  align-items: flex-start;
  gap: 10px;
  width: fit-content;
  max-width: min(100%, 460px);
  padding: 8px 10px 8px 8px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface-2);
}
.compose-pick[hidden] { display: none; }
.compose-pick-card { flex: 0 0 34px; width: 34px; max-width: 34px; margin: 0; border: 0; box-shadow: none; background: transparent; }
.compose-pick-card .format-frame { width: 34px; height: 49px; padding: 0; border-radius: 4px; }
/* Too small for a mosaic: beside the box the chip is 34px wide, so the sequence
   shows its opening slide the way the feed does. */
.compose-pick-card .format-mosaic { grid-template-columns: 1fr; gap: 0; }
.compose-pick-card .format-mosaic img:nth-child(n+2) { display: none; }
.compose-pick-card .format-frame-hook,
.compose-pick-card .format-frame-chip { display: none; }
.compose-pick-body {
  min-width: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: 10px;
  row-gap: 2px;
  align-items: center;
}
.compose-pick-body b { font-size: 0.875rem; line-height: 1.3; }
.compose-pick-body b::before { content: "Format \00b7\00a0"; color: var(--fg-3); font-weight: 500; }
.compose-pick-body p {
  grid-column: 1 / -1;
  margin: 0;
  font-size: 0.8125rem;
  line-height: 1.4;
  color: var(--fg-3);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.compose-pick-body .btn { grid-row: 1; grid-column: 2; }

/* Three ways in, under the box, gone once anything is in it. */
.compose-starters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}
.composer.has-input .compose-starters,
.compose-starters.is-other-kind { display: none; }

.compose-starters .chip {
  /* These are the way into a blank screen, so they are sized as buttons --
     they were reading as metadata tags at a tag's height. */
  min-height: 38px;
  padding: 0.42em 0.95em;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--fg-2);
  font-size: 0.8125rem;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.15s var(--ease), color 0.15s var(--ease),
    background-color 0.15s var(--ease);
}
.compose-starters .chip:hover { border-color: var(--brand); color: var(--brand-ink); background: var(--brand-wash); }

/* The chat's answer, under the box, like a reply. */
/* The thread: the owner on the right, the agent on the left, like any
   messaging app. Errors stay in .compose-reply under the box. */
.chat-thread {
  list-style: none;
  margin: 0 0 14px;
  padding: 0 2px 0 0;
  display: flex;
  flex-direction: column;
  /* Tight, because this is the gap between two lines from the same side --
     one speaker carrying on. The gap that matters is the one below. */
  gap: 4px;
}
/* A turn and the answer to it are two different people, and eight pixels of
   air between them read as one block of text alternating colour. Hand-offs get
   the room; a run from one side stays a run. */
.chat-turn.is-user + .chat-turn.is-assistant { margin-top: 18px; }
/* Under a reply the row of actions is already most of that air. */
.chat-turn.is-assistant + .chat-turn.is-user { margin-top: 8px; }
/* The same hand-off with the time between them. */
.chat-when + .chat-turn { margin-top: 0; }
/* The chat fills the window the way a messaging app does: the view is
   sized to the screen, the thread is the scroll box inside it and the box
   sits under the thread, so the box never moves while the owner scrolls.
   It was a sticky box against a page scroll before, and that drifted with
   every bit of padding on the way up the tree. */
@media (max-width: 899px) {
  .dashboard-section:not([hidden]) { display: flex; flex-direction: column; flex: 1; }
}
.app:has(#viewChat.is-active) { height: 100dvh; }
.app:has(#viewChat.is-active) .dashboard-section { flex: 1; min-height: 0; }
.workspace { display: flex; flex-direction: column; flex: 1; align-self: stretch; min-height: 0; }
.portal-legal { margin-top: auto; padding: 28px 16px 20px; }
/* The chat's column is the whole page; a footer under it would push the box. */
#viewChat.is-active ~ .portal-legal { display: none; }
.acc-legal { margin-top: 22px; text-align: left; }
#viewChat { width: 100%; max-width: 860px; }
#viewChat.is-active { display: flex; flex-direction: column; flex: 1; min-height: 0; }
/* Chat and History are sections inside the view, so the column has to carry
   through them: without it the thread is no longer the scroll box, the page
   scrolls instead and the box rides up and down with the conversation. */
#viewChat > .tab-section:not([hidden]) { display: flex; flex-direction: column; flex: 1; min-height: 0; }
/* History is a list, not a conversation, so it scrolls as a whole. */
#sectionChatThreads { overflow-y: auto; overscroll-behavior: contain; }
/* The head of a screen whose whole body is a conversation, and which does not
   draw its title (see the h2 in the markup). What is left is the sentence that
   introduces an empty screen, and Start over. Top-aligned, with the sentence
   held to a readable measure, they read as one block; once the thread starts
   the sentence goes and the button is all that is left of the band. */
/* The band over a conversation: its name, and New chat. One line on every
   width, the name giving way to the button rather than wrapping under it. */
/* No rule under it: the thread fades out as it goes under the band (see
   .chat-thread), the way it does in the big chat apps, so the band reads as
   part of the page rather than a second toolbar under the place bar. */
#viewChat .chat-head {
  align-items: center;
  flex-wrap: nowrap;
  gap: 8px;
  min-height: 40px;
  margin-bottom: 0;
  /* Over the thread, so the chat's menu opens on top of it. */
  position: relative;
  z-index: 5;
}
/* Once there is a conversation, its name is the heading of the screen, and
   bare text on the page background read as one more line of the thread. A
   warm band -- brand at the left, fading into the surface -- marks it as the
   top of the chat without turning it into a toolbar. */
#viewChat .chat-head {
  padding: 6px 8px 6px 18px;
  border: 1px solid color-mix(in srgb, var(--brand) 18%, var(--line));
  border-radius: var(--r-lg);
  background: linear-gradient(100deg,
    color-mix(in srgb, var(--brand) 14%, var(--surface)) 0%,
    color-mix(in srgb, var(--brand) 5%, var(--surface)) 45%,
    var(--surface) 100%);
  box-shadow: var(--shadow-1);
}
#viewChat .chat-head .chat-title { font-size: 1rem; font-weight: 700; }
/* On a phone the band was a card of its own -- border, gradient, shadow, a
   44px button -- over a thread that is fighting for every line. It keeps the
   name and New chat, as one quiet line with a rule under it. */
@media (max-width: 599px) {
  #viewChat .chat-head {
    min-height: 0;
    padding: 2px 0 2px 10px;
    border: 0;
    border-bottom: 1px solid var(--line-soft);
    border-radius: 0;
    background: none;
    box-shadow: none;
  }
  #viewChat .chat-head .chat-title { font-size: 0.9375rem; padding-block: 5px; }
  #viewChat .chat-head .chat-new { width: 32px; height: 32px; }
  #viewChat .chat-head .chat-new svg { width: 17px; height: 17px; }
}
#viewChat .chat-head .chat-title:hover:not(:disabled),
#viewChat .chat-head .chat-title[aria-expanded="true"],
#viewChat .chat-head .chat-new:hover {
  background: color-mix(in srgb, var(--brand) 12%, transparent);
}
#viewChat .chat-head .section-head-text { flex: 1 1 auto; }
.chat-title-wrap { position: relative; display: flex; min-width: 0; }
#viewChat .chat-title {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0 0 0 -10px;
  max-width: 100%;
  padding: 6px 10px;
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--fg);
}
#chatTitleText { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-title-caret { flex: none; width: 14px; height: 14px; color: var(--fg-3); }
#viewChat .chat-title:disabled .chat-title-caret { display: none; }
#viewChat .chat-title[aria-expanded="true"] { background: var(--surface-2); }
.chat-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: -10px;
  z-index: 20;
  min-width: 180px;
  padding: 4px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--shadow-3);
}
.chat-menu[hidden] { display: none; }
.chat-menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  font: inherit;
  font-size: 0.875rem;
  color: var(--fg);
  text-align: left;
  cursor: pointer;
}
.chat-menu-item svg { width: 15px; height: 15px; flex: none; color: var(--fg-3); }
.chat-menu-item:hover, .chat-menu-item:focus-visible { background: var(--surface-2); outline: none; }
.chat-menu-item.is-danger, .chat-menu-item.is-danger svg { color: var(--bad); }
#viewChat .chat-title:hover:not(:disabled) { background: var(--surface-2); color: var(--fg); }
#viewChat .chat-title:disabled { cursor: default; }
#viewChat .chat-title:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
/* New chat is the square-and-pen every chat app uses, as an icon. */
.chat-new {
  flex: none;
  display: inline-grid;
  place-items: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  color: var(--fg-2);
  cursor: pointer;
  transition: background-color 0.15s var(--ease), color 0.15s var(--ease);
}
.chat-new svg { width: 19px; height: 19px; }
.chat-new:hover { background: var(--surface-2); color: var(--fg); }
.chat-new:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
/* A blank screen has nothing to name and nothing to start over from. */
#sectionChatTalk:has(#chatEmpty:not([hidden])) .chat-head { display: none; }
/* The blank page is a screen in its own right, not a caption sitting where the
   first reply will go. It gets a mark, a line at reading size and the chips
   under it, centred as a block -- so an owner opening the agent for the first
   time is looking at something composed rather than at an empty box with a
   note beside it. */
/* The empty screen is laid out the way every chat app opens: a question, the
   box right under it and ways in under the box, as one block in the middle of
   the screen. The box lives in the dock, below the empty block in the markup,
   so the block steps aside (display: contents) and its lines are placed
   around the dock by order. It used to be the question at the top and the box
   at the foot, with the whole screen empty between them. */
.chat-empty:not([hidden]) { display: contents; }
.chat-loading:not([hidden]) {
  display: flex;
  flex: 1;
  min-height: 160px;
  align-items: center;
  justify-content: center;
  color: var(--fg-3);
  font-size: 0.875rem;
}
#sectionChatTalk:has(#chatLoading:not([hidden])) .chat-head { display: none; }
.chat-hello {
  order: 1;
  align-self: center;
  margin: auto 0 26px;
  padding-top: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  text-align: center;
  font-family: var(--display, var(--sans));
  font-size: clamp(1.6rem, 1.1rem + 1.6vw, 2.2rem);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: var(--fg);
}
/* The flame, quiet: the empty screen is the one place in the portal with room
   for the mark, and it says whose agent this is without a line of copy. */
.chat-hello::before {
  content: "";
  flex: none;
  width: 1.15em;
  height: 1.15em;
  background: url("/static/img/logo-mark.svg") center / contain no-repeat;
}
#chatEmpty:not([hidden]) ~ .chat-dock { order: 2; }
/* On the Agent screen the chips are not part of the composer, so nothing
   hides them when the box fills -- the empty screen goes when the thread has
   a line on it, which is the moment they stop being the way in. */
.chat-starters { order: 3; margin: 14px 0 0; padding-bottom: 10px; justify-content: center; }
/* Under the ways in, the way back to past chats; it takes the space the chips
   used to, so the foot stays at the bottom. */
.chat-past { order: 3; align-self: center; margin: 0 auto auto; }
.chat-foot { order: 4; }
.chat-thread {
  flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 18px);
  mask-image: linear-gradient(to bottom, transparent, #000 18px);
  padding-top: 12px;
}
/* A short conversation sits against the box, the way a messaging app stacks
   from the bottom, rather than hanging from the heading with a hole under it.
   An auto margin on the first line and not justify-content, which clips the
   top of a thread once it is long enough to scroll. */
.chat-thread > :first-child { margin-top: auto; }
/* The thread takes the slack, so the conversation fills the screen and the
   rail and the box sit under it. An auto margin here would take that slack
   first -- auto margins are served before flex-grow -- which left the thread
   at the height of its own lines with a hole beneath it. It is still what
   holds the box at the foot before anything has been said. */
.chat-dock { margin-top: 0; }
/* Under the box, the one thing worth saying every time: it is a draft until
   they say yes. */
.chat-foot { margin: 8px 0 0; text-align: center; font-size: 0.75rem; color: var(--fg-4); }
/* Said once, on the blank screen, where it is news. Under every conversation
   after that it was a line the thread could have had. */
#sectionChatTalk:has(#chatEmpty[hidden]) .chat-foot { display: none; }
/* On a desk the thread runs the full width of the work so its scrollbar is
   at the edge of the window, not down the middle of the screen at the edge
   of the column. The words keep the column: the gutter is the same sum the
   place bar uses. */
@media (min-width: 900px) {
  /* Every other view is --col wide so a form, a card and a heading share one
     left and one right edge across the whole portal. This one is wider, and
     deliberately: the others are a column of work on a page, while this is the
     screen itself -- the thread, the drop it is about and the box you answer
     in, and at 880px on a wide monitor those sat in a strip with a hand's
     width of empty background down either side. Raising --col here rather
     than writing a second number into each rule below means the thread's
     gutter and the card's edges move together, as they must. */
  #viewChat { --col: 960px; max-width: none; padding: 16px 0 12px; }
  #viewChat > .tab-section > *,
  #chatEmpty > * { width: calc(100% - 64px); max-width: var(--col); margin-inline: auto; }
  /* The box and the thread's words share one reading column, as in any chat
     app: the full width of the work is too long a line to type into. */
  #viewChat { --col: 780px; }
  #sectionChatTalk > .chat-thread { width: 100%; max-width: none; padding-inline: max(32px, calc((100% - var(--col)) / 2)); }
}

/* A share of the column, up to a measure. The share is what keeps a bubble
   looking like a bubble rather than a full-width band on any screen; the cap
   is because a share of a wide column is a line of prose nobody can track
   back to the start of. The agent gets the longer of the two -- it writes
   paragraphs, the owner writes a sentence. */
.chat-turn {
  max-width: min(78%, 640px);
  padding: 12px 16px;
  border-radius: var(--r-lg);
  /* The thread is the content of this screen, not chrome on the side of it, so
     it reads a size up from the labels and captions elsewhere in the portal --
     reading size, with the tightening a sans wants at that size. */
  font-size: 1rem;
  line-height: 1.4;
  letter-spacing: -0.012em;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.chat-turn.is-user {
  align-self: flex-end;
  max-width: min(75%, 560px);
  padding: 10px 16px;
  background: var(--surface-3);
  color: var(--fg);
}
/* The agent does not get a bubble. It writes paragraphs, lists and cards, and
   a tinted box around those reads as a quoted block rather than as the page
   talking back; the owner's sentence is the thing that needs a shape to sit
   in. So: the reply is just the page's own prose, one step down in weight of
   colour, with the room a paragraph wants. */
.chat-turn.is-assistant {
  align-self: flex-start;
  max-width: min(100%, 820px);
  padding: 2px 4px;
  border-radius: 0;
  background: none;
  /* The reply is the page talking, at full strength: in a grey a step down
     it read as a caption under the owner's line. */
  color: var(--fg);
  line-height: 1.65;
  white-space: normal;
}
.chat-turn.is-assistant strong { font-weight: 650; }

/* Under a reply, what can be done with it. Always there on the newest one;
   on the ones above it they come up when the reply is pointed at, so a long
   thread is not striped with buttons. */
.chat-actions { display: flex; gap: 2px; margin: 6px 0 0 -8px; }
.chat-act {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 28px;
  padding: 0 8px;
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  color: var(--fg-3);
  font: inherit;
  font-size: 0.75rem;
  font-weight: 600;
  cursor: pointer;
  transition: background-color 0.15s var(--ease), color 0.15s var(--ease);
}
.chat-act svg { width: 14px; height: 14px; }
.chat-act:hover { background: var(--surface-2); color: var(--fg); }
.chat-act:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.chat-act.is-done { color: var(--brand-ink); }
/* Copy under every reply was a column of the same word down the thread. The
   newest keeps it; the rest show theirs when pointed at, or on a phone when
   tapped. Held open with opacity on a desk so the thread does not jump as the
   pointer crosses it; taken out on a phone, where it is height the thread
   needs. */
@media (hover: hover) {
  .chat-turn.is-assistant:not(.is-latest) .chat-actions { opacity: 0; transition: opacity 0.15s var(--ease); }
  .chat-turn.is-assistant:hover .chat-actions,
  .chat-turn.is-assistant:focus-within .chat-actions { opacity: 1; }
}
@media (hover: none) {
  .chat-turn.is-assistant:not(.is-latest):not(.is-picked) .chat-actions { display: none; }
}
/* Only the newest line comes in. The thread is rewritten whole whenever it
   changes, so every bubble is a new element every time -- animating all of
   them would flash the whole conversation on each reply. :last-child is the
   one that was not there a moment ago, and the one before it stops matching
   the moment it is no longer last. */
.chat-thread .chat-turn:last-child { animation: chat-turn-in 0.26s var(--ease) both; }
.chat-thread .chat-turn.is-user:last-child { animation-name: chat-turn-in-right; }
@keyframes chat-turn-in {
  from { opacity: 0; transform: translateY(6px) translateX(-4px); }
  to { opacity: 1; transform: none; }
}
@keyframes chat-turn-in-right {
  from { opacity: 0; transform: translateY(6px) translateX(4px); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .chat-thread .chat-turn:last-child { animation: none; }
}
/* A reply arriving word by word rewrites the line on every word, and a line
   that faded in on each of them shook. */
.chat-thread.is-settling .chat-turn:last-child { animation: none; }
.chat-turn p, .compose-reply p { margin: 0; }
.chat-turn p + p, .chat-turn p + ul, .chat-turn p + ol, .chat-turn ul + p, .chat-turn ol + p { margin-top: 10px; }
.compose-reply p + p, .compose-reply p + ul, .compose-reply ul + p { margin-top: 8px; }
.chat-turn ul, .chat-turn ol, .compose-reply ul, .compose-reply ol { margin: 0; padding-left: 1.2em; }
.chat-turn li + li { margin-top: 6px; }
.compose-reply li + li { margin-top: 4px; }
.chat-turn li::marker { color: var(--brand-ink); }
.chat-turn a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.chat-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.chat-chip { cursor: pointer; }
.chat-chip:hover { border-color: var(--brand); color: var(--brand-ink); }
.chat-turn.is-pending {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--fg-3);
}
.chat-step { font-size: 0.8125rem; animation: chat-step-in 0.25s var(--ease); }
.chat-dots { display: inline-flex; gap: 4px; }
/* Waiting is the one moment the screen has nothing to say, so it is worth the
   brand's own two colours rather than three grey dots. They swell instead of
   hopping -- a bounce reads as a page still loading, a pulse reads as
   something thinking. */
.chat-dots i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--brand);
  animation: chat-dot 1.2s infinite ease-in-out;
}
.chat-dots i:nth-child(2) { background: var(--navy); animation-delay: 0.2s; }
.chat-dots i:nth-child(3) { background: var(--brand-strong); animation-delay: 0.4s; }
@keyframes chat-dot {
  0%, 60%, 100% { opacity: 0.4; transform: scale(0.9); }
  30% { opacity: 1; transform: scale(1.25); }
}
@keyframes chat-step-in { from { opacity: 0; transform: translateX(-4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .chat-dots i { animation: chat-dot-fade 1.2s infinite ease-in-out; }
  .chat-step { animation: none; }
  .chat-cursor { animation: none; }
}
@keyframes chat-dot-fade { 0%, 60%, 100% { opacity: 0.4; } 30% { opacity: 1; } }

/* The steps of a turn stack: what it has done, quiet and ticked, over what it
   is doing. */
.chat-work { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
/* The reply being written is the reply, in its own colour and size, not one
   more status line in the grey the steps use; a hair of air between them. */
.chat-turn.is-pending .chat-text { color: var(--fg); font-size: 1rem; margin-top: 3px; }
/* The reply being written: a cursor at the end of the last word. */
.chat-cursor {
  display: inline-block; width: 2px; height: 1em; margin-left: 2px; vertical-align: text-bottom;
  background: currentColor; animation: chat-cursor-blink 1s steps(2, start) infinite;
}
@keyframes chat-cursor-blink { to { visibility: hidden; } }
.chat-live { display: flex; align-items: center; gap: 10px; }
.chat-step.is-done { display: flex; align-items: center; gap: 6px; opacity: 0.6; }
.chat-step.is-done svg { width: 11px; height: 11px; flex: none; color: var(--brand-ink); }

/* The word beside the dots until the first real step, and the seconds once a
   wait is long enough to wonder about -- tabular, so the line does not shuffle
   as they count. */
.chat-think { font-size: 0.8125rem; }
.chat-elapsed { font-size: 0.75rem; color: var(--fg-4); font-variant-numeric: tabular-nums; }
.chat-elapsed:empty { display: none; }

/* What the agent did on its way to the reply, folded shut above it. Quiet: it
   is there for the owner who wonders, not in the way of the one who reads. */
.chat-trail { margin: 0 0 6px -2px; font-size: 0.8125rem; color: var(--fg-3); }
.chat-trail summary {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 6px; border-radius: var(--r-sm);
  cursor: pointer; list-style: none; user-select: none;
}
.chat-trail summary::-webkit-details-marker { display: none; }
.chat-trail summary::after {
  content: ""; width: 5px; height: 5px; margin-left: 2px;
  border: solid currentColor; border-width: 0 1.5px 1.5px 0;
  transform: translateY(-1px) rotate(-45deg); transition: transform 0.15s var(--ease);
}
.chat-trail[open] summary::after { transform: translateY(-2px) rotate(45deg); }
.chat-trail summary:hover { background: var(--surface-2); color: var(--fg); }
.chat-trail summary:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.chat-trail ol { list-style: none; margin: 4px 0 2px; padding: 0 0 0 8px; border-left: 1px solid var(--line); }
.chat-trail li { display: flex; align-items: center; gap: 6px; padding: 2px 0 2px 6px; }
.chat-trail li + li { margin-top: 0; }
.chat-trail li svg { width: 11px; height: 11px; flex: none; color: var(--brand-ink); }
.chat-turn .chat-trail li::marker { content: none; }

/* When it was said, between lines far apart. */
.chat-when {
  align-self: center; margin: 14px 0 6px;
  font-size: 0.75rem; font-weight: 600; letter-spacing: 0.02em; color: var(--fg-4);
}

/* The connection went while the agent was working: not a failure of theirs,
   and not a reply -- a line from the page, in the middle. */
.chat-note {
  align-self: center; max-width: min(90%, 520px); margin: 10px 0;
  padding: 8px 14px; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--fg-2);
  font-size: 0.8125rem; text-align: center;
}

/* A message that never landed: their own words, kept, but plainly not sent. */
.chat-turn.is-user.is-failed {
  background: transparent;
  color: var(--fg-3);
  border: 1px dashed var(--line-strong);
}
.chat-turn.is-failed .chat-chips { margin-top: 6px; }
.chat-fail-why { display: block; margin-top: 6px; font-size: 0.8125rem; color: var(--bad, var(--fg-3)); white-space: normal; }

/* Scrolled up, something arrived: a pill over the foot of the thread rather
   than a jump the owner did not ask for. */
.chat-jump {
  align-self: center;
  display: inline-grid;
  place-items: center;
  width: 36px;
  height: 36px;
  margin: -46px auto 10px;
  position: relative;
  z-index: 2;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--surface);
  box-shadow: var(--shadow-2);
  color: var(--fg);
  cursor: pointer;
  transition: background-color 0.15s var(--ease);
}
.chat-jump[hidden] { display: none; }
.chat-jump:hover { background: var(--surface-2); }
@media (min-width: 900px) { #sectionChatTalk > .chat-jump { width: 36px; } }

/* The drop the conversation is about, between the thread and the box: it is
   the subject of every follow-up, so it sits where the follow-ups are typed
   rather than one tab away. Shut it is a strip; opened, it is the reel itself,
   because the Agent screen used to be the one place that would not show the
   owner what the agent had just made. */
.chat-drop { margin: 0 0 10px; }
.chat-drop-card {
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--shadow-1);
}
/* The rail arrives when the agent starts something. Coming up from under the
   box rather than appearing between two frames is what makes it read as a
   consequence of the message they just sent.

   On the class and not on the card, because the card is a fresh element every
   time anything about the drop changes -- a second ticking off the estimate,
   a change spent. Left on the element, the entrance played four times a minute
   while the owner watched a render, which is a flicker, not an arrival. */
.chat-drop-card.is-new { animation: chat-rail-in 0.28s var(--ease) both; }
.chat-drop-row { display: flex; gap: 12px; align-items: flex-start; }

/* The corner of it. 9:16 whatever is inside, so a reel and a still sit at the
   same size and the row does not jump when the render replaces the upload. */
.chat-drop-shot {
  position: relative;
  width: 62px;
  aspect-ratio: 9 / 16;
  flex: none;
  padding: 0;
  border: 0;
  overflow: hidden;
  border-radius: var(--r-sm);
  background: var(--surface-3);
}
.chat-drop-shot > video, .chat-drop-shot > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.35s var(--ease), filter 0.35s var(--ease);
}
/* Nothing has come back yet: their own upload, held down, so the card is about
   their plate from the first second and still reads as unfinished. */
.chat-drop-shot.is-waiting > video, .chat-drop-shot.is-waiting > img {
  filter: saturate(0.5) brightness(0.72);
}
.chat-drop-shot.is-ready { cursor: pointer; }
/* Playing: the same element, wider. A reel keeps 9:16; a still is 4:5 and is
   let alone rather than cropped, because this is the frame being approved. */
/* Sized off what the window leaves after the bars, the band and the box, not
   off a share of it: at a fixed 34vh the player on a laptop screen took the
   thread down to its floor, and the conversation could not be read above it. */
.chat-drop-shot.is-open {
  width: clamp(88px, (100dvh - 540px) * 9 / 16, 176px);

  background: #16120f;
  animation: chat-shot-open 0.3s var(--ease) both;
}
.chat-drop-shot.is-open.is-still { aspect-ratio: 4 / 5; width: clamp(100px, (100dvh - 540px) * 4 / 5, 200px); }
.chat-drop-shot.is-open > video, .chat-drop-shot.is-open > img { object-fit: contain; }
.chat-drop-shot.is-open > img { cursor: zoom-in; }
.chat-drop-shut {
  position: absolute;
  top: 5px;
  right: 5px;
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(20, 16, 12, 0.6);
  backdrop-filter: blur(3px);
  color: #fff;
  cursor: pointer;
  transition: background 0.2s var(--ease);
}
.chat-drop-shut svg { width: 11px; height: 11px; }
.chat-drop-shut:hover { background: var(--brand); }
.chat-drop-shot.is-ready:hover > video, .chat-drop-shot.is-ready:hover > img { transform: scale(1.06); }
.chat-drop-shot:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

/* A sweep across the held-down upload, so the strip says "still working" from
   across the room. The bar under the line says how far along; this only has to
   say it is moving. */
.chat-drop-sweep {
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg, transparent 30%, rgba(255, 255, 255, 0.34) 50%, transparent 70%);
  transform: translateX(-100%);
  animation: chat-sweep 1.9s var(--ease) infinite;
}

.chat-drop-disc {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 26px;
  height: 26px;
  margin: -13px 0 0 -13px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(20, 16, 12, 0.56);
  backdrop-filter: blur(3px);
  color: #fff;
  transition: transform 0.2s var(--ease), background 0.2s var(--ease);
}
/* The nudge right is the play triangle's own weight, which sits left of the
   glyph's box. */
.chat-drop-disc svg { width: 12px; height: 12px; margin-left: 1px; }
.chat-drop-shot.is-ready:hover .chat-drop-disc { transform: scale(1.12); background: var(--brand); }

.chat-drop-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
/* Watching it, there is room to read the whole caption beside the player, and
   the column runs the height of it so the follow-ups sit at its foot rather
   than stranded halfway up a tall card. */
.chat-drop-card.is-watching .chat-drop-body { align-self: stretch; }
.chat-drop-card.is-watching .chat-drop-why { -webkit-line-clamp: 6; }
.chat-drop-card.is-watching .chat-drop-note { margin-top: auto; }
.chat-drop-head { display: flex; align-items: center; gap: 8px; }
.chat-drop-head b { font-size: 0.875rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-drop-open {
  /* What it is and where it stands are one fact, so they stay together on the
     left; only the way out goes to the far edge. The whole group used to be
     pushed right as a block, which on a wide card left the title alone at one
     end and its own status a foot away at the other. */
  margin-left: auto;
  flex: none;
  border: 0;
  margin-block: -4px;
  padding: 4px 8px;
  border-radius: var(--r-sm);
  background: none;
  color: var(--fg-3);
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 600;
  cursor: pointer;
  transition: background-color 0.15s var(--ease), color 0.15s var(--ease);
}
.chat-drop-open:hover { background: var(--surface-2); color: var(--fg); }
/* Fold it down / let it out. The chevron points the way the card will go. */
.chat-drop-min {
  flex: none;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  margin: -4px -4px -4px 0;
  padding: 0;
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  color: var(--fg-3);
  cursor: pointer;
  transition: background-color 0.15s var(--ease), color 0.15s var(--ease);
}
.chat-drop-min svg { width: 16px; height: 16px; transition: transform 0.2s var(--ease); }
.chat-drop-min:hover { background: var(--surface-2); color: var(--fg); }
.chat-drop-min:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.chat-drop-card.is-min .chat-drop-min svg { transform: rotate(180deg); }
/* Folded: what it is, where it stands, and the corner of it -- one line, so
   the thread gets the screen back. Tapping the corner still plays it, and
   lets the card out to do so. */
.chat-drop-card.is-min { padding-block: 6px; }
.chat-drop-card.is-min .chat-drop-row { align-items: center; }
.chat-drop-card.is-min .chat-drop-shot { width: 22px; border-radius: 4px; }
.chat-drop-card.is-min .chat-drop-disc { display: none; }
.chat-drop-card.is-min .chat-drop-why:not(.is-live),
.chat-drop-card.is-min .chat-drop-bar,
.chat-drop-card.is-min .chat-chips,
.chat-drop-card.is-min .chat-drop-note { display: none; }
.chat-drop-why {
  font-size: 0.8125rem;
  color: var(--fg-3);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.chat-drop-why.is-live { display: flex; align-items: center; gap: 8px; color: var(--fg); }
.chat-drop-eta { color: var(--fg-3); }
.chat-drop-bar {
  display: block;
  height: 3px;
  border-radius: var(--r-pill);
  background: var(--surface-3);
  overflow: hidden;
}
.chat-drop-bar i { display: block; height: 100%; background: var(--brand); transition: width 0.6s var(--ease); }
.chat-drop-note { margin: 0; font-size: 0.75rem; color: var(--fg-3); }
.chat-drop-hint { font-size: 0.75rem; color: var(--fg-4); }
.chat-drop-card.is-min .chat-drop-hint { display: none; }
/* Nothing to show yet: a warm wash and a film mark, breathing, in place of a
   grey box. */
.chat-drop-blank {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: linear-gradient(160deg,
    color-mix(in srgb, var(--brand) 22%, var(--surface-3)),
    color-mix(in srgb, var(--brand) 6%, var(--surface-3)));
  color: color-mix(in srgb, var(--brand) 70%, var(--fg-3));
}
.chat-drop-blank svg { width: 40%; max-width: 22px; animation: chat-blank 1.8s var(--ease) infinite; }
@keyframes chat-blank { 50% { opacity: 0.45; } }
@media (prefers-reduced-motion: reduce) { .chat-drop-blank svg { animation: none; } }


/* The follow-ups come in behind the card rather than with it, left to right,
   so the eye lands on the drop and then on what can be done to it. Only on the
   two renders worth an entrance, for the same reason as the card. */
.chat-drop-card.is-new .chat-chip, .chat-drop-card.is-landed .chat-chip {
  animation: chat-chip-in 0.24s var(--ease) both;
  animation-delay: calc(60ms + var(--i, 0) * 32ms);
}

/* It finished while they were watching it finish. One pass of brand light
   around the card is the whole announcement: the player opening under it is
   the rest. */
.chat-drop-card.is-landed { animation: chat-landed 0.72s var(--ease) both; }

@keyframes chat-rail-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}
@keyframes chat-shot-open {
  from { opacity: 0.3; transform: scale(0.88); transform-origin: left center; }
  to { opacity: 1; transform: none; }
}
@keyframes chat-chip-in {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: none; }
}
@keyframes chat-sweep {
  0% { transform: translateX(-100%); }
  60%, 100% { transform: translateX(100%); }
}
@keyframes chat-landed {
  0% { border-color: var(--brand); box-shadow: 0 0 0 0 var(--brand-wash); }
  40% { border-color: var(--brand); box-shadow: 0 0 0 5px var(--brand-wash); }
  100% { box-shadow: var(--shadow-1); }
}

/* Motion is the wrong way to tell someone something when they have asked for
   none of it. The states stay; only the movement goes. */
@media (prefers-reduced-motion: reduce) {
  .chat-drop-card, .chat-drop-shot.is-open, .chat-drop-card .chat-chip { animation: none; }
  .chat-drop-sweep { animation: none; opacity: 0.25; }
  .chat-drop-shot.is-ready:hover > video, .chat-drop-shot.is-ready:hover > img { transform: none; }
}

/* On a phone the rail, the box and the heading between them will take the
   whole screen if they are allowed to: the thread is the flexible one, so it
   is the one that gets squeezed, and it went to nothing. The rail gives up the
   second line of caption and puts its follow-ups on one scrolling row, and the
   thread keeps a floor under it. */
@media (max-width: 599px) {
  .chat-drop-card { padding: 8px; }
  .chat-drop-row { gap: 10px; }
  .chat-drop-shot { width: 50px; }
  .chat-drop-why { -webkit-line-clamp: 1; }
  .chat-drop-style { display: none; }
  .chat-drop .chat-chips {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    padding-bottom: 2px;
  }
  .chat-drop .chat-chips::-webkit-scrollbar { display: none; }
  .chat-drop .chat-chip { flex: none; }
  /* The player is the reason to be on this screen, so it keeps a size worth
     watching even where the card has least room -- but the box under it has to
     stay reachable, so it gives up what the taller screen could afford. */
  .chat-drop-shot.is-open { width: clamp(100px, 26vh * 9 / 16, 128px); }
  .chat-drop-shot.is-open.is-still { width: clamp(112px, 23vh * 4 / 5, 148px); }
  /* Beside the player there is half a card's width for the head, which is not
     enough for a format name, a pill and a way out on one line. */
  .chat-drop-card.is-watching .chat-drop-head { flex-wrap: wrap; }
  .chat-drop-card.is-watching .chat-drop-head b { white-space: normal; margin-right: 0; flex: 1 0 100%; }
}
#sectionChatTalk > .chat-thread:not([hidden]) { min-height: 110px; }
/* The one follow-up that is most likely the next thing they want, coloured
   like the button it stands in for on the card. */
.chat-chip.is-primary { border-color: var(--brand); background: var(--brand); color: var(--on-brand); }
.chat-chip.is-primary:hover { border-color: var(--brand); color: var(--on-brand); filter: brightness(1.06); }
.chat-chip.is-quiet { color: var(--fg-3); }

/* ---------------- History ---------------- */
/* One narrow column, the way every chat app lists past chats: a search and
   New chat at the top, then titles grouped by when, one line each. The rows
   are text on the page, not cards -- a hover and the open one get a wash. */
#sectionChatThreads > .history-col { max-width: 760px; }
.history-col { width: 100%; margin: 0 auto; padding: 4px 0 32px; }

.history-bar {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  gap: 10px;
  padding: 4px 0 12px;
  background: var(--bg);
}
.history-search {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  height: 40px;
  padding: 0 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--fg-3);
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.history-search:focus-within { border-color: var(--line-strong); box-shadow: 0 0 0 3px var(--surface-3); }
.history-search svg { width: 16px; height: 16px; flex: none; }
.history-search input {
  flex: 1;
  min-width: 0;
  border: 0;
  outline: 0;
  background: none;
  font: inherit;
  font-size: 16px; /* under 16px iOS zooms the page on focus */
  color: var(--fg);
}
.history-new {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 40px;
  padding: 0 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  font: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--fg);
  cursor: pointer;
  transition: background-color 0.15s var(--ease);
}
.history-new:hover { background: var(--surface-2); }
.history-new svg { width: 16px; height: 16px; }

.history-day {
  margin: 20px 12px 6px;
  font-family: inherit;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--fg-3);
}
.history-group:first-child .history-day { margin-top: 6px; }
.history-rows { list-style: none; margin: 0; padding: 0; }
/* A row is the button that opens the chat, with rename and delete over its
   end. They come up on hover or focus; on a touch screen they stay. */
.history-item { position: relative; border-radius: var(--r-sm); }
.history-item:hover, .history-item:focus-within { background: var(--surface-2); }
.history-item.is-current { background: var(--surface); box-shadow: inset 0 0 0 1px var(--line); }
.history-row {
  display: flex;
  flex-direction: column;
  gap: 3px;
  width: 100%;
  padding: 10px 12px;
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  font: inherit;
  font-size: 0.9375rem;
  color: var(--fg);
  text-align: left;
  cursor: pointer;
  transition: background-color 0.12s var(--ease);
}
.history-item.is-current .history-title { font-weight: 600; }
.history-row:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.history-line { display: flex; align-items: baseline; gap: 12px; min-width: 0; }
.history-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.history-when { flex: none; font-size: 0.75rem; color: var(--fg-3); }
.history-match {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--fg-3);
}
.history-row mark { background: var(--brand-wash); color: var(--fg); border-radius: 3px; padding: 0 1px; }
.history-acts {
  position: absolute;
  top: 5px;
  right: 6px;
  display: flex;
  gap: 2px;
  padding-left: 16px;
  background: linear-gradient(to right, transparent, var(--surface-2) 16px);
  opacity: 0;
  transition: opacity 0.12s var(--ease);
}
.history-item.is-current .history-acts { background: linear-gradient(to right, transparent, var(--surface) 16px); }
.history-item:hover .history-acts, .history-item:focus-within .history-acts { opacity: 1; }
@media (hover: none) {
  .history-acts { opacity: 1; background: none; }
  .history-line { padding-right: 64px; }
  .history-when { display: none; }
}
.history-act {
  display: inline-grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  border-radius: var(--r-xs);
  background: none;
  color: var(--fg-3);
  cursor: pointer;
}
.history-act svg { width: 15px; height: 15px; }
.history-act:hover { background: var(--surface-3); color: var(--fg); }
.history-act.is-danger:hover { color: var(--bad); }
.history-act:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.history-kbd {
  flex: none;
  padding: 1px 6px;
  border: 1px solid var(--line);
  border-radius: var(--r-xs);
  font: inherit;
  font-size: 0.75rem;
  color: var(--fg-4);
}
.history-search:focus-within .history-kbd { display: none; }
@media (hover: none) { .history-kbd { display: none; } }
.history-count { margin: 2px 12px 6px; font-size: 0.75rem; color: var(--fg-3); }
.history-count[hidden], .history-foot[hidden] { display: none; }
.history-foot { display: flex; justify-content: center; margin-top: 28px; padding-top: 16px; border-top: 1px solid var(--line-soft); }
.history-clear {
  padding: 8px 14px;
  border: 0;
  border-radius: var(--r-pill);
  background: none;
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--fg-3);
  cursor: pointer;
}
.history-clear:hover { background: var(--surface-2); color: var(--bad); }

.history-row.is-skeleton { cursor: default; padding: 13px 12px; }
.history-row.is-skeleton:hover { background: none; }
.sk {
  display: block;
  height: 12px;
  border-radius: 6px;
  background: linear-gradient(90deg, var(--surface-2) 0%, var(--surface-3) 50%, var(--surface-2) 100%);
  background-size: 200% 100%;
  animation: kd-shimmer 1.2s linear infinite;
}

.history-empty {
  display: grid;
  justify-items: center;
  gap: 8px;
  margin: 12px 0 0;
  padding: 40px 20px;
  border: 1.5px dashed var(--line-strong);
  border-radius: var(--r-lg);
  text-align: center;
}
.history-empty p { margin: 0; max-width: 40ch; font-size: 0.875rem; line-height: 1.5; color: var(--fg-3); }
.history-empty b { font-size: 1rem; font-weight: 600; color: var(--fg); }
.history-empty .btn { margin-top: 8px; }
.history-empty-icon {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  margin-bottom: 4px;
  border-radius: 14px;
  background: var(--violet-wash);
  color: var(--violet);
}
.history-empty-icon svg { width: 22px; height: 22px; }
.history-empty[hidden] { display: none; }

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

.compose-reply {
  margin: 12px 0 0;
  padding: 10px 14px;
  border-radius: var(--r-md);
  border-top-left-radius: var(--r-xs);
  background: var(--brand-wash);
  color: var(--fg);
  font-size: 0.875rem;
  line-height: 1.5;
}
.compose-reply.is-bad { background: var(--bad-wash); }

.compose-foot {
  margin: 12px 2px 0;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--fg-3);
}
/* The allowance, as the AI tools show theirs: a thin bar, the count, when
   it resets. One row, one line, quiet until it runs low. */
.compose-usage {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 18px;
  margin: 10px 2px 0;
  font-size: 0.8125rem;
  color: var(--fg-3);
}
.usage-meter {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.usage-meter[hidden] { display: none; }
.usage-label { white-space: nowrap; }
.usage-label b { color: var(--fg); font-weight: 600; }
.usage-bar {
  display: inline-block;
  width: 96px;
  height: 4px;
  border-radius: 2px;
  background: var(--surface-3);
  overflow: hidden;
}
.usage-bar i {
  display: block;
  height: 100%;
  border-radius: 2px;
  background: var(--fg-3);
  transition: width 0.3s var(--ease);
}
.usage-reset { color: var(--fg-4); white-space: nowrap; }
.usage-meter.is-low .usage-bar i { background: var(--warn); }
.usage-meter.is-low .usage-label b { color: var(--warn); }
.usage-meter.is-out .usage-bar i { background: var(--bad); }
.usage-meter.is-out .usage-label { color: var(--bad); font-weight: 600; }
.usage-note {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-left: auto;
  color: var(--fg-4);
}
.usage-note svg { color: var(--fg-4); }
@media (max-width: 560px) { .usage-note { margin-left: 0; } }
.composer .is-other-kind { display: none; }

@media (max-width: 560px) {
  .compose-tools .dropzone b { display: none; }
  .compose-tools .dropzone { padding: 8px; }
  .compose-send { flex: 1 1 100%; }
  /* In the thread it is the round arrow, and stays on the toolbar's row. */
  #viewChat .compose-send { flex: none; }
}

.drop-section .create { margin-bottom: 0; }

/* ---------------- Ideas, next to the buttons that need them ----------------
   The catalogue itself lives in Studio and is browsed there. This is a look at
   it from the one screen where "what should I film?" is the actual question. */

.idea-strip {
  margin-top: 20px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}

.idea-strip[hidden] { display: none; }

.idea-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.idea-head b {
  display: block;
  font-size: 0.9375rem;
  font-weight: 620;
  letter-spacing: -0.01em;
}

.idea-head span {
  display: block;
  margin-top: 2px;
  font-size: 0.8125rem;
  line-height: 1.35;
  color: var(--fg-3);
}

.idea-head .btn { flex: none; }

/* Scrolls sideways: a second row would push the two things you came here to
   press off the top of the screen. */
.idea-rail {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  padding-bottom: 6px;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
}

.idea-rail::-webkit-scrollbar { display: none; }

.idea-card {
  flex: 0 0 152px;
  scroll-snap-align: start;
}

/* The hook is set for a card twice this wide; at rail size it needs to come
   down or every one of them wraps to six lines. */
.idea-card .format-frame { padding: 26px 11px 11px; }

.idea-card .format-frame-hook { font-size: 0.8125rem; }

.idea-card .format-body {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 9px 10px;
}

/* The rail's whole point once a format can actually be used. Full width so it
   is a target on a phone, not a word to aim at, and pushed to the floor for the
   same reason the gallery's is: a one-line name and a two-line name otherwise
   put their buttons at different heights along the row. */
.idea-use {
  justify-content: center;
  margin-top: auto;
}
/* An outlined button, not a quiet one: as bare text under the title it read
   as a caption, and it is the card's one action. */
.idea-card:hover .idea-use { border-color: var(--brand); color: var(--brand-ink); }

/* Always there, never on hover. Revealing it on hover hid the one thing the
   gallery is now for behind a gesture that does not exist on a phone and that
   nobody performs on a card they were only reading.

   margin-top:auto, not a fixed gap: the beats above run from two lines to five,
   so a button spaced off the text lands at a different height on every card and
   a row of them reads as crooked. Pinned to the bottom, they line up across the
   row whatever the copy does — the same thing .drop-body does with its
   actions. */
.format-use {
  width: 100%;
  justify-content: center;
  margin-top: auto;
  border-color: var(--line-strong);
}

.format-card:hover .format-use {
  border-color: var(--brand);
  color: var(--brand-ink);
}

/* The chosen format's beats, under the picker: an instruction, not a caption,
   so it gets the weight of one. */
.hint.is-brief {
  color: var(--fg-2);
  border-left: 2px solid var(--brand);
  padding-left: 9px;
}

.idea-card .format-body h3 {
  font-size: 0.8125rem;
  line-height: 1.25;
}

@media (max-width: 420px) {
  .idea-head { flex-direction: column; align-items: flex-start; gap: 8px; }
  .idea-card { flex-basis: 132px; }
}

@keyframes kd-create-in {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: none; }
}

.make-foot {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin: 10px 2px 0;
  font-size: 0.8125rem;
  color: var(--fg-3);
  line-height: 1.4;
}

.make-foot svg { flex: none; margin-top: 2px; color: var(--fg-4); }

/* ---------------- Where the picture comes from ----------------
   A photo and a drawing are the same post with a different camera, so this is a
   source switch inside one sheet, not a choice between two products. */
.seg {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 3px;
  padding: 3px;
  margin-bottom: 18px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  border: 1px solid var(--line);
}

.seg-btn {
  padding: 8px 10px;
  border: 0;
  border-radius: var(--r-pill);
  background: transparent;
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--fg-3);
  cursor: pointer;
  transition: background-color 0.15s var(--ease), color 0.15s var(--ease);
}

.seg-btn:hover { color: var(--fg); }

.seg-btn.is-on {
  background: var(--surface);
  color: var(--fg);
  font-weight: 600;
  box-shadow: var(--shadow-1);
}

.seg-btn:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 1px;
}

/* ---------------- Photo post: what happens to the picture ---------------- */
.mode-choices { display: grid; gap: 8px; }
.mode-choice {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 11px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  cursor: pointer;
}
.mode-choice input { margin-top: 3px; accent-color: var(--brand); }
.mode-choice b { display: block; font-size: 0.875rem; }
.mode-choice em {
  display: block; font-style: normal;
  font-size: 0.8125rem; color: var(--fg-3); line-height: 1.4; margin-top: 1px;
}
/* The chosen option was washed with a literal cream that never flipped: in
   dark mode it put near-white label text on near-white paper and the option
   you had just picked was the one you could not read. --brand-wash is the
   same wash in light and a low-alpha ember in dark. */
.mode-choice:has(input:checked) {
  border-color: var(--brand);
  background: var(--brand-wash);
}

/* ---------- A row of three, when three stacked cards is too much ----------
   Same radios as .mode-choice, but for a secondary decision whose options are
   a couple of words each. Three of those as full-width cards with two lines of
   prose apiece took more of the sheet than the photo they were about. */

.pick-row {
  display: grid;
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}

.pick {
  position: relative;
  display: block;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  cursor: pointer;
  text-align: center;
  transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease);
}

.pick input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.pick b {
  display: block;
  font-size: 0.8125rem;
  font-weight: 600;
}

.pick em {
  display: block;
  margin-top: 2px;
  font-style: normal;
  font-size: 0.6875rem;
  line-height: 1.3;
  color: var(--fg-3);
}

.pick:hover { border-color: var(--line-strong); }

.pick-row:disabled .pick { opacity: 0.45; cursor: default; }
.pick-row:disabled .pick:hover { border-color: var(--line); }

.pick:has(input:checked) {
  border-color: var(--brand);
  background: var(--brand-wash);
}

.pick:has(input:checked) b { color: var(--brand-ink); }

.pick:has(input:focus-visible) {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

/* Two words each is tight at three across on a small phone. */
@media (max-width: 380px) {
  .pick-row { grid-template-columns: 1fr; }
  .pick { text-align: left; }
}

/* ---------- Settings that have a right default ----------




.more-options[open] > summary svg { transform: rotate(180deg); }

.more-options[open] > summary {
  border-bottom: 1px solid var(--line);
}


.more-options[open] > summary + * { padding-top: 14px; }


/* A caveat the owner has to read once, where the thing it warns about is



/* ---------------- Drop sections ----------------
   Making a drop and judging the ones you already made are two different jobs.
   They are switched from the nav rather than stacked, so only ever one is on
   screen; what is left here is that one's masthead. */

.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
  margin-bottom: 16px;
}

.section-head-text {
  flex: 1 1 260px;
  min-width: 0;
}

/* A short brand rule above the title — the mark that says this heading names
   the whole view rather than the first card under it. */
.section-head-text h2::before {
  content: "";
  display: block;
  width: 22px;
  height: 3px;
  margin-bottom: 9px;
  border-radius: var(--r-pill);
  background: var(--brand);
}

/* Bigger than the card headings inside the band, so the hierarchy is obvious:
   this names the section, those name the things in it. */
.section-head-text h2 {
  font-family: var(--sans);
  font-size: 1.125rem;
  font-weight: 650;
  letter-spacing: -0.02em;
  margin: 0;
}

/* One line of what the band is for. It drops away on a phone, where the
   heading and the controls under it already say it. */
.section-head-text p {
  /* A line of explanation is prose, and prose set to whatever width the
     column happens to be runs past 100 characters on a desktop, which is
     roughly twice what stays readable. */
  max-width: 62ch;
  margin: 3px 0 0;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--fg-3);
}

.create-active-section {
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
  animation: kd-create-in 0.2s var(--ease);
}

.create-active-section[hidden] { display: none; }

/* Done: the pulse stops, the heading turns the colour of "Needs a yes". */
.create-active-section.is-done .agent-pulse-dot { animation: none; background: var(--gold); }
.create-active-section.is-done h3 { color: var(--gold); }

.create-active-title-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.create-active-title-row h3 {
  font-family: var(--sans);
  font-size: 1.0625rem;
  font-weight: 650;
  letter-spacing: -0.01em;
  margin: 0;
}

.feed-tools {
  display: flex;
  align-items: center;
  gap: 2px;
}

.feed-filters {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  scrollbar-width: none;
  padding: 2px;
  margin: -2px -2px 12px;
}

/* display:flex above outranks the UA's [hidden] rule, so collapsing the feed
   left its filters sitting there. */
.feed-filters[hidden] { display: none; }

.feed-filters::-webkit-scrollbar { display: none; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: none;
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 500;
  padding: 5px 11px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--fg-2);
  cursor: pointer;
  transition: background-color 0.15s var(--ease), border-color 0.15s var(--ease), color 0.15s var(--ease);
}

.chip:hover { border-color: var(--line-strong); }

.chip.is-on {
  background: var(--brand-ink);
  border-color: var(--brand-ink);
  color: var(--on-brand);
}

.chip:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

.chip-count {
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 500;
  padding: 1px 5px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  color: var(--fg-3);
}

.chip.is-on .chip-count {
  background: rgba(255, 255, 255, 0.22);
  color: inherit;
}

/* The last cell of the grid, not a block beneath it. Running out of drops and
   finding the way to more in the same place you were already looking beats a
   full-width button under content you may never have scrolled to the end of.
   It takes a cell like a card so the grid stays regular, but it is dashed and
   empty so it does not read as one. */
.feed-more {
  display: grid;
  place-items: center;
  gap: 8px;
  min-height: 200px;
  padding: 16px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-lg);
  background: transparent;
  color: var(--fg-2);
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.4;
  text-align: center;
  cursor: pointer;
  transition: background-color 0.15s var(--ease), border-color 0.15s var(--ease),
    color 0.15s var(--ease);
}

.feed-more:hover {
  border-color: var(--brand);
  background: var(--brand-wash);
  color: var(--brand-strong);
}

.feed-more:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

.feed-more[hidden] { display: none; }

.feed-hidden-note {
  padding: 16px;
  border: 1px dashed var(--line);
  border-radius: var(--r-md);
  text-align: center;
  font-size: 0.8125rem;
  color: var(--fg-3);
}

/* A quiet remove on each drop — destructive, so it never competes with the
   approve action for attention. It stays visible rather than appearing on
   hover: on a phone there is no hover to reveal it with. */
.drop-remove {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 2;
  pointer-events: auto;
  padding: 6px;
  border: 0;
  border-radius: var(--r-pill);
  background: rgba(10, 14, 24, 0.5);
  color: rgba(255, 255, 255, 0.88);
  cursor: pointer;
  display: inline-grid;
  place-items: center;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition: background-color 0.16s var(--ease), color 0.16s var(--ease), opacity 0.2s var(--ease);
}
.drop-remove:hover { background: var(--bad); color: #fff; }
.drop-remove:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }


/* ---- Intel: claiming what the scan found ---- */

.claim-banner {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 14px 16px;
  margin-bottom: 16px;
  background: var(--warn-wash);
  border: 1px solid var(--warn-wash);
  border-left: 3px solid var(--warn);
  border-radius: var(--r-md);
}

.claim-banner-text b {
  display: block;
  font-size: 14px;
  color: var(--warn);
}

.claim-banner-text span {
  display: block;
  margin-top: 3px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--fg-2);
}

.claim-banner-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.claim-verified-note {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 4px 16px;
  color: var(--good);
  font-size: 0.8125rem;
  font-weight: 500;
}

.claim-verified-note svg { flex-shrink: 0; }

.deal-claim-btn { white-space: nowrap; }

/* ---- Intel: menu knowledge base ---- */

.menu-card-summary:not(:empty) { margin-bottom: 12px; }

.menu-summary-meta {
  font-size: 0.8125rem;
  color: var(--fg-3);
}

.menu-cat-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  margin-bottom: 14px;
}

.menu-cat-chips:empty { display: none; }

.menu-cat-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 11px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--fg-2);
  font-size: 0.75rem;
  font-weight: 500;
  cursor: pointer;
  transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease);
}

.menu-cat-chip:hover { border-color: var(--line-strong); }

.menu-cat-chip.is-active {
  border-color: var(--brand);
  background: var(--brand-wash);
  color: var(--brand-strong);
}

.menu-cat-chip b {
  color: var(--fg-3);
  font-weight: 600;
  font-size: 0.75rem;
}

.menu-cat-chip.is-active b { color: var(--brand-strong); }

/* Newspaper columns, not a grid: grid rows are as tall as their tallest cell,
   so a short section next to a long one left a hole the height of the long one.
   Columns flow, and a section is kept whole inside one of them. */
.menu-list {
  column-width: 330px;
  column-gap: 34px;
}

.menu-cat-block { break-inside: avoid; }

/* One column while a dish is open, so the form has the page's full width. */
.menu-list.is-editing { columns: 1; }

.menu-cat-block + .menu-cat-block { margin-top: 20px; }

.menu-cat-title {
  margin: 0 0 8px;
  font-size: 0.8125rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--fg-3);
  border-bottom: 1px solid var(--line);
  padding-bottom: 6px;
}

.menu-item-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 0;
}

.menu-item-row + .menu-item-row { border-top: 1px dashed var(--line); }

.menu-item-main {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.menu-item-photo {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: 8px;
  overflow: hidden;
  background: var(--line);
}

.menu-item-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.menu-item-main { flex: 1; }

.menu-item-name {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--fg-1);
}

.menu-item-desc {
  font-size: 0.8125rem;
  line-height: 1.4;
  color: var(--fg-2);
}

.menu-item-tags {
  font-size: 0.6875rem;
  color: var(--fg-3);
}

.menu-item-price {
  flex-shrink: 0;
  font-family: "JetBrains Mono", monospace;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--fg-1);
}

/* ---- Menu: the owner's own edits ---- */

.menu-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-bottom: 12px;
}

.menu-toolbar .input { flex: 1 1 200px; min-width: 0; }
.menu-toolbar .btn { flex-shrink: 0; }

.menu-item-side {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}

.menu-row-edit {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  color: var(--fg-3);
  opacity: 0.55;
}

.menu-item-row:hover .menu-row-edit,
.menu-row-edit:focus-visible { opacity: 1; }

/* A touch screen has no hover to reveal it with. */
@media (hover: none) {
  .menu-row-edit { opacity: 1; }
}

/* Two columns of fields when the sheet is wide, one when it is not — a form
   this tall pushes its own Save button off a laptop screen otherwise. */
.menu-item-edit {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  align-items: start;
  gap: 12px 20px;
  padding: 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
}

/* auto-fit, not two fixed halves: on a phone these become one field per line
   instead of two boxes too narrow to read a dish name in. */
.menu-item-edit .field { margin-bottom: 0; }
.menu-item-edit .field-pair { gap: 0 14px; }

.menu-edit-title,
.menu-edit-actions { grid-column: 1 / -1; }

.menu-edit-title {
  margin: 0 0 2px;
  font-size: 0.9375rem;
  font-weight: 600;
}

.menu-edit-flags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  font-size: 0.8125rem;
  color: var(--fg-2);
}

.menu-edit-flags label {
  display: flex;
  align-items: center;
  gap: 6px;
}

.menu-edit-photo {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

.menu-edit-photo img,
.menu-edit-photo-empty {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  flex-shrink: 0;
  border-radius: var(--r-sm);
  background: var(--surface);
  border: 1px dashed var(--line);
  object-fit: cover;
  font-size: 0.6875rem;
  color: var(--fg-3);
  text-align: center;
}

.menu-edit-photo img { border-style: solid; }

/* The native file input is a grey box with a filename in it. The label is the
   button; the input only has to be reachable, not looked at. */
.menu-edit-photo label { cursor: pointer; }
.menu-edit-photo .hint { flex: 1 1 200px; margin-top: 0; }

.menu-edit-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-top: 2px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
}

.menu-edit-del { margin-left: auto; color: var(--bad); }

/* ---- Profile: what came from the web, and what the owner owns ---- */

.found-banner {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: flex-start;
  padding: 14px 16px;
  margin-bottom: 14px;
  background: var(--warn-wash);
  border: 1px solid var(--warn-wash);
  border-left: 3px solid var(--warn);
  border-radius: var(--r-md);
}

.found-banner-text { flex: 1 1 240px; min-width: 0; }

.found-banner-btn {
  flex-shrink: 0;
  align-self: center;
  border-color: var(--warn);
  color: var(--warn);
}

.found-banner b { display: block; font-size: 14px; color: var(--warn); }

.found-banner span {
  display: block;
  margin-top: 3px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--fg-2);
}

/* Sits on the label of whichever field it belongs to, so the claim is next to
   the value it is making a claim about rather than in a list somewhere. */
/* Profile: their own words suggest a claim about all their food, and nothing
   is on file (renderFoodFactsAsk). Body text colour on the warn wash, so it
   reads at AA; the border carries the colour. */
.food-facts-ask {
  margin: 0.55rem 0 0;
  padding: 0.55rem 0.75rem;
  border-left: 3px solid var(--warn);
  border-radius: var(--r-sm, 6px);
  background: var(--warn-wash);
  color: var(--fg-2);
  font-size: 0.8125rem;
  line-height: 1.45;
}

.found-chip {
  margin-left: 8px;
  padding: 1px 8px;
  border: 1px solid var(--warn);
  border-radius: var(--r-pill);
  background: var(--warn-wash);
  color: var(--warn);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  vertical-align: middle;
  cursor: help;
}

/* ---- Profile: identity ---- */

.profile-identity {
  display: grid;
  grid-template-columns: 190px minmax(0, 1fr);
  gap: 20px;
  align-items: start;
}

.profile-identity-fields { display: grid; gap: 0; }

.logo-slot { display: grid; gap: 8px; }

.logo-frame,
.logo-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--r-md);
  min-height: 130px;
  padding: 16px;
}

/* The closing card is drawn on this exact panel colour, so a white wordmark
   previews the way it will actually appear rather than as a broken image. */
.logo-frame {
  background: #111418;
  border: 1px solid var(--line);
}

.logo-frame img { max-width: 100%; max-height: 110px; object-fit: contain; }

.logo-empty {
  flex-direction: column;
  gap: 8px;
  border: 1px dashed var(--line-strong);
  color: var(--fg-3);
  font-size: 12px;
}

.logo-empty svg { width: 26px; height: 26px; }

.logo-actions { display: grid; gap: 6px; }

@media (max-width: 620px) {
  .profile-identity { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   Memory & Content Strategy Dashboard
   ========================================================================== */

.memory-hero-card {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 14px;
  padding: 20px 22px;
  margin-bottom: 16px;
  border-radius: var(--r-lg);
  background:
    radial-gradient(120% 140% at 100% 0%, var(--brand-wash) 0%, transparent 55%),
    var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-1);
  overflow: hidden;
}

@media (min-width: 560px) {
  .memory-hero-card {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
  }
}

.memory-hero-content {
  min-width: 0;
}

.memory-hero-content h2 {
  margin: 0;
  font-family: var(--display);
  font-size: 1.625rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.15;
}

.memory-hero-lede {
  margin: 4px 0 0;
  max-width: 52ch;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--fg-2);
}

.memory-hero-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.memory-status-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 8px;
}

/* The strategist's own line about the week, set as the plan it is rather than
   an italic quote nobody could tell was the point of the card. */
.memory-strategy-summary {
  grid-column: 1 / -1;
  display: grid;
  gap: 4px;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
}

.memory-strategy-summary[hidden] {
  display: none;
}

.memory-strategy-label {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--brand-strong);
}

.memory-strategy-summary p {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.55;
  color: var(--fg-1);
}

/* Intent Mix Meters */
.intent-mix-grid {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-top: 16px;
}

.mix-row {
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.mix-caption {
  margin: 14px 0 0;
  font-size: 0.8125rem;
  color: var(--fg-3);
}

.mix-row-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.mix-row-title-wrap {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.mix-row-title {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--fg-1);
}

.mix-row-stats {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 0.8125rem;
  color: var(--fg-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.mix-row-stats b {
  color: var(--fg-1);
  font-size: 0.875rem;
}

.mix-deficit-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 1px 8px 1px 7px;
  border-radius: var(--r-pill);
  font-size: 0.6875rem;
  font-weight: 600;
  background: var(--warn-wash);
  color: var(--warn);
}

.mix-deficit-badge::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
}

.mix-bar-wrap {
  position: relative;
  width: 100%;
  height: 10px;
  background: var(--surface-3);
  border-radius: var(--r-pill);
  overflow: visible;
}

.mix-bar-fill {
  height: 100%;
  border-radius: var(--r-pill);
  background: var(--intent, var(--brand));
  transition: width 0.4s var(--ease);
}

/* The target is a notch cut through the bar, not a post standing on it. */
.mix-target-marker {
  position: absolute;
  top: -3px;
  width: 3px;
  height: 16px;
  background: var(--fg-1);
  border-radius: 2px;
  transform: translateX(-50%);
  pointer-events: none;
  z-index: 2;
  box-shadow: 0 0 0 2px var(--surface);
}

/* Coverage Gaps */
/* Four gaps, side by side once there is width for it. Each one is tinted its
   own way so the four read apart at a glance: the brand for dishes never
   shown, amber for ones gone quiet, green for offers, ink for hooks. */
.coverage-sections {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 14px;
  margin-top: 16px;
}

.coverage-section {
  --gap: var(--brand-strong);
  --gap-wash: var(--brand-wash);
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0;
  padding: 14px 16px 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.coverage-section[data-gap="stale"] { --gap: var(--warn); --gap-wash: var(--warn-wash); }
.coverage-section[data-gap="deals"] { --gap: var(--good); --gap-wash: var(--good-wash); }
.coverage-section[data-gap="hooks"] { --gap: var(--navy-strong); --gap-wash: var(--navy-wash); }

.coverage-sec-head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: start;
  gap: 10px;
}

.coverage-icon {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 9px;
  background: var(--gap-wash);
  color: var(--gap);
}

.coverage-sec-title {
  display: grid;
  gap: 1px;
  padding-top: 1px;
}

.coverage-sec-title b {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--fg-1);
}

.coverage-sec-title span {
  font-size: 0.75rem;
  line-height: 1.4;
  color: var(--fg-3);
}

.coverage-count {
  padding: 3px 9px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--fg-2);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.coverage-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.coverage-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 100%;
  padding: 4px 10px;
  background: var(--surface-2);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-pill);
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--fg-1);
  overflow-wrap: anywhere;
}

.coverage-chip.is-signature,
.coverage-chip.is-stale {
  background: var(--gap-wash);
  border-color: transparent;
  color: var(--gap);
}

/* The remainder is a count, not an item — it must not look tappable like the
   dish chips beside it. */
.coverage-chip.is-more {
  background: none;
  border: 1px dashed var(--line-strong);
  color: var(--fg-3);
}

.coverage-chip .chip-sub {
  padding: 0 5px;
  border-radius: var(--r-pill);
  background: var(--surface);
  font-size: 0.6875rem;
  font-weight: 600;
  color: var(--fg-3);
  font-variant-numeric: tabular-nums;
}

/* Hooks as they were burned into the reels: heavy, upper case, on dark. */
.recent-hooks-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.hook-quote-pill {
  max-width: 100%;
  padding: 5px 10px;
  border-radius: 7px;
  background: #16203a;
  color: #fff;
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  line-height: 1.3;
  overflow-wrap: anywhere;
}

[data-theme="dark"] .hook-quote-pill {
  background: #000;
  box-shadow: inset 0 0 0 1px var(--line);
}

.none-yet-inline {
  display: block;
  width: 100%;
  padding: 10px 12px;
  border: 1px dashed var(--line);
  border-radius: var(--r-sm);
  font-size: 0.8125rem;
  color: var(--fg-3);
}

/* Suggestions & Pitches */
.pitches-list {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-top: 16px;
}

/* One pitch. The agent's colour runs down its edge, so a page of them sorts
   by goal at a glance; everything else is the neutral card. */
.pitch-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 16px 18px 14px 20px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-1);
  overflow: hidden;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.pitch-card::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 4px;
  background: var(--intent, var(--brand));
}

.pitch-card:hover {
  border-color: var(--line-strong);
  box-shadow: var(--shadow-2);
}

.pitch-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px 12px;
}

.pitch-badges-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  min-width: 0;
}

.pitch-agent-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px;
  border-radius: var(--r-pill);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background: var(--intent-wash, var(--surface-3));
  color: var(--intent, var(--fg-2));
}

.pitch-slot {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--fg-2);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.pitch-slot svg {
  color: var(--fg-3);
}

/* Scoped to the Playbook's card: Trends draws its own .pitch-headline in its
   own voice, and a bare selector here handed it the display serif. */
.pitch-card .pitch-headline {
  margin: 0;
  font-family: var(--display);
  font-size: 1.125rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--fg-1);
  line-height: 1.3;
}

.pitch-rationale {
  margin: -4px 0 0;
  font-size: 0.875rem;
  color: var(--fg-2);
  line-height: 1.55;
}

.pitch-rationale b {
  color: var(--fg-1);
  font-weight: 600;
}

/* The hook set as the renderer burns it: heavy, upper case, on dark. */
.pitch-hook-box {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
}

.pitch-hook-box b {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg-3);
}

.pitch-hook-text {
  display: inline-block;
  max-width: 100%;
  padding: 6px 12px;
  border-radius: 8px;
  background: #16203a;
  color: #fff;
  font-size: 0.8125rem;
  font-weight: 800;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  line-height: 1.3;
  overflow-wrap: anywhere;
}

[data-theme="dark"] .pitch-hook-text {
  background: #000;
  box-shadow: inset 0 0 0 1px var(--line);
}

.pitch-plan {
  border: 1px solid var(--line-soft);
  border-radius: var(--r-sm);
  background: var(--surface-2);
}

.pitch-plan summary {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 12px;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--fg-2);
  cursor: pointer;
  list-style: none;
  user-select: none;
}

.pitch-plan summary::-webkit-details-marker {
  display: none;
}

.pitch-plan summary::before {
  content: "";
  width: 6px;
  height: 6px;
  border-right: 1.6px solid currentColor;
  border-bottom: 1.6px solid currentColor;
  transform: rotate(-45deg);
  transition: transform 0.15s ease;
}

.pitch-plan[open] summary::before {
  transform: rotate(45deg);
}

.pitch-plan summary:hover {
  color: var(--fg-1);
}

.pitch-plan-body {
  display: grid;
  gap: 10px;
  padding: 2px 14px 14px 26px;
}

.pitch-step {
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--fg-2);
}

.pitch-step b {
  display: block;
  margin-bottom: 1px;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg-3);
}

.pitch-step-shots span {
  display: block;
  padding: 8px 10px;
  border-radius: 8px;
  background: var(--surface);
  border: 1px dashed var(--line-strong);
  color: var(--fg-1);
}

.pitch-meta-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
  padding-top: 12px;
  border-top: 1px solid var(--line-soft);
}

.pitch-action-note {
  flex-basis: 100%;
  margin: -2px 0 0;
  color: var(--fg-3);
  font-size: 0.75rem;
  line-height: 1.4;
  text-align: right;
}

.pitch-recommendation {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--brand-strong);
  font-size: 0.75rem;
  font-weight: 650;
}

.pitch-recommendation::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}

.pitch-priority {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--fg-3);
}

.pitch-priority.is-high {
  color: var(--brand-strong);
  font-weight: 600;
}

.pitch-priority-bar {
  width: 44px;
  height: 5px;
  border-radius: var(--r-pill);
  background: var(--surface-3);
  overflow: hidden;
}

.pitch-priority-bar i {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--fg-3);
}

.pitch-priority.is-high .pitch-priority-bar i {
  background: var(--grad-brand, var(--brand));
}

.pitch-tags {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
}

.pitch-tag {
  font-size: 0.75rem;
  color: var(--fg-2);
  background: var(--surface-2);
  padding: 3px 9px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line-soft);
}

.pitch-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
}

@media (max-width: 520px) {
  .pitch-card {
    padding: 14px 14px 12px 17px;
  }

  .pitch-actions {
    width: 100%;
  }

  .pitch-actions .btn-film-pitch {
    flex: 1;
  }

  .pitch-action-note { text-align: left; }
}

/* Episodic Memory Feed */
.memory-filter-bar {
  margin-bottom: 12px;
  overflow-x: auto;
  padding-bottom: 4px;
}

.memory-feed {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.memory-card {
  display: grid;
  grid-template-columns: 88px minmax(0, 1fr);
  gap: 14px;
  padding: 12px 14px;
  background: var(--surface-2);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
  transition: border-color 0.15s ease;
}

@media (max-width: 440px) {
  .memory-card {
    grid-template-columns: 72px minmax(0, 1fr);
    gap: 10px;
    padding: 10px 12px;
  }
}

.memory-card-thumb-wrap {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: var(--r-sm);
  overflow: hidden;
  background: var(--surface-3);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

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

.memory-card-play-icon {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.65);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(4px);
}

.memory-card-content {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

.memory-card-meta-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  flex-wrap: wrap;
}

.memory-card-pills {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 5px;
}

.memory-pill-intent {
  padding: 1px 6px;
  border-radius: 4px;
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
}

.memory-pill-intent {
  background: var(--intent-wash, var(--surface-3));
  color: var(--intent, var(--fg-2));
}

.memory-pill-source {
  padding: 1px 5px;
  border-radius: 4px;
  font-size: 0.6875rem;
  background: var(--surface-3);
  color: var(--fg-3);
  font-weight: 500;
}

.memory-pill-dish {
  padding: 1px 6px;
  border-radius: 4px;
  font-size: 0.75rem;
  background: var(--surface);
  color: var(--fg-1);
  font-weight: 500;
  border: 1px solid var(--line-soft);
}

.memory-card-time {
  font-size: 0.75rem;
  color: var(--fg-3);
  flex-shrink: 0;
}

.memory-card-hook {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--fg-1);
  line-height: 1.35;
}

.memory-card-caption {
  font-size: 0.8125rem;
  color: var(--fg-2);
  line-height: 1.38;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  word-break: break-word;
}

.memory-card-stats {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 2px;
  font-size: 0.75rem;
  color: var(--fg-3);
}

.memory-stat-item {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

/* Standing Notes */
.add-note-form {
  display: grid;
  gap: 10px;
  margin-top: 16px;
  padding: 14px;
  background: var(--surface-2);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
}

.note-kinds {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.note-kind {
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 600;
  padding: 6px 12px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--fg-2);
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.note-kind:hover {
  color: var(--fg-1);
  border-color: var(--line-strong);
}

.note-kind.is-on {
  border-color: transparent;
  background: var(--fg-1);
  color: var(--surface);
}

.note-kind:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

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

.note-compose-row .input {
  flex: 1;
  min-width: 0;
}

.note-compose-row .btn {
  flex: none;
}

.note-kind-hint {
  margin: 0;
  font-size: 0.8125rem;
  color: var(--fg-3);
}

@media (max-width: 520px) {
  .note-compose-row {
    flex-direction: column;
  }
}

.standing-notes-list {
  display: grid;
  gap: 22px;
  margin-top: 22px;
}

.notes-group-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 2px 12px;
  margin-bottom: 10px;
}

.notes-group-head h3 {
  font-family: var(--sans);
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--fg-1);
}

.notes-group-head p {
  margin: 0;
  font-size: 0.8125rem;
  color: var(--fg-3);
}

.notes-count {
  min-width: 20px;
  padding: 1px 7px;
  border-radius: var(--r-pill);
  background: var(--surface-3);
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--fg-2);
  text-align: center;
}

.notes-empty {
  margin: 0;
  padding: 14px;
  border: 1px dashed var(--line);
  border-radius: var(--r-sm);
  font-size: 0.8125rem;
  color: var(--fg-3);
  text-align: center;
}

.standing-notes-items {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  overflow: hidden;
}

.standing-note-card {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 10px 12px 14px;
  transition: background-color 0.15s ease;
}

.standing-note-card + .standing-note-card {
  border-top: 1px solid var(--line-soft);
}

.standing-note-card:hover {
  background: var(--surface-2);
}

.standing-note-icon {
  display: grid;
  place-items: center;
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 8px;
  background: var(--brand-wash);
  color: var(--brand-strong);
}

.standing-note-card[data-kind="constraint"] .standing-note-icon {
  background: var(--bad-wash);
  color: var(--bad);
}

.standing-note-card[data-kind="fact"] .standing-note-icon {
  background: var(--navy-wash);
  color: var(--navy-strong);
}

.standing-note-card[data-kind="observation"] .standing-note-icon {
  background: var(--good-wash);
  color: var(--good);
}

.standing-note-main {
  display: grid;
  gap: 3px;
  flex: 1;
  min-width: 0;
  padding-top: 3px;
}

.standing-note-text {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--fg-1);
  overflow-wrap: anywhere;
}

.standing-note-meta {
  font-size: 0.75rem;
  color: var(--fg-3);
}

.btn-note-delete {
  flex: none;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--fg-4);
  cursor: pointer;
  transition: color 0.15s ease, background 0.15s ease, opacity 0.15s ease;
}

.btn-note-delete:hover,
.btn-note-delete:focus-visible {
  color: var(--bad);
  background: var(--bad-wash);
}

/* With a mouse, the remove button waits until the row is pointed at. */
@media (hover: hover) {
  .btn-note-delete { opacity: 0; }
  .standing-note-card:hover .btn-note-delete,
  .btn-note-delete:focus-visible { opacity: 1; }
}

/* Modals & Tuning */
.mix-tuner { padding: 10px 0; }

/* The mix as one bar, in the same four colours the pitch pills and the
   balance meters use, so the setting and its result look like the same
   thing in two places. */
.mix-preview {
  display: flex;
  height: 12px;
  border-radius: var(--r-pill);
  overflow: hidden;
  background: var(--surface-3);
}

.mix-preview-seg {
  background: var(--intent, var(--brand));
  transition: width 0.2s var(--ease);
}

.mix-preview-caption {
  margin: 8px 0 18px;
}

.mix-sliders-grid {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* The agent's colour sits down the left of its own slider, so the bar above
   can be read back to the control that moves it without a legend. */
.mix-slider {
  padding-left: 12px;
  border-left: 3px solid var(--intent, var(--brand));
}

.mix-slider-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 6px;
}

.mix-slider-head label {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--fg);
}

/* The parenthesised half of the name — what the agent is for, not what it is
   called. Quiet enough that four of them stacked read as one column of names. */
.mix-slider-head label span {
  margin-left: 6px;
  font-size: 0.8125rem;
  font-weight: 400;
  color: var(--fg-3);
}

.mix-slider-head b {
  font-size: 0.875rem;
  font-variant-numeric: tabular-nums;
  color: var(--intent, var(--brand));
}

.mix-slider .input-range { accent-color: var(--intent, var(--brand)); }

.mix-run-settings { margin-top: 20px; }

.mix-auto-row {
  padding: 0;
  border-top: 0;
  justify-content: flex-start;
  gap: 8px;
  min-height: 40px;
  cursor: pointer;
}

.mix-auto-row input { width: 18px; height: 18px; accent-color: var(--brand); }

.mix-auto-row b { font-size: 0.875rem; }

.input-range {
  width: 100%;
  height: 6px;
  background: var(--surface-3);
  border-radius: var(--r-pill);
  outline: none;
  accent-color: var(--brand);
  cursor: pointer;
}
.input-range:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 3px;
}

.feedback-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 6px;
}


/* Sleek SaaS refinements for Dark Mode */
[data-theme="dark"] .card {
  background: var(--surface);
  border: 1px solid var(--line-strong);
  box-shadow: 0 4px 12px rgba(0,0,0,0.5);
  border-radius: var(--r-lg);
}

[data-theme="dark"] .app-bar {
  border-bottom: 1px solid var(--line-strong);
  background: rgba(25, 29, 42, 0.85); /* Matches surface but translucent */
}

[data-theme="dark"] .tab-bar {
  background: rgba(20, 24, 36, 0.85);
  border-right: 1px solid var(--line-strong);
}

[data-theme="dark"] .btn-primary {
  box-shadow: 0 4px 14px rgba(224, 95, 36, 0.4);
}

/* The format picker on a pitch card. It wears .pitch-tag, so it only has to
   undo what a browser does to a <select> that a span does not get. */
.pitch-format-select {
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  max-width: 15rem;
  font-family: inherit;
  line-height: 1.35;
  padding-right: 18px;
  background-image: linear-gradient(45deg, transparent 50%, var(--fg-3) 50%),
                    linear-gradient(135deg, var(--fg-3) 50%, transparent 50%);
  background-position: right 8px top 52%, right 4px top 52%;
  background-size: 4px 4px, 4px 4px;
  background-repeat: no-repeat;
}

.pitch-format-select:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 1px;
}

/* =============================================================================
   The format gallery
   -----------------------------------------------------------------------------
   A browsable wall of shapes rather than a list of names. Each card carries a
   9:16 frame with the example hook set the way the renderer burns it — upper
   case, high on the frame — so the format reads as a thing you can picture
   before the description is read. The tint is the goal it serves, which is the
   only colour in the grid and therefore the thing the eye sorts by.
============================================================================= */

.gallery-search {
  position: relative;
  flex: 1 1 240px;
}

.gallery-search svg {
  position: absolute;
  left: 10px;
  top: 50%;
  width: 15px;
  height: 15px;
  transform: translateY(-50%);
  color: var(--fg-3);
  pointer-events: none;
}

.gallery-search .input { padding-left: 32px; }

.gallery-filters {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding-bottom: 10px;
  margin-bottom: 14px;
  scrollbar-width: none;
}

.gallery-filters::-webkit-scrollbar { display: none; }

.gallery-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  padding: 7px 13px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--fg-2);
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.gallery-pill:hover { border-color: var(--line-strong); color: var(--fg); }

.gallery-pill.is-on {
  background: var(--fg);
  border-color: var(--fg);
  color: var(--bg);
}

.gallery-pill-n {
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
  opacity: 0.6;
}

/* Three generous previews per row. At four columns the 9:16 cards were narrow
   enough that their labels and two actions competed with the footage. */
.format-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.template-defaults { margin: 16px 0 20px; }
.template-defaults[hidden] { display: none; }
.template-defaults .card { margin-bottom: 0; }

.template-controls {
  position: sticky;
  top: 60px;
  z-index: 12;
  margin-bottom: 16px;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: color-mix(in srgb, var(--surface) 94%, transparent);
  box-shadow: var(--shadow-1);
  backdrop-filter: blur(12px);
}

.template-control-top {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 10px;
}
.template-control-top .seg { flex: 0 1 auto; margin: 0; }
.template-control-top .gallery-search { min-width: 180px; }

.template-filter-axes {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.72fr);
  gap: 12px 24px;
  margin-bottom: 0;
  padding: 14px 16px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
  background: var(--surface-2);
}

.template-filter-axis { min-width: 0; }

.template-filter-label {
  display: block;
  margin-bottom: 8px;
  color: var(--fg-3);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* These are choices, not a carousel. Wrapping keeps the final option visible
   instead of putting it behind a scrollbar we deliberately hide elsewhere. */
.template-filter-axis .gallery-filters {
  flex-wrap: wrap;
  overflow-x: visible;
  margin: 0;
  padding-bottom: 0;
}

.template-result-count {
  margin: 8px 4px 0;
  color: var(--fg-3);
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
}

.template-empty { display: grid; justify-items: center; gap: 7px; }
.template-empty[hidden] { display: none; }
.template-empty b { color: var(--fg); font-size: 0.9375rem; }
.template-empty span { display: block; }
.template-empty .btn { margin-top: 5px; }

@media (max-width: 980px) {
  .format-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 700px) {
  .template-filter-axes { grid-template-columns: minmax(0, 1fr); gap: 14px; }
  .template-controls { top: 56px; margin-inline: -4px; padding: 8px; }
  .template-control-top { align-items: stretch; flex-direction: column; gap: 8px; }
  .template-control-top .seg { width: 100%; }
  .template-control-top .seg-btn { flex: 1 1 50%; }
}

.format-card {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  overflow: hidden;
  transition: transform 0.15s var(--ease), box-shadow 0.15s var(--ease);
}

/* The card lifts, and that is all it does. A border that darkens under a card
   that is already rising is a second answer to the same question. */
.format-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-2);
}

/* The frame is the point of the card, so it gets the space a phone gives it. */
.format-frame {
  position: relative;
  aspect-ratio: 9 / 13;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 30px 14px 14px;
  background: var(--grad-navy);
  overflow: hidden;
}

.template-personalized {
  position: absolute;
  left: 9px;
  right: 9px;
  bottom: 9px;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  padding: 6px 8px;
  border: 1px solid rgba(255, 255, 255, 0.26);
  border-radius: 10px;
  background: rgba(10, 16, 28, 0.7);
  color: #fff;
  backdrop-filter: blur(7px);
}
.format-card.has-film .template-personalized { bottom: 84px; }
.template-personalized img,
.template-personalized-mark {
  width: 24px;
  height: 24px;
  flex: none;
  border-radius: 7px;
  object-fit: contain;
  background: #fff;
}
.template-personalized-mark { background: var(--brand); }
.template-personalized > span:last-child { min-width: 0; }
.template-personalized b,
.template-personalized small {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.template-personalized b { font-size: 0.6875rem; }
.template-personalized small { margin-top: 1px; font-size: 0.625rem; opacity: 0.8; }

.format-card[data-intent="craving"] .format-frame { background: var(--grad-brand); }
.format-card[data-intent="trust"]   .format-frame { background: var(--grad-good); }
.format-card[data-intent="booking_order"] .format-frame { background: var(--grad-violet); }

.format-frame-chip.is-camera { left: auto; right: 9px; }
.format-frame-chip {
  position: absolute;
  top: 9px;
  left: 9px;
  padding: 2px 7px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.18);
  color: #fff;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  backdrop-filter: blur(3px);
}

/* Six words or fewer, burned high on the frame — the renderer's own rule. */
.format-frame-hook {
  color: #fff;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.01em;
  text-align: center;
  text-wrap: balance;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.35);
}

/* A stage direction is not a line anyone says, so it must not look like one. */
.format-frame-hook.is-direction {
  align-self: center;
  margin-top: 12%;
  font-size: 0.8125rem;
  font-weight: 600;
  font-style: italic;
  text-transform: none;
  opacity: 0.85;
}

/* Takes the slack the grid gives a short card, so the button below can be
   pushed to the floor rather than sitting wherever the beats happened to end. */
.format-body {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 6px;
  padding: 12px 13px 13px;
}

/* The body's own 6px gap is the minimum clearance above the button on whichever
   card in a row has no slack to give it; every shorter card gets more from the
   button's auto margin. Kept as a gap rather than padding on the button, which
   would only make the button taller and push its label off centre. */

.format-body h3 {
  margin: 0;
  font-family: var(--sans);
  font-size: 0.9375rem;
  font-weight: 700;
  line-height: 1.25;
}

/* The one fact that disqualifies a format outright, so it stays on the card
   while the rest of the brief moves into the sheet. One line, ellipsised: a
   card is not the place to read a list of three requirements either. */
.format-needs {
  margin: 0;
  font-size: 0.75rem;
  line-height: 1.4;
  color: var(--fg-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.format-needs b {
  font-weight: 700;
  color: var(--fg-2);
}

/* Stacked, not side by side: at four columns a gallery card is ~180px wide and
   at two columns on a phone it is narrower still, so a link and a button in a
   row either truncate or wrap raggedly. The pair is pinned to the floor of the
   card for the reason .format-use always was -- names run one line or two and
   a row of buttons at two heights reads as crooked. */
.format-actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 7px;
  margin-top: auto;
}

/* .format-use carries its own margin-top:auto for the cards that have no
   actions wrapper; inside one, two auto margins would split the slack and
   push the link away from the button. */
.format-actions .format-use { margin-top: 0; }

.format-brief-btn {
  align-self: flex-start;
  font-size: 0.75rem;
  text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
  text-underline-offset: 2px;
}

.format-body p {
  margin: 0;
  color: var(--fg-2);
  font-size: 0.8125rem;
  line-height: 1.45;
}

/* The gallery card is its frame. A real phone's 9:16, footage edge to edge,
   and everything that used to stack under it sits on a scrim at the foot: the
   name always, the beats and the shot list when the pointer is on the card.
   Scoped to the grid because the composer's idea rail wears the same card with
   its own body. */
.format-grid .format-card { background: transparent; }

.format-grid .format-frame {
  aspect-ratio: 9 / 16;
  border-radius: var(--r-md);
}

.format-over {
  position: absolute;
  inset: auto 0 0 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 100%;
  padding: 44px 12px 12px;
  color: #fff;
  background: linear-gradient(to top, rgba(8, 10, 18, 0.92) 0%, rgba(8, 10, 18, 0.72) 55%, rgba(8, 10, 18, 0) 100%);
  overflow: hidden;
  text-align: left;
  transition: opacity 0.2s ease;
}

.format-over h3 {
  margin: 0;
  font-family: var(--sans);
  font-size: 0.9375rem;
  font-weight: 700;
  line-height: 1.2;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.4);
}

/* Folded until the pointer arrives: three lines of beats, and that is all the
   scrim ever holds now. The shot list used to unfold under this into four
   labelled paragraphs inside a 12rem scrolling box, on a card 180px wide --
   it is a sheet instead, reached from the link below. */
.format-over p {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  margin: 0;
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  font-size: 0.75rem;
  line-height: 1.4;
  color: rgba(255, 255, 255, 0.88);
  transition: max-height 0.25s ease, opacity 0.2s ease;
}

.format-grid .format-card:hover .format-over p,
.format-grid .format-card:focus-within .format-over p { max-height: 4.5rem; opacity: 1; }

/* The brief has to be reachable without a pointer -- the old folded panel was
   not -- so the link is on the scrim always, like the button under it. */
.format-over .format-brief-btn {
  color: rgba(255, 255, 255, 0.82);
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.45);
}

.format-over .format-brief-btn:hover { color: #fff; }

/* Always there, never on hover -- see .format-use above. On the scrim it is
   white on glass, and turns brand when the card is under the pointer. */
.format-over .format-use {
  margin-top: 4px;
  border-color: rgba(255, 255, 255, 0.35);
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
  backdrop-filter: blur(4px);
}

.format-grid .format-card:hover .format-over .format-use {
  border-color: var(--brand-ink);
  background: var(--brand-ink);
  color: var(--on-brand);
}

/* A clip with a poster is visible from the first paint -- the poster is the
   footage's own frame, so there is no black box to hide -- and the hook comes
   off it. The footage says what the format is, and the name on the scrim says
   what it is called. Gradient cards keep the hook, their only picture. */
.format-film[poster] { opacity: 1; }
.format-grid .format-card.has-film .format-frame-hook { display: none; }

/* Two chips across a 180px frame: "Booking & Orders" and "On camera" collided
   at the size the old, wider card set them. */
.format-grid .format-frame-chip { font-size: 0.625rem; padding: 2px 6px; }

/* Playback gets the whole frame. The card furniture returns when it pauses. */
.format-grid .format-card.is-playing .format-over,
.format-grid .format-card.is-playing .template-personalized {
  opacity: 0;
  pointer-events: none;
}

@media (max-width: 560px) {
  .format-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .format-body p { display: none; }
  .format-over { padding: 30px 8px 8px; }
  .format-over h3 { font-size: 0.8125rem; }
  .format-actions { gap: 5px; }
  .template-personalized { left: 6px; right: 6px; bottom: 6px; padding: 5px 6px; }
  .format-card.has-film .template-personalized { bottom: 74px; }
  .template-personalized img, .template-personalized-mark { width: 20px; height: 20px; }
  .template-personalized small { display: none; }
}

/* No pointer, no hover: the beats fold away for good, and the name, the brief
   link and the button stay — a tap still plays the clip with sound. */
@media (hover: none) {
  .format-grid .format-card:hover .format-over p { max-height: 0; opacity: 0; }
}

/* The brief in the sheet: sized to the text rather than to a thumbnail. Labels
   in their own column so the answers read as one column down the page, which
   is how a shot list is read -- one line at a time, phone in the other hand.
   A label gutter is a third of a phone screen, so there it stacks instead. */
.format-spec {
  display: grid;
  grid-template-columns: 5.5rem 1fr;
  gap: 9px 14px;
  margin: 2px 0 18px;
  font-size: 0.875rem;
  line-height: 1.5;
}

.format-spec dt {
  font-weight: 700;
  color: var(--fg-3);
}

.format-spec dd {
  margin: 0;
  color: var(--fg);
}

.format-sheet-preview { margin-bottom: 16px; }
.format-sheet-media {
  position: relative;
  max-width: 300px;
  margin-inline: auto;
  overflow: hidden;
  border-radius: var(--r-md);
  background: var(--surface-2);
  box-shadow: var(--shadow-2);
}
.format-sheet-media > video,
.format-sheet-media > img {
  display: block;
  width: 100%;
  max-height: 52vh;
  object-fit: cover;
  aspect-ratio: 9 / 13;
}
.format-sheet-mosaic { display: grid; grid-auto-flow: column; overflow-x: auto; scroll-snap-type: x mandatory; }
.format-sheet-mosaic img { width: 220px; aspect-ratio: 4 / 5; object-fit: cover; scroll-snap-align: start; }
.format-sheet-media .template-personalized { bottom: 12px; }

@media (max-width: 560px) {
  #formatSheet .sheet { max-height: calc(100dvh - 24px); overflow-y: auto; }
  .format-sheet-media { max-width: 230px; }
  .format-sheet-media > video, .format-sheet-media > img { max-height: 38vh; }
  #formatSheetUse { position: sticky; bottom: 0; width: 100%; box-shadow: 0 -8px 18px var(--surface); }
}

@media (max-width: 480px) {
  .format-spec { grid-template-columns: 1fr; gap: 2px; }
  .format-spec dt + dd { margin-bottom: 8px; }
}

/* =============================================================================
   The sound gallery
   -----------------------------------------------------------------------------
   A track list, the way a music app shows records: a cover, a name, the bed's
   own waveform and a play button, one row each. Rows fit six to a phone screen,
   so nothing folds. "Choose for me" and "No music" are a switch above the list
   because they are how a bed is chosen, not beds.

   A bed with no audio file is dimmed and says so. It still renders — its
   fallback is used — and hiding that would make the picker a choice between
   names that play one track.
============================================================================= */

/* ---- "Your reel will sound like" ---- */
.mix-strip {
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas:
    "eyebrow eyebrow"
    "parts   play";
  align-items: center;
  gap: 6px 14px;
  margin-bottom: 18px;
  padding: 14px 16px 15px;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background:
    radial-gradient(120% 140% at 0% 0%, var(--brand-wash), transparent 60%),
    var(--surface);
  box-shadow: var(--shadow-2);
}
.mix-eyebrow {
  grid-area: eyebrow;
  color: var(--fg-3);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.mix-parts { grid-area: parts; display: flex; align-items: center; flex-wrap: wrap; gap: 8px 10px; min-width: 0; }
.mix-part { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
.mix-name { font-weight: 600; font-size: 0.9375rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 16ch; }
.mix-plus { color: var(--fg-4); font-weight: 600; }
.mix-play { grid-area: play; white-space: nowrap; }
.mix-strip.is-loading .mix-play { cursor: progress; opacity: 0.8; }
/* The mix's own progress, a hairline along the bottom edge. */
.mix-progress {
  position: absolute;
  left: 0;
  bottom: 0;
  height: 3px;
  width: calc(var(--p, 0) * 100%);
  background: var(--brand);
}

/* Speakers are orbs, as the voice library draws them; beds are covers. */
.voice-orb {
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  /* Soft and blended, not glossy: a pastel highlight drifting over a slow
     conic sweep between the voice's two colours. */
  background:
    radial-gradient(circle at 30% 28%, var(--o3, #fff) 0, transparent 46%),
    radial-gradient(circle at 72% 78%, var(--o2, #4B4A8F) 0, transparent 62%),
    conic-gradient(from var(--turn, 0deg), var(--o1, #9A8FE0), var(--o2, #4B4A8F), var(--o1, #9A8FE0));
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.25), 0 2px 6px -2px rgba(22, 32, 58, 0.25);
}

/* ---- The switch, and what it means ---- */
.bed-mode { max-width: 420px; margin-bottom: 8px; }
.bed-mode-hint { margin: 0 0 16px; color: var(--fg-2); font-size: 0.8125rem; line-height: 1.45; }

/* ---- Shelves ---- */
.bed-list { display: grid; gap: 22px; transition: opacity 0.18s var(--ease); }
.bed-list.is-muted { opacity: 0.55; }
.bed-list.is-muted:hover,
.bed-list.is-muted:focus-within { opacity: 0.85; }
.bed-shelf { display: grid; gap: 2px; }
.bed-shelf-head { margin: 0 0 6px; }
.bed-shelf-head h3 { margin: 0; font-size: 0.9375rem; font-weight: 700; }
.bed-shelf-head p { margin: 2px 0 0; color: var(--fg-3); font-size: 0.8125rem; line-height: 1.4; }

/* ---- A row ---- */
.bed-row {
  --p: 0;
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr) minmax(90px, 180px) 64px 32px 24px;
  grid-template-areas:
    "cover main wave time play check"
    "detail detail detail detail detail detail";
  align-items: center;
  column-gap: 12px;
  padding: 9px 10px;
  border: 1px solid transparent;
  border-radius: var(--r-md);
  cursor: pointer;
  transition: background-color 0.15s var(--ease), border-color 0.15s var(--ease);
}
.bed-row:hover { background: var(--surface-2); }
.bed-row:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.bed-row.is-on {
  border-color: var(--brand);
  background: var(--brand-wash);
}

.bed-cover {
  grid-area: cover;
  flex: none;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: 10px;
  color: #fff;
  background: linear-gradient(140deg, var(--c1), var(--c2));
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12), 0 1px 2px rgba(22, 32, 58, 0.12);
}
.bed-cover svg { width: 22px; height: 22px; }
.bed-cover.is-plain { background: var(--surface-3); }
.bed-cover-sm { width: 30px; height: 30px; border-radius: 8px; }
.bed-cover-sm svg { width: 16px; height: 16px; }

.bed-main { grid-area: main; display: grid; min-width: 0; }
.bed-name { font-size: 0.9375rem; font-weight: 700; }
.bed-meta {
  color: var(--fg-3);
  font-size: 0.75rem;
  line-height: 1.35;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The waveform: the same bars twice, the top copy in brand colour and clipped
   to how far the bed has played. One custom property moves it. */
.bed-wave {
  grid-area: wave;
  position: relative;
  height: 28px;
  touch-action: none;
  cursor: pointer;
}
.bed-wave.is-empty { cursor: default; }
.bed-wave:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: 4px; }
.bed-bars {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  gap: 2px;
  pointer-events: none;
}
.bed-bars i {
  flex: 1 1 0;
  min-width: 1px;
  border-radius: 2px;
  background: var(--line);
}
.bed-row:hover .bed-bars i,
.bed-row.is-on .bed-bars i { background: color-mix(in srgb, var(--fg-4) 45%, transparent); }
.bed-bars-on { clip-path: inset(0 calc((1 - var(--p)) * 100%) 0 0); }
.bed-bars-on i,
.bed-row:hover .bed-bars-on i,
.bed-row.is-on .bed-bars-on i { background: var(--brand); }

.bed-time {
  grid-area: time;
  color: var(--fg-3);
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}
.bed-row.is-playing .bed-time { color: var(--brand-ink); font-weight: 600; }
.bed-row > .voice-play { grid-area: play; }
.bed-play-gap { grid-area: play; }

.bed-check {
  grid-area: check;
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: transparent;
}
.bed-check svg { width: 13px; height: 13px; }
.bed-row.is-on .bed-check { background: var(--brand-ink); color: var(--on-brand); }

/* In "choose for me" the column says how many formats reach for each bed. */
.bed-uses {
  grid-area: check;
  justify-self: end;
  color: var(--fg-3);
  font-size: 0.6875rem;
  font-weight: 600;
  white-space: nowrap;
}

/* Only the picked row opens: why to reach for it, and which formats do. */
.bed-detail {
  grid-area: detail;
  display: none;
  gap: 8px;
  padding: 10px 0 4px 56px;
}
.bed-row.is-on .bed-detail,
.bed-row.is-missing .bed-detail { display: grid; }
.bed-suits { margin: 0; color: var(--fg-2); font-size: 0.8125rem; line-height: 1.45; }
.bed-suits b { color: var(--fg); font-weight: 600; }
.bed-chips { display: flex; flex-wrap: wrap; gap: 5px; }
.bed-chip {
  padding: 3px 9px;
  border-radius: var(--r-pill);
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--fg-2);
  font-size: 0.75rem;
  font-weight: 500;
}
.bed-chip.is-more { color: var(--fg-3); }

/* Says what will actually play, rather than letting the name imply it. */
.bed-missing {
  margin: 0;
  padding: 7px 9px;
  border-radius: 7px;
  background: var(--warn-wash);
  color: var(--warn);
  font-size: 0.75rem;
  line-height: 1.4;
}
.bed-row.is-missing { cursor: pointer; }
.bed-row.is-missing .bed-cover { filter: grayscale(0.7); opacity: 0.6; }
.bed-row.is-missing .bed-name { color: var(--fg-2); }

@media (max-width: 560px) {
  .mix-strip { grid-template-columns: 1fr; grid-template-areas: "eyebrow" "parts" "play"; }
  /* Stacked, the two parts read as a list; a "+" left at a line end does not. */
  .mix-parts { flex-direction: column; align-items: flex-start; gap: 6px; }
  .mix-plus { display: none; }
  .mix-play { justify-self: start; }
  .bed-mode .seg-btn { padding: 8px 4px; font-size: 0.75rem; white-space: nowrap; }
  .bed-row {
    grid-template-columns: 44px minmax(0, 1fr) auto 32px 22px;
    grid-template-areas:
      "cover main time play check"
      "wave  wave wave wave wave"
      "detail detail detail detail detail";
    row-gap: 6px;
    column-gap: 10px;
    padding: 8px;
  }
  /* The waveform only takes a line of its own once it is being listened to or
     chosen; six of them stacked would double the list's height for nothing. */
  .bed-wave { display: none; padding-left: 54px; height: 24px; }
  .bed-row.is-playing .bed-wave,
  .bed-row.is-on .bed-wave { display: block; }
  .bed-bars { left: 54px; }
  .bed-detail { padding-left: 54px; }
  .bed-uses { font-size: 0.625rem; }
}

@media (prefers-reduced-motion: reduce) {
  .bed-row, .bed-list { transition: none; }
}

/* A format with a generated example clip plays it in its own frame. The hook is
   the poster: it says what the format is until the film shows it, then clears. */
/* Clicking plays it with sound on every device, so the promise is honest. */
.format-card.has-film .format-frame { cursor: default; }

/* A still posts at 4:5, not a reel's 9:16; in the reel's frame a quarter of
   its width was cut off. */
.format-grid .format-card.is-still .format-frame { aspect-ratio: 4 / 5; }

/* A still's drawn preview fills the frame the way a clip does. */
.format-still {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  cursor: zoom-in;
}

/* A sequence's frame: every slide, so the card reads as several pictures at a
   glance. Odd counts lead with a full-width first slide -- that is the one most
   people see in the feed. */
.format-mosaic {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2px;
}
.format-mosaic img {
  width: 100%;
  height: 100%;
  min-height: 0;
  object-fit: cover;
  cursor: zoom-in;
}
.format-mosaic img:first-child:nth-last-child(odd) { grid-column: span 2; }

.format-film {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Hidden until it has something to show: an unloaded video paints a black
     box over the gradient, which looks like a broken card. */
  opacity: 0;
  transition: opacity 0.25s ease;
}

.format-card.is-playing .format-film { opacity: 1; }

/* Once the film runs, the frame is the film. The chip and hook are poster
   furniture, so they get out of the way instead of covering the footage. */
.format-card .format-frame-chip,
.format-card .format-frame-hook {
  position: relative;
  z-index: 1;
  transition: opacity 0.2s ease;
}

.format-card.is-playing .format-frame-chip,
.format-card.is-playing .format-frame-hook {
  opacity: 0;
}

/* The chip is corner furniture, not flow content. */
.format-card .format-frame-chip {
  position: absolute;
  white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  .format-film { transition: none; }
}

/* ---------- The roster ----------
   A horizontal strip of the people who can front a reel, because a restaurant
   has two or three of them, not twenty — a scrolling row reads faster than a
   list and never pushes the cards it governs below the fold. */

.staff-strip {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 10px;
}

/* A person, as a card that says whether they are ready. */
.staff-chip {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  color: var(--fg-2);
  font: inherit;
  font-size: 0.875rem;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease), background-color 0.15s var(--ease);
}

.staff-chip:hover { border-color: var(--line-strong); box-shadow: var(--shadow-1); }

.staff-chip.is-on {
  border-color: var(--brand);
  background: var(--brand-wash);
  box-shadow: 0 0 0 1px var(--brand);
  color: var(--fg);
}

.staff-chip[hidden] { display: none; }

.staff-chip img,
.staff-chip .staff-initial {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  object-fit: cover;
  flex: 0 0 auto;
}

.staff-chip .staff-initial {
  display: grid;
  place-items: center;
  background: var(--surface-3);
  color: var(--fg-3);
  font-size: 1rem;
  font-weight: 600;
}

.staff-chip-text { display: grid; gap: 1px; min-width: 0; }

.staff-chip-text b {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--fg);
}

.staff-state { font-size: 0.75rem; color: var(--fg-3); }
.staff-state.is-ready { color: var(--good); font-weight: 600; }
.staff-state.is-busy { color: var(--warn); font-weight: 600; }
.staff-state.is-owed { color: var(--fg-3); }

.staff-badge {
  position: absolute;
  top: -8px;
  right: 10px;
  padding: 2px 8px;
  border-radius: var(--r-pill);
  background: var(--grad-brand, var(--brand));
  color: var(--on-brand);
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.staff-chip-add {
  border-style: dashed;
  border-color: var(--line-strong);
  background: transparent;
}

.staff-chip-add .staff-initial {
  background: var(--brand-wash);
  color: var(--brand-strong);
  font-size: 1.25rem;
  font-weight: 500;
}

.staff-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.staff-actions:empty { display: none; }

/* ---------- One person, everything about them ----------
   Identity, then what they have, then the one thing to do next. Anything a
   manager could do instead of that one thing is behind the fold-away, because
   the wrong shortcut here -- uploading someone's face for them -- is the one
   the product exists to avoid. */

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

.person-face {
  width: 56px;
  height: 56px;
  flex: 0 0 auto;
  border-radius: 50%;
  overflow: hidden;
}

.person-face:has(img) { cursor: pointer; }

/* The photo, big enough to judge, over the page rather than pushing it about. */
.face-sheet {
  width: min(320px, 84vw);
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--shadow-3);
}

.face-sheet::backdrop { background: rgba(0, 0, 0, 0.45); }

.face-sheet img {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--r-sm);
}

.face-sheet-actions {
  display: flex;
  gap: 8px;
  margin-top: 12px;
}

.face-sheet-actions .btn { flex: 1; }

.person-face img,
.person-face .staff-initial {
  width: 100%;
  height: 100%;
  object-fit: cover;
  font-size: 1.25rem;
}

.person-id h2 { margin: 0; }

.person-id p {
  margin: 2px 0 0;
  color: var(--fg-3);
  font-size: 0.875rem;
}

/* Looks like the line it replaces, until you go near it. A dashed underline is
   the whole affordance -- a pencil icon on a one-word field is more furniture
   than field. */
.role-edit {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  cursor: text;
  border-bottom: 1px dashed var(--line-strong);
}

.role-edit:hover,
.role-edit:focus-visible { color: var(--fg-1); }

.person-id p b { color: var(--brand-ink); }

/* What a person has, as two short lines with a mark each -- not two slabs. */
.person-status {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 14px;
}

.person-stat {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 14px 7px 8px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  font-size: 0.875rem;
}

.person-stat-icon {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--surface-3);
  color: var(--fg-4);
}

.person-stat-icon svg { width: 12px; height: 12px; }

.person-stat b { font-weight: 600; color: var(--fg); }
.person-stat span:last-child { color: var(--fg-3); }

.person-stat.is-done { border-color: transparent; background: var(--good-wash); }
.person-stat.is-done .person-stat-icon { background: var(--good); color: #fff; }
.person-stat.is-done span:last-child { color: var(--good); }

.person-stat.is-busy { border-color: transparent; background: var(--warn-wash); }
.person-stat.is-busy .person-stat-icon { background: var(--warn); color: #fff; }
.person-stat.is-busy span:last-child { color: var(--warn); }

.person-say {
  margin: 0 0 12px;
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--fg-2);
}

.person-say.is-good { color: var(--good); }

.person-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.person-manual {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--line-soft);
}

.person-manual > summary {
  color: var(--fg-3);
  font-size: 0.875rem;
  font-weight: 600;
  cursor: pointer;
}

.person-manual > summary:hover { color: var(--fg-1); }
.person-manual > summary::marker { color: var(--fg-4); }
.person-manual > .hint { margin: 10px 0 0; font-size: 0.8125rem; line-height: 1.5; color: var(--fg-3); }
.person-manual .person-block > .hint { margin: 8px 0 0; font-size: 0.8125rem; color: var(--fg-3); }

/* The photo, at its own size, with its buttons beside it -- not a black slab
   the width of the card with the picture lost in the middle. */
#personCard .logo-slot {
  grid-template-columns: 96px minmax(0, 220px);
  align-items: center;
  gap: 14px;
}

#personCard .logo-frame,
#personCard .logo-empty {
  width: 96px;
  height: 96px;
  padding: 0;
  border-radius: 14px;
  overflow: hidden;
}

#personCard .logo-frame img { width: 100%; height: 100%; max-height: none; object-fit: cover; }
#personCard .logo-slot > .connect-status { grid-column: 1 / -1; }

.person-block {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--line-soft);
}

.person-block h4 {
  margin: 0 0 10px;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--fg-3);
}

/* Three inputs and a button in one row is unreadable on a phone, which is
   where this is used. Name takes a line, role and mobile share the next. */
.staff-add {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 14px;
  padding: 14px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
  background: var(--surface-2);
}

.staff-add[hidden] { display: none !important; }

.staff-add-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex: 1 1 100%;
  grid-column: 1 / -1;
  font-size: 0.875rem;
}

.staff-add-head b { font-weight: 600; color: var(--fg); }
.staff-add .staff-add-head .btn-link { flex: none; font-size: 0.8125rem; }

.staff-add #staffName { flex: 1 1 100%; }

.staff-add #staffRole,
.staff-add #staffPhone { flex: 1 1 40%; }

.staff-add button { flex: 1 1 100%; }

/* Four fields and a submit wrapped into two ragged flex rows, which left Add
   as a 60px button squeezed onto the end of the email line — the one control
   that commits the form, drawn as an afterthought. A 2x2 grid with the action
   on its own row says what the form is and where it ends. */
@media (min-width: 620px) {
  .staff-add {
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: start;
  }

  .staff-add button {
    grid-column: 1 / -1;
    justify-self: end;
  }
}

.staff-add input {
  min-width: 0;
  flex: 1;
  padding: 9px 11px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--field);
  color: var(--fg);
  font: inherit;
  font-size: 0.875rem;
}

.staff-add input:focus-visible {
  outline: none;
  border-color: var(--brand);
}


/* ---------- The self-enrolment page ----------
   Opened on a phone, by somebody who has never seen this product and did not
   ask to. One column, generous type, nothing to navigate. */

/* Opened from a text message, on a phone, by somebody who has never seen this
   product: the soft wash says "someone made this for you", the steps are
   numbered and tick off, and the reassurance is a note, not the loudest
   paragraph on the page. */
body:has(> .join) {
  background:
    radial-gradient(80% 40% at 50% -6%, var(--brand-wash) 0%, transparent 70%),
    var(--bg);
}

/* The body is a centring flex row, so without a width the column shrank to
   its content: a dead link's one short card came out narrower than the page. */
.join {
  width: 100%;
  max-width: 560px;
  margin: 0 auto;
  padding: 0 16px 48px;
}

.join .card > .hint { margin: 0; font-size: 0.875rem; line-height: 1.5; color: var(--fg-3); }

.join-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 22px 0 14px;
}

.join .card { margin-bottom: 14px; border-radius: var(--r-lg); }

.join-hello h1 {
  margin: 0 0 8px;
  font-size: 1.75rem;
  letter-spacing: -0.02em;
}

.join-hello .card-head p { font-size: 0.9375rem; line-height: 1.6; color: var(--fg-2); }
.join-hello .card-head p b { color: var(--fg); }

.join-note {
  display: flex;
  gap: 10px;
  margin: 4px 0 0;
  padding: 12px 14px;
  border-radius: var(--r-md);
  background: var(--surface-2);
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--fg-2);
}

.join-note svg { flex: none; width: 17px; height: 17px; margin-top: 1px; color: var(--good); }

.join-step h2 { display: flex; align-items: center; gap: 10px; }

.join-num {
  display: grid;
  place-items: center;
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--brand-ink);
  color: var(--on-brand);
  font-size: 0.8125rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* A step that is done says so where the number was. */
.join-step:has(.join-done:not([hidden])) .join-num {
  font-size: 0;
  background: var(--good) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E") center / 13px no-repeat;
}

.join .consent-row { margin: 14px 0; }
.rec-playback { width: 100%; margin-bottom: 14px; }

.join-done {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 12px;
  padding: 10px 12px;
  border-radius: var(--r-sm);
  background: var(--good-wash);
  color: var(--good);
  font-weight: 600;
  font-size: 0.875rem;
}

.join-done::before { content: "\2713"; }

.join-foot {
  margin: 20px 4px 0;
  color: var(--fg-3);
  font-size: 0.8125rem;
  line-height: 1.5;
}



.person-stat.is-busy {
  border-color: var(--warn);
  background: var(--warn-wash);
}

.person-stat.is-busy b,
.person-stat.is-busy span { color: var(--warn); }

.join-shot {
  display: block;
  width: 128px;
  height: 128px;
  margin: 0 0 12px;
  border-radius: var(--r-md);
  object-fit: cover;
  border: 1px solid var(--line);
}

.staff-mismatch {
  margin-top: 12px;
  padding: 12px 14px;
  border: 1px solid var(--warn);
  border-radius: var(--r-sm);
  background: var(--warn-wash);
}

.staff-mismatch p {
  margin: 0 0 10px;
  color: var(--warn);
  font-size: 0.875rem;
  line-height: 1.5;
}

/* ---------- Sending the invite ----------
   A row of ordinary links, because that is what they are: each one opens an app
   the manager already has, with the message already written. */

.invite-share {
  margin: 14px 0 0;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface-2);
}

.invite-hint {
  margin: 0 0 10px;
  color: var(--fg-2);
  font-size: 0.875rem;
  line-height: 1.5;
}

.invite-channels {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.invite-channels .btn { text-decoration: none; }

.staff-add #staffEmail { flex: 1 1 100%; }

.invite-hint.is-bad { color: var(--bad); }

/* The scene script, as somebody would read it on a page before agreeing to
   shoot it. Monospace because it is laid out in columns, and scrollable because
   a four-line scene with its cast notes is taller than a sheet. */
/* The caveat under the script, in the sheet where the clips are bought. */
.scene-beta {
  margin: 10px 0 0;
  padding: 10px 12px;
  border-radius: var(--r-sm);
  background: var(--warn-wash);
  color: var(--warn);
  font-size: 0.8125rem;
  line-height: 1.5;
}

.scene-script {
  margin: 0;
  padding: 14px;
  max-height: 46vh;
  overflow: auto;
  white-space: pre-wrap;
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.65;
  color: var(--fg);
  background: var(--surface-2);
  border-radius: var(--r-sm);
}

/* The ask box above the composer: one line, the input takes the room. */

/* ---- The form: the older composer beside the box ---- */
.compose-way { margin-bottom: 12px; }
.composer .is-other-way { display: none; }

.compose-grid {
  display: grid;
  /* The media side leads: it is the part being judged, and the options are
     short. Not 50/50 — a column of selects does not need half a page. */
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 22px;
  align-items: start;
}
.compose-grid[hidden] { display: none; }
.compose-media { min-width: 0; }
.compose-side { min-width: 0; display: flex; flex-direction: column; }
.compose-side .seg-mini { align-self: flex-start; margin-bottom: 14px; }
.compose-side .field { margin-bottom: 14px; }
.compose-side .compose-pick { margin-bottom: 14px; }
.field-pair-tight { gap: 8px; margin-bottom: 6px; }

/* Named rather than bare `.dropzone`: `.field label` in brand.css otherwise
   forces display:block and collapses the icon, title and hint onto one line. */
.compose-media .dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 40px 18px;
  border: 1.5px dashed var(--line-strong);
  border-radius: var(--r-md);
  background: var(--surface-2);
  cursor: pointer;
  text-align: center;
  transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease);
}
.compose-media .dropzone svg { width: 22px; height: 22px; margin-bottom: 5px; color: var(--fg-3); }
.compose-media .dropzone b { margin: 0; color: var(--fg); font-size: 0.875rem; font-weight: 600; }
.compose-media .dropzone span { font-size: 0.8125rem; color: var(--fg-3); }
.compose-media .file-list { margin-top: 12px; }


@media (max-width: 720px) {
  .compose-grid { grid-template-columns: minmax(0, 1fr); gap: 16px; }
}

/* ---- Worth boosting ----

   Sits inside the recommended drop's card, under the "Live on @handle" stamp.
   It is the only thing in the feed that asks for money, so it is the only
   thing carrying the brand wash -- everything around it is neutral, and that
   contrast is doing the whole job of drawing the eye.

   All tokens, so dark mode follows on its own. */
.boost-note {
  margin: 12px 0 0;
  padding: 12px 13px;
  border: 1px solid var(--brand-wash);
  border-left: 3px solid var(--brand);
  border-radius: var(--r-sm);
  background: var(--brand-wash);
}

.boost-note-head {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--brand-strong);
}

.boost-note-head svg { flex: none; }

.boost-note-head b {
  font-size: 0.875rem;
  font-weight: 650;
}

.boost-note-why {
  margin: 5px 0 0;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--fg);
}

/* The working, deliberately quieter than the recommendation it supports --
   there to be checked, not to be read every time. */
.boost-note-evidence {
  margin: 3px 0 10px;
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--fg-2);
}

/* Says "this is a sample" on the card itself. A screenshot outlives the query
   string it was taken under, and a made-up 3.2x passed round as real is the
   exact failure the rest of this loop exists to prevent. */
.boost-note-tag {
  margin-left: auto;
  padding: 1px 6px;
  border: 1px solid var(--brand);
  border-radius: var(--r-pill);
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--brand-strong);
}

/* The multiple, given the weight it deserves. It is the one number the decision
   turns on, and as a word in a sentence it read like every other number. */
.boost-proof {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 10px;
}

.boost-multiple {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-right: 14px;
  border-right: 1px solid var(--brand);
  line-height: 1.05;
}

.boost-multiple b {
  font-size: 1.625rem;
  font-weight: 700;
  color: var(--brand-strong);
  font-variant-numeric: tabular-nums;
}

.boost-multiple span {
  margin-top: 2px;
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--fg-3);
}

.boost-bars {
  flex: 1;
  min-width: 0;
  display: grid;
  gap: 4px;
}

/* Two bars scaled against each other rather than one bar against a maximum
   nobody chose. The comparison is the whole argument, so it is the thing drawn:
   a long bar over a short one says "ahead of normal" before a word is read. */
.boost-bar {
  display: grid;
  grid-template-columns: 4.6rem 1fr 2.2rem;
  align-items: center;
  gap: 7px;
  font-size: 0.6875rem;
}

.boost-bar-label { color: var(--fg-3); }

.boost-bar-track {
  height: 7px;
  border-radius: 4px;
  background: var(--surface-3);
  overflow: hidden;
}

.boost-bar-fill {
  display: block;
  height: 100%;
  border-radius: 4px;
  background: var(--fg-4);
}

.boost-bar.is-mine .boost-bar-fill { background: var(--brand); }
.boost-bar.is-mine .boost-bar-label { color: var(--fg-2); font-weight: 600; }

.boost-bar-value {
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--fg-2);
}

/* The half of the evidence an owner cannot check from their own phone: that the
   post has not already peaked. Only drawn when two readings exist to say so. */
.boost-climb {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin: 7px 0 9px;
  padding: 2px 7px;
  border-radius: var(--r-pill);
  background: var(--good-wash);
  color: var(--good);
  font-size: 0.6875rem;
  font-weight: 600;
}

.boost-climb svg { flex: none; }

/* What the money buys. Three facts to be scanned, rather than the same three
   numbers buried in a sentence that has to be read to the end. */
.boost-terms {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 10px;
}

.boost-terms span {
  display: flex;
  flex-direction: column;
  flex: 1 1 4.5rem;
  padding: 6px 9px;
  border-radius: var(--r-sm);
  background: var(--surface);
  font-size: 0.625rem;
  line-height: 1.3;
  color: var(--fg-3);
}

.boost-terms b {
  font-size: 0.8125rem;
  font-weight: 650;
  color: var(--fg);
}

/* A boost already running is a status line, not a card of argument. Same
   family, a fraction of the weight. */
.boost-note.is-live {
  padding: 9px 12px;
  background: var(--surface-2);
  border-color: var(--line);
  border-left-color: var(--good);
}

.boost-note-done {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--brand-strong);
}

/* Live, and saying so without a word. Money is going out right now, which is
   worth one steady mark on the card. */
.boost-live-dot {
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: 50%;
  background: var(--good);
  box-shadow: 0 0 0 3px var(--good-wash);
}

.boost-note-cap {
  margin: 7px 0 0;
  font-size: 0.6875rem;
  text-align: center;
  color: var(--fg-3);
}

/* ---------- Boost settings ----------
   Two states, and the quiet one is the common one. A restaurant with no ad
   account gets a sentence and one button, not five credential fields. */

.boost-connect {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

.boost-connect p {
  margin: 0 0 10px;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--fg-2);
}

.boost-connected {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  display: grid;
  gap: 12px;
}

.boost-account-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.boost-account-row b {
  display: block;
  font-size: 0.875rem;
}

.boost-account-row span {
  font-size: 0.75rem;
  color: var(--fg-3);
  font-variant-numeric: tabular-nums;
}

.boost-ad-account {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

.boost-ad-account code {
  padding: 1px 4px;
  border-radius: 3px;
  background: var(--surface-2);
  font-size: 0.75rem;
}

/* The dollar lives outside the field rather than inside the number, so what is
   typed stays a number the browser can step and validate. */
.boost-cap-field {
  display: flex;
  align-items: center;
  gap: 6px;
}

.boost-cap-field span {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--fg-3);
}

.boost-cap-field .input { flex: 1; }

/* What is true right now rather than what could be: the deployment switch, and
   anything the ledger could not answer. */
.boost-settings-state {
  margin: 14px 0 0;
  padding: 9px 11px;
  border-radius: var(--r-sm);
  background: var(--gold-wash);
  color: var(--gold);
  font-size: 0.75rem;
  line-height: 1.5;
}

.boost-settings-actions #btnDisconnectAdAccount { order: -2; margin-right: auto; }

/* ---- One save bar for every settings form ----
   It was a full-width grey slab between cards whether or not anything had
   changed, and the one time it mattered -- an edit halfway down a long form --
   it was off the bottom of the screen. Now it sits quietly at the form's end
   until something changes, then rides the bottom of the screen with the
   change named, until it is saved. */
.savebar {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  margin: 4px 0 16px;
  transition: box-shadow 0.18s var(--ease), background-color 0.18s var(--ease);
}

.savebar .btn { width: auto; min-width: 150px; }

.savebar .btn-primary:disabled {
  background: transparent;
  border: 1px solid var(--line);
  box-shadow: none;
  color: var(--fg-4);
  opacity: 1;
}

.savebar-note {
  display: none;
  align-items: center;
  gap: 8px;
  margin-right: auto;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--fg);
}

.savebar-note::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--warn);
}

.savebar:has(> .btn-primary:not(:disabled)) {
  position: sticky;
  bottom: 16px;
  z-index: 20;
  padding: 10px 10px 10px 18px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: var(--shadow-3);
}

.savebar:has(> .btn-primary:not(:disabled)) > .savebar-note { display: inline-flex; }

/* The phone's tab bar is fixed along the bottom; the bar rides above it. */
@media (max-width: 760px) {
  .savebar:has(> .btn-primary:not(:disabled)) { bottom: calc(var(--savebar-lift, 132px) + env(safe-area-inset-bottom)); }
  .savebar .btn { min-width: 0; }
}

@media (max-width: 420px) {
  .boost-proof { gap: 10px; }
  .boost-multiple { padding-right: 10px; }
  .boost-bar { grid-template-columns: 4rem 1fr 2rem; }
}

/* ==========================================================================
   Fill the Cut & Edit the Cut (Timeline Strip, Gaps, Asks & Veo Meter)
   ========================================================================== */

/* Editing a video wants room: the drop editor is as close to the whole
   window as a dialog gets, and the phone preview stays beside both panes. */
/* Editing a post is two things at once: the post, and what there is to change
   about it. They sit side by side — the preview on its own dark stage, the
   form beside it — so nothing being edited is ever off screen. */
.sheet-editor {
  max-width: 1120px;
  width: 96vw;
  height: calc(100vh - 32px);
  padding: 0;
  display: grid;
  grid-template-columns: minmax(250px, 380px) 1fr;
  overflow: hidden;
}

.editor-stage {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 20px;
  overflow-y: auto;
  /* Held dark in both themes: it is a stage for a picture, not a surface. */
  background: #16203a;
  background-image: radial-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px);
  background-size: 14px 14px;
}

.editor-stage-head,
.editor-stage-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.editor-stage-foot {
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  margin-top: auto;
}

.editor-stage-label {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.5);
}

.editor-stage-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 11px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.editor-stage .picks { margin: 0; }
.editor-stage .picks-hint { color: rgba(255, 255, 255, 0.5); }

.editor-form {
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding: 20px 22px 0;
  background: var(--surface);
}

#editorSheet .sheet-head { margin-bottom: 1rem; }

#editorSheet .sheet-head p {
  font-size: 0.8125rem;
  color: var(--fg-3);
}

.editor-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding-bottom: 14px;
}

/* One row of choices, not a row of links: the tabs read as a switch. */
.editor-tabs {
  display: flex;
  gap: 4px;
  padding: 4px;
  margin-bottom: 16px;
  border-radius: var(--r-md);
  background: var(--surface-2);
}

.editor-tabs[hidden] { display: none; }

.editor-tab {
  flex: 1;
  padding: 8px 14px;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--fg-2);
  background: transparent;
  border: none;
  border-radius: var(--r-sm);
  cursor: pointer;
}

.editor-tab:hover { color: var(--fg); }

.editor-tab.is-on {
  color: var(--fg);
  background: var(--surface);
  box-shadow: var(--shadow-1);
}

/* The footer belongs to the drop, not to the open tab, so it stays put while
   the pane above it scrolls. */
.editor-foot {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 0 14px;
  border-top: 1px solid var(--line);
  background: var(--surface);
}

.editor-foot .hint { max-width: 34ch; }

/* Narrow, the note squeezes into a column of two-word lines and pushes the
   buttons off the bottom. The buttons are the part that has to be there. */
@media (max-width: 900px) {
  .editor-foot .hint { display: none; }
}

.editor-foot-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}

/* Side by side for as long as there is room for both: the window a portal is
   read in is often half a laptop screen, and stacking it there would hide the
   post under the form it is being edited with. */
@media (max-width: 700px) {
  .sheet-editor {
    grid-template-columns: 1fr;
    grid-template-rows: auto 1fr;
  }

  .editor-stage { padding: 14px; }
  .editor-stage .cut-phone { max-width: 190px; }
  .editor-form { padding: 14px 16px 0; }
}

.cut-preview-area {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.cut-phone {
  width: 100%;
  max-width: 300px;
  aspect-ratio: 9 / 16;
  border-radius: 12px;
  background: #000;
  border: 1px solid var(--line);
  position: relative;
  overflow: hidden;
  box-shadow: var(--shadow-2);
}

.cut-phone video,
.cut-phone img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* A still is not a reel and is not shot to a reel's frame. Cropped to 9:16 by
   the rule above, a 4:5 slide lost a strip off each side -- which on a slide
   is where the headline starts, so the owner was approving a picture whose
   first word was off screen. The post's own shape, and nothing cropped: these
   are the exact pixels that publish. */
.cut-phone.is-still { aspect-ratio: 4 / 5; }
.cut-phone.is-still img { object-fit: contain; }

/* display:block above outranks the browser's own [hidden] rule, so the
   player and the still each need telling. */
.cut-phone video[hidden],
.cut-phone img[hidden] { display: none; }

.cut-phone-hook {
  position: absolute;
  top: 12px;
  left: 8px;
  right: 8px;
  font-family: var(--sans);
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  color: #fff;
  letter-spacing: 0.03em;
  text-shadow: 0 1px 3px rgba(0,0,0,0.85);
  pointer-events: none;
  line-height: 1.2;
}

.cut-phone-sub {
  position: absolute;
  bottom: 28px;
  left: 8px;
  right: 8px;
  font-family: var(--sans);
  font-size: 0.625rem;
  line-height: 1.3;
  color: #fff;
  background: rgba(18, 21, 31, 0.75);
  backdrop-filter: blur(4px);
  padding: 4px 6px;
  border-radius: 4px;
  pointer-events: none;
  min-height: 20px;
  transition: opacity 0.15s ease;
}

.cut-phone-time {
  position: absolute;
  bottom: 6px;
  left: 8px;
  font-family: var(--mono);
  font-size: 0.625rem;
  color: rgba(255,255,255,0.75);
  pointer-events: none;
}

/* Timeline & strip area */
.cut-timeline-area {
  min-width: 0;
  display: flex;
  flex-direction: column;
}

#editorSheet .strip-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 0.8125rem;
  color: var(--fg-3);
  margin-bottom: 8px;
}

#editorSheet .strip-head b {
  font-weight: 600;
  color: var(--fg);
}

.cut-strip-hint {
  font-size: 0.75rem;
  color: var(--fg-3);
}

/* Read back, not a warning: what the worker already put right. */
.cut-repairs {
  list-style: none;
  margin: 10px 0 0;
  padding: 0;
  display: grid;
  gap: 5px;
}

.cut-repairs li {
  position: relative;
  padding-left: 20px;
  font-size: 0.75rem;
  line-height: 1.4;
  color: var(--fg-2);
}

.cut-repairs li::before {
  content: "\2713";
  position: absolute;
  left: 3px;
  font-weight: 700;
  color: var(--good);
}

#editorSheet .strip {
  display: flex;
  gap: 4px;
  height: 156px;
  overflow-x: auto;
  padding: 4px 0;
  align-items: stretch;
}

#editorSheet .shot {
  position: relative;
  border-radius: 6px;
  padding: 6px 7px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  background: var(--surface-2);
  border: 1px solid var(--line);
  min-width: 96px;
  cursor: grab;
  user-select: none;
  transition: transform 0.12s var(--ease), border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}

#editorSheet .shot:hover {
  border-color: var(--line-strong);
}

#editorSheet .shot .thumb {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 5px;
  opacity: 0.34;
  pointer-events: none;
}

#editorSheet .shot > div {
  position: relative;
}

#editorSheet .shot:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 1px;
}

#editorSheet .shot:active {
  cursor: grabbing;
}

#editorSheet .shot.is-dragging {
  opacity: 0.4;
  transform: scale(0.96);
}

#editorSheet .shot.is-drop-target {
  border-color: var(--brand);
  box-shadow: 0 0 0 2px var(--brand-wash);
}

#editorSheet .shot.is-on {
  outline: 2px solid var(--brand);
  outline-offset: -1px;
}

#editorSheet .shot.is-playing {
  box-shadow: 0 0 0 2px var(--good);
}

#editorSheet .shot .k {
  font-family: var(--mono);
  font-size: 0.625rem;
  gap: 4px;
  white-space: nowrap;
  overflow: hidden;
  font-weight: 500;
  color: var(--fg-3);
  display: flex;
  justify-content: space-between;
  align-items: center;
}

#editorSheet .shot .k i {
  font-style: normal;
  width: 7px;
  height: 7px;
  border-radius: 2px;
  display: inline-block;
}

#editorSheet .shot.clip .k i { background: var(--shot-clip); }
#editorSheet .shot.photo .k i { background: var(--shot-photo); }
#editorSheet .shot.lib .k i { background: var(--shot-lib); }
#editorSheet .shot.gen {
  border-color: var(--shot-gen);
  background: var(--violet-wash);
}
#editorSheet .shot.gen .k i { background: var(--shot-gen); }
#editorSheet .shot.gen.is-on { outline-color: var(--shot-gen); }

#editorSheet .shot .say {
  font-size: 0.6875rem;
  line-height: 1.25;
  color: var(--fg-2);
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
}

#editorSheet .shot .s {
  font-family: var(--mono);
  font-size: 0.625rem;
  font-weight: 500;
  color: var(--fg);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Gap styles */
#editorSheet .gap {
  border: 1px dashed var(--warn);
  border-radius: 6px;
  background: repeating-linear-gradient(135deg, var(--warn-wash) 0 6px, transparent 6px 12px);
  padding: 6px 7px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 4px;
  min-width: 132px;
}

#editorSheet .gap .k {
  font-size: 0.6875rem;
  font-weight: 700;
  color: var(--warn);
}

#editorSheet .gap .say {
  font-size: 0.625rem;
  line-height: 1.2;
  color: var(--fg-2);
}







/* Veo Meter */
#editorSheet .meter {
  margin-top: 12px;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.75rem;
  color: var(--fg-2);
  padding: 6px 0;
}

#editorSheet .meter .bar {
  flex: 1;
  height: 6px;
  border-radius: 3px;
  background: var(--surface-3);
  overflow: hidden;
}

#editorSheet .meter .bar i {
  display: block;
  height: 100%;
  background: var(--violet);
  transition: width 0.3s ease, background-color 0.2s ease;
}

#editorSheet .meter.is-warn .bar i {
  background: var(--warn);
}

#editorSheet .meter .n {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.75rem;
}

/* Shot Edit Panel */
#editorSheet .panel {
  margin-top: 14px;
  border-top: 1px dashed var(--line);
  padding-top: 12px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  font-size: 0.8125rem;
}

@media (max-width: 640px) {
  #editorSheet .panel { grid-template-columns: 1fr; }
}

#editorSheet .panel label {
  display: block;
  font-family: var(--sans);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg-3);
  margin-bottom: 5px;
}

#editorSheet .panel .v {
  font-family: var(--mono);
  font-size: 0.75rem;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 6px 8px;
  color: var(--fg);
}

#editorSheet .panel .v.text {
  font-family: var(--sans);
  font-size: 0.75rem;
  max-height: 48px;
  overflow-y: auto;
  line-height: 1.35;
}

.cut-field-row {
  display: flex;
  align-items: center;
  gap: 6px;
}

.cut-field-row .input-sm {
  width: 74px;
  padding: 4px 6px;
  font-size: 0.75rem;
}

/* Buttons in panel */
#editorSheet .btnrow {
  grid-column: 1 / -1;
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 4px;
}

#editorSheet .b {
  font-family: var(--sans);
  font-size: 0.75rem;
  font-weight: 500;
  padding: 6px 11px;
  border-radius: 6px;
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--fg);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  transition: background-color 0.15s, border-color 0.15s;
}

#editorSheet .b:hover {
  background: var(--surface-2);
}

.cut-take-picker {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.75rem;
}

.cut-take-picker select {
  padding: 3px 6px;
  font-size: 0.75rem;
}

/* Swap picker */
.cut-swap-modal {
  margin-top: 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 12px;
  background: var(--surface-2);
}

.cut-swap-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
  font-size: 0.8125rem;
  font-weight: 600;
}

.cut-swap-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(105px, 1fr));
  gap: 8px;
  max-height: 200px;
  overflow-y: auto;
  padding: 2px;
}

.cut-swap-item {
  position: relative;
  aspect-ratio: 9 / 16;
  border-radius: 6px;
  overflow: hidden;
  border: 2px solid transparent;
  cursor: pointer;
  background: #000;
  transition: border-color 0.15s, transform 0.12s;
}

.cut-swap-item:hover {
  border-color: var(--brand);
  transform: scale(1.02);
}

.cut-swap-item img, .cut-swap-item video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.cut-swap-badge {
  position: absolute;
  bottom: 4px;
  left: 4px;
  font-size: 0.625rem;
  padding: 1px 4px;
  border-radius: 3px;
  background: rgba(0,0,0,0.65);
  color: #fff;
  font-family: var(--mono);
}

/* ---------- The menu, as a customer reads it ---------- */

/* A menu is read at a glance across the page, not scrolled through a
   430px slot. The sheet takes most of the window, the head stays put, and
   only the menu itself scrolls. */
.sheet.sheet-menu {
  max-width: 1040px;
  width: 96vw;
  height: calc(100vh - 32px);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: 1.4rem 1.6rem;
}

.sheet-menu .sheet-head { flex: none; }

.menu-preview {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 4px 12px 8px;
}

/* Two columns of sections once there is room, the way a printed menu sets
   them; a section never breaks across the columns. The columns sit inside
   the scroller, not on it: a multicol box with a fixed height spills its
   extra columns off to the side instead of scrolling down. */
@media (min-width: 820px) {
  .menu-preview-cols {
    column-count: 2;
    column-gap: 48px;
  }
  .menu-preview-cat {
    break-inside: avoid;
    margin-bottom: 26px;
  }
  .menu-preview-cat + .menu-preview-cat { margin-top: 0; }
}

.menu-preview-place {
  margin: 4px 0 24px;
  text-align: center;
  font-size: 1.375rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg);
}

.menu-preview-cat + .menu-preview-cat {
  margin-top: 22px;
}

.menu-preview-cat h5 {
  margin: 0 0 10px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-3);
}

.menu-preview-row {
  display: flex;
  gap: 12px;
  padding: 9px 0;
}

.menu-preview-row + .menu-preview-row {
  border-top: 1px solid var(--line);
}

.menu-preview-photo {
  width: 52px;
  height: 52px;
  flex: none;
  border-radius: 6px;
  object-fit: cover;
}

.menu-preview-main { flex: 1; min-width: 0; }

/* Name, then a rule to the price, the way a printed menu runs it. */
.menu-preview-line {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 0.9375rem;
}

.menu-preview-leader {
  flex: 1;
  border-bottom: 1px dotted var(--line-strong);
  transform: translateY(-3px);
}

.menu-preview-noprice {
  font-size: 0.75rem;
  font-style: italic;
  color: var(--warn);
}

.menu-preview-main p {
  margin: 3px 0 0;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--fg-2);
}

.menu-preview-tags {
  display: inline-block;
  margin-top: 4px;
  font-size: 0.75rem;
  color: var(--fg-3);
}

.menu-preview-gaps {
  flex: none;
  margin: 14px 0 0;
  padding-top: 10px;
  border-top: 1px solid var(--line);
}

/* ---------- A post that is several pictures ---------- */

/* Instagram stamps a carousel so you know there is more than one frame. The
   feed card shows the first slide and nothing else, so without this the owner
   approves what looks like a single photograph. */
.drop-slides {
  position: absolute;
  top: 10px;
  right: 46px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 8px;
  border-radius: var(--r-pill);
  background: rgba(8, 12, 20, 0.66);
  backdrop-filter: blur(6px);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 700;
  line-height: 1;
}

/* The dots and arrows under the editor's preview. */
.slide-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
}

.slide-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  cursor: pointer;
}

.slide-arrow:hover:not(:disabled) { background: rgba(255, 255, 255, 0.22); }
.slide-arrow:disabled { opacity: 0.3; cursor: default; }

.slide-dots { display: flex; align-items: center; gap: 7px; }

.slide-dot {
  width: 7px;
  height: 7px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.3);
  cursor: pointer;
}

/* The one being edited is wider, not just brighter: on a phone-sized preview
   a brightness difference between two 7px dots is not a difference. */
.slide-dot.is-on {
  width: 20px;
  border-radius: var(--r-pill);
  background: #fff;
}

/* ---------- The words set on one slide ---------- */

.slide-words {
  padding-bottom: 4px;
  margin-bottom: 16px;
  border-bottom: 1px solid var(--line);
}

.slide-words-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
}

.slide-words-head .editor-stage-label { color: var(--fg-3); }

.slide-badge {
  padding: 3px 9px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  color: var(--fg-2);
  font-size: 0.6875rem;
  font-weight: 700;
}

.field-aside {
  margin-left: 6px;
  color: var(--fg-3);
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
}

.slide-note { margin: 4px 0 0; }

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

.slide-step { display: flex; align-items: center; gap: 8px; }

/* The same disc the renderer draws, so the row in the form reads as the row
   that will be on the picture. */
.slide-step-n {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--brand);
  color: #14110a;
  font-size: 0.75rem;
  font-weight: 700;
}

.slide-step input { flex: 1 1 auto; min-width: 0; }
.slide-step-cut { flex: 0 0 auto; }

.slide-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 14px 0 6px;
}

/* ---------- Picking a time ---------- */

.slot-picks {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}

.slot-pick {
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--fg);
  font-size: 0.8125rem;
  font-weight: 600;
  cursor: pointer;
}

.slot-pick:hover { border-color: var(--brand); }

.slot-pick.is-on {
  border-color: var(--brand);
  background: var(--brand-wash);
}

.slot-when { display: flex; gap: 8px; }
.slot-when .input { flex: 1 1 0; min-width: 0; }

.slot-says {
  margin: 12px 0 0;
  padding: 10px 12px;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  font-size: 0.8125rem;
  font-weight: 600;
}

.slot-says.is-bad { color: var(--bad); }

@media (max-width: 560px) {
  .slot-picks { grid-template-columns: 1fr; }
}

.account-plan-head > div { min-width: 0; }
.account-plan-head .plan-title { display: block; }
.account-billing-link { display: inline-flex; margin-top: 8px; }
.nav-plan-btn { white-space: nowrap; flex-shrink: 0; }
#navAddRestaurant svg { width: 17px; height: 17px; }
/* "Add restaurant" on an account that is already at its plan's location limit.
   Still a live control -- it goes to the plans, which is the only answer to it
   -- but it should not read as the plain next step the way it does with room
   left. Not `disabled`: a dead button explains nothing. */
#navAddRestaurant.is-locked { opacity: 0.55; }
#navAddRestaurant.is-locked:hover { opacity: 1; }
.settings-plan-line { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0 0 4px; }
#sectionBilling .btn-primary { margin-top: 14px; }
.plan-head-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
/* The portal's own small round controls, given the finger-height target
   described over .icon-btn in brand.css: the paint stays put, the area that
   answers a touch grows to 44px tall around it. Growing sideways instead would
   push each target 5-8px past its paint and into the 8px gap beside it, so a
   sign-out would start answering for the control next to it. .prompt-box's
   remove button keeps its own absolute placement -- that rule is more specific
   and still wins. */
.btn-logout,
.btn-icon-subtle,
.file-remove-btn,
.slide-arrow {
  position: relative;
}

.btn-logout::after,
.btn-icon-subtle::after,
.file-remove-btn::after,
.slide-arrow::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: max(100%, 24px);
  height: 44px;
  transform: translate(-50%, -50%);
}

/* ---------- Touch keeps the 16px floor ----------
   The rest of the controls that sit under 16px are deliberately dense: a
   trim box 74 pixels wide, a take picker inside a button row, the place
   switcher reading as a line of text rather than a field. At a desk that
   density is the point, and a mouse never triggers the zoom -- so they keep
   their size there and meet the floor only where a finger is doing the
   tapping. Gated on the pointer rather than the width, because a narrow
   window on a laptop is still a mouse. */
@media (pointer: coarse) {
  .place-select,
  .staff-add input,
  .cut-field-row .input-sm,
  .cut-take-picker select {
    font-size: 1rem;
  }
}

/* ---------- Plan & billing: Settings ---------- */
.billing-summary-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.billing-plan-name {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 4px 0 4px;
  font-family: var(--display);
}
.billing-summary-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.billing-alert {
  margin: 14px 0 0;
  padding: 10px 12px;
  border-radius: var(--r-sm);
  background: var(--warn-wash);
  color: var(--warn);
  font-size: 0.875rem;
  font-weight: 500;
}

.billing-locations {
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  padding: 10px 14px 12px;
  margin: 0 0 16px;
}
.billing-locations legend { padding: 0 6px; font-size: 0.8125rem; font-weight: 600; color: var(--fg-2); }
.billing-location-list { display: flex; flex-wrap: wrap; gap: 6px 18px; }
.billing-location { display: inline-flex; align-items: center; gap: 8px; font-size: 0.875rem; cursor: pointer; }

.billing-tiers {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 12px;
}
.billing-tier {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 16px;
  border-radius: var(--r-md, 14px);
  border: 1px solid var(--line);
  background: var(--surface);
  min-width: 0;
}
.billing-tier.is-current {
  border-color: var(--brand);
  box-shadow: 0 0 0 1px var(--brand) inset;
  background: color-mix(in srgb, var(--brand-wash) 45%, var(--surface));
}
.billing-tier-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.billing-tier-head h3 { margin: 0; font-size: 1rem; }
.billing-tier-price { margin: 0; display: flex; align-items: baseline; gap: 4px; }
.billing-tier-price b { font-size: 1.625rem; font-variant-numeric: tabular-nums; }
.billing-tier-price span { color: var(--fg-3); font-size: 0.8125rem; }
.billing-tier-allow { margin: 0; color: var(--fg-2); font-size: 0.875rem; }
.billing-tier-features {
  margin: 2px 0 6px;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 5px;
  font-size: 0.8125rem;
  color: var(--fg-2);
  flex: 1;
  align-content: start;
}
.billing-tier-features li { position: relative; padding-left: 18px; }
.billing-tier-features li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 0.35em;
  width: 8px;
  height: 4px;
  border-left: 2px solid var(--good);
  border-bottom: 2px solid var(--good);
  transform: rotate(-45deg);
}
.billing-tier .btn { width: 100%; justify-content: center; }
.billing-msg { margin: 12px 0 0; font-size: 0.875rem; color: var(--fg-2); min-height: 1.2em; }
.billing-msg.is-bad { color: var(--bad); }

/* ---------- Account window ----------
   A settings window like the ones people already know: sections down the
   left, the chosen one on the right, rows of label + sentence + control. */
.sheet.account-sheet {
  max-width: 880px;
  height: min(600px, calc(100vh - 32px));
  padding: 0;
  display: grid;
  grid-template-columns: 210px minmax(0, 1fr);
  overflow: hidden;
}

.acc-nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 20px 12px;
  background: var(--surface-2);
  border-right: 1px solid var(--line);
}
.acc-nav-label { margin: 0 10px 10px; font-size: 0.8125rem; font-weight: 600; color: var(--fg-3); }
.acc-nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 10px;
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--fg-2);
  font: inherit;
  font-size: 0.9375rem;
  text-align: left;
  cursor: pointer;
}
.acc-nav-item svg { width: 18px; height: 18px; flex: none; }
.acc-nav-item:hover { background: var(--surface-3); color: var(--fg); }
.acc-nav-item.is-active { background: var(--surface); color: var(--fg); font-weight: 600; box-shadow: 0 0 0 1px var(--line); }
.acc-nav-item.is-active svg { color: var(--brand-ink); }

.acc-main { position: relative; overflow-y: auto; padding: 28px 32px 32px; }
.acc-close { position: absolute; top: 18px; right: 18px; }
.acc-pane[hidden] { display: none; }
.acc-title { margin: 0 0 20px; font-family: var(--display); font-weight: 600; font-size: 1.5rem; letter-spacing: -0.015em; }
.acc-lede { margin: -12px 0 20px; font-size: 0.875rem; color: var(--fg-3); }

.acc-who { display: flex; align-items: center; gap: 14px; min-width: 0; }
.acc-avatar {
  display: grid; place-items: center; flex: none;
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--grad-brand, var(--brand)); color: var(--on-brand);
}
.acc-who > div { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; min-width: 0; }
.acc-who b { font-size: 1rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }

.acc-profile { margin-top: 22px; }
.acc-profile-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.acc-profile-fields .field { margin: 0; min-width: 0; }
.acc-profile-foot { display: flex; justify-content: flex-end; margin-top: 14px; }
.acc-phone-proof {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 14px;
  margin-top: 18px;
  padding: 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface-2);
}
.acc-phone-proof b { display: block; font-size: 0.9375rem; }
.acc-phone-proof p { margin: 3px 0 0; color: var(--fg-3); font-size: 0.8125rem; }
.acc-phone-code {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: 10px;
}
.acc-phone-code[hidden] { display: none; }
.acc-phone-code label { grid-column: 1 / -1; font-size: 0.8125rem; font-weight: 600; }
.hint.is-good { color: var(--good); }
.acc-password-form {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  padding: 18px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface-2);
}
.acc-password-form[hidden] { display: none; }
.acc-password-form .field:first-child,
.acc-password-form .acc-profile-foot { grid-column: 1 / -1; }
.acc-password-form .field { margin: 0; min-width: 0; }
.acc-password-form + .acc-row { margin-top: 24px; }

.acc-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 18px 0;
  border-top: 1px solid var(--line);
}
.acc-profile + .acc-row,
.acc-plan-card + .acc-row,
.acc-plan-reset + .acc-row { margin-top: 24px; }
.acc-row b { display: block; font-size: 0.9375rem; color: var(--fg); }
.acc-row p { margin: 3px 0 0; font-size: 0.875rem; line-height: 1.45; color: var(--fg-3); max-width: 46ch; }
.acc-row .btn { flex: none; }
.acc-row [hidden] { display: none; }
.acc-row-danger b { color: var(--bad); }

.acc-plan-card {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 16px;
  padding: 18px;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--surface-2);
}
.acc-plan-mark {
  display: grid; place-items: center;
  width: 48px; height: 48px; border-radius: 12px;
  background: var(--brand-wash); color: var(--brand-ink);
}
.acc-plan-mark svg { width: 26px; height: 26px; }
.acc-plan-line { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.acc-plan-name { font-family: var(--display); font-weight: 600; font-size: 1.25rem; color: var(--fg); }
.acc-plan-renewal { display: block; margin-top: 3px; font-size: 0.875rem; color: var(--fg-2); }
.acc-plan-renewal:empty { display: none; }
.acc-plan-renewal.is-ending { color: var(--warn); font-weight: 600; }
.acc-plan-info .plan-sub { margin: 3px 0 0; font-size: 0.875rem; }
.acc-plan-actions { display: flex; flex-direction: column; gap: 8px; }
.acc-plan-actions [hidden] { display: none; }
.acc-plan-actions .btn { justify-content: center; white-space: nowrap; }

.acc-pane .account-plan-usage {
  display: grid;
  gap: 18px;
  margin: 0;
  padding: 20px;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--surface-2);
}
.account-plan-usage .usage-meter {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  justify-content: stretch;
  gap: 8px;
  font-size: 0.9375rem;
  color: var(--fg-2);
  min-width: 0;
}
.account-plan-usage .usage-label { white-space: normal; }
.account-plan-usage .usage-bar { width: 100%; height: 8px; border-radius: 4px; background: var(--line-strong); }
.account-plan-usage .usage-bar i { background: var(--brand); border-radius: 4px; }
.account-plan-usage .usage-reset { display: none; }
.acc-plan-reset { margin: 10px 0 0; font-size: 0.8125rem; color: var(--fg-3); }
.acc-plan-reset:empty { display: none; }

/* Phones: the sections become a row of tabs over the content. */
@media (max-width: 680px) {
  .sheet.account-sheet { grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr); height: calc(100vh - 32px); }
  .acc-nav { flex-direction: row; overflow-x: auto; padding: 10px; border-right: 0; border-bottom: 1px solid var(--line); }
  .acc-nav-label { display: none; }
  .acc-nav-item { width: auto; flex: none; }
  .acc-main { padding: 22px 18px 24px; }
  .acc-profile-fields { grid-template-columns: 1fr; }
  .acc-phone-proof,
  .acc-phone-code,
  .acc-password-form { grid-template-columns: 1fr; }
  .acc-plan-card { grid-template-columns: auto minmax(0, 1fr); }
  .acc-plan-actions { grid-column: 1 / -1; flex-direction: row; }
  .acc-plan-actions .btn { flex: 1; }
  .acc-row { flex-direction: column; align-items: flex-start; gap: 10px; }
}

/* ---------------- Drops, as a library ----------------
   The way the video tools lay out what they have made -- Sora's library,
   Runway's assets, Flow's scenes: a grid of the things themselves, each a
   picture with its name on it, the line it opens on and the one move that
   matters. Everything else a drop carries opens beside the player (the drop
   sheet below). The card used to carry all of it: hook, caption, tags, the
   notes, two folds, a primary button and three more, on every drop. */

@media (min-width: 900px) {
  /* A library wants the width a column of forms does not. On the app, not
     the view, so the place bar above lines up with the grid. */
  .app:has(#viewDrops.is-active) { --col: 1080px; }
}

#viewDrops .feed {
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 22px 16px;
}
@media (max-width: 560px) {
  #viewDrops .feed { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 10px; }
}

/* The tile is the picture: no box around the card, the picture rounded. */
#viewDrops .feed .drop {
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  overflow: visible;
}
#viewDrops .feed .drop-media {
  aspect-ratio: 3 / 4;
  border-radius: var(--r-md);
  overflow: hidden;
  box-shadow: var(--shadow-2);
  transition: box-shadow 0.18s var(--ease), transform 0.18s var(--ease);
}
@media (hover: hover) {
  #viewDrops .feed .drop-media:hover { box-shadow: var(--shadow-3); transform: translateY(-2px); }
}
/* A reel fills its tile, as it does in any grid of reels; the whole frame is
   in the drop's own view. A still keeps its frame whole over its blur. */
#viewDrops .feed .drop-media:not(.is-still) > video {
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  object-fit: cover;
}
#viewDrops .feed .drop-body { padding: 10px 2px 0; }

/* In the grid: the hook, two lines of caption, and the actions. */
#viewDrops .feed .drop-body > .tags,
#viewDrops .feed .drop-body > .caption-more,
#viewDrops .feed .drop-body > .notes-fold,
#viewDrops .feed .drop-body > .drop-folds,
#viewDrops .feed .drop-body > .picks,
#viewDrops .feed .drop-body > .take,
#viewDrops .feed .drop-body > .dub,
#viewDrops .feed .drop-body > .boost-note { display: none; }
#viewDrops .feed .drop-hook {
  display: block;
  margin-bottom: 3px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.875rem;
}
#viewDrops .feed .drop-hook > span:first-child { display: none; }
#viewDrops .feed .caption {
  min-height: calc(2em * 1.5);
  -webkit-line-clamp: 2;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--fg-2);
}
#viewDrops .feed .drop-actions { margin-top: 10px; gap: 6px; }
/* Still pinned to the foot, so a row of tiles puts its buttons on one line
   whatever each caption ran to. */
#viewDrops .feed .drop-body > .drop-actions:last-child,
#viewDrops .feed .drop-body > .stamp:last-child { margin-top: auto; padding-top: 10px; }
#viewDrops .feed .drop-actions .btn-block { min-height: 36px; padding-block: 0.5em; font-size: 0.875rem; }
/* Fifty tiles each ending in a full orange gradient was fifty buttons shouting
   over the pictures they are about. In the grid it is a tint that fills on the
   way to a press; the drop's own view keeps the full button. */
#viewDrops .feed .drop-actions .btn-primary {
  background: var(--brand-wash);
  border-color: transparent;
  box-shadow: none;
  color: var(--brand-strong);
  transition: background 0.15s var(--ease), color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
#viewDrops .feed .drop-actions .btn-primary:hover,
#viewDrops .feed .drop-actions .btn-primary:focus-visible {
  background: var(--grad-brand, var(--brand));
  color: var(--on-brand, #fff);
  box-shadow: var(--shadow-2);
}
#viewDrops .feed .drop-actions-minor { gap: 2px; }
#viewDrops .feed .drop-actions-minor .btn { color: var(--fg-3); }
#viewDrops .feed .drop-actions-minor .btn:hover { color: var(--fg); }
#viewDrops .feed .stamp { margin-top: 10px; }

/* Remove is there when the pointer is; on touch it stays. */
@media (hover: hover) {
  #viewDrops .feed .drop-remove { opacity: 0; }
  #viewDrops .feed .drop-media:hover .drop-remove,
  #viewDrops .feed .drop-remove:focus-visible { opacity: 1; }
}

/* Something to look at before a yes, on the picture, opening the drop. */
.drop-flag {
  position: absolute;
  top: 40px;
  left: 9px;
  z-index: 2;
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 0.28em 0.62em;
  border: 1px solid rgba(253, 186, 116, 0.5);
  border-radius: var(--r-pill);
  background: linear-gradient(rgba(10, 14, 24, 0.62), rgba(10, 14, 24, 0.62)), rgba(249, 115, 22, 0.34);
  color: #ffe6cf;
  font: inherit;
  font-size: 0.75rem;
  font-weight: 650;
  cursor: pointer;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.drop-flag:hover { background: linear-gradient(rgba(10, 14, 24, 0.45), rgba(10, 14, 24, 0.45)), rgba(249, 115, 22, 0.5); }
.drop-flag:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

/* Review keeps its head and filters on one line, the way a library
   puts its tabs beside its title. */
#sectionCreated > .section-head { align-items: flex-end; margin-bottom: 10px; }
#sectionCreated .feed-filters { margin-bottom: 16px; }

.drops-load-status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 0 14px;
  padding: 10px 12px;
  border: 1px solid color-mix(in srgb, var(--warn) 35%, var(--line));
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--warn) 8%, var(--surface));
  color: var(--fg-2);
  font-size: 0.8125rem;
}
.drops-load-status[hidden] { display: none; }

/* The checklist is about making the first drop, so it sits with Create. */
#viewDrops:has(#sectionCreated:not([hidden])) #setupChecklist { display: none; }
/* So are the counts: on Posts they repeat its own sub-tabs, Needs your yes,
   Scheduled and Didn't make it, one row above. */
#viewDrops:has(#sectionCreated:not([hidden])) #todayOverview { display: none; }

/* ---------------- A drop, opened ---------------- */
.sheet.sheet-drop {
  max-width: 1040px;
  width: 96vw;
  height: min(780px, calc(100dvh - 32px));
  padding: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(320px, 400px);
  overflow: hidden;
}
/* Held dark in both themes: a stage for the picture, not a surface. */
.drop-sheet-media {
  position: relative;
  min-height: 0;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: #0a0e0b;
}
/* Pinned to the stage: a percentage height does not resolve in a grid row,
   so a tall reel ran a phone screen past the bottom of the sheet. */
.drop-sheet-media > video,
.drop-sheet-media > img,
.drop-sheet-media > .drop-media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  object-fit: contain;
}
.drop-sheet-media > .drop-media { aspect-ratio: auto; }
.drop-sheet-none { color: rgba(255, 255, 255, 0.7); font-size: 0.875rem; }
.drop-sheet-side { display: flex; flex-direction: column; min-height: 0; min-width: 0; }
.drop-sheet-head { margin: 0; padding: 18px 18px 6px; }
.drop-sheet-head .pill { margin-bottom: 8px; }
.drop-sheet-head .pill:empty { display: none; }
.drop-sheet-head h3 { font-size: 1.125rem; }
.drop-sheet-body.drop {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
}
.drop-sheet-body .drop-body { padding: 6px 18px 18px; }
.drop-sheet-body .caption { display: block; min-height: 0; -webkit-line-clamp: unset; }
.drop-sheet-body .caption-more { display: none; }
.drop-sheet-body .tags { white-space: normal; overflow: visible; -webkit-line-clamp: unset; display: block; }
.drop-sheet-body .drop-folds { flex-direction: column; }
.drop-sheet-body .drop-body > .drop-actions:last-child,
.drop-sheet-body .drop-body > .stamp:last-child { margin-top: 18px; }
.drop-sheet-foot {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 10px 14px;
  border-top: 1px solid var(--line);
}
.drop-sheet-foot [hidden] { display: none; }
.drop-sheet-remove { margin-left: auto; }
.drop-sheet-remove:hover { color: var(--bad); }
@media (max-width: 760px) {
  .sheet.sheet-drop {
    width: 100%;
    height: calc(100dvh - 32px);
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(220px, 46%) minmax(0, 1fr);
  }
}

/* ---------------- Create, as a prompt ----------------
   Opened the way the Agent screen is, and the way the generators open: one
   question at display size, the box under it, the ways in under the box. The
   in-progress row and the formats keep the full width of the library. */
@media (min-width: 900px) {
  #setupChecklist,
  #sectionCreate > .section-head,
  #sectionCreate > .composer { max-width: 780px; margin-inline: auto; }
}
#sectionCreate > .section-head {
  justify-content: center;
  text-align: center;
  margin: 20px auto 22px;
}
#sectionCreate > .section-head .section-head-text { flex: 1 1 100%; }
#sectionCreate .section-head-text h2 {
  font-family: var(--display, var(--sans));
  font-size: clamp(1.6rem, 1.1rem + 1.6vw, 2.2rem);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: -0.02em;
}
#sectionCreate .section-head-text h2::before { display: none; }
#sectionCreate .section-head-text p { max-width: 52ch; margin: 8px auto 0; color: var(--fg-3); }
/* Just ask or the form: a small switch over the box, not two tabs the width
   of it. */
#sectionCreate .compose-way { display: flex; width: max-content; margin: 0 auto 14px; }
#sectionCreate .composer .prompt-box { border-radius: var(--r-xl); padding: 14px 14px 12px 18px; }
#sectionCreate .compose-starters { justify-content: center; }
#sectionCreate .compose-foot { text-align: center; }
#sectionCreate .compose-usage { justify-content: center; gap: 16px; }
#sectionCreate .compose-usage .usage-note { margin-left: 0; }
#viewDrops .create-active-section,
#viewDrops .idea-strip { margin-top: 36px; }
/* Hovering plays the reel where it sits, so the disc is only a sign it can
   be opened -- there when the pointer is, and on touch, where it is not. */
@media (hover: hover) {
  #viewDrops .feed .drop-play-disc { opacity: 0; transform: scale(0.9); transition: opacity 0.16s var(--ease), transform 0.16s var(--ease); }
  #viewDrops .feed .drop-media:hover .drop-play-disc,
  #viewDrops .feed .drop-open:focus-visible .drop-play-disc { opacity: 1; transform: none; }
}

/* ---- On the picture: the state when it is news, then what to check. ---- */
.drop-badges {
  position: absolute;
  top: 9px;
  left: 9px;
  right: 60px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
}
.drop-badges .pill { position: static; max-width: 100%; }
.drop-badges .drop-flag { position: static; }
/* The kind, top right, where a library marks it. */
.drop-kind {
  position: absolute;
  top: 9px;
  right: 9px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 7px;
  border-radius: var(--r-pill);
  background: rgba(8, 12, 20, 0.62);
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  pointer-events: none;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.drop-slides { right: 9px; }

/* ---- Picking several ---- */
.drop-check {
  position: absolute;
  top: 9px;
  right: 9px;
  z-index: 3;
  display: none;
  place-items: center;
  width: 26px;
  height: 26px;
  border: 2px solid #fff;
  border-radius: 50%;
  background: rgba(8, 12, 20, 0.35);
  color: transparent;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.35);
}
.feed.is-selecting .drop-check { display: grid; }
.feed.is-selecting .drop-kind,
.feed.is-selecting .drop-slides,
.feed.is-selecting .drop-play-disc { display: none; }
.feed.is-selecting .drop { cursor: pointer; }
.feed.is-selecting .drop-body { opacity: 0.55; pointer-events: none; }
.feed.is-selecting .drop-media { transform: none !important; }
.feed .drop.is-selected .drop-check { border-color: var(--brand); background: var(--brand-ink); color: var(--on-brand); }
.feed .drop.is-selected .drop-media { outline: 3px solid var(--brand); outline-offset: 2px; }

.feed-select-bar {
  position: sticky;
  bottom: 16px;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 8px;
  width: max-content;
  max-width: 100%;
  margin: 18px auto 0;
  padding: 8px 8px 8px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  box-shadow: var(--shadow-3);
}
.feed-select-bar[hidden] { display: none; }
.feed-select-count { font-size: 0.875rem; font-weight: 650; white-space: nowrap; }
.feed-select-gap { width: 8px; }
@media (max-width: 560px) {
  .feed-select-bar { bottom: calc(76px + env(safe-area-inset-bottom)); flex-wrap: wrap; justify-content: center; border-radius: var(--r-lg); }
}

/* ---- Day heads over the grid ---- */
.feed-day {
  grid-column: 1 / -1;
  margin: 10px 2px -6px;
  font-family: inherit;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--fg-3);
}
.feed-day:first-child { margin-top: 0; }

/* ---- Filters, kind and search on one bar ---- */
.feed-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 16px;
  margin-bottom: 18px;
}
.feed-bar[hidden] { display: none; }
.feed-bar-tools { display: flex; align-items: center; gap: 8px; flex: 0 1 auto; min-width: 0; }
.feed-kind { flex: none; }
.feed-search { height: 34px; width: 220px; flex: 0 1 220px; padding: 0 12px; }
.feed-search input { font-size: 0.875rem; }
@media (max-width: 560px) {
  .feed-bar-tools { width: 100%; }
  .feed-search { flex: 1 1 auto; width: auto; }
  .feed-search input { font-size: 16px; }
}
.feed-select-btn[aria-pressed="true"] { color: var(--brand-ink); }

/* ---- The drop's own view: moving along, and changing the words ---- */
.drop-sheet-head { align-items: flex-start; }
.drop-sheet-head > div:first-child { flex: 1; min-width: 0; }
.drop-sheet-nav { display: flex; align-items: center; gap: 2px; flex: none; }
.drop-sheet-nav .icon-btn:disabled { opacity: 0.35; cursor: default; background: none; }
.drop-sheet-pos { min-width: 52px; text-align: center; font-size: 0.75rem; color: var(--fg-3); font-variant-numeric: tabular-nums; }
.drop-sheet-edit {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  align-self: flex-start;
  margin: 6px 0 2px -8px;
  padding: 5px 8px;
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  color: var(--fg-3);
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 600;
  cursor: pointer;
}
.drop-sheet-edit:hover { background: var(--surface-2); color: var(--fg); }
.drop-caption-form { display: flex; flex-direction: column; gap: 8px; margin: 4px 0 6px; }
.drop-caption-form textarea { resize: vertical; min-height: 110px; line-height: 1.5; }
.drop-caption-actions { display: flex; justify-content: flex-end; gap: 6px; }
.drop-sheet-body .caption[hidden],
.drop-sheet-body .tags[hidden] { display: none; }

/* ---- Two tiles across a phone: the small actions as icons, one row ---- */
@media (max-width: 560px) {
  #viewDrops .feed .drop-actions-minor { flex-wrap: nowrap; justify-content: space-around; }
  /* Only the ones with an icon to fall back on: "Unschedule" or "Used 2/2"
     have none, and would vanish. */
  #viewDrops .feed .drop-actions-minor .btn:has(svg) { flex: 0 0 auto; font-size: 0; gap: 0; padding: 0.55em; }
  #viewDrops .feed .drop-actions-minor .btn svg { width: 16px; height: 16px; }
}
.feed-select-btn[hidden] { display: none; }

/* ---------------- The cut, as a filmstrip ----------------
   The way CapCut and Premiere Rush show a running order: the pictures
   themselves, in order, at full strength, each marked with its place, its
   length and a bar for where it came from. The tiles used to be a third-
   opacity picture under three lines of mono caption, so a library shot read as
   a paragraph and a shot with no picture read the same as one with. */
#editorSheet .strip {
  gap: 6px;
  height: auto;
  padding: 4px 2px 8px;
  align-items: flex-start;
}
#editorSheet .shot {
  flex: none;
  height: 150px;
  min-width: 0;
  padding: 0;
  overflow: hidden;
  border-radius: var(--r-sm);
  background: #16203a;
  border: 0;
  box-shadow: 0 0 0 1px var(--line);
}
#editorSheet .shot .thumb { opacity: 1; border-radius: 0; }
#editorSheet .shot:hover { box-shadow: 0 0 0 1px var(--line-strong); }
#editorSheet .shot.is-on { outline: 3px solid var(--brand); outline-offset: 1px; }
#editorSheet .shot.gen { background: #2a1f4a; border: 0; }
#editorSheet .shot::after {
  /* A scrim for the marks, top and bottom, whatever the picture. */
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(rgba(0, 0, 0, 0.38), transparent 30%, transparent 62%, rgba(0, 0, 0, 0.55));
  pointer-events: none;
}
#editorSheet .shot > span, #editorSheet .shot > i { position: absolute; z-index: 1; }
#editorSheet .shot-n {
  top: 6px;
  left: 6px;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  display: grid;
  place-items: center;
  border-radius: var(--r-pill);
  background: rgba(8, 12, 20, 0.6);
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 700;
}
#editorSheet .shot-flag {
  top: 6px;
  right: 6px;
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--warn);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 800;
}
#editorSheet .shot.has-issue { box-shadow: 0 0 0 2px var(--warn); }
#editorSheet .shot > .s {
  right: 6px;
  bottom: 9px;
  font-family: var(--sans);
  font-size: 0.6875rem;
  font-weight: 650;
  color: #fff;
  font-variant-numeric: tabular-nums;
}
#editorSheet .shot-bar {
  left: 0;
  right: 0;
  bottom: 0;
  height: 4px;
  background: var(--shot-clip);
}
#editorSheet .shot.photo .shot-bar { background: var(--shot-photo); }
#editorSheet .shot.lib .shot-bar { background: var(--shot-lib); }
#editorSheet .shot.gen .shot-bar { background: var(--shot-gen); }
#editorSheet .shot .shot-empty,
.insp-thumb .shot-empty {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 8px;
  text-align: center;
  font-size: 0.6875rem;
  color: rgba(255, 255, 255, 0.6);
}

.cut-legend { display: inline-flex; flex-wrap: wrap; gap: 4px 12px; }
.cut-legend-item { display: inline-flex; align-items: center; gap: 5px; font-size: 0.75rem; color: var(--fg-3); }
.cut-legend-item i { width: 10px; height: 4px; border-radius: 2px; background: var(--shot-clip); }
.cut-legend-item.photo i { background: var(--shot-photo); }
.cut-legend-item.lib i { background: var(--shot-lib); }
.cut-legend-item.gen i { background: var(--shot-gen); }
#editorSheet .cut-strip-hint { margin: 2px 0 0; font-size: 0.75rem; color: var(--fg-3); }

/* What to look at, each with its shot. */
.cut-issues { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 6px; }
.cut-issues[hidden] { display: none; }
.cut-issues li {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid color-mix(in srgb, var(--warn) 35%, transparent);
  border-radius: var(--r-sm);
  background: var(--warn-wash);
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--fg-2);
}
.cut-issue-mark {
  flex: none;
  width: 18px;
  height: 18px;
  margin-top: 1px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--warn);
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 800;
}
.cut-issue-text { flex: 1; min-width: 0; }
.cut-issue-text b { color: var(--fg); font-weight: 650; }
.cut-issue-go { flex: none; font-size: 0.8125rem; font-weight: 650; white-space: nowrap; }

/* ---- The shot that is open ---- */
#editorSheet .panel.shot-inspector {
  display: grid;
  grid-template-columns: 92px minmax(0, 1fr);
  gap: 16px;
  margin-top: 16px;
  padding: 14px;
  border: 1px solid var(--line);
  border-top: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
}
.insp-thumb {
  position: relative;
  width: 92px;
  aspect-ratio: 9 / 16;
  overflow: hidden;
  border-radius: var(--r-sm);
  background: #16203a;
}
.insp-thumb .thumb,
.insp-thumb img,
.insp-thumb video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 1; }
.insp-main { min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.insp-head { display: flex; align-items: baseline; gap: 10px; }
.insp-head b { font-size: 0.9375rem; font-weight: 650; color: var(--fg); }
.insp-kind { font-size: 0.8125rem; color: var(--fg-3); }
.insp-says-label {
  margin: 4px 0 0;
  font-size: 0.6875rem;
  font-weight: 650;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg-3);
}
.insp-says { margin: 0; font-size: 0.9375rem; line-height: 1.5; color: var(--fg); }
.insp-says.is-empty { color: var(--fg-3); font-style: italic; }
.insp-fields { display: flex; flex-wrap: wrap; gap: 10px 22px; margin-top: 6px; }
.insp-field { display: flex; flex-direction: column; gap: 5px; }
.insp-field[hidden] { display: none; }
#editorSheet .panel .insp-field label {
  font-size: 0.6875rem;
  font-weight: 650;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg-3);
}
.stepper { display: flex; align-items: center; gap: 4px; }
.stepper .input { width: 64px; text-align: center; }
.stepper-btn {
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--fg);
  font: inherit;
  font-size: 1rem;
  cursor: pointer;
}
.stepper-btn:hover { background: var(--surface-3); }
.insp-actions { display: flex; gap: 6px; margin-top: 8px; }
.insp-actions .btn svg { flex: none; }
@media (max-width: 640px) {
  #editorSheet .panel.shot-inspector { grid-template-columns: 72px minmax(0, 1fr); }
  .insp-thumb { width: 72px; }
}

/* ---- The cut, reworked: a timeline to read, a shot to work on ----
   The strip fills its row with each shot as wide as its share of the reel, a
   play head runs across it with the preview, and the open shot plays the
   stretch of its clip that is used. Later than the rules above, so these win. */
#editorSheet .strip-head { align-items: center; flex-wrap: wrap; gap: 6px 14px; margin-bottom: 10px; }
.strip-sum { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }
.strip-sum b { font-size: 0.875rem; }
.strip-dur {
  font-size: 0.8125rem;
  font-variant-numeric: tabular-nums;
  color: var(--fg-3);
}
.strip-dur::before { content: "\00b7"; margin-right: 8px; }
.cut-issue-pill[hidden] { display: none; }
.cut-issue-pill { font-size: 0.75rem; }

.strip-wrap { position: relative; }
#editorSheet .strip { gap: 4px; padding: 5px 4px 8px; scroll-snap-type: x proximity; }
#editorSheet .shot {
  flex: 1 0 0;
  min-width: 76px;
  height: 140px;
  scroll-snap-align: start;
  transition: transform 0.15s var(--ease), box-shadow 0.15s var(--ease), opacity 0.15s var(--ease);
}
#editorSheet .shot:hover { transform: translateY(-2px); }
#editorSheet .shot.is-on { outline: 3px solid var(--brand); outline-offset: 2px; }
#editorSheet .shot.is-dragging { opacity: 0.35; transform: scale(0.95); }
#editorSheet .shot.is-drop-target { box-shadow: -4px 0 0 0 var(--brand); }
/* The play head says where the preview is; the ring it used to wear fought
   the picked shot's and the warning's for the same edge. */
#editorSheet .shot.is-playing { box-shadow: 0 0 0 1px var(--line); }
#editorSheet .shot.has-issue.is-playing,
#editorSheet .shot.has-issue { box-shadow: 0 0 0 2px var(--warn); }
#editorSheet .shot.is-playing .shot-n { background: var(--brand); }

.strip-playhead {
  position: absolute;
  top: 0;
  bottom: 4px;
  left: 0;
  width: 2px;
  margin-left: -1px;
  background: #fff;
  border-radius: 1px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.45);
  pointer-events: none;
  z-index: 2;
  transition: transform 0.25s linear;
}
.strip-playhead::before {
  content: "";
  position: absolute;
  top: -1px;
  left: -4px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.45);
}
.strip-playhead[hidden] { display: none; }

#editorSheet .cut-strip-hint { margin: 4px 0 0; }
#editorSheet .cut-strip-hint kbd {
  display: inline-block;
  min-width: 1.5em;
  padding: 0 4px;
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 4px;
  font: inherit;
  font-size: 0.6875rem;
  line-height: 1.4;
  text-align: center;
  color: var(--fg-2);
  background: var(--surface);
}
/* A finger cannot drag a tile or hold alt, so it is pointed at the arrows. */
.cut-strip-hint .hint-touch { display: none; }
@media (hover: none) {
  .cut-strip-hint .hint-pointer { display: none; }
  .cut-strip-hint .hint-touch { display: inline; }
}

/* An issue: the shot as a picture, what is wrong, and the fix beside it. */
.cut-issues li { align-items: center; gap: 12px; padding: 8px 10px; }
.cut-issue-thumb {
  position: relative;
  flex: none;
  width: 34px;
  height: 46px;
  overflow: hidden;
  border-radius: 6px;
  background: #16203a;
  box-shadow: 0 0 0 2px var(--warn);
}
.cut-issue-thumb .thumb { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.cut-issue-n {
  position: absolute;
  left: 3px;
  top: 3px;
  min-width: 15px;
  height: 15px;
  padding: 0 3px;
  display: grid;
  place-items: center;
  border-radius: var(--r-pill);
  background: rgba(8, 12, 20, 0.65);
  color: #fff;
  font-size: 0.625rem;
  font-weight: 700;
}
.cut-issue-text { display: flex; flex-direction: column; gap: 1px; }
.cut-issue-text span { color: var(--fg-2); }
.cut-issue-acts { flex: none; display: inline-flex; align-items: center; gap: 12px; }

/* The generated meter: a footnote, not a section. */
#editorSheet .meter { margin-top: 10px; gap: 10px; font-size: 0.75rem; }
#editorSheet .meter .meter-label { color: var(--fg-3); white-space: nowrap; }
#editorSheet .meter .bar { flex: 0 1 180px; height: 5px; }
#editorSheet .meter .n { color: var(--fg-2); white-space: nowrap; }
#editorSheet .meter .pill[hidden] { display: none; }

/* ---- The open shot ---- */
#editorSheet .panel.shot-inspector {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 14px 16px 16px;
}
#editorSheet .panel.shot-inspector[hidden] { display: none; }
.shot-inspector .insp-head { display: flex; align-items: center; gap: 12px; }
.insp-title { display: flex; align-items: center; gap: 10px; min-width: 0; }
.insp-title b { font-size: 1rem; font-weight: 650; color: var(--fg); white-space: nowrap; }
.insp-kind {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px 9px;
  border-radius: var(--r-pill);
  background: var(--surface);
  border: 1px solid var(--line);
  font-size: 0.75rem;
  color: var(--fg-2);
  white-space: nowrap;
}
.insp-kind i { width: 8px; height: 8px; border-radius: 50%; background: var(--shot-clip); }
.insp-kind.photo i { background: var(--shot-photo); }
.insp-kind.lib i { background: var(--shot-lib); }
.insp-kind.gen i { background: var(--shot-gen); }
.insp-when {
  margin-left: auto;
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
  color: var(--fg-3);
  white-space: nowrap;
}
.insp-nav { display: inline-flex; gap: 2px; }
.insp-nav .icon-btn { width: 30px; height: 30px; }
.insp-nav .icon-btn:disabled { opacity: 0.3; cursor: default; background: none; }

.insp-body {
  display: grid;
  grid-template-columns: 112px minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}
#editorSheet .insp-thumb {
  width: 112px;
  box-shadow: 0 0 0 1px var(--line), var(--shadow-2);
}
.insp-thumb::after {
  /* Which kind it is, along the foot, the same bar the strip uses. */
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 4px;
  background: var(--shot-clip);
}
.insp-thumb.photo::after { background: var(--shot-photo); }
.insp-thumb.lib::after { background: var(--shot-lib); }
.insp-thumb.gen::after { background: var(--shot-gen); }
.shot-inspector .insp-main { gap: 14px; }

.insp-says-box {
  padding: 8px 12px;
  border-left: 3px solid var(--brand);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  background: var(--surface);
}
.insp-says-box .insp-says-label { margin: 0 0 2px; }
.insp-says-box .insp-says { font-size: 0.9375rem; line-height: 1.45; }

.shot-inspector .insp-fields { margin-top: 0; gap: 12px 28px; }
.shot-inspector .stepper .input { width: 64px; height: 32px; padding: 0 6px; -moz-appearance: textfield; }
.shot-inspector .stepper .input::-webkit-inner-spin-button,
.shot-inspector .stepper .input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.shot-inspector .stepper-btn { width: 32px; height: 32px; }
.shot-inspector .stepper .hint { margin-left: 2px; }

/* The clip, with the stretch used lit; the range rides along it, as wide as
   the starts that leave room for the hold, so its handle sits on the window's
   left edge. */
.trim-track { position: relative; max-width: 360px; }
.trim-track[hidden] { display: none; }
.trim-rail {
  position: relative;
  height: 22px;
  border-radius: 6px;
  background: repeating-linear-gradient(90deg, var(--surface-3) 0 2px, var(--surface) 2px 10px);
  border: 1px solid var(--line);
  overflow: hidden;
}
.trim-window {
  position: absolute;
  top: 0;
  bottom: 0;
  border-radius: 5px;
  background: var(--brand-wash);
  border: 2px solid var(--brand);
  transition: left 0.12s var(--ease), width 0.12s var(--ease);
}
.trim-window.is-over { border-color: var(--warn); background: var(--warn-wash); }
.trim-range {
  position: absolute;
  top: 0;
  left: 0;
  height: 22px;
  margin: 0;
  background: transparent;
  -webkit-appearance: none;
  appearance: none;
  cursor: ew-resize;
}
.trim-range::-webkit-slider-runnable-track { height: 22px; background: transparent; }
.trim-range::-moz-range-track { height: 22px; background: transparent; }
.trim-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 14px;
  height: 22px;
  border-radius: 4px;
  background: var(--brand);
  box-shadow: inset 0 0 0 4px var(--brand), inset 0 0 0 5px rgba(255, 255, 255, 0.7);
}
.trim-range::-moz-range-thumb {
  width: 14px;
  height: 22px;
  border: 0;
  border-radius: 4px;
  background: var(--brand);
}
.trim-range:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; border-radius: 6px; }
.trim-range:disabled { cursor: default; }
.trim-range:disabled::-webkit-slider-thumb { opacity: 0; }
.trim-scale {
  display: flex;
  justify-content: space-between;
  margin-top: 4px;
  font-size: 0.6875rem;
  font-variant-numeric: tabular-nums;
  color: var(--fg-3);
}

.shot-inspector .insp-actions {
  margin-top: 0;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  align-items: center;
  gap: 8px;
}
.insp-move { display: inline-flex; gap: 2px; }
.insp-move .btn { padding-left: 9px; padding-right: 9px; }
.insp-move .btn:disabled { opacity: 0.35; cursor: default; }
.insp-remove { margin-left: auto; }
.insp-remove.is-armed { color: var(--bad); background: var(--bad-wash); }

/* The swap picker, under the shot it is for. */
#editorSheet .cut-swap-modal { margin-top: 12px; border-radius: var(--r-md); }
#editorSheet .cut-swap-modal[hidden] { display: none; }
.cut-swap-grid { grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); max-height: 280px; }
/* "Loading" and "nothing here" were squeezed into the first 84px column. */
.cut-swap-grid > .hint { grid-column: 1 / -1; padding: 6px 2px; }
button.cut-swap-item { padding: 0; font: inherit; color: inherit; }
.cut-swap-item:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.cut-swap-item.is-current { border-color: var(--brand); cursor: default; }
.cut-swap-item.is-current:hover { transform: none; }
.cut-swap-item.is-used img,
.cut-swap-item.is-used video { opacity: 0.55; }
.cut-swap-used {
  position: absolute;
  top: 4px;
  left: 4px;
  right: 4px;
  padding: 1px 5px;
  border-radius: 4px;
  background: rgba(8, 12, 20, 0.72);
  color: #fff;
  font-size: 0.625rem;
  font-weight: 650;
  text-align: center;
}
.cut-swap-item.is-current .cut-swap-used { background: var(--brand); }

/* The preview of a rendered reel: its hook and words are burned in, and the
   player has its own clock. */
.cut-phone.is-rendered .cut-phone-hook,
.cut-phone.is-rendered .cut-phone-sub { display: none; }
#editorSheet .cut-phone video:not([hidden]) ~ .cut-phone-time { display: none; }

@media (max-width: 640px) {
  #editorSheet .shot { height: 112px; min-width: 64px; }
  .insp-body { grid-template-columns: 84px minmax(0, 1fr); gap: 12px; }
  #editorSheet .insp-thumb { width: 84px; }
  .insp-when { display: none; }
  .insp-title { flex-wrap: wrap; gap: 6px; }
  .shot-inspector .insp-head .insp-nav { margin-left: auto; }
  .cut-issues li { flex-wrap: wrap; }
  .cut-issue-acts { width: 100%; justify-content: flex-end; }
}

/* ---- The cut, second pass ---- */

/* The row was "auto", which grows to the form's whole height: once the Cut
   tab ran taller than the window, the body stopped scrolling and the footer --
   Re-cut with it -- was pushed off the bottom of the sheet. */
.sheet-editor { grid-template-rows: minmax(0, 1fr); }
@media (max-width: 700px) {
  .sheet-editor { grid-template-rows: auto minmax(0, 1fr); }
}

/* Held past its clip's end: said under the rail that shows it. */
.trim-note {
  margin: 6px 0 0;
  font-size: 0.75rem;
  line-height: 1.4;
  color: var(--warn);
}
.trim-note[hidden] { display: none; }

/* What the server suggests filming, under the problem it answers. */
.cut-issue-film {
  margin-top: 4px;
  font-size: 0.8125rem;
  color: var(--fg-2);
}
.cut-issue-film i { font-style: normal; font-weight: 650; color: var(--fg); }
.cut-issue-upload { cursor: pointer; }
.cut-issue-upload.is-busy { opacity: 0.6; pointer-events: none; }
.cut-issues li { align-items: flex-start; }
.cut-issue-acts { align-self: center; flex-wrap: wrap; justify-content: flex-end; gap: 8px 12px; }

/* The generated meter: the share of the reel, with the 40% mark on the bar,
   and what generating has cost underneath. */
#editorSheet .meter { display: block; padding: 4px 0; }
#editorSheet .meter-row { display: flex; align-items: center; gap: 10px; }
#editorSheet .meter .bar { position: relative; overflow: visible; }
#editorSheet .meter .bar i { border-radius: 3px; }
.meter-tick {
  position: absolute;
  left: 40%;
  top: -3px;
  bottom: -3px;
  width: 2px;
  margin-left: -1px;
  border-radius: 1px;
  background: var(--fg-3);
  opacity: 0.6;
}
.meter-sub { margin: 4px 0 0; font-size: 0.75rem; color: var(--fg-3); }
.meter-sub:empty { display: none; }

/* Keys, for whoever edits with a keyboard. */
#editorSheet .cut-keys {
  margin: 4px 0 0;
  font-size: 0.75rem;
  color: var(--fg-3);
}
#editorSheet .cut-keys kbd {
  display: inline-block;
  min-width: 1.5em;
  padding: 0 4px;
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 4px;
  font: inherit;
  font-size: 0.6875rem;
  line-height: 1.4;
  text-align: center;
  color: var(--fg-2);
  background: var(--surface);
}
@media (hover: none) { #editorSheet .cut-keys { display: none; } }

/* A held tile is being carried, not scrolled or long-pressed for a menu. */
#editorSheet .shot { -webkit-touch-callout: none; -webkit-user-select: none; }
#editorSheet .shot.is-dragging { transform: scale(1.04); opacity: 0.75; box-shadow: var(--shadow-2); z-index: 3; }

/* The footer: what would change, then the steps back. */
.editor-foot .cut-recut-note b { color: var(--fg); font-weight: 650; }
.cut-recut-eta { color: var(--fg-3); }
.cut-history { display: inline-flex; align-items: center; gap: 2px; }
.cut-history .btn svg { flex: none; }
.cut-history [hidden] { display: none; }
.cut-revert { margin-left: 6px; font-size: 0.8125rem; white-space: nowrap; }
.editor-foot.is-cut-dirty #btnEditorPost,
.editor-foot.is-cut-dirty #btnEditorSchedule { display: none; }
.editor-foot .cut-recut-note { max-width: none; flex: 1; min-width: 0; }
#btnCutRedo[hidden], #btnCutRevert[hidden] { display: none; }

/* The preview, playing the edits. */
.cut-draft {
  position: absolute;
  inset: 0;
  background: #000;
  cursor: pointer;
}
.cut-draft[hidden] { display: none; }
.cut-draft-media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
}
.cut-draft-media.is-on { opacity: 1; }
.cut-draft.is-empty::after {
  content: "No picture for this shot";
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.6);
}
.cut-draft-play {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 1;
  width: 54px;
  height: 54px;
  margin: -27px 0 0 -27px;
  border-radius: 50%;
  background: rgba(8, 12, 20, 0.55);
  opacity: 0;
  transition: opacity 0.15s var(--ease);
  pointer-events: none;
}
.cut-draft-play::after {
  content: "";
  position: absolute;
  left: 21px;
  top: 16px;
  border-style: solid;
  border-width: 11px 0 11px 17px;
  border-color: transparent transparent transparent #fff;
}
.cut-draft.is-paused .cut-draft-play { opacity: 1; }
/* With the edits playing, the words and the clock are drawn over them again:
   the render that has them burned in is underneath. */
.cut-phone.is-draft.is-rendered .cut-phone-hook,
.cut-phone.is-draft.is-rendered .cut-phone-sub:not([hidden]) { display: block; }
#editorSheet .cut-phone.is-draft video:not([hidden]) ~ .cut-phone-time { display: block; z-index: 1; }
.cut-phone.is-draft .cut-phone-hook,
.cut-phone.is-draft .cut-phone-sub { z-index: 1; }

.cut-view {
  width: 100%;
  max-width: 300px;
  margin: 12px auto 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}
.cut-view[hidden] { display: none; }
.cut-view-seg {
  display: inline-flex;
  padding: 3px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.12);
}
.cut-view-seg button {
  padding: 5px 12px;
  border: 0;
  border-radius: var(--r-pill);
  background: none;
  color: rgba(255, 255, 255, 0.7);
  font: inherit;
  font-size: 0.75rem;
  font-weight: 600;
  cursor: pointer;
}
.cut-view-seg button.is-on { background: #fff; color: #111; }
.cut-view-seg button:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
@media (max-width: 700px) {
  /* The stage already takes most of a phone; the switch says enough. */
  .cut-view { margin-top: 8px; }
  .cut-view-note { display: none; }
}
.cut-view-note {
  margin: 0;
  font-size: 0.6875rem;
  line-height: 1.4;
  text-align: center;
  color: rgba(255, 255, 255, 0.55);
}

/* The editor's footer: Undo sits with the note that says there is a change. */
#btnCutUndo[hidden] { display: none; }
.editor-foot #btnEditorPost:disabled,
.editor-foot #btnEditorSchedule:disabled { opacity: 0.45; cursor: not-allowed; }

/* ---------------- A new take ----------------
   Not on the tile: it is starting over, and the tile's row is for the moves
   that keep what is there. In the drop's own view it asks twice. */
#viewDrops .feed .drop-newtake { display: none; }
.drop-newtake.is-armed { color: var(--brand-ink); background: var(--brand-wash); }

/* ---------------- Timelines ----------------
   Activity, the post log and the playbook's history, drawn one way: the days
   as heads, a panel of rows under each, divided rather than boxed one by one
   -- the way Linear, GitHub and the Instagram insights list lay out a history.
   Each of the three was its own card-per-row design before. */
.tl { display: flex; flex-direction: column; gap: 18px; }
.tl-day-head {
  margin: 0 0 8px 4px;
  font-family: inherit;
  font-size: 0.8125rem;
  font-weight: 650;
  color: var(--fg-3);
}
.tl-list {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  overflow: hidden;
}
.tl-row {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr) auto;
  align-items: center;
  gap: 14px;
  padding: 12px 16px;
  transition: background-color 0.12s var(--ease);
}
.tl-row + .tl-row { border-top: 1px solid var(--line-soft, var(--line)); }
.tl-row:hover { background: var(--surface-2); }
.tl-thumb {
  position: relative;
  width: 52px;
  height: 52px;
  padding: 0;
  border: 0;
  border-radius: var(--r-sm);
  overflow: hidden;
  display: grid;
  place-items: center;
  background: var(--surface-3);
  color: var(--fg-3);
}
button.tl-thumb { cursor: zoom-in; }
button.tl-thumb:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.tl-thumb > svg { width: 20px; height: 20px; }
.tl-thumb > img,
.tl-thumb > video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.tl-play {
  position: absolute;
  right: 4px;
  bottom: 4px;
  width: 16px;
  height: 16px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(8, 12, 20, 0.62);
  color: #fff;
}
.tl-play svg { width: 9px; height: 9px; margin-left: 1px; }
.tl-main { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.tl-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--fg);
}
.tl-sub {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.8125rem;
  color: var(--fg-2);
}
.tl-meta { display: flex; flex-wrap: wrap; align-items: center; margin-top: 2px; font-size: 0.75rem; color: var(--fg-3); }
.tl-meta span + span::before { content: "\00b7"; margin: 0 6px; }
.tl-error { font-size: 0.8125rem; color: var(--bad); }
.tl-side { display: flex; align-items: center; gap: 10px; flex: none; }
.tl-action { font-size: 0.8125rem; font-weight: 600; color: var(--fg-2); text-decoration: none; }
.tl-action:hover { color: var(--brand-ink); }
.tl-intent { border-color: transparent; background: var(--intent-wash, var(--surface-2)); color: var(--intent, var(--fg-2)); }
.tl-more {
  display: block;
  margin: 14px auto 0;
  padding: 8px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--fg-2);
  cursor: pointer;
}
.tl-more:hover { background: var(--surface-2); color: var(--fg); }
.tl-more[hidden] { display: none; }
@media (max-width: 560px) {
  .tl-row { grid-template-columns: 44px minmax(0, 1fr); gap: 12px; padding: 12px; }
  .tl-thumb { width: 44px; height: 44px; }
  .tl-side { grid-column: 2; justify-content: flex-start; }
}

/* The three filter rows, one chip -- the one Review uses. */
.tl-filters { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 18px; padding: 0; border: 0; background: none; }
.tl-filters[hidden] { display: none; }
.tl-filters > button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  padding: 5px 11px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--fg-2);
  cursor: pointer;
  box-shadow: none;
}
.tl-filters > button:hover { border-color: var(--line-strong); }
.tl-filters > button.is-active,
.tl-filters > button.is-on { background: var(--brand); border-color: var(--brand); color: #fff; }
.tl-filters .gallery-pill-n {
  font-family: var(--mono);
  font-size: 0.6875rem;
  padding: 1px 5px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  color: var(--fg-3);
}
.tl-filters > button.is-on .gallery-pill-n { background: rgba(255, 255, 255, 0.22); color: #fff; }

/* Activity: the numbers are a strip above the list, and the plan -- which
   is where things stand, not what happened -- closes the page. */
#viewActivity .metrics-grid { margin-bottom: 22px; }
#viewActivity .plan-card { margin-top: 32px; }
#sectionPostLog .tl-row { grid-template-columns: 52px minmax(0, 1fr) auto; padding: 13px 16px; }
#sectionPostLog .tl-thumb { width: 52px; height: 66px; border-radius: 10px; }
#sectionPostLog .tl-row[data-state="cancelled"] .tl-title { color: var(--fg-2); }
#sectionPostLog .tl-row[data-state="cancelled"] .tl-thumb { opacity: 0.6; }
#sectionPostLog .tl-day-head {
  margin-left: 2px;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}

/* The filter is the same switch History uses, not a row of loose chips. */
.activity-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 0 0 18px; }
#viewActivity .activity-filter-bar {
  display: grid;
  flex-wrap: nowrap;
  gap: 3px;
  margin: 0;
  max-width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
}
#viewActivity .activity-filter-bar::-webkit-scrollbar { display: none; }
#viewActivity .activity-filter-bar .seg-btn { white-space: nowrap; padding: 7px 16px; }

/* Each kind of event gets its own tile colour, so a day of chats, plans and
   reels sorts itself before a word is read. A tile with the post's own
   picture shows the picture instead. */
#viewActivity .tl-row { padding: 13px 16px; }
#viewActivity .tl-thumb { width: 44px; height: 44px; border-radius: 12px; }
#viewActivity .tl-row { grid-template-columns: 44px minmax(0, 1fr) auto; }
#viewActivity .tl-row:has(.tl-thumb > img, .tl-thumb > video) { grid-template-columns: 52px minmax(0, 1fr) auto; }
#viewActivity .tl-thumb:has(> img, > video) { width: 52px; height: 66px; border-radius: 10px; }
#viewActivity .tl-thumb > svg { width: 19px; height: 19px; }
.tl-row[data-kind="reel"] .tl-thumb { background: var(--brand-wash); color: var(--brand-strong); }
.tl-row[data-kind="image"] .tl-thumb { background: var(--navy-wash); color: var(--navy-strong); }
.tl-row[data-kind="publish"] .tl-thumb { background: var(--good-wash); color: var(--good); }
.tl-row[data-kind="plan"] .tl-thumb { background: var(--warn-wash); color: var(--warn); }
.tl-row[data-kind="chat"] .tl-thumb { background: var(--violet-wash); color: var(--violet); }
#viewActivity .tl-title { font-size: 0.875rem; }
#viewActivity .tl-sub { font-size: 0.8125rem; color: var(--fg-3); }
#viewActivity .tl-meta > span:first-child { font-weight: 600; color: var(--fg-2); }
#viewActivity .tl-day-head {
  margin-left: 2px;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}

/* The plan card closes the page: the meters on white, the counts read first. */
#viewActivity .plan-card { padding: 20px 22px; }
#viewActivity .plan-title { font-family: var(--display); font-size: 1.25rem; letter-spacing: -0.015em; }
#viewActivity .quota-box { background: var(--surface); border-color: var(--line); border-radius: var(--r-md); padding: 14px 16px; }
#viewActivity .quota-head b { font-size: 0.875rem; font-weight: 600; }
#viewActivity .quota-head span { font-variant-numeric: tabular-nums; }
#viewActivity .progress-bar-bg { height: 10px; border-radius: var(--r-pill); }
#viewActivity .progress-bar-fill { border-radius: var(--r-pill); }
#viewActivity .syndication-channels-row { margin-top: 18px; padding-top: 14px; border-top-color: var(--line-soft); }
@media (max-width: 560px) {
  #viewActivity .plan-card { padding: 16px; }
  #viewActivity .plan-head-row { flex-direction: column; gap: 10px; }
}
/* Made is not posted: a drop still waiting says so in the warm colour the
   Needs-a-yes state uses, and one that went out in the posted green. */
.tl-meta .tl-unposted { color: var(--warn); font-weight: 600; }
.tl-meta .tl-posted { color: var(--good); font-weight: 600; }

/* ---- The history's filters: which, what kind, what for ---- */
.mem-filters { display: flex; flex-direction: column; gap: 10px; margin: 0 0 18px; }
.mem-filters[hidden] { display: none; }
.mem-filter-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; }
.mem-seg { max-width: 100%; overflow-x: auto; scrollbar-width: none; }
.mem-seg::-webkit-scrollbar { display: none; }
.mem-seg .seg-btn { white-space: nowrap; gap: 6px; }
.mem-seg .seg-n {
  font-family: var(--mono);
  font-size: 0.6875rem;
  color: var(--fg-3);
}
.mem-seg .seg-btn.is-on .seg-n { color: inherit; opacity: 0.75; }
.mem-intents { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.mem-filter-label { margin-right: 4px; font-size: 0.75rem; font-weight: 650; color: var(--fg-3); }
.mem-intent {
  padding: 4px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--intent, var(--fg-2));
  cursor: pointer;
}
.mem-intent:hover { border-color: var(--intent, var(--line-strong)); }
.mem-intent.is-on {
  border-color: var(--intent, var(--brand));
  background: var(--intent-wash, var(--brand-wash));
  color: var(--intent, var(--brand));
}
.mem-intent[data-mem-intent="all"].is-on { border-color: var(--fg-2); background: var(--surface-2); color: var(--fg); }

/* ---- The playbook's history, set apart from Activity's list it shares ---- */
/* The filters sit on one panel, so the three questions read as one toolbar
   over the list rather than three loose rows of buttons. */
#memoryTimelineCard .mem-filters {
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
}
#memoryTimelineCard .mem-intents {
  padding-top: 12px;
  border-top: 1px solid var(--line-soft);
}
#memoryTimelineCard .mem-intent[data-intent]::before {
  content: "";
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-right: 6px;
  border-radius: 50%;
  background: var(--intent);
  vertical-align: 1px;
}
#memoryTimelineCard .mem-intent { color: var(--fg-2); }
#memoryTimelineCard .mem-intent.is-on { color: var(--intent, var(--fg)); }

/* Posts are pictures first: a taller, portrait thumb, the caption given two
   lines, and how it did as three small numbers. */
#memoryTimelineCard .tl-row {
  grid-template-columns: 60px minmax(0, 1fr) auto;
  align-items: start;
  gap: 16px;
  padding: 14px 16px;
}
#memoryTimelineCard .tl-thumb {
  width: 60px;
  height: 76px;
  border-radius: 10px;
}
#memoryTimelineCard .tl-main { gap: 3px; }
#memoryTimelineCard .tl-sub {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  white-space: normal;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--fg-3);
}
#memoryTimelineCard .tl-meta { margin-top: 4px; }
#memoryTimelineCard .tl-side { padding-top: 2px; }
#memoryTimelineCard .tl-day-head {
  margin-left: 2px;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}
.tl-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 6px;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--fg-2);
  font-variant-numeric: tabular-nums;
}
.tl-stats > span {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.tl-stats svg {
  width: 14px;
  height: 14px;
  color: var(--fg-3);
}
@media (max-width: 560px) {
  #memoryTimelineCard .tl-row { grid-template-columns: 52px minmax(0, 1fr); gap: 12px; padding: 12px; }
  #memoryTimelineCard .tl-thumb { width: 52px; height: 66px; }
}

/* A run of versions folded into one row, and the way to open it. */
.tl-fold {
  align-self: flex-start;
  margin-top: 6px;
  padding: 3px 9px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface-2);
  font: inherit;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--fg-2);
  cursor: pointer;
}
.tl-fold:hover { color: var(--fg); border-color: var(--line-strong); }

/* ---------------- The plan, before anything is made ----------------
   The agent's proposal, under its reply: one row per drop, and the yes. */
.plan-card {
  display: block;
  margin-top: 10px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
}
.plan-head { display: block; font-size: 0.8125rem; color: var(--fg-3); margin-bottom: 6px; }
.plan-items { list-style: none; margin: 0; padding: 0; }
.chat-turn .plan-items li + li { margin-top: 8px; }
.plan-item { display: grid; grid-template-columns: auto 1fr; gap: 2px 10px; align-items: baseline; }
.plan-kind {
  font-size: 0.6875rem;
  padding: 1px 7px;
  border-radius: var(--r-pill);
  background: var(--brand-wash);
  color: var(--brand-strong);
  white-space: nowrap;
}
.plan-what { min-width: 0; overflow-wrap: anywhere; }
.plan-from { grid-column: 2; font-size: 0.8125rem; color: var(--fg-3); }
.plan-acts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }

.chat-auto-pill {
  margin-left: auto;
  margin-right: 8px;
  padding: 3px 10px;
  border: 1px solid var(--brand);
  border-radius: var(--r-pill);
  background: var(--brand-wash);
  color: var(--brand-strong);
  font: inherit;
  font-size: 0.75rem;
  cursor: pointer;
}
.chat-auto-pill:hover { filter: brightness(1.05); }

/* Several drops being made at once: where the worker has got to. */
.batch-strip {
  margin: 0 0 10px;
  padding: 8px 12px;
  border-radius: var(--r-md);
  background: var(--surface-2);
  color: var(--fg-2);
  font-size: 0.875rem;
}
#viewDrops .batch-strip { margin: 0 0 12px; }

.inline-select { font: inherit; padding: 0 4px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface); color: var(--fg); }

/* The ask sheet can carry a short list, one line each. */
#askBody { white-space: pre-line; }

/* The hidden <img> that notices a missing poster (see feedVideoHtml). Its
   containers style every img as display:block, which beats [hidden]. */
.poster-probe { display: none !important; }

/* The visible control is an icon; its accessible name carries the instruction. */
.format-card .format-play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 3;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.5);
  border-radius: 50%;
  background: rgba(15, 23, 42, 0.88);
  color: #fff;
  cursor: pointer;
  transition: opacity 0.18s ease, transform 0.18s ease;
}
.format-play svg { width: 22px; height: 22px; fill: currentColor; }
.format-play-spinner {
  width: 20px;
  height: 20px;
  border: 2px solid rgba(255, 255, 255, 0.4);
  border-top-color: #fff;
  border-radius: 50%;
  animation: kd-spin 0.8s linear infinite;
}
.format-card.is-playing .format-play { opacity: 0; }
/* Previewing under the pointer: the footage is the point, so the play disc
   steps into the corner as the way to hear it. */
.format-card.is-previewing .format-film { opacity: 1; }
.format-card.is-previewing .format-play {
  top: auto;
  left: auto;
  right: 8px;
  bottom: 8px;
  width: 34px;
  height: 34px;
  transform: none;
}
.format-card.is-previewing .format-play svg { width: 16px; height: 16px; }
.format-card.is-playing:hover .format-play,
.format-card.is-playing .format-play:focus-visible { opacity: 1; }
.format-play:focus-visible { outline: 3px solid var(--brand); outline-offset: 3px; }
/* Poster specificity must beat the base film rule, which comes later. */
.format-card .format-film[poster] { opacity: 1; }
.video-feedback {
  position: absolute;
  left: 12px;
  right: 12px;
  top: 12px;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px;
  padding: 10px 14px;
  border-radius: 12px;
  background: rgba(15, 23, 42, 0.9);
  color: #fff;
  font-size: 0.875rem;
  pointer-events: none;
}
.video-feedback[hidden] { display: none; }
.video-feedback .video-retry { pointer-events: auto; min-height: 44px; background: #fff; color: #16203a; }
#mediaPreviewBody { position: relative; }
@media (max-width: 760px) {
  .format-actions { flex-direction: column; align-items: stretch; }
  .format-over .format-use,
  .idea-use {
    min-height: 44px;
    padding: 10px 12px;
    border-radius: 12px;
    background: var(--brand-ink);
    border-color: var(--brand-ink);
    color: var(--on-brand);
    font-weight: 650;
  }
  .format-over .format-brief-btn { min-height: 44px; }
  .drop-sheet-foot { gap: 8px; padding: 12px; }
  .drop-sheet-foot .btn { min-height: 44px; border-radius: 12px; }
  .drop-play-disc { width: 48px; height: 48px; padding-left: 3px; }
  .drop-play-disc svg { width: 20px; height: 20px; }
}
.compose-pick-card .format-play { display: none; }


/* ---------- Versions of a drop ----------
   Pills for the original and each version, a stage under them for the one
   being watched or the panel making the next. Looks like the library's
   chips, because it is the same choice -- voice, language, music -- made
   for one reel. */
.dub {
  margin-top: 14px;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
}
.dub-head { display: grid; gap: 1px; margin-bottom: 10px; }
.dub-head b { font-size: 0.875rem; }
.dub-head span { color: var(--fg-3); font-size: 0.75rem; }
.dub-pills { display: flex; flex-wrap: wrap; gap: 6px; }
.dub-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 32px;
  padding: 5px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--fg);
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 600;
  cursor: pointer;
}
.dub-pill:hover { border-color: var(--fg-4); }
.dub-pill:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.dub-pill.is-on { border-color: var(--brand); background: var(--brand-wash); color: var(--brand-strong); }
.dub-pill.is-original { cursor: default; background: transparent; color: var(--fg-2); }
.dub-pill.is-live { color: var(--fg-2); }
.dub-pill.is-failed { border-color: var(--warn); color: var(--warn); }
.dub-pill .stamp-spin { width: 12px; height: 12px; }
.dub-warn {
  width: 16px;
  height: 16px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--warn);
  color: #fff;
  font-size: 0.6875rem;
}
.dub-add { border-style: dashed; color: var(--brand-ink); }
.dub-stage:not(:empty) { margin-top: 12px; }
.dub-video { width: 100%; max-height: 420px; border-radius: var(--r-md); background: #000; }
.dub-actions { margin-top: 8px; }
.dub-note, .dub-error { margin: 0 0 8px; font-size: 0.8125rem; line-height: 1.45; color: var(--fg-2); }
.dub-error { padding: 7px 9px; border-radius: 7px; background: var(--warn-wash); color: var(--warn); }

/* Rows, not columns: the drop sheet is a phone's width even on a desktop, and
   three selects side by side cut every one of them short. */
.dub-panel { display: grid; gap: 8px; }
.dub-field { display: grid; grid-template-columns: 96px minmax(0, 1fr); align-items: center; gap: 8px; min-width: 0; }
.dub-field-label {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--fg-2);
  font-size: 0.75rem;
  font-weight: 600;
}
.dub-field-label svg { width: 14px; height: 14px; }
.dub-field select.input { border-radius: var(--r-pill); font-size: 0.8125rem; }
.dub-panel-foot { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.dub-panel-foot .is-armed { background: var(--brand-strong); border-color: var(--brand-strong); }
.dub-count { margin-left: auto; color: var(--fg-3); font-size: 0.75rem; }

@media (max-width: 380px) {
  .dub-field { grid-template-columns: 1fr; gap: 4px; }
}

/* ---------------- Voice Lab ----------------
   One card per person. Phone first: every row wraps rather than scrolls, and
   every colour is a theme token, so dark mode needs nothing of its own. The
   status pill writes in the body colour on a tinted wash with a coloured dot:
   the tinted text of .pill-good/.pill-brand sits under AA at this size. */
.vlab-list { display: grid; gap: 0; min-width: 0; }

.vlab-card { min-width: 0; }

.vlab-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

.vlab-who { min-width: 0; }
.vlab-who h2 {
  font-family: var(--sans);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -0.012em;
  overflow-wrap: anywhere;
}
.vlab-who p { margin-top: 2px; font-size: 0.8125rem; color: var(--fg-3); }

.vlab-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  color: var(--fg);
  font-size: 0.75rem;
  font-weight: 600;
  white-space: nowrap;
}
.vlab-pill::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--fg-4);
  flex: none;
}
.vlab-pill.is-auto { background: var(--good-wash); }
.vlab-pill.is-auto::before { background: var(--good); }
.vlab-pill.is-owner { background: var(--violet-wash); }
.vlab-pill.is-owner::before { background: var(--violet); }
.vlab-pill.is-busy { background: var(--brand-wash); }
.vlab-pill.is-busy::before { background: var(--brand); animation: kd-pulse 1.6s var(--ease) infinite; }
.vlab-pill.is-none { background: var(--warn-wash); }
.vlab-pill.is-none::before { background: var(--warn); }

.vlab-label { margin: 12px 0 6px; }
.vlab-card > .vlab-label:first-of-type { margin-top: 0; }

.vlab-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* Taps are made at the pass with a thumb: 40px tall, not the feed chip's 28. */
.vlab-chip { min-height: 40px; padding: 6px 12px; }
.vlab-chip-sub { color: var(--fg-3); font-weight: 400; }

.vlab-ico { width: 13px; height: 13px; flex: none; }
.vlab-ico-pause { display: none; }
.is-playing > .vlab-ico .vlab-ico-play { display: none; }
.is-playing > .vlab-ico .vlab-ico-pause { display: inline; }
.is-loading > .vlab-ico { animation: kd-pulse 1s var(--ease) infinite; }

.vlab-chip.is-playing,
.vlab-hear.is-playing,
.vlab-play.is-playing,
.vlab-toggle.is-on {
  background: var(--brand-strong);
  border-color: var(--brand-strong);
  color: var(--on-brand);
}
.vlab-chip.is-playing .vlab-chip-sub { color: inherit; }

.vlab-dub { margin-top: 12px; }
.vlab-dub-row {
  display: flex;
  gap: 8px;
  align-items: center;
  min-width: 0;
}
.vlab-dub-row .input { flex: 1; min-width: 0; }
.vlab-dub-row .btn { flex: none; min-height: 40px; }
.vlab-hear { display: inline-flex; align-items: center; gap: 6px; }

.vlab-status {
  min-height: 1.4em;
  margin: 10px 0 2px;
  font-size: 0.8125rem;
  color: var(--fg-2);
}
.vlab-status:empty { min-height: 0; margin: 4px 0 0; }

.vlab-fold {
  margin-top: 10px;
  border-top: 1px solid var(--line-soft);
  padding-top: 10px;
}
.vlab-fold > summary {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--fg);
  cursor: pointer;
  list-style: none;
}
.vlab-fold > summary::-webkit-details-marker { display: none; }
.vlab-fold > summary::after {
  content: "";
  width: 8px;
  height: 8px;
  margin-left: auto;
  border-right: 2px solid var(--fg-3);
  border-bottom: 2px solid var(--fg-3);
  transform: rotate(45deg);
  transition: transform 0.15s var(--ease);
}
.vlab-fold[open] > summary::after { transform: rotate(-135deg); }
.vlab-fold > summary:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: var(--r-sm); }
.vlab-fold-hint { font-size: 0.8125rem; color: var(--fg-3); margin: 2px 0 8px; }

.vlab-takes { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.vlab-take {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  min-width: 0;
}
.vlab-take.is-current { border-color: var(--good); background: var(--good-wash); }
.vlab-take-text { flex: 1; min-width: 0; }
.vlab-take-text b { font-size: 0.875rem; font-weight: 600; }
.vlab-take-text small { display: block; margin-top: 2px; font-size: 0.75rem; color: var(--fg-3); overflow-wrap: anywhere; }
.vlab-take .btn { flex: none; }

.vlab-badge {
  display: inline-block;
  margin-left: 4px;
  padding: 1px 7px;
  border-radius: var(--r-pill);
  background: var(--surface);
  border: 1px solid var(--good);
  color: var(--fg);
  font-size: 0.6875rem;
  font-weight: 700;
  vertical-align: 1px;
}

.vlab-play {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  background: var(--surface-2);
  color: var(--fg);
  cursor: pointer;
}
.vlab-play:focus-visible,
.vlab-step:focus-visible,
.vlab-hear:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

.vlab-tune { padding-top: 4px; }
.vlab-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}
.vlab-row .field-label { margin: 0; }
.vlab-row-text { min-width: 0; }
.vlab-row-text .hint { display: block; margin-top: 2px; font-size: 0.8125rem; color: var(--fg-3); }
.vlab-toggle { min-height: 40px; flex: none; }

.vlab-stepper { display: inline-flex; align-items: center; gap: 6px; flex: none; }
.vlab-step { min-width: 40px; min-height: 40px; font-size: 1rem; justify-content: center; }
.vlab-pitch {
  min-width: 2.6em;
  text-align: center;
  font-family: var(--mono);
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--fg);
}

/* Deliveries can be five or six words long; a pill track of them would run
   off a phone, so this one wraps into a grid. */
.vlab-seg {
  grid-auto-flow: row;
  grid-template-columns: repeat(auto-fit, minmax(92px, 1fr));
  border-radius: var(--r-sm);
  margin-bottom: 0;
}
.vlab-seg .seg-btn { min-height: 38px; border-radius: calc(var(--r-sm) - 3px); }

.vlab-actions { display: flex; flex-wrap: wrap; gap: 8px; }

.vlab-foot {
  display: flex;
  justify-content: flex-end;
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--line-soft);
}
.vlab-foot .btn { max-width: 100%; white-space: normal; text-align: center; }
.vlab-refit.is-armed { color: var(--bad); background: var(--bad-wash); }

@media (max-width: 400px) {
  .vlab-take { flex-wrap: wrap; }
  .vlab-take .btn { margin-left: 50px; }
  .vlab-actions .btn { flex: 1 1 100%; }
}

/* Library results stay identifiable beside the photos they came from. */
.own-media-tools { display: grid; gap: 10px; margin: 0 0 12px; }
.own-media-tools > label { font-size: 0.8125rem; font-weight: 600; color: var(--fg-2); }
.own-media-tools input { width: 100%; min-width: 0; }
.own-media-filters { display: flex; flex-wrap: wrap; gap: 8px; }
.own-media-filters [aria-pressed="true"] { color: var(--brand-ink); background: var(--brand-wash); border-color: var(--brand-ink); }
.own-media-matches, .own-made-note { color: var(--fg-3); font-size: 0.8125rem; }
.own-media-matches:empty { display: none; }
.own-media-error { color: var(--fg-2); padding: 12px; border: 1px solid var(--line); border-radius: 10px; }
.own-made-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 180px), 1fr)); gap: 12px; margin-bottom: 12px; }
.own-made-card { margin: 0; min-width: 0; border: 1px solid var(--line); border-radius: 12px; overflow: hidden; background: var(--surface-2); }
.own-made-card > .lib-tile { display: block; width: 100%; border: 0; border-radius: 0; }
.own-made-card > video { display: block; width: 100%; aspect-ratio: 1; object-fit: contain; background: var(--surface-2); }
.own-made-card figcaption { display: grid; gap: 6px; padding: 12px; font-size: 0.8125rem; overflow-wrap: anywhere; }
.own-made-card figcaption b { color: var(--fg); }
.own-made-card figcaption span { color: var(--fg-3); }
.own-made-card figcaption a { color: var(--brand-ink); }
.own-media-tools[hidden] { display: none; }
