:root {
  /* Discord-ish neutrals: near-black canvas, one step up for panels. */
  --bg: #313338;
  --bg-deep: #1e1f22;
  --surface: #2b2d31;
  --surface-2: #383a40;
  --surface-3: #404249;
  --border: #3f4147;
  --text: #dbdee1;
  --text-strong: #f2f3f5;
  --muted: #949ba4;
  --accent: #5865f2;
  --accent-hover: #4752c4;
  --accent-soft: rgba(88, 101, 242, 0.15);
  --bubble-mine: #4752c4;
  --success: #23a55a;
  --danger: #f23f43;
  --warning: #f0b132;

  /*
   * One colour per network, used everywhere a platform appears so the same
   * thing is never two colours. YouTube sits a shade under its own red, which
   * is loud enough to pull the eye off everything beside it on a dark page.
   */
  --youtube: #cc2229;
  --youtube-soft: rgba(204, 34, 41, 0.18);
  --instagram: #e8508d;
  --instagram-soft: rgba(232, 80, 141, 0.18);
  --tiktok: #29b6e8;
  --tiktok-soft: rgba(41, 182, 232, 0.18);

  --radius: 8px;
  --radius-sm: 6px;
  font-family: "gg sans", "Segoe UI", system-ui, -apple-system, sans-serif;
  font-size: 15px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  height: 100vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}

button {
  font: inherit;
  font-weight: 500;
  cursor: pointer;
  border: none;
  background: var(--surface-2);
  color: var(--text-strong);
  padding: 8px 16px;
  border-radius: var(--radius-sm);
  transition: background 0.12s, opacity 0.12s;
}
button:hover:not(:disabled) { background: var(--surface-3); }
button:disabled { opacity: 0.45; cursor: not-allowed; }
button.primary { background: var(--accent); color: #fff; }
button.primary:hover:not(:disabled) { background: var(--accent-hover); }
button.danger { background: transparent; color: var(--danger); box-shadow: inset 0 0 0 1px var(--danger); }
button.danger:hover:not(:disabled) { background: var(--danger); color: #fff; }
button.ghost { background: transparent; color: var(--muted); }
button.ghost:hover:not(:disabled) { background: var(--surface-2); color: var(--text-strong); }

input, select, textarea {
  font: inherit;
  background: var(--bg-deep);
  color: var(--text-strong);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  padding: 9px 12px;
  width: 100%;
}
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--accent);
}
input::placeholder, textarea::placeholder { color: var(--muted); }

/* ---- Top bar ---- */
/*
 * The whole app, exactly as tall as the screen really is.
 *
 * `100vh` on a phone means the tallest the viewport could be, ignoring the
 * browser's own bars — so the page was a little taller than the glass and could
 * scroll, taking the top bar up under the address bar. That is the "sometimes I
 * cannot press the buttons at the top". `100dvh` follows the visible viewport;
 * the `100vh` line above it is for browsers that do not know `dvh` yet.
 */
.app-shell {
  display: flex; flex-direction: column;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}

header.topbar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 16px;
  height: 48px;
  background: var(--surface);
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
  flex-shrink: 0;
  z-index: 10;
}
.brand {
  font-weight: 700;
  letter-spacing: -0.01em;
  margin-right: 16px;
  color: var(--text-strong);
}
.tabs { display: flex; gap: 2px; }
.tab {
  background: transparent;
  color: var(--muted);
  padding: 6px 12px;
  border-radius: var(--radius-sm);
  font-size: 15px;
}
.tab:hover { background: var(--surface-2); color: var(--text-strong); }
.tab.active { background: var(--surface-3); color: #fff; }
.spacer { flex: 1; }
.whoami { color: var(--muted); font-size: 14px; }

/* min-width: 0 on both, or a wide child stops the whole page from shrinking
   and the grid pushes the buttons off the side of the screen. */
main { flex: 1; overflow: hidden; display: flex; min-width: 0; }
.view { flex: 1; display: none; overflow: hidden; min-width: 0; }
.view.active { display: flex; }

/* ---- On a phone ----
   The tabs scroll sideways instead of wrapping into the page, and everything
   that was two or three columns becomes one. */
@media (max-width: 720px) {
  header.topbar {
    padding: 8px 12px; gap: 8px;
    flex-wrap: wrap; height: auto;
  }
  .topbar .brand { font-size: 15px; }
  .topbar .whoami { display: none; }

  /*
   * Every tab on screen, wrapped onto as many rows as it takes.
   *
   * They used to scroll sideways: nine tabs is 627px of buttons in 366px of
   * phone, so five of them sat off the edge with nothing to say they were
   * there — which reads as having no tabs at all.
   */
  .tabs {
    order: 3; width: 100%;
    display: flex; flex-wrap: wrap; gap: 4px;
    padding-bottom: 2px;
  }
  .tab {
    flex: 1 1 auto; white-space: nowrap;
    padding: 6px 10px; font-size: 14px; text-align: center;
  }
}

/* ---- Sign in ---- */
.center-screen {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: var(--bg-deep);
}
.card {
  background: var(--surface);
  border-radius: var(--radius);
  padding: 32px;
  width: 100%;
  max-width: 400px;
  box-shadow: 0 8px 16px rgba(0, 0, 0, 0.24);
}
.card h1 { margin: 0 0 4px; font-size: 22px; color: var(--text-strong); text-align: center; }
.card p.sub { margin: 0 0 20px; color: var(--muted); font-size: 15px; text-align: center; }
.field { margin-bottom: 16px; }
.field label {
  display: block; margin-bottom: 8px;
  font-size: 12px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.02em; color: var(--muted);
}
.error-text { color: var(--danger); font-size: 14px; margin-top: 12px; min-height: 20px; }
.ok-text { color: var(--success); font-size: 14px; margin-top: 12px; }

/* ---- Progress ---- */
.progress {
  height: 4px;
  background: var(--bg-deep);
  border-radius: 999px;
  overflow: hidden;
}
.progress .bar {
  height: 100%;
  background: var(--accent);
  width: 0;
  transition: width 0.25s ease-out;
}
.progress.done .bar { background: var(--success); }
.progress.failed .bar { background: var(--danger); }

.badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: var(--radius-sm);
  font-size: 12px;
  font-weight: 500;
  background: var(--surface-3);
  color: var(--muted);
}
.badge.suggestion { background: var(--accent-soft); color: #a5b0ff; }
.badge.approved { background: rgba(35, 165, 90, 0.15); color: #4ac57e; }
.badge.rejected { background: rgba(242, 63, 67, 0.15); color: #f77b7e; }
.badge.pending { background: rgba(240, 177, 50, 0.15); color: #f0b132; }

.empty { color: var(--muted); text-align: center; padding: 48px 16px; }

::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--bg-deep); border-radius: 999px; }
::-webkit-scrollbar-thumb:hover { background: #111214; }

/* Reminders stack in the corner, above everything, on every tab. */
#notices {
  position: fixed; right: 18px; bottom: 18px; z-index: 300;
  display: flex; flex-direction: column; gap: 10px; max-width: 320px;
}
.notice {
  position: relative; cursor: pointer;
  padding: 12px 34px 12px 14px; border-radius: var(--radius);
  background: var(--surface); color: var(--text);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45), inset 0 0 0 1px var(--border);
  border-left: 3px solid #f0b232;
  animation: notice-in 0.18s ease-out;
}
.notice-head {
  font-size: 11px; font-weight: 700; letter-spacing: 0.05em;
  text-transform: uppercase; color: #ffcc4d;
}
.notice-title { font-size: 14px; color: var(--text-strong); margin-top: 2px; word-break: break-word; }
.notice-when { font-size: 12px; color: var(--muted); margin-top: 2px; }
.notice-close {
  position: absolute; top: 6px; right: 6px;
  width: 22px; height: 22px; padding: 0; line-height: 1;
  background: transparent; color: var(--muted); font-size: 16px;
}
.notice-close:hover { color: var(--text-strong); }
@keyframes notice-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

/* One video player, over whatever tab you are on. Opening a second browser tab
   loses your place, your filters and the tab you were reading. */
.watch-overlay {
  position: fixed; inset: 0; z-index: 400;
  background: rgba(8, 9, 12, 0.9);
  display: grid; place-items: center; padding: 24px;
}
.watch-card {
  background: var(--surface); border-radius: var(--radius);
  width: min(760px, 100%); max-height: 90vh;
  display: flex; flex-direction: column; overflow: hidden;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5);
}
.watch-card header {
  display: flex; align-items: center; gap: 12px; padding: 12px 16px;
}
.watch-title {
  flex: 1; min-width: 0; font-size: 14px; color: var(--text-strong);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.watch-card video { width: 100%; max-height: 74vh; background: #000; display: block; }
.watch-error { padding: 24px; text-align: center; color: var(--muted); font-size: 14px; }
.watch-error a { color: #a5b0ff; margin-left: 6px; }

/*
 * Followers per network and the month's views, across the top. Each network in
 * its own colour so which is which is read without the label, and the exact
 * figures on hover.
 */
.followers {
  display: flex; align-items: center; gap: 4px;
  font-size: 12px; font-variant-numeric: tabular-nums; cursor: default;
}
.followers[hidden] { display: none; }
.followers .net {
  padding: 3px 8px; border-radius: 999px; font-weight: 600;
  background: var(--surface-2); color: var(--muted);
  border: none; font-size: 12px; font-variant-numeric: tabular-nums;
  cursor: pointer;
}
.followers .net:hover { filter: brightness(1.25); }
.followers .net.instagram { background: var(--instagram-soft); color: #f39ec0; }
.followers .net.tiktok { background: var(--tiktok-soft); color: #7ed2ee; }
.followers .net.youtube { background: var(--youtube-soft); color: #ef8f93; }
.followers .net.views { background: rgba(35, 165, 90, 0.15); color: #5fd894; }

@media (max-width: 900px) { .followers .net.youtube, .followers .net.tiktok { display: none; } }
@media (max-width: 720px) {
  .followers { font-size: 11px; gap: 3px; }
  .followers .net { padding: 2px 6px; }
  .followers .net.instagram { display: none; }
}

/*
 * What the review made of a video, above the player.
 *
 * The fixes come first because whoever opened this is about to carry them out;
 * the title and hashtags sit under them because those are for later, at posting
 * time. Both used to be a thin strip that read as a caption on the video.
 */
.watch-card.with-meta { width: min(880px, 100%); }
.watch-meta {
  overflow-y: auto; padding: 0 16px 16px;
  display: flex; flex-direction: column; gap: 14px;
}
.watch-block-head {
  display: flex; align-items: baseline; gap: 10px;
  margin: 14px 0 8px;
}
.watch-block-title {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--muted);
}
.watch-dropped { font-size: 11px; color: var(--muted); }

.watch-fix-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.watch-fix {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 9px 11px; border-radius: var(--radius-sm);
  background: var(--surface-2);
  box-shadow: inset 3px 0 0 var(--warning);
}
.watch-fix.dropped {
  opacity: 0.5; box-shadow: inset 3px 0 0 var(--muted);
}
.watch-fix.dropped .watch-fix-label { text-decoration: line-through; }

/* The moment is a button: finding 1:05.4 by hand on a scrubber is no fun. */
.watch-at {
  flex: none; font-size: 12px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  padding: 3px 8px; border-radius: 999px; cursor: pointer;
  background: var(--surface-3); color: var(--text-strong); border: none;
}
.watch-at:hover { background: var(--accent); color: #fff; }
.watch-fix-text { min-width: 0; }
.watch-fix-label { font-size: 14px; font-weight: 600; color: var(--text-strong); }
.watch-fix-body { font-size: 13px; color: var(--text); margin-top: 2px; line-height: 1.45; }

.watch-post { border-top: 1px solid var(--border); }
.watch-field { display: flex; gap: 10px; align-items: baseline; padding: 4px 0; }
.watch-field-label {
  flex: none; width: 66px; font-size: 12px; color: var(--muted);
}
/* Click to copy: this is the text that gets pasted into the post. */
.watch-field-value {
  font-size: 14px; color: var(--text-strong); cursor: pointer;
  padding: 3px 8px; border-radius: var(--radius-sm); background: var(--surface-2);
}
.watch-field-value:hover { background: var(--surface-3); }
.watch-field-value.copied { background: rgba(35, 165, 90, 0.25); color: #5fd894; }
.watch-field-value.tags { color: #a5b0ff; }

@media (max-width: 720px) {
  .watch-overlay { padding: 8px; }
  .watch-field { flex-direction: column; gap: 2px; }
  .watch-field-label { width: auto; }
}

/*
 * AICHECK — the editor's own second opinion, in Gemini.
 *
 * A page cannot put a file into another site's upload box, so it does the two
 * halves it can: the prompt onto the clipboard and the file into Downloads.
 * These steps say so plainly rather than leaving him to guess why nothing
 * happened.
 */
.aicheck-btn {
  font-size: 12px; font-weight: 700; letter-spacing: 0.03em;
  padding: 6px 12px; border-radius: var(--radius-sm);
  background: rgba(88, 101, 242, 0.18); color: #a5b0ff;
}
.aicheck-btn:hover { background: var(--accent); color: #fff; }

.aicheck-how {
  position: fixed; inset: 0; z-index: 500;
  background: rgba(8, 9, 12, 0.7);
  display: grid; place-items: center; padding: 20px;
}
.aicheck-card {
  background: var(--surface); border-radius: var(--radius);
  padding: 20px; width: min(460px, 100%);
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5);
}
.aicheck-card header {
  display: flex; align-items: center; justify-content: space-between;
  font-size: 12px; font-weight: 700; letter-spacing: 0.05em;
  color: #a5b0ff; margin-bottom: 12px;
}
.aicheck-card ol { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 8px; }
.aicheck-card li { font-size: 14px; line-height: 1.5; color: var(--text); }
.aicheck-card a { color: #a5b0ff; }
.aicheck-file { color: var(--text-strong); word-break: break-all; }
.aicheck-prompt {
  margin-top: 12px; font-size: 12px; font-family: ui-monospace, monospace;
  resize: vertical;
}
.aicheck-note { margin: 12px 0 0; font-size: 12px; color: var(--muted); line-height: 1.5; }

/*
 * The small form that replaced a run of `prompt()` boxes. Same shape as the
 * AICHECK card, because two dialogs that behave the same should look the same.
 */
.ask-sheet {
  position: fixed; inset: 0; z-index: 500;
  background: rgba(8, 9, 12, 0.7);
  display: grid; place-items: center; padding: 20px;
}
.ask-card {
  background: var(--surface); border-radius: var(--radius);
  padding: 20px; width: min(400px, 100%);
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5);
}
.ask-card header {
  display: flex; align-items: center; justify-content: space-between;
  font-size: 15px; font-weight: 600; color: var(--text-strong); margin-bottom: 16px;
}
.ask-fields { display: flex; flex-direction: column; gap: 14px; }
.ask-field { display: flex; flex-direction: column; gap: 5px; }
.ask-label { font-size: 12px; color: var(--muted); }
.ask-hint { font-size: 11px; color: var(--muted); opacity: 0.75; }
.ask-card footer { display: flex; justify-content: flex-end; gap: 8px; margin-top: 18px; }

/*
 * How many videos are recorded and still to edit. A slider rather than a field:
 * it is a rough count that changes daily, and either of them may know it.
 */
.stock-card {
  background: var(--surface-2); border-radius: var(--radius);
  padding: 14px 16px; margin-bottom: 14px;
}
.stock-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.stock-label { font-size: 13px; color: var(--muted); }
.stock-figure { font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; }
.stock-figure.red { color: var(--danger); }
.stock-figure.orange { color: #ff9d3d; }
.stock-figure.yellow { color: var(--warning); }
.stock-figure.green { color: var(--success); }
.stock-card input[type=range] { width: 100%; margin: 10px 0 4px; accent-color: var(--accent); }
.stock-hint { margin: 0; font-size: 11px; color: var(--muted); line-height: 1.5; }

/* The same tag as the schedule warning, next to it, in the same colours. */
.videos-left {
  font-size: 11px; font-weight: 600; padding: 3px 10px; border-radius: 999px;
}
.videos-left.red { background: rgba(224, 87, 74, 0.18); color: #ff9093; }
.videos-left.orange { background: rgba(255, 157, 61, 0.18); color: #ffb877; }
.videos-left.yellow { background: rgba(240, 177, 50, 0.18); color: #f5cd77; }

/*
 * The tab menu, folded away.
 *
 * Three rows of buttons is most of a phone screen, and once you have chosen a
 * tab they are only in the way. Tapping the name folds them; tapping it again
 * brings them back, and the arrow says which of the two will happen.
 */
@media (max-width: 720px) {
  .topbar .brand { cursor: pointer; user-select: none; }
  .topbar .brand::after {
    content: ' ▾'; font-size: 11px; opacity: 0.6;
  }
  .topbar.folded .brand::after { content: ' ▸'; }
  .topbar.folded .tabs { display: none; }
}

/* A check in progress, on the Check tab, in place of the button. */
.check-progress-row { display: flex; align-items: center; gap: 8px; flex: none; min-width: 150px; }
.check-progress-row .check-progress {
  flex: 1; height: 5px; border-radius: 999px; overflow: hidden;
  background: var(--bg-deep);
}
.check-progress-row .check-progress .bar {
  height: 100%; background: var(--warning); transition: width 0.3s ease;
}
.check-progress-row .check-stage { font-size: 11px; color: var(--warning); white-space: nowrap; }

/*
 * The title picker shown inside the watch overlay when a checked video has
 * five AI-generated ideas but none has been chosen yet. Each idea is a
 * clickable row; the last row is a free-text field.
 */
.title-pick-list {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 6px;
}
/*
 * Nineteen ideas, side by side.
 *
 * A title is chosen by comparing it against the others, so a list you have to
 * scroll to finish reading is one you cannot compare. Ten on the left, nine on
 * the right with the free-text row under them — which is what makes the two
 * columns end at the same height.
 */
.title-pick-columns {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px; align-items: start;
}
.title-pick-side { display: flex; flex-direction: column; gap: 6px; }
.title-pick-side .title-custom-row { margin-top: 4px; }
/* One column on a phone, where two would be two narrow columns of wrapped
   words rather than two readable lists. */
@media (max-width: 720px) {
  .title-pick-columns { grid-template-columns: 1fr; }
}
.title-pick-item {
  display: flex; gap: 10px; align-items: center;
  padding: 10px 12px; border-radius: var(--radius-sm);
  background: var(--surface-2); cursor: pointer;
  transition: background 0.12s;
}
.title-pick-item:hover { background: var(--surface-3); }
/* The one it is going out under, so opening this again answers "which did I
   pick" before you have read a single line. */
.title-pick-item.chosen {
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px var(--accent);
}
.title-pick-item.chosen .title-pick-text { font-weight: 600; }
.title-pick-num {
  flex: none; width: 22px; height: 22px; border-radius: 50%;
  background: var(--accent); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 700;
}
.title-pick-text { font-size: 14px; color: var(--text-strong); line-height: 1.35; }
.title-custom-row {
  display: flex; gap: 8px; margin-top: 10px;
}
.title-custom-input { flex: 1; }
/* Carries both "saved" and "that failed", so it is quiet by default and only
   goes red when something actually went wrong. */
.title-pick-status {
  margin-top: 6px; font-size: 12px; color: var(--muted); min-height: 18px;
}
.title-pick-status.bad { color: var(--danger); }

/*
 * A page that is older than the server says so.
 *
 * Without this, a tab left open across a deploy runs last week's JavaScript for
 * ever, and every fix since is invisible — including the ones you are looking
 * straight at and reporting as broken.
 */
.stale-bar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 900;
  background: var(--warning); color: #1a1206;
  padding: 8px 14px; font-size: 13px; font-weight: 600;
  display: flex; align-items: center; justify-content: center; gap: 12px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.35);
}
.stale-reload {
  background: #1a1206; color: var(--warning);
  border: 0; border-radius: var(--radius-sm);
  padding: 4px 12px; font-size: 12px; font-weight: 700; cursor: pointer;
}
.stale-reload:hover { opacity: 0.85; }

/*
 * Sending a video back for a second look, once the first found something.
 *
 * A different word from the first check on purpose: the first is "look at
 * this", this one is "the fix landed, look again". Same colour family as the
 * mistakes it follows, so it reads as belonging to them.
 */
.run-check.again,
.do-check.again {
  background: transparent;
  color: var(--warning);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--warning) 55%, transparent);
}
.run-check.again:hover,
.do-check.again:hover { background: var(--warning); color: #1a1206; }
