/* TikTok Lab — a neutral frame around the team's videos, with one accent (cobalt) for what is chosen
   or pressed and three status colours (green, amber, red) for how things are going. Hierarchy still
   comes from weight, size and space; the colours only ever say "selected", "live", "wait" or "wrong". */

/* ---- type -------------------------------------------------------------------------------------- */
/* Onest for everything, JetBrains Mono for codes, ids and file names: served from /fonts, so no
   third party sees the team load a page. Latin subsets only — the UI is English. */
@font-face { font-family: "Onest"; src: url("/fonts/onest.woff2") format("woff2"); font-weight: 100 900; font-style: normal; font-display: swap; }
@font-face { font-family: "JetBrains Mono"; src: url("/fonts/jetbrains-mono.woff2") format("woff2"); font-weight: 100 800; font-style: normal; font-display: swap; }

/* ---- tokens ---------------------------------------------------------------------------------- */
:root {
  --topbar-h: 56px; /* the sticky bar's real height, kept by common.js: two or three lines on a phone */
  --bg: #f4f5f7;
  --surface: #ffffff;
  --sunken: #f1f2f5;
  --fg: #101217;
  --fg-2: #3c4049;
  --muted: #6a6f7a;
  --faint: #a3a8b2;
  --line: #e5e7eb;
  --line-strong: #d3d6dc;
  --invert-bg: #101217;
  --invert-fg: #ffffff;
  --chip: var(--sunken);
  /* the accent: primary buttons, the chosen chip or card, focus, progress */
  --accent: #2b6cf5;
  --accent-strong: #1f58d8;
  --accent-fg: #ffffff;
  --accent-text: #1d55cf;
  --accent-soft: #e9efff;
  --accent-line: #b9ccff;
  --ring: rgb(43 108 245 / 0.26);
  /* how things are going */
  --ok: #178a4c;
  --ok-soft: #e3f6ea;
  --ok-line: #a9dfc0;
  --ok-ring: rgb(23 138 76 / 0.32);
  --warn: #b1660a;
  --warn-soft: #fdf2dd;
  --warn-line: #f0d49c;
  --bad: #cc3333;
  --bad-soft: #fdeaea;
  --bad-line: #f4b9b9;
  --shadow-sm: 0 1px 2px rgb(16 18 23 / 0.05);
  --shadow: 0 1px 2px rgb(16 18 23 / 0.04), 0 12px 32px -16px rgb(16 18 23 / 0.16);
  --shadow-lg: 0 2px 6px rgb(16 18 23 / 0.06), 0 20px 48px -12px rgb(16 18 23 / 0.28);
  --font: "Onest", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --sans: var(--font);
  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  color-scheme: light dark;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0b0c0f;
    --surface: #141518;
    --sunken: #1c1e23;
    --fg: #f1f2f4;
    --fg-2: #c7cad1;
    --muted: #8d929c;
    --faint: #5b6069;
    --line: #24262c;
    --line-strong: #34373f;
    --invert-bg: #f1f2f4;
    --invert-fg: #101217;
    /* White on these is 4.6:1 and, hovered, 5.5:1. The brighter pair before them (#4d82ff, #679aff)
       gave 3.5:1 and 2.75:1: every primary button's words, weaker still under the pointer. */
    --accent: #3b6dee;
    --accent-strong: #3160d8;
    --accent-fg: #ffffff;
    --accent-text: #8db1ff;
    --accent-soft: #182542;
    --accent-line: #2f4a86;
    --ring: rgb(59 109 238 / 0.45);
    --ok: #3ecf7a;
    --ok-soft: #10281c;
    --ok-line: #1f5a39;
    --ok-ring: rgb(62 207 122 / 0.35);
    --warn: #f2b23d;
    --warn-soft: #2d2210;
    --warn-line: #6b4d14;
    --bad: #ff6b6b;
    --bad-soft: #321417;
    --bad-line: #7a2a2e;
    --shadow-sm: none;
    --shadow: 0 1px 2px rgb(0 0 0 / 0.5), 0 16px 40px -16px rgb(0 0 0 / 0.8);
    --shadow-lg: 0 2px 6px rgb(0 0 0 / 0.5), 0 20px 48px -12px rgb(0 0 0 / 0.9);
  }
}

/* ---- base ------------------------------------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
/* The download-only login: the parts of the creatives page that are not the downloader. */
body.download-only .team-only { display: none !important; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 14px/1.5 var(--font);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  -webkit-tap-highlight-color: transparent;
}
h1, h2, h3, p { margin: 0; }
b, strong { font-weight: 600; }
a { color: inherit; }
::selection { background: color-mix(in srgb, var(--accent) 22%, transparent); }
code, pre, .mono { font-family: var(--mono); }
code { font-size: 12.5px; padding: 2px 6px; border-radius: 6px; background: var(--sunken); overflow-wrap: anywhere; }
.muted { color: var(--muted); }
.num { font-variant-numeric: tabular-nums; }
svg.icon { flex: none; display: block; }
[data-icon] { display: inline-flex; }

/* The page appears once its data is in. The animation is a safety net: it shows the page anyway. */
body.booting main { opacity: 0; animation: appear 0.2s 2.5s forwards; }
main { transition: opacity 0.2s; }
@keyframes appear { to { opacity: 1; } }
/* Meanwhile the page is not blank: two panel shapes stand where the panels will be, from a third
   of a second in, so a quick read never flashes them. Drawn, not markup — nothing for a reader or a
   test to find — and gone with the booting class. */
body.booting::before, body.booting::after {
  content: ""; position: fixed; z-index: 1; left: 50%; transform: translateX(-50%); pointer-events: none;
  box-sizing: border-box; width: min(1040px, 100% - 40px); padding: 22px 24px;
  border: 1px solid var(--line); border-radius: 16px; background-color: var(--surface);
  background-image: linear-gradient(var(--sunken), var(--sunken)), linear-gradient(var(--sunken), var(--sunken)), linear-gradient(var(--sunken), var(--sunken));
  background-repeat: no-repeat; background-origin: content-box;
  background-size: 160px 16px, 70% 12px, 45% 12px; background-position: 0 0, 0 36px, 0 58px;
  opacity: 0; animation: appear 0.2s 0.35s forwards, breathe 1.6s 0.55s ease-in-out infinite alternate;
}
body.booting::before { top: calc(var(--topbar-h) + 24px); height: 150px; }
body.booting::after { top: calc(var(--topbar-h) + 190px); height: 44vh; }
body.wide.booting::before, body.wide.booting::after { width: min(1280px, 100% - 40px); }
@keyframes breathe { from { opacity: 1; } to { opacity: 0.55; } }

/* ---- top bar --------------------------------------------------------------------------------- */
.topbar {
  position: sticky; top: 0; z-index: 20;
  background: color-mix(in srgb, var(--bg) 80%, transparent);
  -webkit-backdrop-filter: saturate(1.5) blur(14px); backdrop-filter: saturate(1.5) blur(14px);
  border-bottom: 1px solid var(--line);
}
.topbar-in, main { max-width: 1080px; margin: 0 auto; padding-left: 20px; padding-right: 20px; }
/* The bar is the page's width, and wider when its words need more, up to 1320px: the admin's eight
   tabs, the VA view's extra button and the Filipino words then still sit on one line. Before, the
   bar's parts gave way instead — the brand broke in two and the language switch was drawn over
   the sign-out button (2026-10-25). In a window too narrow for all of it, the right side drops to
   a line of its own (flex-wrap), never into its neighbours, and the tabs stay beside the brand:
   the right side is pushed right by its own margin, not by spreading the bar's parts apart. The
   8px above and below keep the one-line bar at 56px. */
.topbar-in { width: fit-content; min-width: min(1080px, 100%); max-width: min(1320px, 100%); min-height: 56px; padding-top: 8px; padding-bottom: 8px; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; }
.brand { display: inline-flex; flex: none; align-items: center; gap: 10px; font-size: 16px; font-weight: 600; letter-spacing: -0.01em; text-decoration: none; color: var(--fg); }
/* The mark: the accent's square with a white star, in either theme. */
.brand svg { color: var(--accent); }
.brand-star { fill: #fff; }
.topbar-side { display: flex; align-items: center; gap: 16px; min-width: 0; margin-left: auto; }
.who { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
.user { font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 22ch; }
/* The language switch (lang.js): a globe and the other language's name, last in the bar; under
   the form on the sign-in page. */
.language { gap: 5px; white-space: nowrap; color: var(--fg-2); }
.language .icon { flex: none; }
.login .language { display: flex; height: 28px; margin: 18px auto 0; }
.live { display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--muted); white-space: nowrap; }
/* the clock-in button: plain until clocked in, then marked with a pulsing dot like the live mark */
button.clock { white-space: nowrap; }
button.clock .clock-time { font-variant-numeric: tabular-nums; } /* the running timer keeps its width as it ticks */
button.clock.on { border-color: var(--ok-line); background: var(--ok-soft); color: var(--ok); }
button.clock.on:hover:not(:disabled) { border-color: var(--ok); background: var(--ok-soft); }
button.clock.on i { --pulse-ring: var(--ok-ring); width: 8px; height: 8px; border-radius: 50%; background: var(--ok); animation: pulse 2.4s ease-in-out infinite; }
.live i { width: 8px; height: 8px; border-radius: 50%; background: var(--faint); }
.live[data-state="ok"] i { --pulse-ring: var(--ok-ring); background: var(--ok); animation: pulse 2.4s ease-in-out infinite; }
.live[data-state="connecting"] i, .live[data-state="down"] i { background: transparent; border: 2px solid var(--faint); border-top-color: var(--accent); animation: spin 0.8s linear infinite; }
.live[data-state="down"] { color: var(--warn); font-weight: 550; }
@keyframes pulse { 0%, 100% { box-shadow: 0 0 0 0 var(--pulse-ring, var(--ring)); } 50% { box-shadow: 0 0 0 6px transparent; } }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---- layout ---------------------------------------------------------------------------------- */
main { display: grid; gap: 16px; padding-top: 24px; padding-bottom: 72px; }
.panel { background: var(--surface); border: 1px solid var(--line); border-radius: 16px; padding: 22px 24px 24px; min-width: 0; box-shadow: var(--shadow-sm); }
.panel.quiet { background: transparent; box-shadow: none; }
.panel-head { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.panel-head h2 { font-size: 16px; font-weight: 600; letter-spacing: -0.01em; }
/* A panel that folds (the campaigns screen, user 2026-09-23): its head is the summary, with the
   same chevron as the folds inside it, and folded it is one bar with the note still on it. */
details.panel > summary.panel-head { cursor: pointer; list-style: none; user-select: none; }
details.panel > summary.panel-head::-webkit-details-marker { display: none; }
details.panel:not([open]) > summary.panel-head { margin-bottom: 0; }
details.panel:not([open]) { padding-bottom: 22px; }
.panel-head .chev { display: inline-grid; place-items: center; flex: none; color: var(--muted); transition: transform 0.18s; }
details.panel[open] > .panel-head .chev { transform: rotate(90deg); }
.step {
  display: inline-grid; place-items: center; width: 24px; height: 24px; border-radius: 50%;
  background: var(--accent); color: var(--accent-fg); font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums;
}
.count { margin-left: auto; color: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; }
.hint { color: var(--muted); font-size: 13px; text-wrap: pretty; }
p.hint { margin-top: 12px; }
.actions { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 12px; margin-top: 16px; }
.actions .hint { flex: 1 1 240px; min-width: 0; }
.field-row { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; margin-top: 14px; }
.field-label { color: var(--muted); font-size: 13px; }
.field-row .spacer { flex: 1; }

/* ---- controls -------------------------------------------------------------------------------- */
button, .button, input, select, textarea { font: inherit; color: inherit; }
button, .button {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px; height: 36px; padding: 0 14px;
  border: 1px solid var(--line-strong); border-radius: 10px; background: var(--surface);
  font-weight: 550; white-space: nowrap; text-decoration: none; cursor: pointer; user-select: none;
  transition: background-color 0.15s, border-color 0.15s, color 0.15s, opacity 0.15s, transform 0.06s;
}
button:hover:not(:disabled), .button:hover { background: var(--sunken); border-color: var(--faint); }
button:active:not(:disabled), .button:active { transform: translateY(1px); }
button:disabled { opacity: 0.38; cursor: default; }
button.primary, .button.primary { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); }
button.primary:hover:not(:disabled), .button.primary:hover { background: var(--accent-strong); border-color: var(--accent-strong); }
button.ghost, .button.ghost { border-color: transparent; background: transparent; color: var(--fg-2); }
button.ghost:hover:not(:disabled), .button.ghost:hover { background: var(--sunken); border-color: transparent; color: var(--fg); }
button.small, .button.small { height: 28px; padding: 0 10px; border-radius: 8px; font-size: 12.5px; gap: 6px; }
button.link { height: auto; padding: 0; border: 0; border-radius: 4px; background: none; color: var(--muted); font-weight: inherit; text-decoration: underline; text-underline-offset: 2px; }
button.link:hover:not(:disabled) { background: none; color: var(--fg); }
a.link { color: var(--muted); text-decoration: underline; text-underline-offset: 2px; }
a.link:hover { color: var(--fg); }
button.busy { position: relative; color: transparent !important; pointer-events: none; }
button.busy::after {
  content: ""; position: absolute; width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid var(--faint); border-top-color: var(--fg); animation: spin 0.7s linear infinite;
}
button.primary.busy::after { border-color: color-mix(in srgb, var(--accent-fg) 35%, transparent); border-top-color: var(--accent-fg); }

/* :where() keeps this base rule at an element's weight. Written plainly, the three :not()s made it
   outweigh a page's own `.page .box input` rule, so the Check and Listings paste boxes never got
   the room their link icon needs and the icon sat on the first letters (2026-10-25). */
input:where(:not([type="checkbox"]):not([type="radio"]):not([type="file"])), select, textarea {
  width: 100%; min-height: 38px; padding: 8px 12px; border: 1px solid var(--line-strong); border-radius: 10px;
  background: var(--surface); transition: border-color 0.15s, box-shadow 0.15s;
}
select { width: auto; padding-right: 30px; cursor: pointer; }
/* The tick that says a part of the launch form is filled in, and the line that says what is
   wrong when it is not. Monochrome like the rest: an icon and weight, never a colour. */
.field-mark { display: flex; align-items: flex-start; gap: 6px; line-height: 1.5; font-size: 12.5px; color: var(--muted); min-width: 0; overflow-wrap: anywhere; }
/* flex, not inline-flex: inline-flex sizes to max-content, so a whole sentence refused to wrap and
   ran off the side of a phone. Named field-mark and not check because .check was already taken by
   the checkbox label below, which is nowrap — the collision is what pinned this to one line. */
.field-mark .icon { flex: none; margin-top: 2px; } /* sits on the first line, not the middle of a wrapped one */
.field-mark.ok { color: var(--ok); }
.field-mark.bad { color: var(--bad); font-weight: 550; }
.field-mark.warn { color: var(--warn); font-weight: 550; }
p.field-mark { margin: 8px 0 0; }
/* A select that stands in a row of small ghost buttons has to be their height, not a field's. */
select.small { min-height: 28px; padding: 3px 26px 3px 10px; border-radius: 8px; font-size: 12.5px; }
/* A box grows with what is pasted into it — twenty links show as twenty lines, not four and a
   scrollbar — up to most of the screen, where it scrolls as before. Browsers without field-sizing
   keep their rows. */
textarea { resize: vertical; line-height: 1.55; field-sizing: content; min-height: calc(4lh + 22px); max-height: min(60vh, 560px); }
::placeholder { color: var(--faint); opacity: 1; }
input:not([type="checkbox"]):not([type="radio"]):focus, select:focus, textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--ring); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
input:not([type="checkbox"]):not([type="radio"]):focus-visible, select:focus-visible, textarea:focus-visible { outline: none; }
/* Whatever the browser scrolls to — a field it focuses, a row brought into view — lands clear of
   the sticky bar rather than under it. */
input, select, textarea, button, .account, .video, .field-mark, summary { scroll-margin-top: calc(var(--topbar-h) + 16px); }

/* Tick boxes: drawn here so they look the same everywhere; ticked, they take the accent. */
input[type="checkbox"] {
  appearance: none; -webkit-appearance: none; flex: none; width: 18px; height: 18px; margin: 0; border-radius: 6px; cursor: pointer;
  border: 1.5px solid var(--faint); background: var(--surface) center / 12px no-repeat; transition: background-color 0.12s, border-color 0.12s;
}
input[type="checkbox"]:hover { border-color: var(--accent); }
input[type="checkbox"]:checked {
  border-color: var(--accent); background-color: var(--accent);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 6.2l2.4 2.4 4.6-5' fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
/* Round ticks (one pick of a few, e.g. what a customer still gets on the support desk): drawn like the tick
   boxes; the chosen one takes the accent. Until 2026-10-24 the field rule above took them for text fields,
   so each one stretched across its row and its words ran off the side. */
input[type="radio"] {
  appearance: none; -webkit-appearance: none; flex: none; width: 18px; height: 18px; margin: 0; border-radius: 50%; cursor: pointer;
  border: 1.5px solid var(--faint); background: var(--surface); transition: background-color 0.12s, border-color 0.12s, box-shadow 0.12s;
}
input[type="radio"]:hover { border-color: var(--accent); }
input[type="radio"]:checked { border-color: var(--accent); background-color: var(--accent); box-shadow: inset 0 0 0 3.5px var(--surface); }
.check { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; color: var(--fg-2); font-size: 13.5px; white-space: nowrap; }

/* ---- chips (accounts to pick) ---------------------------------------------------------------- */
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  height: 32px; padding: 0 12px; gap: 7px; border-radius: 999px; font-weight: 500; font-size: 13.5px;
}
/* A chip that opens with a face sits it near the edge, the way a pill with a picture does; a chip
   of words alone keeps the same room on both sides, or the words sit off centre (user, 2026-09-23). */
.chip .avatar { width: 22px; height: 22px; font-size: 10.5px; }
.chip > .avatar:first-child { margin-left: -7px; }
.chip[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent-text); border-color: var(--accent-line); }
.chip[aria-pressed="true"]:hover:not(:disabled) { background: var(--accent-soft); border-color: var(--accent); }
.chip[aria-pressed="true"] .avatar { outline: 1.5px solid var(--accent); }
.chip .tick { display: none; margin-left: -1px; }
.chip[aria-pressed="true"] .tick { display: inline-flex; }

.avatar {
  flex: none; display: inline-grid; place-items: center; width: 36px; height: 36px; border-radius: 50%; overflow: hidden;
  background: var(--sunken); color: var(--muted); font-size: 14px; font-weight: 650; text-transform: uppercase;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ---- step 1: links and files ----------------------------------------------------------------- */
.dropzone {
  position: relative; border: 1.5px dashed var(--line-strong); border-radius: 14px; background: var(--sunken);
  transition: border-color 0.15s, background-color 0.15s, box-shadow 0.15s;
}
.dropzone:focus-within { border-color: var(--accent); border-style: solid; box-shadow: 0 0 0 3px var(--ring); background: var(--surface); }
.dropzone textarea { display: block; min-height: 104px; padding: 14px 16px 6px; border: 0; border-radius: 14px; background: transparent; box-shadow: none !important; }
.dropzone-foot { padding: 0 16px 12px; font-size: 12.5px; pointer-events: none; }
.dropzone-over {
  position: absolute; inset: -1.5px; display: none; place-items: center; border-radius: 14px; pointer-events: none;
  background: var(--accent); color: var(--accent-fg); font-weight: 600; font-size: 15px;
}
.dragging .dropzone-over { display: grid; }

.upload { margin-top: 14px; }
.upload-line { display: flex; justify-content: space-between; gap: 12px; font-size: 13px; color: var(--fg-2); }
.upload-line span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bar { height: 6px; margin-top: 8px; border-radius: 999px; background: var(--sunken); overflow: hidden; }
.bar i { display: block; height: 100%; width: 0; border-radius: inherit; background: var(--accent); transition: width 0.3s ease; }
.bar.working i { width: 34% !important; animation: slide 1.2s ease-in-out infinite; }
@keyframes slide { 0% { transform: translateX(-110%); } 100% { transform: translateX(310%); } }

/* ---- folds (details) ------------------------------------------------------------------------- */
.fold { margin-top: 18px; border-top: 1px solid var(--line); padding-top: 4px; }
.fold.bare { margin-top: 0; border-top: 0; padding-top: 0; }
.fold > summary {
  display: flex; align-items: center; gap: 8px; padding: 12px 0 4px; cursor: pointer; list-style: none; border-radius: 8px;
}
.fold.bare > summary { padding: 0; }
.fold > summary::-webkit-details-marker { display: none; }
.fold .chev { color: var(--muted); transition: transform 0.18s; }
.fold[open] > summary .chev { transform: rotate(90deg); }
.fold-title { font-weight: 600; white-space: nowrap; }
.fold-note { color: var(--muted); font-size: 13px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fold-body { padding-top: 12px; }
.texts { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px; }
.texts label, .login label { display: grid; gap: 6px; font-size: 12.5px; font-weight: 550; color: var(--fg-2); }
.texts input, .login input { font-size: 14px; font-weight: 400; color: var(--fg); }
.options { display: flex; align-items: center; flex-wrap: wrap; gap: 12px 22px; margin-top: 16px; }
.inline { display: inline-flex; align-items: center; gap: 10px; font-size: 13.5px; color: var(--fg-2); white-space: nowrap; }

/* ---- empty states ---------------------------------------------------------------------------- */
.empty { display: grid; justify-items: center; gap: 10px; padding: 28px 16px; text-align: center; color: var(--muted); font-size: 13.5px; border: 1.5px dashed var(--line); border-radius: 14px; }
.empty b { color: var(--fg); font-weight: 600; }
.empty p { max-width: 46ch; }
.empty-icon { display: grid; place-items: center; width: 40px; height: 40px; border-radius: 12px; background: var(--accent-soft); color: var(--accent-text); }

/* ---- step 2, a video before it has posted ------------------------------------------------- */
/* The same tile as a posted card: .grid, .frame, .shade, .label and .veil are shared, and
   only what a video tile needs on top of a code card is set here. */
.video { min-width: 0; display: flex; flex-direction: column; animation: rise 0.25s ease both; }
/* Tiles in a row are as tall as the tallest, so the destination and the actions are pushed to the
   bottom — otherwise one extra line of meta leaves every neighbour's buttons at a different height. */
.video .card-actions { margin-top: auto; padding-top: 8px; display: flex; align-items: center; flex-wrap: wrap; justify-content: flex-start; gap: 12px; font-size: 12px; color: var(--muted); }
.video .frame > .open { display: block; width: 100%; height: 100%; padding: 0; border: 0; border-radius: 0; background: none; cursor: pointer; }
.video .frame > .open img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 0.35s ease; }
.video .frame > .open:hover img { transform: scale(1.03); }
.play-mark { position: absolute; inset: 0; margin: auto; display: grid; place-items: center; width: 38px; height: 38px; border-radius: 50%; background: rgb(0 0 0 / 0.55); color: #fff; -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); transition: transform 0.15s, background-color 0.15s; }
.video .frame > .open:hover .play-mark { transform: scale(1.08); background: rgb(0 0 0 / 0.75); }
.video .meta .warn { color: var(--warn); font-weight: 550; }
/* Where it is going, once that is settled — a line, not a control to press again. */
/* A veil over a real thumbnail is dark for contrast; a video still downloading (or one that failed)
   has no picture under it, so the same treatment turns the row into a wall of dark blocks. */
.video .veil { gap: 8px; }
.video .frame.blank .veil { background: none; -webkit-backdrop-filter: none; backdrop-filter: none; color: var(--fg-2); }
.video .frame.blank .veil .spinner { border-color: var(--line-strong); border-top-color: var(--accent); }
.video .frame.blank .veil .bar { background: var(--line); }
.video .frame.blank .veil .bar i { background: var(--accent); }
.video .frame.blank .veil button { background: var(--bg); border-color: var(--line-strong); color: var(--fg); }
.video .frame.blank .veil button:hover:not(:disabled) { border-color: var(--fg-2); background: var(--bg); }
.video .frame.blank .veil button.primary { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); }
.video .frame.blank .veil button.primary:hover:not(:disabled) { background: var(--accent-strong); border-color: var(--accent-strong); }
/* A card in line waits under its picture — a link's is its post's cover: the words sit at the foot, so the picture still reads. */
.frame.covered .veil { align-content: end; padding-bottom: 14px; background: linear-gradient(to top, rgb(0 0 0 / 0.88), rgb(0 0 0 / 0.6) 42%, rgb(0 0 0 / 0.05) 78%); -webkit-backdrop-filter: none; backdrop-filter: none; }
.creative .frame.covered .veil { padding-bottom: 38px; } /* clear of the file name along the foot */
.video .veil .bar { width: 100%; background: rgb(255 255 255 / 0.25); }
.video .veil .bar i { background: #fff; }
.video .veil .stage-text { font-size: 12px; line-height: 1.35; }
.video .veil .num { font-size: 12px; font-variant-numeric: tabular-nums; opacity: 0.85; }
.pills { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.pill { padding: 2px 8px; border-radius: 7px; background: var(--sunken); color: var(--fg-2); font-size: 12px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.badge { padding: 2px 8px; border-radius: 999px; border: 1px solid var(--line-strong); font-size: 11.5px; font-weight: 600; white-space: nowrap; }
.badge.solid { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); }
.notes { margin-top: 8px; display: grid; gap: 3px; font-size: 12.5px; color: var(--muted); }
.alert { display: flex; gap: 8px; margin-top: 10px; padding: 9px 11px; border: 1px solid var(--bad-line); border-left: 3px solid var(--bad); border-radius: 10px; background: var(--bad-soft); font-size: 13px; color: var(--fg); overflow-wrap: anywhere; }
.alert svg { flex: none; margin-top: 2px; color: var(--bad); }
.video .veil .spinner { width: 20px; height: 20px; border-color: rgb(255 255 255 / 0.3); border-top-color: #fff; }
/* inline-block: as a plain <span> in a line of text it had no width or height to draw, and showed as a still sliver. */
.spinner { display: inline-block; vertical-align: -2px; flex: none; width: 14px; height: 14px; border-radius: 50%; border: 2px solid var(--line-strong); border-top-color: var(--accent); animation: spin 0.7s linear infinite; }
@keyframes rise { from { opacity: 0; transform: translateY(4px); } }
.sticky-actions { padding-top: 16px; border-top: 1px solid var(--line); }

/* ---- step 2, a video once it has posted ---------------------------------------------------- */
.toolbar { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }
.search { position: relative; flex: 1 1 280px; min-width: 0; display: flex; align-items: center; }
.search [data-icon] { position: absolute; left: 12px; color: var(--muted); pointer-events: none; }
.search input { padding-left: 36px !important; }
.account-group { margin-top: 24px; }
.account-group:first-child { margin-top: 20px; }
.group-head { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 10px; margin-bottom: 12px; cursor: pointer; list-style: none; }
.group-head::-webkit-details-marker { display: none; }
.group-head .chev { display: inline-grid; place-items: center; color: var(--muted); transition: transform 0.18s; }
.account-group[open] > .group-head .chev { transform: rotate(90deg); }
/* A shut block still says what is in it, so the margin below its head is only earned when open. */
.account-group:not([open]) > .group-head { margin-bottom: 0; }
.group-head .avatar { width: 28px; height: 28px; font-size: 12px; }
.group-head h3 { font-size: 14.5px; font-weight: 650; }
.group-head .spacer { flex: 1; }
/* The block for videos nobody is posting: an icon in place of an account's avatar, and a line
   saying what it is for, since it has no handle to explain itself. */
.group-head .group-icon { display: grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; background: var(--chip); color: var(--fg-2); }

/* ---- the Posts page's way around: a stretch of time, one account, kinds and codes, an order ---- */
/* The user, 2026-10-17: "i want to look at posts for a certain month but i cant". The bar with
   ‹ the stretch › and the count stays at the top while a month of tiles scrolls under it (wide
   screens only: on a phone the topbar already takes two lines). #navAt marks where it sits. */
.nav-at { height: 0; }
.post-nav {
  position: relative; z-index: 12; display: flex; align-items: center; flex-wrap: wrap; gap: 8px 14px;
  margin: 12px -24px 0; padding: 8px 24px; background: var(--surface);
  border-bottom: 1px solid transparent; transition: border-color 0.15s, box-shadow 0.15s;
}
@media (min-width: 641px) {
  .post-nav { position: sticky; top: var(--topbar-h); }
  .post-nav.stuck { border-bottom-color: var(--line); box-shadow: 0 12px 20px -18px rgb(16 18 23 / 0.45); }
}
.nav-stepper { display: inline-flex; align-items: center; gap: 2px; min-width: 0; }
button.nav-step { width: 36px; padding: 0; border-color: transparent; background: transparent; color: var(--fg-2); }
button.nav-step:hover:not(:disabled) { background: var(--sunken); border-color: transparent; color: var(--fg); }
.nav-step.back svg { transform: rotate(180deg); }
button.nav-when { min-width: 188px; justify-content: flex-start; gap: 8px; padding: 0 10px 0 12px; font-weight: 600; }
.nav-when > [data-icon]:first-child { color: var(--muted); }
.nav-when .nav-caret { margin-left: auto; color: var(--muted); }
.nav-when .nav-caret svg { transform: rotate(90deg); transition: transform 0.18s; }
.nav-when[aria-expanded="true"] .nav-caret svg { transform: rotate(-90deg); }
/* A stretch picked (anything but all the posts) wears the accent, as a picked chip does. */
button.nav-when.on { background: var(--accent-soft); color: var(--accent-text); border-color: var(--accent-line); }
button.nav-when.on:hover:not(:disabled) { background: var(--accent-soft); border-color: var(--accent); }
.nav-when.on > [data-icon]:first-child, .nav-when.on .nav-caret { color: var(--accent-text); }
.post-nav .count { margin-left: auto; }

/* The picker that drops from the stretch's button. */
.when-picker {
  position: absolute; top: calc(100% + 2px); left: 58px; z-index: 5; width: min(344px, calc(100vw - 24px));
  display: grid; gap: 14px; padding: 16px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px; box-shadow: var(--shadow-lg);
  animation: rise 0.15s ease both;
}
.pick-quick { display: flex; flex-wrap: wrap; gap: 6px; }
.pick-quick .chip { height: 30px; padding: 0 11px; font-size: 13px; }
.pick-year { display: flex; align-items: center; justify-content: space-between; padding-top: 12px; border-top: 1px solid var(--line); }
.pick-year b { font-size: 14.5px; font-weight: 650; font-variant-numeric: tabular-nums; }
.pick-months { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
button.pick-month { position: relative; height: 36px; padding: 0; font-weight: 550; }
/* This month, marked under its name. */
button.pick-month.now::after { content: ""; position: absolute; bottom: 4px; left: 50%; width: 4px; height: 4px; margin-left: -2px; border-radius: 50%; background: var(--accent); }
button.pick-month[aria-pressed="true"], button.pick-month[aria-pressed="true"]:hover:not(:disabled) { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); }
button.pick-month[aria-pressed="true"].now::after { background: var(--accent-fg); }
.pick-day { display: flex; align-items: center; gap: 10px; padding-top: 12px; border-top: 1px solid var(--line); color: var(--fg-2); font-size: 13.5px; white-space: nowrap; }
.pick-day input { flex: 1; min-width: 0; }

/* One account alone, the kind and code filters, the order. A filter in force wears the accent. */
.post-filters { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; margin-top: 6px; }
.filter-selects { display: flex; flex-wrap: wrap; gap: 8px; margin-left: auto; }
.post-filters select { min-height: 32px; padding-top: 4px; padding-bottom: 4px; border-radius: 999px; font-size: 13px; }
.post-filters select.on { border-color: var(--accent-line); background-color: var(--accent-soft); color: var(--accent-text); }
.find-note { margin-top: 10px; }

/* A day's cell among an account's tiles: the size of a tile's picture, like a page off a calendar,
   so a day of three posts does not leave a row empty under a heading of its own. */
.day-cell {
  align-self: start; aspect-ratio: 9 / 16; min-width: 0; display: grid; align-content: center; justify-items: center; gap: 6px;
  padding: 8px 4px; border: 1px solid var(--line); border-radius: 9px; background: var(--sunken); text-align: center;
  animation: rise 0.25s ease both;
}
button.day-open { display: grid; justify-items: center; height: auto; padding: 4px 8px; border: 0; border-radius: 8px; background: none; line-height: 1.15; }
button.day-open:hover:not(:disabled) { background: var(--surface); }
.day-open .dow, .day-open .mon { color: var(--muted); font-size: 10px; font-weight: 650; letter-spacing: 0.07em; text-transform: uppercase; }
.day-open .dom { color: var(--fg); font-size: 26px; font-weight: 700; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.day-count { padding: 0 2px; color: var(--muted); font-size: 10.5px; line-height: 1.35; font-variant-numeric: tabular-nums; }
button.day-copy { height: 22px; padding: 0 7px; gap: 4px; border-radius: 6px; font-size: 10.5px; }
/* The tile a pasted link led to. */
.creative.found .frame { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent), 0 0 0 6px var(--ring); }
/* Codes picked by hand (the user, 2026-10-20: "let me select and copy code"). A post with a code has
   its picture for its tick box, as on the Creatives page, so the post opens from the corner. */
.frame .post-open {
  position: absolute; top: 5px; right: 5px; display: grid; place-items: center; width: 22px; height: 22px; border-radius: 50%;
  background: rgb(0 0 0 / 0.5); color: #fff; -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); transition: background-color 0.15s;
}
.frame .post-open:hover { background: rgb(0 0 0 / 0.72); }
/* The bar at the foot of the window while any code is picked: how many, Clear, Copy. */
.select-bar {
  position: fixed; z-index: 25; left: 0; right: 0; bottom: 20px; width: max-content; max-width: calc(100% - 24px); margin: 0 auto;
  display: flex; align-items: center; gap: 6px; padding: 6px 6px 6px 16px;
  border: 1px solid var(--line); border-radius: 999px; background: var(--surface); color: var(--fg); box-shadow: var(--shadow-lg);
  animation: toast-in 0.22s ease both;
}
.select-what { min-width: 0; margin-right: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13.5px; font-variant-numeric: tabular-nums; }
.select-what b { font-weight: 650; }
#selectAway { color: var(--muted); }
.select-bar button.small { flex: none; height: 32px; padding: 0 14px; border-radius: 999px; font-size: 13px; }
/* Room for it: the last row of tiles scrolls clear of it, and a message shows above it. */
body:has(.select-bar:not([hidden])) main { padding-bottom: 104px; }
body:has(.select-bar:not([hidden])) .toasts { bottom: 78px; }
@media (max-width: 640px) {
  .select-bar { bottom: 12px; padding-left: 14px; }
  body:has(.select-bar:not([hidden])) .toasts { bottom: 66px; }
  .post-nav { margin-left: -16px; margin-right: -16px; padding: 8px 16px; }
  .nav-stepper { flex: 1 1 auto; }
  button.nav-when { flex: 1; min-width: 0; }
  #whenText { overflow: hidden; text-overflow: ellipsis; }
  .when-picker { left: 16px; }
  /* The accounts in one line that swipes sideways, edge to edge. */
  .post-filters .chips { flex-wrap: nowrap; width: calc(100% + 32px); margin: 0 -16px; padding: 2px 16px; overflow-x: auto; scrollbar-width: none; }
  .post-filters .chips::-webkit-scrollbar { display: none; }
  .post-filters .chip { flex: none; }
  .filter-selects { width: 100%; margin-left: 0; }
  .post-filters select { font-size: 16px; } /* iOS zooms into a field with smaller words */
}

.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); gap: 22px 16px; }
.grid .more-row { grid-column: 1 / -1; margin: 0; } /* "Show more" under the tiles, on a line of its own */
.creative { min-width: 0; animation: rise 0.25s ease both; }
.frame { position: relative; aspect-ratio: 9 / 16; border-radius: 14px; overflow: hidden; background: var(--sunken); border: 1px solid var(--line); isolation: isolate; }
.frame > a, .frame > .hit { display: block; width: 100%; height: 100%; }
/* The whole picture is its tick box's label (Creatives): a tap anywhere on it picks the code. */
.frame > .hit { cursor: pointer; }
/* The ring is drawn outside its element, and these fill a frame that cuts off what is outside it. */
.frame > .open:focus-visible, .frame > a:focus-visible { outline-offset: -3px; border-radius: 13px; }
.frame img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 0.35s ease, opacity 0.2s; }
.frame > a:hover img, .frame > .hit:hover img { transform: scale(1.03); }
/* Always a dark veil with white text: thumbnails can be any brightness, in either theme. */
.frame .shade { position: absolute; inset: auto 0 0 0; height: 46%; background: linear-gradient(to top, rgb(0 0 0 / 0.78), rgb(0 0 0 / 0)); pointer-events: none; }
.frame .label { position: absolute; left: 10px; right: 10px; bottom: 9px; display: flex; align-items: center; justify-content: space-between; gap: 6px; color: #fff; pointer-events: none; }
.frame .label .file { font: 650 12.5px var(--mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-shadow: 0 1px 2px rgb(0 0 0 / 0.5); }
.frame .tag { flex: none; padding: 2px 6px; border-radius: 6px; background: rgb(255 255 255 / 0.2); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); font-size: 10.5px; font-weight: 650; letter-spacing: 0.02em; }
.frame .corner { position: absolute; top: 9px; right: 9px; height: 28px; padding: 0 10px; gap: 5px; border-radius: 999px; font-size: 12px; font-weight: 600; background: var(--accent); color: var(--accent-fg); border-color: var(--accent); box-shadow: 0 2px 8px rgb(0 0 0 / 0.25); }
.frame .corner:hover:not(:disabled) { background: var(--accent-strong); border-color: var(--accent-strong); }
.frame .corner:disabled { opacity: 0.75; }
.frame .pick {
  position: absolute; top: 10px; left: 10px; width: 24px; height: 24px; border-radius: 8px; border: 1.5px solid rgb(0 0 0 / 0.55);
  background-color: rgb(255 255 255 / 0.92); background-size: 14px; box-shadow: 0 1px 4px rgb(0 0 0 / 0.25);
}
.frame .pick:checked { border-color: var(--accent); background-color: var(--accent); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 6.2l2.4 2.4 4.6-5' fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); outline: 1.5px solid rgb(255 255 255 / 0.9); }
.frame .veil { position: absolute; inset: 0; display: grid; place-content: center; justify-items: center; gap: 10px; padding: 12px; text-align: center; font-size: 13px; font-weight: 600; color: #fff; background: rgb(0 0 0 / 0.62); -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px); }
.frame .veil .spinner { width: 20px; height: 20px; border-color: rgb(255 255 255 / 0.3); border-top-color: #fff; }
.frame .veil button { background: rgb(255 255 255 / 0.16); border-color: transparent; color: #fff; }
.frame .veil button:hover:not(:disabled) { background: rgb(255 255 255 / 0.28); border-color: transparent; }
.frame .veil button.primary, .frame .veil button.primary:hover:not(:disabled) { background: #fff; color: #000; opacity: 1; }
.frame .veil ~ .label { z-index: 1; }
.frame .veil .veil-note { font-size: 12px; font-weight: 500; line-height: 1.35; opacity: 0.85; }
.frame .veil-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; }
.creative.copied .frame img { opacity: 0.4; filter: grayscale(1); }
.creative.picked .frame { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent); }
.creative .code {
  display: flex; align-items: center; gap: 6px; width: 100%; height: 32px; margin-top: 8px; padding: 0 9px; border-radius: 9px; justify-content: space-between;
  background: var(--sunken); border-color: transparent; font: 500 12px var(--mono); color: var(--fg);
}
.creative .code span { overflow: hidden; text-overflow: ellipsis; }
.creative .code svg { color: var(--muted); }
.creative .code:hover:not(:disabled) { border-color: var(--line-strong); }
.video .get {
  display: flex; align-items: center; gap: 6px; width: 100%; height: 32px; margin-top: 8px; padding: 0 9px; border-radius: 9px; justify-content: space-between;
  background: var(--sunken); border: 1px solid transparent; font: 600 12px var(--sans); color: var(--fg); text-decoration: none;
}
.video .get:hover { border-color: var(--line-strong); }
.video .get svg { color: var(--muted); }
/* On an iPhone the button fetches the file and hands it to the share sheet (app.js, saveFiles): the
   fill behind the label is how far the fetch is, and an armed button is the tap still to come. */
button.save { position: relative; overflow: hidden; }
button.save::before { content: ''; position: absolute; inset: 0; width: var(--p, 0%); background: var(--accent-soft); transition: width 0.2s ease; }
button.save > * { position: relative; }
button.save.fetching { cursor: progress; }
button.save.armed, button.save.armed:hover { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); }
button.save.armed svg { color: inherit; }
.nowrap { white-space: nowrap; }
.facts { margin-top: 8px; }
.meta + .facts { margin-top: 4px; }
.facts > summary {
  display: flex; align-items: center; gap: 5px; cursor: pointer; list-style: none;
  font-size: 12px; line-height: 1.45; color: var(--fg-2);
}
.facts > summary::-webkit-details-marker { display: none; }
.facts > summary:hover { color: var(--fg); }
.facts .chev { flex: none; color: var(--muted); transition: transform 0.18s; }
.facts[open] > summary .chev { transform: rotate(90deg); }
.facts-body { display: grid; gap: 8px; padding: 8px 0 2px; }
.facts-body .pills { margin-top: 0; }
.facts-body .from, .facts-body .notes { font-size: 11.5px; line-height: 1.5; color: var(--muted); overflow-wrap: anywhere; }
.facts-body .notes { display: grid; gap: 4px; }
.facts-body a { color: inherit; text-decoration: underline; text-decoration-color: var(--line-strong); text-underline-offset: 2px; }
.facts-body a:hover { color: var(--fg); text-decoration-color: currentColor; }

.creative .meta, .video .meta { margin-top: 8px; display: grid; gap: 2px; font-size: 12px; line-height: 1.45; color: var(--muted); overflow-wrap: anywhere; }
.creative .meta .strong, .video .meta .strong { color: var(--fg-2); }
.video .meta:empty { display: none; }
.creative .meta .done { color: var(--ok); font-weight: 550; }
.creative .alert, .video .alert { margin-top: 8px; font-size: 12px; padding: 7px 9px; }
.creative .card-actions { display: flex; align-items: center; justify-content: space-between; gap: 6px; margin-top: 6px; font-size: 12px; color: var(--muted); }
.creative .card-actions .link, .video .card-actions .link { font-size: 12px; }
.creative .card-actions.start { justify-content: flex-start; gap: 12px; }

/* ---- accounts -------------------------------------------------------------------------------- */
.accounts { display: grid; }
/* A grid item is as wide as its longest unbreakable line unless told otherwise: a launch's product
   link, kept on one line (.launch-what), pushed its whole row past the side of a phone. */
.accounts > * { min-width: 0; }
/* Display cards carry no name, so the picker is the pictures themselves. */
/* What an ad account takes (the admin's choosers under the product link): chips to tick, and a box
   to add a domain nobody has launched on yet. */
.allow-list { margin-top: 12px; }
.allow-list .field-row { margin-top: 10px; }
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 12px; margin-top: 12px; }
/* The card is shown exactly as TikTok sends it — a flattened JPEG, white background and all.
   `contain`, not `cover`, so nothing is cropped. */
.cards button {
  width: 100%; height: auto; padding: 0; border-radius: 12px; overflow: hidden; aspect-ratio: 750 / 421;
  border: 0; opacity: 0.5; transition: opacity 0.12s, box-shadow 0.12s;
  background: var(--sunken);
}
.cards img { display: block; width: 100%; height: 100%; object-fit: contain; }
.cards button:hover { opacity: 0.8; }
/* The chosen one is said three ways: it is the only one at full strength, it wears the accent's
   ring held off the artwork by a gap, and it carries a tick. A border alone was invisible — the
   cards are white. */
.cards button[aria-pressed="true"] { opacity: 1; box-shadow: 0 0 0 2px var(--surface), 0 0 0 5px var(--accent); }
.cards .tick {
  position: absolute; top: 6px; right: 6px; display: grid; place-items: center; width: 22px; height: 22px;
  border-radius: 50%; background: var(--accent); color: var(--accent-fg);
}
.cards .holder { position: relative; display: block; min-width: 0; }
/* The Spark picker reuses the creatives grid, but every tile is a button — pressing one picks that
   post for the launch — so it needs a button's reset and the same three-way "chosen" signal the
   display cards use: full strength, a ring held off the artwork, and a tick. A post with no Spark
   code behind it is disabled rather than hidden, so it is clear the post was seen and skipped. */
.posts { grid-template-columns: repeat(auto-fill, minmax(124px, 1fr)); gap: 16px 12px; margin: 12px 0; }
/* Links to post first: the account they go to and the links themselves are one choice, so they sit
   in one box, apart from the codes box under it — two boxes that both take pasted text must not
   look like one. */
.link-box { margin: 12px 0; padding: 12px; border: 1px solid var(--line-strong); border-radius: 12px; }
.link-box .field-row { margin-top: 0; }
.link-box textarea { margin-top: 10px; }
.creative.pick { position: relative; }
/* The button covers the tile rather than containing it, so it is still a real button to the
   keyboard and to a screen reader while the thumbnail keeps the tile's full width. */
.creative.pick .hit {
  position: absolute; inset: 0; width: 100%; height: auto; padding: 0;
  border: 0; border-radius: 14px; background: none;
}
.creative.pick .hit:hover:not(:disabled), .creative.pick .hit:active { background: none; transform: none; }
.creative.pick .frame { opacity: 0.55; transition: opacity 0.12s, box-shadow 0.12s; }
.creative.pick:hover:not(.bare) .frame { opacity: 0.85; }
.creative.pick.on .frame { opacity: 1; box-shadow: 0 0 0 2px var(--surface), 0 0 0 5px var(--accent); }
.creative.pick.bare .frame { opacity: 0.28; }
.creative.pick.bare .hit { cursor: default; }
/* Asking for a code sits above the dimmed thumbnail, not inside it, so it stays readable while
   the tile behind it is faded out. */
.creative.pick .get-code {
  position: absolute; top: 9px; right: 9px; z-index: 1;
  height: 28px; padding: 0 10px; border-radius: 999px; font-size: 12px; font-weight: 600;
  background: var(--accent); color: var(--accent-fg); border-color: var(--accent);
  box-shadow: 0 2px 8px rgb(0 0 0 / 0.25);
}
.creative.pick .get-code:hover:not(:disabled) { background: var(--accent-strong); border-color: var(--accent-strong); }

/* Two tags in a narrow tile have to share the room rather than run off the edge. */
.posts .tag { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* Quarter-size tiles (the user, 2026-10-14: "4x smaller", first for the Posts page, then "the same
   in the creatives page"): half the width, so a glance takes in an account's whole list. Everything
   on a tile is scaled with it. A tile's plain lines of words keep to one line, with the whole text
   in their title (titled() in app.js, the Posts page's own titles); a line with something to press
   in it, the alerts and the folds still wrap, so nothing that can be pressed or has to be read is
   cut off. */
.dense { grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)); gap: 12px 8px; }
.dense .frame { border-radius: 9px; }
/* Three tags (the date, SLIDES, AD) are more than a tile this narrow holds on one line, so they go
   on to a second rather than past the edge. */
.dense .frame .label { left: 5px; right: 5px; bottom: 5px; flex-wrap: wrap; gap: 3px; }
.dense .frame .label .file { font-size: 9.5px; }
.dense .frame .tag { padding: 1px 4px; border-radius: 4px; font-size: 9px; }
.dense .frame .corner { top: 5px; right: 5px; height: 22px; padding: 0 7px; gap: 3px; font-size: 10.5px; }
.dense .frame .corner svg { width: 11px; height: 11px; }
.dense .frame .pick { top: 5px; left: 5px; width: 18px; height: 18px; border-radius: 6px; background-size: 11px; }
.dense .frame .veil { gap: 5px; padding: 6px; font-size: 10.5px; }
.dense .frame .veil > svg { width: 16px; height: 16px; }
.dense .frame .veil .spinner { width: 14px; height: 14px; }
.dense .frame .veil .veil-note, .dense .video .veil .stage-text, .dense .video .veil .num { font-size: 9.5px; }
.dense .frame .veil-actions { gap: 4px; }
.dense .frame .veil button { height: 22px; padding: 0 7px; border-radius: 6px; font-size: 10.5px; gap: 3px; }
.dense .frame .veil button svg { width: 11px; height: 11px; }
.dense .frame.covered .veil { padding-bottom: 8px; }
.dense .creative .frame.covered .veil { padding-bottom: 22px; }
.dense .play-mark { width: 24px; height: 24px; }
.dense .play-mark svg { width: 13px; height: 13px; }
.dense .creative .meta, .dense .video .meta { margin-top: 5px; gap: 1px; font-size: 10.5px; line-height: 1.35; }
.dense .meta > div:not(.done) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dense .meta > div.full { white-space: normal; } /* opened out by a tap (common.js, tapToOpen) */
.dense .creative .code, .dense .video .get { height: 22px; margin-top: 4px; padding: 0 6px; gap: 4px; border-radius: 6px; font-size: 10px; }
.dense .video .get span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dense .creative .code svg, .dense .video .get svg { flex: none; width: 11px; height: 11px; }
.dense .creative .alert, .dense .video .alert { margin-top: 5px; padding: 5px 7px; gap: 5px; border-radius: 7px; font-size: 10.5px; }
.dense .creative .alert svg, .dense .video .alert svg { width: 12px; height: 12px; margin-top: 1px; }
.dense .creative .card-actions, .dense .video .card-actions { flex-wrap: wrap; gap: 3px 8px; margin-top: 4px; font-size: 10.5px; }
.dense .creative .card-actions .link, .dense .video .card-actions .link { font-size: 10.5px; }
.dense .facts { margin-top: 5px; }
.dense .facts > summary { font-size: 10.5px; line-height: 1.35; }
.dense .facts-body { gap: 5px; padding: 5px 0 1px; }
.dense .facts-body .from, .dense .facts-body .notes { font-size: 10px; }
.dense .pills { gap: 3px; margin-top: 5px; }
.dense .pill { padding: 1px 5px; border-radius: 5px; font-size: 10px; }
.frame .tick {
  position: absolute; top: 8px; right: 8px; display: grid; place-items: center; width: 22px; height: 22px;
  border-radius: 50%; background: var(--accent); color: var(--accent-fg);
}

/* A search box with the magnifier inside it, so the field reads as a search rather than as another
   text input that happens to sit above a list. */
.search-field { position: relative; display: block; margin: 14px 0 0; }
.search-field [data-icon] { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--muted); pointer-events: none; display: grid; }
/* The base input rule is input:not([type=checkbox]):not([type=file]), which out-specifies a plain
   .search-field input — so the magnifier sat on top of the placeholder. Matched here on purpose. */
.search-field input[type="search"] { width: 100%; padding-left: 38px; appearance: none; -webkit-appearance: none; }
.search-field input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }

/* One of many, exactly one chosen. Rows rather than a dropdown because there are dozens of them and
   the id matters as much as the name — both are shown, and both are searched. */
.picklist { margin-top: 4px; max-height: 268px; overflow-y: auto; border-radius: 12px; }
.pick-row {
  display: flex; align-items: center; gap: 12px; width: 100%; height: auto; padding: 10px 2px;
  border: 0; border-top: 1px solid var(--line); border-radius: 0; background: none;
  text-align: left; white-space: normal; font: inherit;
}
.pick-row:first-child { border-top: 0; }
.pick-row:hover:not(:disabled) { background: none; border-color: var(--line); }
.pick-row .grow { flex: 1; min-width: 0; display: grid; gap: 1px; }
.pick-row .who-name { font-weight: 600; overflow-wrap: anywhere; }
.pick-row .status { font-size: 12px; color: var(--muted); font-family: var(--mono); }
/* The ring is the unchosen state and the filled disc the chosen one, the way a radio reads. */
.pick-row .dot {
  flex: none; display: grid; place-items: center; width: 20px; height: 20px; border-radius: 50%;
  border: 1.5px solid var(--line-strong); color: var(--accent-fg);
}
.pick-row.on .dot { background: var(--accent); border-color: var(--accent); }
.pick-row .hint { padding: 10px 2px; }

/* A list under a panel head sits flush; one under a form or a line of explanation needs the same
   gap the form itself keeps, or its first name reads as the end of the sentence above it. */
.field-row + .accounts, .hint + .accounts { margin-top: 14px; }
.account { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-top: 1px solid var(--line); }
.account:first-child { border-top: 0; padding-top: 0; }
.account.slim { padding: 7px 0; gap: 10px; }
.account .who-name { font-weight: 600; }
/* The "TikTok Lab" mark after the name of a pixel made here. */
.who-name .made-here { margin-left: 6px; font-size: 11px; font-weight: 500; vertical-align: 1px; }
.pill.made-here { background: var(--accent-soft); color: var(--accent-text); }
.pill.ok { background: var(--ok-soft); color: var(--ok); }
.pill.warn { background: var(--warn-soft); color: var(--warn); }
.account .status { font-size: 12.5px; color: var(--muted); text-wrap: pretty; }
/* A line that needs a look is amber; one that says something went wrong is red. */
.account .status.warn { color: var(--warn); font-weight: 500; }
.account .status.bad, .status.bad { color: var(--bad); }
.account .status.bad { font-weight: 500; }
.account .grow { flex: 1; min-width: 0; }

/* ---- setup ----------------------------------------------------------------------------------- */
.facts-list { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 8px 16px; margin: 0; font-size: 13px; }
.facts-list dt { color: var(--muted); }
.facts-list dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.facts-list.system { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--line); }
.raw { margin-top: 10px; font-size: 13px; color: var(--muted); }
.raw summary { cursor: pointer; }
pre { margin: 8px 0 0; padding: 12px; background: var(--sunken); border-radius: 10px; font-size: 12px; white-space: pre-wrap; overflow-wrap: anywhere; color: var(--fg); }

/* ---- notices, toasts, dialog ----------------------------------------------------------------- */
.notices { display: grid; gap: 10px; }
.notices:empty { display: none; }
/* A notice is something to see to: amber, like the warnings on the cards. */
.notice { display: flex; gap: 12px; padding: 14px 16px; border: 1px solid var(--warn-line); border-radius: 14px; background: var(--warn-soft); font-size: 13.5px; }
.notice > svg { flex: none; margin-top: 2px; color: var(--warn); }
/* The admin looking at a VA's side (setViewSwitch in common.js): said above everything else, in
   the accent rather than amber — nothing is wrong, it is a mode. */
.view-banner { align-items: center; margin-bottom: 16px; border-color: var(--accent-line); background: var(--accent-soft); }
.view-banner > div { flex: 1; min-width: 0; }
/* Another VA and Exit VA view, side by side at the strip's end. */
.view-banner > .view-banner-actions { flex: none; display: flex; gap: 8px; }
.notice ul { margin: 6px 0 0; padding-left: 18px; display: grid; gap: 4px; color: var(--fg-2); }

/* The list is a popover (see toast in common.js), which is what puts a message above an open dialog
   and its backdrop. The resets undo a popover's own box: centred, bordered, padded, with a background. */
.toasts { position: fixed; z-index: 40; inset: auto auto 20px 50%; transform: translateX(-50%); margin: 0; border: 0; padding: 0; background: none; color: inherit; overflow: visible; display: grid; gap: 8px; width: min(560px, calc(100% - 24px)); pointer-events: none; }
.toast {
  display: flex; align-items: flex-start; gap: 10px; padding: 12px 12px 12px 14px; border-radius: 14px; pointer-events: auto;
  background: var(--surface); color: var(--fg); border: 1px solid var(--line); box-shadow: var(--shadow-lg); font-size: 13.5px; animation: toast-in 0.22s ease both;
}
.toast > svg { flex: none; margin-top: 2px; color: var(--accent); }
.toast.ok > svg { color: var(--ok); }
.toast.error > svg { color: var(--bad); }
.toast .text { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.toast button { height: 26px; padding: 0 8px; border-radius: 8px; border-color: transparent; background: var(--sunken); color: var(--fg-2); font-size: 12.5px; }
.toast button:hover:not(:disabled) { background: var(--line); border-color: transparent; color: var(--fg); }
.toast.leaving { animation: toast-out 0.18s ease forwards; }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px) scale(0.98); } }
@keyframes toast-out { to { opacity: 0; transform: translateY(6px); } }

.dialog { width: min(440px, calc(100vw - 32px)); padding: 0; border: 1px solid var(--line); border-radius: 18px; background: var(--surface); color: var(--fg); box-shadow: var(--shadow); }
.dialog::backdrop { background: rgb(0 0 0 / 0.5); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); }
.dialog form { padding: 22px; }
.dialog h3 { font-size: 16px; font-weight: 650; }
.dialog p { margin-top: 8px; color: var(--fg-2); font-size: 13.5px; }
.dialog input { width: 100%; margin-top: 16px; }
.dialog-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 20px; }
.dialog-actions.choices { flex-direction: column; align-items: stretch; }
/* An answer with a line under it saying what it means (the clock's "Clock in for" question, VA view's
   "See the tool as"). One column the button's full width: left to fit its words, an answer of one
   line was centred in its button, beside the two-line ones at the left. */
.dialog-actions.choices .choice { display: grid; grid-template-columns: minmax(0, 1fr); justify-items: start; gap: 2px; height: auto; padding: 11px 14px; border-radius: 12px; text-align: left; white-space: normal; }
.dialog-actions.choices .choice b { font-size: 14px; font-weight: 600; }
.dialog-actions.choices .choice span { font-size: 12.5px; font-weight: 450; color: var(--muted); }
.dialog[open] { animation: toast-in 0.18s ease both; }
.dialog-actions .spacer { flex: 1; }
/* The store dialog: steps to follow, then three boxes, each named above itself. */
.store-dialog { width: min(520px, calc(100vw - 32px)); }
.dialog-steps p { margin-top: 10px; }
.dialog .steps { display: grid; gap: 6px; margin-top: 10px; padding-left: 20px; color: var(--fg-2); font-size: 13px; line-height: 1.5; }
.dialog .steps code { font-size: 12px; }
.dialog-field { display: grid; gap: 6px; margin-top: 14px; color: var(--fg-2); font-size: 13px; }
.dialog .dialog-field input { margin-top: 0; }
.account .store-line .link { font-size: inherit; }

.viewer { padding: 0; border: 0; background: transparent; max-width: 100vw; max-height: 100vh; max-height: 100dvh; overflow: visible; color: #fff; }
.viewer::backdrop { background: rgb(0 0 0 / 0.86); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
.viewer[open] { display: grid; justify-items: center; gap: 12px; animation: toast-in 0.2s ease both; }
.viewer-stage video, .viewer-stage img { display: block; max-width: min(92vw, 560px); max-height: 80vh; max-height: 80dvh; border-radius: 16px; background: #000; }
.viewer-stage.slides { display: flex; gap: 12px; max-width: 94vw; overflow-x: auto; scroll-snap-type: x mandatory; border-radius: 16px; }
/* Each slide stands over its number, and over the button that takes it out before posting. The
   slides are kept shorter than a video is: what was removed, and where the slideshow goes next, are
   said under them, and at a video's height that part fell off the bottom of the screen. */
.viewer-stage.slides figure { flex: none; display: grid; justify-items: center; gap: 8px; margin: 0; scroll-snap-align: center; }
.viewer-stage.slides img { max-height: calc(64vh - 42px); max-height: calc(64dvh - 42px); }
.viewer-stage figcaption { display: flex; align-items: center; justify-content: center; gap: 10px; min-height: 34px; font-size: 12.5px; color: rgb(255 255 255 / 0.75); }
.viewer-stage figcaption button { border-color: rgb(255 255 255 / 0.26); background: rgb(255 255 255 / 0.1); color: #fff; }
.viewer-stage figcaption button:hover:not(:disabled) { border-color: rgb(255 255 255 / 0.5); background: rgb(255 255 255 / 0.2); }
.viewer-caption { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 8px; font: 600 13px var(--mono); color: rgb(255 255 255 / 0.9); text-align: center; }
.viewer-caption .badge { border-color: rgb(255 255 255 / 0.35); font-family: var(--sans); }
/* What the tile leaves out. Always on a dark backdrop, so these do not follow the page's theme. */
.viewer-facts { display: grid; gap: 10px; justify-items: center; width: min(92vw, 560px); max-height: 28vh; overflow-y: auto; padding-bottom: 4px; }
.viewer-facts .from { font-size: 12.5px; color: rgb(255 255 255 / 0.6); }
.viewer-facts .said { font-size: 13px; color: #fff; text-align: center; }
.viewer-facts .pills { justify-content: center; margin-top: 0; }
.viewer-facts .pill { background: rgb(255 255 255 / 0.14); color: rgb(255 255 255 / 0.92); }
.viewer-facts .notes { margin-top: 0; text-align: center; color: rgb(255 255 255 / 0.62); }
.viewer-facts .send { display: flex; align-items: center; flex-wrap: wrap; justify-content: center; gap: 8px; padding-top: 4px; font-size: 12.5px; color: rgb(255 255 255 / 0.7); }
.viewer-facts .send .chips { margin: 0; }
.viewer-facts .send .chip { border-color: rgb(255 255 255 / 0.26); background: rgb(255 255 255 / 0.1); color: #fff; }
.viewer-facts .send button.link { color: #fff; }
.viewer-facts .alert { margin-top: 0; width: 100%; border-color: rgb(255 255 255 / 0.3); border-left-color: #fff; background: rgb(255 255 255 / 0.08); color: #fff; text-align: left; }
.viewer-facts .alert svg { color: #fff; }
.viewer-close { position: fixed; top: 16px; right: 16px; width: 40px; height: 40px; padding: 0; border-radius: 50%; border-color: transparent; background: rgb(255 255 255 / 0.14); color: #fff; }
.viewer-close:hover:not(:disabled) { background: rgb(255 255 255 / 0.26); border-color: transparent; }

/* ---- sign-in page ---------------------------------------------------------------------------- */
.login-page { min-height: 100vh; min-height: 100dvh; display: grid; place-items: center; padding: 24px; background: radial-gradient(70% 55% at 50% -10%, var(--accent-soft), transparent 70%) var(--bg); }
.login { width: min(380px, 100%); padding: 32px 28px; border: 1px solid var(--line); border-radius: 22px; background: var(--surface); box-shadow: var(--shadow); }
.login .brand { font-size: 19px; }
.login .lead { margin-top: 8px; color: var(--muted); font-size: 13.5px; }
/* The one line a browser outside the tool gets: how an ad-account sign-in went. */
.result-title { margin-top: 16px; font-size: 16px; font-weight: 650; }
.result-title + .lead, .result-title + .alert { margin-top: 8px; }
.login form { display: grid; gap: 16px; margin-top: 24px; }
.login button { height: 42px; margin-top: 4px; }
/* The Shopify app's own pages — the store report and the privacy policy — on the same card, wider. */
.login.store-report { width: min(680px, 100%); }
.store-report .lead + .lead { margin-top: 12px; }
.store-report code { font-size: 12px; }
.report-figures { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin-top: 20px; }
.report-figures div { display: grid; gap: 2px; }
.report-figures b { font-size: 18px; font-weight: 650; font-variant-numeric: tabular-nums; }
.report-figures span { color: var(--muted); font-size: 12.5px; }
.report-days { width: 100%; margin-top: 20px; border-collapse: collapse; font-size: 13px; font-variant-numeric: tabular-nums; }
.report-days th { color: var(--muted); font-weight: 550; text-align: left; }
.report-days th, .report-days td { padding: 6px 4px; border-top: 1px solid var(--line); }
.report-days .num { text-align: right; }
.report-note { margin-top: 14px; color: var(--muted); font-size: 12.5px; line-height: 1.5; }
@media (max-width: 520px) {
  .report-figures { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ---- small screens --------------------------------------------------------------------------- */
@media (max-width: 640px) {
  .topbar-in, main { padding-left: 12px; padding-right: 12px; }
  /* A phone cannot hold the brand, both tabs, the live dot and Sign out on one line: the row came
     to 435px inside 366px, and what gave way was the Sign out button, which ran 27px off the side
     of the screen. The tabs drop to a line of their own instead, which fits without hiding
     anything. `height: auto` because the bar is a fixed 56px everywhere else. */
  .topbar-in { width: auto; flex-wrap: wrap; height: auto; padding-top: 9px; padding-bottom: 9px; row-gap: 6px; column-gap: 12px; }
  .tabs { order: 3; flex: 1 0 100%; }
  /* Clocked in ("Clock out · research since 10:42 PM") while "Reconnecting…" shows, the group came
     to 450px in 366px: Sign out ran off the side again, and the whole page scrolled sideways. The
     group breaks onto a second line instead. */
  .topbar-side { margin-left: auto; flex-wrap: wrap; justify-content: flex-end; row-gap: 6px; }
  main { gap: 12px; padding-top: 12px; }
  .panel { padding: 18px 16px 20px; border-radius: 16px; }
  /* A panel's title and the note beside it share a line only while both fit. Squeezed, the title
     broke onto two lines ("Launch a / campaign") beside a note broken into three; now the note
     goes under it instead. */
  .panel-head { flex-wrap: wrap; row-gap: 2px; }
  .panel-head h2 { flex: none; max-width: 100%; }
  .live span { display: none; }
  .live[data-state="down"] span { display: inline; }
  .user { max-width: 12ch; }
  /* In VA view the strip at the top of the page has the way out; its longer twin in the bar pushed
     the bar onto a third line. */
  .viewing-as-team #viewAs { display: none; }
  /* The strip's words over its two buttons, which keep to the right. */
  .view-banner { flex-direction: column; align-items: stretch; gap: 10px; }
  .view-banner > .view-banner-actions { justify-content: flex-end; }
  .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px 12px; }
  .dense { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px 8px; } /* the quarter-size tiles, three to a row */
  .toolbar button:not(.ghost) { flex: 1 1 auto; }
  .fold > summary { flex-wrap: wrap; }
  .fold-note { flex-basis: 100%; white-space: normal; padding-left: 24px; }
  .facts-list { grid-template-columns: minmax(0, 1fr); gap: 2px; }
  .facts-list dd { margin-bottom: 10px; }
  .toasts { bottom: 12px; }
  input:not([type="checkbox"]):not([type="radio"]), select, textarea { font-size: 16px; } /* stops iOS from zooming into a focused field */
  body.booting::before, body.booting::after { width: calc(100% - 24px); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.001s !important; animation-iteration-count: 1 !important; transition-duration: 0.001s !important; }
}
.field-row input { flex: 0 1 200px; min-width: 0; }
/* The buttons at the end of a row stay together at its right-hand end, and wrap there as a group —
   left loose, the second one fell to the start of the next line under the row's label. */
.field-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: 6px 4px; margin-left: auto; }
.field-row input.wide { flex: 1 1 280px; }
/* Slide numbers are a few digits: a short box, and its hint takes the rest of the row. */
.field-row input.slide-numbers { flex: 0 1 150px; }
.field-row input.bad { border-color: var(--bad); }
.field-row input.slide-numbers ~ .hint { flex: 1 1 240px; min-width: 0; }
.hint.bad { color: var(--bad); }
/* An ad account carries three buttons where a TikTok account carries one: they travel together and
   drop under the name rather than off the side of a phone. */
.account.ad { align-items: flex-start; flex-wrap: wrap; }
.row-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-left: auto; }
/* A launch's pixel and product link on one line (cut short, never wrapped: a link can be long), and
   beside them a picture of each post that went into it, four to a line. At 40px under the text they
   were too small to tell apart (the user, 2026-09-22). */
.launch-what { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.launch-what a { color: inherit; text-decoration: underline; text-decoration-color: var(--line-strong); text-underline-offset: 2px; }
.launch-what a:hover { color: var(--fg); text-decoration-color: currentColor; }
.launch-covers { display: flex; flex-wrap: wrap; gap: 8px; max-width: calc(4 * 90px + 3 * 8px); }
.launch-cover { width: 90px; aspect-ratio: 9 / 16; overflow: hidden; border: 1px solid var(--line); border-radius: 10px; background: var(--sunken); }
.launch-cover img { display: block; width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 640px) {
  .account.ad .grow { flex: 1 1 100%; }
  .row-actions { margin-left: 0; }
  /* No room beside the words on a phone: under them, on a line of their own. */
  .launch-covers { flex: 1 1 100%; max-width: none; }
}
/* Two screens, one tool: the creatives side and the campaigns side. */
.tabs { display: flex; gap: 2px; margin-left: 18px; }
.tabs a { padding: 6px 12px; border-radius: 999px; font-size: 13.5px; font-weight: 550; color: var(--muted); text-decoration: none; white-space: nowrap; }
.tabs a:hover { color: var(--fg); background: var(--sunken); }
.tabs a.here { color: var(--accent-text); background: var(--accent-soft); }
@media (max-width: 640px) {
  /* On a line of their own there, from the line's start: the step in from the brand belongs beside
     it. With it, five tabs ("Listings" and "My time", or "Admin", at the end) came to 386px in
     366px, "My time" was cut off and the page zoomed out. A sixth scrolls along the line instead. */
  .tabs { margin-left: -4px; overflow-x: auto; scrollbar-width: none; }
  .tabs::-webkit-scrollbar { display: none; }
  .tabs a { padding: 6px 9px; }
}

/* ---- the admin screen ------------------------------------------------------------------------ */
/* A figure and what it is, stacked, so a row of them reads across without a header line. */
.figure { display: grid; gap: 1px; justify-items: end; min-width: 92px; text-align: right; }
.figure b { font-size: 15px; font-variant-numeric: tabular-nums; }
.figure span { font-size: 11.5px; color: var(--muted); }
.account.total { border-top-width: 2px; }
.account.total .figure b { font-weight: 650; }
/* On a phone the five figures go under the account's name, three to a line, instead of running
   off the side and dragging the whole page sideways with them. A third of the width (less the two
   12px gaps) holds a six-figure amount; five squeezed onto one line did not. */
@media (max-width: 640px) {
  .account.sums { flex-wrap: wrap; row-gap: 8px; align-items: flex-start; }
  .account.sums .grow { flex: 1 1 100%; }
  .account.sums .figure { flex: 0 0 calc((100% - 12px) / 2); min-width: 0; justify-items: start; text-align: left; }
}

/* The admin side's pages, a switch at the top of each: the ad accounts and the team (admin.html), and the store-support
   bot's refunds and supplier chats (lib/support.js), pressed like a chosen chip. */
.subnav { display: flex; flex-wrap: wrap; gap: 6px; }
.subnav a {
  display: inline-flex; align-items: center; height: 32px; padding: 0 13px; border: 1px solid var(--line-strong); border-radius: 999px;
  background: var(--surface); color: var(--fg-2); font-size: 13.5px; font-weight: 550; text-decoration: none; white-space: nowrap;
}
.subnav a:hover { background: var(--sunken); color: var(--fg); }
.subnav a.here { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent-text); }
/* How many orders not shipped yet need the admin, on the Unfulfilled link (common.js countUnfulfilled). */
.subnav-count {
  display: inline-grid; place-items: center; min-width: 20px; height: 20px; margin: 0 -6px 0 7px; padding: 0 6px; border: 1px solid var(--bad-line);
  border-radius: 999px; background: var(--bad-soft); color: var(--bad); font-size: 12px; font-weight: 650; font-variant-numeric: tabular-nums; line-height: 1;
}
/* The Launch page's tab per ad account (listings.js renderTabs): the open one in the accent, with how many of its cards are
   in progress. On a phone the two share the row's width, each still a whole tap target. */
.acct-tabs { margin: -4px 0 16px; }
.acct-count {
  display: inline-grid; place-items: center; min-width: 20px; height: 20px; margin: 0 -6px 0 8px; padding: 0 6px; border: 1px solid var(--line-strong);
  border-radius: 999px; background: var(--sunken); color: var(--fg-2); font-size: 12px; font-weight: 650; font-variant-numeric: tabular-nums; line-height: 1;
}
.acct-tabs a.here .acct-count { border-color: var(--accent-line); background: var(--surface); color: var(--accent-text); }
@media (max-width: 640px) {
  .acct-tabs a { flex: 1 1 0; justify-content: center; height: 40px; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
}
/* The support bot's last run, where the live mark sits on the other pages: a still dot when it ran lately, an empty one and
   the words in weight when it is late. */
.live[data-state="ran"] i { background: var(--ok); }
.live[data-state="stale"] { color: var(--warn); font-weight: 550; }
.live[data-state="stale"] i { background: transparent; border: 2px solid var(--warn); }
.support-foot { padding: 0 2px; }
@media (max-width: 640px) {
  .live[data-state="stale"] span { display: inline; }
}

/* The admin screen is tables of numbers, so it may use more of a wide screen than the others. */
.wide .topbar-in, .wide main { max-width: 1320px; }
/* The bar's own cap, after the line above: a flat 1320px let a phone's bar grow to hold every tab
   on one line, and the whole page zoomed out to fit it. */
.wide .topbar-in { min-width: min(1320px, 100%); max-width: min(1320px, 100%); }

/* The campaigns tables, one per ad account. Each scrolls sideways on a narrow screen rather than
   dropping columns, since which column matters changes with what is being judged — and the name
   stays pinned at the left while it does, so a row of numbers never loses its campaign. The column
   widths are fixed so that stacked accounts line up column for column; the name takes the rest. */
.account-group > .hint { margin-top: 0; }
/* The admin campaigns: a bubble per ad account picks the table shown, in place of a fold each. A
   long label is cut short with an ellipsis rather than pushing the bubble past the edge. */
#campaigns > .chips { margin-top: 14px; }
#campaigns .chip { max-width: 100%; }
#campaigns .chip > span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.chip .count { font-weight: 500; opacity: 0.55; font-variant-numeric: tabular-nums; }
#campaigns .account-group { margin-top: 16px; }
#campaigns .group-sum { margin-bottom: 8px; font-size: 12.5px; color: var(--muted); }
/* Its bottom line: every account together, under whichever table is shown. */
#campaignTotals .account.total { margin-top: 22px; border-top: 2px solid var(--line); padding: 14px 0 0; }
.group-sum { color: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.poll-line { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; margin-top: 10px; font-size: 13px; color: var(--muted); font-variant-numeric: tabular-nums; }
.poll-line button { flex: none; }
.sort-line { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; margin-top: 10px; font-size: 13px; color: var(--fg-2); }
.sort-line button.link { font-size: 13px; }
.scroller { overflow-x: auto; }
.sheet { width: 100%; min-width: 940px; table-layout: fixed; border-collapse: collapse; font-size: 13px; }
.sheet th, .sheet td { padding: 8px; text-align: left; vertical-align: middle; border-top: 1px solid var(--line); white-space: nowrap; }
/* Ads Manager's own column names are long, so a heading wraps onto two or three lines and sits on
   the rule, the way Ads Manager's do. */
.sheet th { padding-top: 0; vertical-align: bottom; white-space: normal; line-height: 1.3; font-size: 11.5px; font-weight: 550; color: var(--muted); border-top: 0; }
/* Fourteen columns on a 1440 laptop with about 190px left for the name (2026-10-27): TikTok's
   figures at 80px, the Lab's own counts — small numbers over a short line — at 70px. */
.sheet th.n { width: 80px; }
.sheet th.lab { width: 70px; }
.sheet th.budget { width: 118px; }
.sheet th:first-child, .sheet td:first-child { padding-left: 0; position: sticky; left: 0; z-index: 1; background: var(--surface); }
.sheet th:last-child, .sheet td:last-child { padding-right: 0; }
.sheet .n { text-align: right; font-variant-numeric: tabular-nums; }
.sheet tbody tr:hover td { background: var(--sunken); }
.sheet .sub { display: block; font-size: 11.5px; color: var(--muted); }
/* The Lab's lines under its count wrap in the column rather than run into the next one. On a wide
   screen its 70px columns give up most of their padding, so "1 unproven" (62px in Onest) stays one line. */
.sheet td.lab .sub { white-space: normal; }
@media (min-width: 641px) { .sheet th.lab, .sheet td.lab { padding-left: 2px; padding-right: 4px; } }
/* A heading is a button that sorts. It keeps the heading's look; the arrow says which way. */
.sheet th button.sort {
  display: inline; height: auto; padding: 0; border: 0; border-radius: 4px; background: none;
  font: inherit; color: inherit; text-align: inherit; white-space: normal; cursor: pointer;
}
.sheet th button.sort .short { display: none; }
.sheet th button.sort:hover:not(:disabled) { background: none; color: var(--fg); }
.sheet th button.sort:active:not(:disabled) { transform: none; }
.sheet th[aria-sort="ascending"], .sheet th[aria-sort="descending"] { color: var(--accent-text); }
.sheet th .arrow:not(:empty) { margin-left: 3px; }
/* The name and its status dot. Two lines of name before it is cut, because a copy's name only says
   which copy at its end. */
.cname { display: flex; align-items: flex-start; gap: 8px; min-width: 0; }
.cname > .state { height: 1.5em; } /* centred on the name's first line, however many it wraps to */
.cname > div { min-width: 0; }
.cname .nm { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; white-space: normal; overflow-wrap: anywhere; font-weight: 550; }
/* On or off: a filled dot or an empty one. */
.state { display: inline-flex; align-items: center; color: var(--muted); }
.state i { flex: none; width: 7px; height: 7px; border-radius: 50%; border: 1.5px solid currentColor; }
.state.on { color: var(--ok); }
.state.on i { background: currentColor; }
/* The switch beside the name: a track that carries the state and a knob that slides. Off, the track
   is grey and the knob white in either theme; on, the track takes the accent. A button underneath,
   so it is reached and pressed like one; none of the button look, though. */
.switch {
  flex: none; position: relative; display: inline-block; width: 34px; height: 20px; margin: 0; padding: 0;
  border: 0; border-radius: 999px; background: var(--line-strong); cursor: pointer;
  transition: background-color .18s, opacity .15s;
}
.switch i {
  position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 2px rgb(0 0 0 / .3), 0 0 0 .5px rgb(0 0 0 / .08);
  transition: transform .18s, background-color .18s;
}
.switch.on { background: var(--accent); }
.switch.on i { background: #fff; transform: translateX(14px); box-shadow: 0 1px 2px rgb(0 0 0 / .25); }
.switch:hover:not(:disabled) { background: var(--faint); border-color: transparent; }
.switch.on:hover:not(:disabled) { background: var(--accent-strong); }
.switch:active:not(:disabled) { transform: none; }
.switch:disabled { opacity: .6; cursor: progress; }
.switch.busy { color: inherit !important; }
.switch.busy::after { display: none; }
.switch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Rows that are words rather than a campaign. The group — the campaigns that are on, then under a
   rule the ones that are off — and inside each the purchase-optimized apart from the add-to-cart. */
.sheet tr.group td { padding: 18px 0 2px; border-top: 0; }
.sheet tbody tr.group:first-child td { padding-top: 6px; }
.sheet tr.group.inactive td { border-top: 2px solid var(--line-strong); padding-top: 12px; }
.sheet tr.group b { font-size: 11.5px; font-weight: 650; letter-spacing: .05em; text-transform: uppercase; color: var(--fg-2); }
/* The heading is a button that folds the group away; the chevron points down while it is open. */
.sheet tr.group button.fold { display: inline-flex; align-items: center; gap: 6px; height: auto; padding: 0; border: 0; border-radius: 4px; background: none; font: inherit; color: inherit; cursor: pointer; }
.sheet tr.group button.fold:hover:not(:disabled) { background: none; }
.sheet tr.group button.fold:hover:not(:disabled) b { color: var(--fg); }
.sheet tr.group button.fold:active:not(:disabled) { transform: none; }
.sheet tr.group .chev { display: inline-grid; place-items: center; color: var(--muted); transform: rotate(90deg); transition: transform 0.18s; }
.sheet tr.group.folded .chev { transform: none; }
.sheet tr[hidden] { display: none !important; } /* the phone's block and grid rows would otherwise stay */
.sheet tr.section td { padding: 8px 0 4px; border-top: 0; font-size: 11.5px; color: var(--muted); }
.sheet tbody tr.group:hover td, .sheet tbody tr.section:hover td { background: var(--surface); }
.sheet tbody tr.off .nm { color: var(--fg-2); }
/* The budget: a small field with a pencil, since a bare figure did not look like something to
   change; then a box to type in, with a tick. */
.budget-cell { display: grid; justify-items: end; gap: 2px; }
.sheet td.budget .budget-edit {
  display: inline-flex; align-items: center; justify-content: flex-end; gap: 6px; height: 28px; min-width: 0; padding: 0 7px 0 9px;
  border: 1px solid var(--line-strong); border-radius: 8px; background: var(--surface);
  font: inherit; font-weight: 500; font-variant-numeric: tabular-nums; color: inherit; cursor: pointer;
}
.sheet td.budget .budget-edit .icon { flex: none; color: var(--muted); }
.sheet td.budget .budget-edit:hover:not(:disabled) { background: var(--sunken); border-color: var(--accent); }
.sheet td.budget .budget-edit:hover:not(:disabled) .icon { color: var(--accent-text); }
.sheet td.budget .budget-edit:active:not(:disabled) { transform: none; }
.budget-form { display: flex; justify-content: flex-end; gap: 4px; }
.budget-form input { width: 62px; min-height: 0; height: 28px; padding: 0 7px; border-radius: 8px; font-size: 13px; text-align: right; -moz-appearance: textfield; appearance: textfield; }
.budget-form input::-webkit-inner-spin-button, .budget-form input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.budget-form button { width: 28px; height: 28px; min-width: 0; padding: 0; border-radius: 8px; }
/* A deleted campaign's budget: the figure alone, set where the pencilled ones have theirs. */
.budget-fixed { display: inline-flex; align-items: center; height: 28px; padding-right: 27px; font-weight: 500; font-variant-numeric: tabular-nums; color: var(--fg-2); }
/* A finger, whatever the screen's width: under 16 px, iOS zooms the page into a box when it is
   touched and leaves it zoomed. */
@media (pointer: coarse) {
  .budget-form input { font-size: 16px; }
}
/* A phone scrolls the numbers under the pinned name, which gets an edge to scroll under. */
/* A phone (user, 2026-09-25, twice): a ten-column table is the wrong shape for it — two columns
   showed and the rest scrolled off the side. Each campaign is a card instead: the switch, the name
   and the budget on the first line, its figures three to a line under them, each with its word.
   The headings become a strip of sort buttons above the cards, which scrolls sideways on its own. */
@media (max-width: 640px) {
  .hint .more { display: none; } /* the longer explanation is for a screen with room for it */
  #campaigns > .chips { gap: 5px; }
  #campaigns .chip { height: 30px; padding: 0 11px; font-size: 13px; }
  #campaigns .account-group { margin-top: 12px; }
  .scroller { overflow: visible; }
  .sheet, .sheet thead, .sheet tbody, .sheet tr, .sheet th, .sheet td { display: block; min-width: 0; width: auto; }
  .sheet th:first-child, .sheet td:first-child { position: static; z-index: auto; }
  .sheet thead { overflow-x: auto; padding-bottom: 8px; scrollbar-width: none; }
  .sheet thead::-webkit-scrollbar { display: none; }
  .sheet thead tr { display: flex; align-items: center; gap: 6px; }
  .sheet thead tr::before { content: 'Sort'; flex: none; margin-right: 2px; font-size: 11.5px; color: var(--muted); }
  .sheet th, .sheet th.n, .sheet th.budget { flex: none; width: auto; padding: 0; border: 0; white-space: nowrap; }
  .sheet th button.sort {
    display: inline-flex; align-items: center; height: 26px; padding: 0 9px; border: 1px solid var(--line-strong); border-radius: 999px;
    background: var(--surface); font-size: 11.5px; font-weight: 550; color: var(--fg-2); white-space: nowrap;
  }
  .sheet th button.sort .long { display: none; }
  .sheet th button.sort .short { display: inline; }
  .sheet th[aria-sort="ascending"] button.sort, .sheet th[aria-sort="descending"] button.sort { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); }
  .sheet tbody tr.on, .sheet tbody tr.off { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 9px 10px; padding: 11px 0 13px; border-top: 1px solid var(--line); }
  .sheet tbody tr.on td, .sheet tbody tr.off td { padding: 0; border: 0; white-space: normal; background: none; }
  .sheet tbody tr:hover td { background: none; }
  .sheet td.name { grid-column: 1 / 3; }
  .cname .nm { -webkit-line-clamp: 3; }
  .sheet td.budget { grid-column: 3; justify-self: end; }
  .budget-cell .sub.daily { display: none; }
  .budget-fixed { padding-right: 0; }
  /* The box and its tick at a size a thumb can use, the text at the 16 px that keeps iOS from
     zooming in (the 13 px above won over the phone's general rule, being later in the file). */
  .sheet td.budget .budget-edit { height: 34px; }
  /* Wider than its third of the card, so that 5000.00 shows whole at that size: the box reaches
     left over the end of the name's column for as long as it is open. */
  .budget-form input { flex: none; width: 104px; height: 34px; font-size: 16px; }
  .budget-form button { flex: none; width: 34px; height: 34px; }
  /* The small live controls keep their look and get a touch area of about 40 px around them:
     the campaign's switch (34 by 20), the Active / Inactive fold, a store line's links. */
  .switch, .sheet tr.group button.fold, .account .store-line .link { position: relative; }
  .switch::before, .sheet tr.group button.fold::before, .account .store-line .link::before { content: ''; position: absolute; inset: -11px -6px; }
  .sheet td.n { text-align: left; }
  .sheet td.n:not(.budget) { display: grid; gap: 1px; font-size: 14px; font-weight: 550; }
  .sheet td.n:not(.budget)::after { content: attr(data-label); font-size: 11px; font-weight: 400; color: var(--muted); }
  /* On a card the figure's word sits under the count, and the Lab's lines below both. */
  .sheet td.lab .sub { order: 1; font-size: 11px; font-weight: 400; }
  .sheet tr.group td { padding: 16px 0 2px; }
  .sheet tbody tr.group:first-child td { padding-top: 4px; }
  .sheet tr.group.inactive td { padding-top: 12px; }
  .sheet tr.section td { padding: 6px 0 2px; }
}

/* ---- conversions (admin) ---------------------------------------------------------------------- */
.conv-store { display: block; margin-top: 12px; }
.pixel-wrap { overflow-x: auto; }
.conv-store .conv-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-left: auto; }
.conv-store .conv-figures { display: flex; gap: 14px 22px; flex-wrap: wrap; margin-top: 10px; }
.conv-figures .figure { justify-items: start; min-width: 0; text-align: left; }
@media (max-width: 640px) {
  .pixel-list th:nth-child(4), .pixel-list td:nth-child(4), .pixel-list th:nth-child(5), .pixel-list td:nth-child(5) { display: none; }
  .pixel-list .code { overflow-wrap: anywhere; }
  .pixel-list .row-actions { flex-direction: column; gap: 4px; }
}
.pixel-list { width: 100%; margin-top: 10px; border-collapse: collapse; font-size: 13px; }
.pixel-list th { text-align: left; font-weight: 500; color: var(--muted); font-size: 12px; padding: 4px 8px 4px 0; border-bottom: 1px solid var(--line); }
.pixel-list td { padding: 7px 8px 7px 0; border-bottom: 1px solid var(--line); vertical-align: top; }
.pixel-list td.pixel-for { max-width: 300px; }
.pixel-product { line-height: 1.45; overflow-wrap: anywhere; }
.pixel-list th.num, .pixel-list td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.pixel-list .code { font-family: var(--mono); font-size: 12px; color: var(--muted); }
.pixel-list .row-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.conv-events { margin-top: 8px; font-size: 12.5px; }
.conv-events summary { cursor: pointer; color: var(--muted); }
.conv-events ul { list-style: none; margin: 6px 0 0; padding: 0; }
.conv-events li { display: grid; grid-template-columns: 62px 1fr; gap: 8px; padding: 3px 0; border-bottom: 1px solid var(--line); }
.conv-events time { color: var(--muted); font-variant-numeric: tabular-nums; }
.conv-events .bad { color: var(--bad); }
.conv-signal .signal-scroll { overflow-x: auto; margin-top: 6px; }
.conv-signal .status { margin-top: 6px; }
.signal-table { border-collapse: collapse; font-size: 12.5px; }
.signal-table th { text-align: left; font-weight: 500; color: var(--muted); font-size: 12px; padding: 4px 10px 4px 0; border-bottom: 1px solid var(--line); white-space: nowrap; }
.signal-table td { padding: 4px 10px 4px 0; border-bottom: 1px solid var(--line); white-space: nowrap; }
.signal-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.signal-table tr.lead td { font-weight: 600; }
.signal-table td.dim { color: var(--muted); }
.signal-table td.low { color: var(--warn); font-weight: 600; }
.signal-table th:first-child, .signal-table td:first-child { position: sticky; left: 0; z-index: 1; background: var(--surface); }
.signal-table .split { padding-right: 14px; border-right: 1px solid var(--line); }
.signal-table .split + th, .signal-table .split + td { padding-left: 10px; }
.snippet-box { width: 100%; min-height: 260px; margin-top: 8px; font-family: var(--mono); font-size: 11.5px; white-space: pre; overflow: auto; }
.dialog-field textarea { min-height: 84px; font-family: var(--mono); font-size: 12.5px; }
.dialog.snippet { width: min(720px, calc(100vw - 32px)); }

/* ---- the time tracker: the Team page (admin) ------------------------------------------------
   The day on top with the ways to another, four figures for the team, a row a person (initials
   with a dot for where they are, a bar of the day, the hours in columns), the days as a table, and
   the team settings in a card of their own. Green is time worked, red the slacking taken off it,
   amber a phone worth a look; the accent only marks what is picked. */
.tracker { display: grid; gap: 16px; min-width: 0; }
.tracker-bar { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 12px; margin-top: 6px; }
.day-step { display: flex; align-items: center; gap: 2px; min-width: 0; }
.time-day { margin: 0 4px; font-size: 21px; font-weight: 650; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; white-space: nowrap; }
.time-day .z { font-size: 14px; font-weight: 500; letter-spacing: 0; color: var(--muted); }
button.icon-only { width: 34px; padding: 0; }
button.icon-only:disabled { opacity: 0.25; }
.flip svg { transform: rotate(180deg); }
.tracker-tools { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
/* Today, where it is said rather than offered: pressed like a picked chip, nothing to press. */
#timeToday[aria-pressed="true"] { opacity: 1; cursor: default; background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent-text); }
.watch { margin-left: auto; display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; cursor: default; }
.watch .dot { flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--faint); }
.watch .dot.on { background: var(--ok); }
.watch .dot.stale { background: var(--warn); }

/* The team in four figures. */
.stats { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 12px; }
.stat { display: grid; align-content: start; gap: 3px; min-width: 0; padding: 15px 18px 16px; border: 1px solid var(--line); border-radius: 14px; background: var(--surface); box-shadow: var(--shadow-sm); }
.stat-label { display: flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 550; color: var(--muted); }
.stat-value { font-size: 28px; line-height: 1.15; font-weight: 650; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }
.stat-sub { font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stat.bad .stat-value { color: var(--bad); }
.stat.clocked-now .stat-label::before { content: ""; flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--ok); --pulse-ring: var(--ok-ring); animation: pulse 2.4s ease-in-out infinite; }

/* What the bars show, beside the heading. */
#people .panel-head { flex-wrap: wrap; row-gap: 6px; }
#people .panel-head .count { margin-left: 0; }
.legend { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 0 0 0 auto; padding: 0; list-style: none; font-size: 12px; color: var(--muted); }
.legend li { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.legend i { flex: none; width: 14px; height: 8px; border-radius: 3px; }

/* A day as a bar (common.js dayLane): the track with a faint mark every three hours, the shifts on
   it, the slacking on top of them, and now. */
.lane { position: relative; height: 10px; border-radius: 999px; background: var(--sunken); overflow: hidden; }
.lane::before { content: ""; position: absolute; inset: 0; background: repeating-linear-gradient(to right, transparent 0 calc(12.5% - 1px), var(--line) calc(12.5% - 1px) 12.5%); }
.lane > i { position: absolute; top: 0; bottom: 0; left: var(--a); right: calc(100% - var(--b)); min-width: 3px; border-radius: 2px; }
.lane > b.now { position: absolute; top: 0; bottom: 0; left: var(--a); width: 2px; margin-left: -1px; border-radius: 1px; background: var(--accent); }
.lane > i.work, .legend i.work { background: var(--ok); }
.lane > i.soft, .legend i.soft { background: color-mix(in srgb, var(--ok) 34%, var(--surface)); }
.lane > i.slack, .legend i.slack { background: var(--bad); }
.lane > i.flag, .legend i.flag { background: var(--warn); }
.lane > i.loose, .legend i.loose { background: repeating-linear-gradient(135deg, var(--warn) 0 2px, color-mix(in srgb, var(--warn) 22%, var(--surface)) 2px 4.5px); }
.lane-axis { position: relative; height: 15px; font-size: 11px; font-weight: 500; color: var(--muted); font-variant-numeric: tabular-nums; }
.lane-axis span { position: absolute; top: 0; left: var(--a); transform: translateX(-50%); white-space: nowrap; }
.lane-axis span:first-child { transform: none; }

/* A bar for each day of a stretch: worked from the bottom, the slacking over it. */
.bars { display: flex; align-items: stretch; gap: 4px; height: 30px; }
.bars span { flex: 1 1 0; min-width: 2px; max-width: 28px; border-radius: 3px; background: linear-gradient(to top, var(--ok) 0 var(--w, 0%), var(--bad) var(--w, 0%) calc(var(--w, 0%) + var(--s, 0%)), var(--sunken) calc(var(--w, 0%) + var(--s, 0%))); }
.bars-head { font-size: 11.5px; }

/* The rows: one grid for the whole list, so every column lines up. */
.roster { display: grid; grid-template-columns: minmax(230px, 1.5fr) minmax(220px, 3fr) repeat(6, minmax(56px, max-content)) 30px; column-gap: 20px; }
.roster > .empty { grid-column: 1 / -1; }
.roster-head, .person, .person-row { grid-column: 1 / -1; display: grid; grid-template-columns: subgrid; align-items: center; }
.roster-head { padding: 0 8px 9px; border-bottom: 1px solid var(--line); font-size: 11.5px; font-weight: 550; color: var(--muted); }
.roster-head .plane { align-self: end; }
.nums { display: contents; }
.n { text-align: right; font-size: 14px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.n small { font-size: 11px; font-weight: 450; color: var(--muted); }
.n.key { font-weight: 650; }
.n.bad { color: var(--bad); }
.n.bad small { color: inherit; opacity: 0.75; }
.n.none { color: var(--faint); }
.roster-head .n { font-size: 11.5px; }
.roster-head .n.key { font-weight: 650; color: var(--fg-2); }
.person { border-bottom: 1px solid var(--line); }
.person:last-child { border-bottom: 0; }
.person-row { min-height: 62px; padding: 10px 8px; border-radius: 12px; cursor: pointer; transition: background-color 0.15s; }
.person-row:hover, .person.open > .person-row { background: var(--sunken); }
.pwho { display: flex; align-items: center; gap: 11px; min-width: 0; }
.pname { display: grid; gap: 1px; min-width: 0; }
.pname b { display: flex; align-items: center; gap: 8px; min-width: 0; font-size: 14px; font-weight: 600; white-space: nowrap; }
.pname small { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; font-size: 12px; line-height: 1.4; color: var(--muted); text-wrap: pretty; }
/* Initials in a circle, and on today a dot for where they are: at the phone, on and untouched, off. */
.person-row .avatar { position: relative; width: 34px; height: 34px; overflow: visible; background: color-mix(in srgb, var(--fg) 7%, var(--surface)); color: var(--fg-2); font-size: 12px; letter-spacing: 0.02em; }
.person-row .avatar::after { content: ""; position: absolute; right: -2px; bottom: -2px; width: 11px; height: 11px; box-sizing: border-box; border-radius: 50%; border: 2px solid var(--surface); background: var(--faint); }
.person-row:hover .avatar::after, .person.open .avatar::after { border-color: var(--sunken); }
.person-row .avatar[data-state="none"]::after { display: none; }
.person-row .avatar[data-state="active"]::after { background: var(--ok); }
.person-row .avatar[data-state="idle"]::after { background: var(--warn); }
.person-row .chev { justify-self: end; width: 30px; height: 30px; padding: 0; color: var(--muted); }
.person-row .chev svg { transform: rotate(90deg); transition: transform 0.18s; }
.person.open .chev svg { transform: rotate(-90deg); }
.team-page .tag { display: inline-flex; align-items: center; height: 18px; padding: 0 6px; border-radius: 6px; background: var(--sunken); color: var(--fg-2); font-size: 11px; font-weight: 600; letter-spacing: 0; }
.team-page .tag.warn { background: var(--warn-soft); color: var(--warn); }

/* What a click on a person opens. */
.person-more { grid-column: 1 / -1; padding: 2px 8px 14px 53px; }
.person-facts { display: grid; gap: 9px; margin: 0; padding: 14px 16px; border: 1px solid var(--line); border-radius: 12px; background: var(--surface); font-size: 13px; }
.person-facts > div { display: grid; grid-template-columns: 116px minmax(0, 1fr); gap: 14px; }
.person-facts dt { color: var(--muted); font-weight: 550; }
.person-facts dd { margin: 0; min-width: 0; color: var(--fg-2); }
.person-facts .plain { display: grid; gap: 3px; margin: 0; padding: 0; list-style: none; font-variant-numeric: tabular-nums; }
.person-facts .pair { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 10px; }
.person-facts .pair .hint { margin: 0; }
.flags { display: grid; gap: 4px; margin: 0; padding: 0; list-style: none; font-variant-numeric: tabular-nums; }
.flags li { position: relative; padding-left: 15px; }
.flags li::before { content: ""; position: absolute; left: 1px; top: 0.6em; width: 6px; height: 6px; border-radius: 50%; background: var(--faint); }
.flags li.bad { color: var(--bad); font-weight: 550; }
.flags li.bad::before { background: var(--bad); }
.flags li.warn::before { background: var(--warn); }

/* How it is all counted, folded away under the rows. */
.explain { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
.explain summary { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; list-style: none; font-size: 13px; color: var(--muted); user-select: none; }
.explain summary::-webkit-details-marker { display: none; }
.explain summary::before { content: ""; width: 6px; height: 6px; margin: 0 2px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(-45deg); transition: transform 0.18s; }
.explain[open] summary::before { transform: rotate(45deg); }
.explain summary:hover { color: var(--fg); }
.explain-body { display: grid; gap: 8px; max-width: 84ch; margin-top: 10px; font-size: 13px; line-height: 1.6; color: var(--fg-2); }
.explain-body b { color: var(--fg); }

/* The days as a table: the hours worked a person a day, the slacking taken off in red beside them. */
.table-wrap { overflow-x: auto; margin: 0 -8px; }
.daygrid { width: 100%; border-collapse: collapse; font-size: 13.5px; font-variant-numeric: tabular-nums; }
.daygrid th, .daygrid td { padding: 9px 10px; border-bottom: 1px solid var(--line); text-align: left; white-space: nowrap; }
.daygrid th:first-child { padding-left: 8px; }
.daygrid th:last-child, .daygrid td:last-child { padding-right: 8px; }
.daygrid thead th { padding-top: 0; border-bottom-color: var(--line); font-size: 11.5px; font-weight: 550; color: var(--muted); }
.daygrid tbody th { font-weight: 500; }
.daygrid tbody th > span:first-child { margin-right: 8px; }
.daygrid .num { text-align: right; }
.daygrid .team { font-weight: 650; }
.daygrid thead .team { color: var(--fg-2); }
.daygrid .minus { display: inline-block; min-width: 3.4ch; margin-left: 6px; font-size: 11.5px; font-weight: 500; color: var(--bad); text-align: left; }
.daygrid .none { color: var(--faint); }
.daygrid tbody tr { cursor: pointer; }
.daygrid tbody tr:hover > * { background: var(--sunken); }
.daygrid tbody tr:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.daygrid tr.here > * { background: var(--accent-soft); }
.daygrid tr.here, .daygrid tr.here:hover > * { cursor: default; background: var(--accent-soft); }
.daygrid tr.here th { color: var(--accent-text); font-weight: 600; }
.daygrid tfoot > tr > * { border-top: 2px solid var(--line-strong); border-bottom: 0; font-weight: 650; }

/* The team settings: a row each, the name on the left, the field and what it means on the right. */
.settings { display: grid; }
.setting { display: grid; grid-template-columns: 220px minmax(0, 1fr); gap: 8px 28px; padding: 16px 0; border-top: 1px solid var(--line); }
.setting:first-child { padding-top: 0; border-top: 0; }
.setting:last-child { padding-bottom: 0; }
.setting > label, .setting-label { padding-top: 8px; font-size: 13.5px; font-weight: 600; }
.setting-field { min-width: 0; max-width: 720px; }
.setting-input { display: flex; gap: 8px; }
.setting-input input { flex: 1; min-width: 0; }
.setting-input button { height: 38px; padding: 0 16px; border-radius: 10px; font-size: 13.5px; }
.setting .hint { margin-top: 8px; }
.rules-edit summary { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; padding-top: 8px; list-style: none; font-size: 13.5px; color: var(--fg-2); user-select: none; }
.rules-edit summary::-webkit-details-marker { display: none; }
.rules-edit summary::before { content: ""; width: 6px; height: 6px; margin: 0 2px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(-45deg); transition: transform 0.18s; }
.rules-edit[open] summary::before { transform: rotate(45deg); }
.rules-edit summary:hover { color: var(--fg); }
.rules-edit textarea { width: 100%; margin-top: 10px; font-size: 13.5px; }
.rules-edit .field-row { margin-top: 10px; }

@media (max-width: 960px) {
  /* The rows as cards: name and arrow, the bar under them, the hours under that, each named. */
  .roster { display: block; }
  .roster-head { display: block; padding: 0 4px 8px; border-bottom: 0; }
  .roster-head > :not(.plane) { display: none; }
  .person, .person-row { display: block; }
  .person-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "who chev" "lane lane" "nums nums"; gap: 10px 8px; padding: 12px 4px; }
  .person-row .pwho { grid-area: who; }
  .person-row .plane { grid-area: lane; }
  .person-row .chev { grid-area: chev; }
  .person-row .nums { grid-area: nums; display: flex; flex-wrap: wrap; gap: 3px 14px; }
  .person-row .n { text-align: left; font-size: 13px; }
  .person-row .n::before { content: attr(data-label) " "; font-weight: 450; color: var(--muted); }
  .person-row .n.none { display: none; }
  .person-row .n.key { order: -1; }
  .person-more { padding: 0 0 14px; }
}
@media (max-width: 640px) {
  .tracker { gap: 12px; }
  .tracker-bar { margin-top: 2px; }
  .day-step { flex: 1 1 100%; }
  .time-day { font-size: 18px; overflow: hidden; text-overflow: ellipsis; }
  .time-day .z { font-size: 13px; }
  .watch { margin-left: 0; flex: 1 1 100%; white-space: normal; }
  .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .stat.wide { grid-column: 1 / -1; }
  .stat { padding: 13px 14px 14px; border-radius: 12px; }
  .stat-value { font-size: 23px; }
  .stat-sub { white-space: normal; }
  .legend { margin-left: 0; flex: 1 1 100%; gap: 4px 12px; }
  .lane-axis span:nth-child(even) { display: none; }
  .person-facts > div { grid-template-columns: minmax(0, 1fr); gap: 2px; }
  .daygrid { font-size: 12.5px; }
  .daygrid th, .daygrid td { padding: 8px 6px; }
  .daygrid .minus { display: block; min-width: 0; margin-left: 0; font-size: 10.5px; text-align: right; }
  .daygrid .tag { display: none; }
  .setting { grid-template-columns: minmax(0, 1fr); gap: 8px; }
  .setting > label, .setting-label { padding-top: 0; }
}

/* A line saying how something stands, under its name: used on the Ads, Campaigns and Creatives
   pages. Empty, it takes no room. */
.status { margin-top: 12px; font-size: 14px; font-weight: 550; }
.status:empty { display: none; }

/* ---- the My time page (a VA's own) ----------------------------------------------------------
   The clock on top, big: the shift so far ticking, and the one button. Then the day: the hours in
   figures over the shifts they are made of, the day as a bar, the GeeLark phones apart with their
   minutes against the cap; then the last seven days as bars, and the rules. */
.clock-card { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 18px 28px; padding: 24px 28px; border: 1px solid var(--line); border-radius: 18px; background: var(--surface); box-shadow: var(--shadow-sm); }
.clock-card.on { border-color: var(--ok-line); background: linear-gradient(180deg, color-mix(in srgb, var(--ok-soft) 70%, var(--surface)), var(--surface) 70%); }
.clock-read { display: grid; gap: 4px; min-width: 0; }
.clock-kind { display: inline-flex; align-items: center; gap: 8px; font-size: 13.5px; font-weight: 600; color: var(--muted); }
.clock-card.on .clock-kind { color: var(--ok); }
.clock-card.on .clock-kind::before { content: ""; flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--ok); --pulse-ring: var(--ok-ring); animation: pulse 2.4s ease-in-out infinite; }
.shift-time { font-size: 60px; line-height: 1; font-weight: 600; letter-spacing: -0.04em; font-variant-numeric: tabular-nums; color: var(--faint); }
.clock-card.on .shift-time { color: var(--fg); }
.clock-card .status { margin-top: 4px; font-size: 13.5px; font-weight: 450; color: var(--fg-2); }
button.clock-button { height: 50px; min-width: 156px; padding: 0 28px; border-radius: 14px; font-size: 15.5px; font-weight: 600; }

.day-head { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 12px; margin: -4px 0 18px -8px; }
.day-title { margin: 0 4px; font-size: 18px; font-weight: 650; letter-spacing: -0.015em; white-space: nowrap; }
.day-zone { color: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; }
#dayToday { margin-left: auto; }

/* Figures with their names over them: the hours, big; the GeeLark phones' quieter. */
.my-figures { display: grid; gap: 18px; }
.tiles { display: flex; flex-wrap: wrap; gap: 14px 40px; }
.tile { display: grid; align-content: start; gap: 2px; min-width: 0; }
.tile-label { font-size: 12.5px; font-weight: 550; color: var(--muted); }
.tile-value { font-size: 26px; line-height: 1.2; font-weight: 650; letter-spacing: -0.025em; font-variant-numeric: tabular-nums; white-space: nowrap; }
.tile-sub { font-size: 12px; color: var(--muted); }
.my-figures.quiet { display: flex; flex-wrap: wrap; gap: 12px 36px; }
.my-figures.quiet .tile-value { font-size: 17px; letter-spacing: -0.01em; }

/* The shifts, a line each: when, then how long and what kind. */
.shift-list { display: grid; grid-template-columns: 64px minmax(0, 1fr); gap: 8px 14px; align-items: baseline; }
.shift-head { font-size: 12.5px; font-weight: 550; color: var(--muted); }
.shift-list ul { display: grid; gap: 5px; margin: 0; padding: 0; list-style: none; }
.shift-list li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; font-size: 13.5px; font-variant-numeric: tabular-nums; }
.shift-list .when { font-weight: 550; }
.shift-list li.open .when { color: var(--ok); }
.shift-list .what { color: var(--muted); font-size: 12.5px; }
.shift-list .none { color: var(--muted); font-size: 13.5px; }

.my-lane { display: grid; gap: 6px; margin-top: 22px; }
.my-lane .lane { height: 12px; }
.my-lane .legend { margin: 4px 0 0; }

/* The GeeLark phones, apart under their own heading. */
.my-geelark { display: grid; gap: 14px; margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--line); }
.sub-head { display: flex; align-items: baseline; gap: 10px; }
.sub-head h3 { font-size: 14px; font-weight: 650; }
.sub-head .count { font-size: 12.5px; }
.my-geelark > p.hint { margin-top: -6px; }
.meter { display: grid; gap: 7px; max-width: 520px; }
.meter > div { display: grid; gap: 7px; }
.meter-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; font-size: 13px; color: var(--fg-2); }
.meter-head b { font-size: 14px; font-variant-numeric: tabular-nums; color: var(--fg); }
.meter-bar { position: relative; display: block; height: 8px; border-radius: 999px; background: var(--sunken); overflow: hidden; }
.meter-bar i { position: absolute; inset: 0 auto 0 0; width: var(--p, 0%); border-radius: inherit; background: var(--accent); transition: width 0.4s ease; }
.meter.full .meter-bar i { background: var(--warn); }
.meter-note { font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
.flag-box { display: grid; gap: 8px; padding: 12px 14px; border: 1px solid var(--line); border-radius: 12px; font-size: 13px; }
.flag-head { font-size: 12.5px; font-weight: 600; color: var(--fg-2); }
#pairHint { margin-top: 18px; }

/* The last seven days: a row each, its hours as a bar. */
.week-list { width: 100%; border-collapse: collapse; font-size: 13.5px; font-variant-numeric: tabular-nums; }
.week-list th, .week-list td { padding: 9px 8px; border-bottom: 1px solid var(--line); text-align: left; white-space: nowrap; vertical-align: top; }
.week-list thead th { padding-top: 0; font-size: 11.5px; font-weight: 550; color: var(--muted); }
.week-list tbody tr:last-child > * { border-bottom: 0; }
.week-list tbody th { font-weight: 500; }
.week-list tbody th > span:first-child { margin-right: 8px; }
.week-list .num { text-align: right; }
.week-list .bar-col { width: 100%; padding-left: 12px; padding-right: 12px; }
.week-list .sub { font-size: 11.5px; color: var(--muted); }
.week-list .none { color: var(--faint); }
.week-bar { display: block; height: 8px; margin-top: 6px; border-radius: 999px; background: linear-gradient(to right, var(--ok) 0 var(--g, 0%), color-mix(in srgb, var(--ok) 34%, var(--surface)) var(--g, 0%) calc(var(--g, 0%) + var(--o, 0%)), var(--sunken) calc(var(--g, 0%) + var(--o, 0%))); }
.week-list tbody tr { cursor: pointer; }
.week-list tbody tr:hover > * { background: var(--sunken); }
.week-list tbody tr:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.week-list tr.here > *, .week-list tr.here:hover > * { cursor: default; background: var(--accent-soft); }
.week-list tr.here th { color: var(--accent-text); font-weight: 600; }
.day-tag { display: inline-flex; align-items: center; height: 18px; padding: 0 6px; border-radius: 6px; background: var(--sunken); color: var(--fg-2); font-size: 11px; font-weight: 600; }
.week-list tr.here .day-tag { background: var(--surface); }

.rules { max-width: 68ch; font-size: 14px; line-height: 1.6; color: var(--fg-2); }
.rules p + p, .rules ul + p, .rules p + ul, .rules ul + ul { margin-top: 10px; }
.rules ul { display: grid; gap: 4px; margin: 0; padding-left: 20px; }
.rules li::marker { color: var(--faint); }

@media (max-width: 640px) {
  .clock-card { padding: 18px 18px 20px; border-radius: 16px; }
  .shift-time { font-size: 48px; }
  button.clock-button { flex: 1 1 100%; height: 50px; }
  .day-head { margin: -2px 0 14px -6px; }
  .day-zone { flex: 1 1 100%; order: 3; margin-left: 6px; }
  .tiles { gap: 12px 28px; }
  .tile-value { font-size: 23px; }
  .shift-list { grid-template-columns: minmax(0, 1fr); gap: 6px; }
  .my-figures.quiet { gap: 10px 24px; }
  .my-lane .lane-axis span:nth-child(even) { display: none; }
  .week-list { font-size: 12.5px; }
  .week-list th, .week-list td { padding: 8px 5px; }
  .week-list .bar-col { padding-left: 6px; padding-right: 6px; }
  .week-list .day-tag { display: none; }
}

/* ---- listings ------------------------------------------------------------------------------- */
/* The Listings page: a paste bar, a card for each post being read or ready to make, and a line for
   each product made. The cards shrink to the screen: a store's long name in the list ("… (needs
   new permissions)") is cut short in its select rather than pushing the page past a phone's width. */

/* The paste bar: the one thing to do when nothing is ready, so it is the page's head. The link and
   Read on one line, the instructions box under them; on a phone Read comes last. */
.intake-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 14px; margin-bottom: 16px; }
.intake-head h1 { font-size: 22px; line-height: 1.2; font-weight: 650; letter-spacing: -0.02em; }
.intake-head .count { margin-left: auto; }
.paste { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 10px; }
.paste-box { grid-area: 1 / 1; position: relative; min-width: 0; display: flex; align-items: center; }
.paste-box > [data-icon], .asks-box > [data-icon] { position: absolute; left: 15px; color: var(--muted); pointer-events: none; }
.listings-page .paste-box input { height: 48px; padding-left: 42px; border-radius: 13px; font-size: 15px; background: var(--surface); }
.listings-page .paste > button { grid-area: 1 / 2; height: 48px; padding: 0 22px; border-radius: 13px; font-size: 14.5px; }
.asks-box { grid-area: 2 / 1 / 3 / -1; position: relative; display: block; min-width: 0; }
.asks-box > [data-icon] { top: 15px; }
.listings-page .asks-box textarea { display: block; width: 100%; min-height: 48px; max-height: 220px; padding: 12px 14px 12px 42px; border-radius: 13px; font-size: 14.5px; background: var(--surface); resize: none; }
/* The Launch page's paste: more links of the product under the link, the instructions under those,
   and the store (when there is a choice) on the button's row. */
.launch-page .more-box { grid-area: 2 / 1 / 3 / -1; }
.launch-page .asks-box:not(.more-box) { grid-area: 3 / 1 / 4 / -1; }
.launch-page .shop-box { grid-area: 4 / 1 / 5 / -1; display: inline-flex; align-items: center; gap: 9px; min-width: 0; }
.launch-page .shop-box select { max-width: 360px; }
.launch-page .hint b { font-weight: 600; color: var(--fg); }
/* The Launch page's card: the More videos box above the price, account and Create and launch row. */
.listing .more-field { display: flex; align-items: flex-start; gap: 9px; margin: 0 0 10px; }
.listing .more-field .field-name { padding-top: 10px; white-space: nowrap; }
.listing .more-field textarea { display: block; flex: 1 1 auto; width: 100%; min-height: 40px; max-height: 160px; padding: 9px 12px; border-radius: 11px; font-size: 14px; background: var(--surface); resize: vertical; }
/* Spark codes under More videos (2026-10-29): the two boxes start at one line, and a code that does
   not look like one is said under them. */
.launch-rows .more-field .field-name { min-width: 84px; }
.listing .codes-note { margin: -4px 0 10px; }
.slim-body .codes-note { margin: 0; }
.listing .left-out { margin-top: 2px; }
/* A card pasted with instructions says what they were, under its head. */
.asked-line { display: flex; align-items: flex-start; gap: 7px; margin: -6px 0 0; font-size: 13px; color: var(--fg-2); overflow-wrap: anywhere; white-space: pre-line; }
.asked-line svg { flex: none; margin-top: 3px; color: var(--muted); }
.slim-body .asked-line { margin: 0; }
/* The More videos box on a Launch card still being read or made, under where it has got to. */
.slim-body .more-field { margin: 0; }
/* A change to ask for under a card's pictures (user, 2026-10-18): one line that grows as it is typed,
   and a Redo beside it. */
:where(.listings-page) .change-box { position: relative; display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: start; gap: 8px; min-width: 0; }
:where(.listings-page) .change-box > svg { position: absolute; top: 12.5px; left: 13px; color: var(--muted); pointer-events: none; }
:where(.listings-page) .change-box textarea { display: block; width: 100%; min-height: 40px; max-height: 160px; padding: 9px 12px 9px 36px; border-radius: 11px; font-size: 14px; line-height: 1.45; resize: none; }
/* Empty, it is one line, whatever its placeholder says: a long one made it three lines tall. */
:where(.listings-page) .change-box textarea:placeholder-shown { white-space: nowrap; overflow: hidden; }
:where(.listings-page) .change-box button { height: 40px; padding: 0 14px; border-radius: 11px; }
:where(.listings-page) .piece-x { margin-left: auto; }
.intake > .hint { margin-top: 10px; }
.intake .setup-note { margin-top: 14px; }
.intake .explain { margin-top: 16px; }
.how { margin: 10px 0 0; padding-left: 20px; }
.how li { padding-left: 4px; }
.how li::marker { color: var(--muted); font-variant-numeric: tabular-nums; }
.picks-note { margin-top: 12px; font-size: 12.5px; color: var(--muted); text-wrap: pretty; }

/* ---- a card ---- */
.listings { display: grid; gap: 14px; min-width: 0; }
.listings:empty { display: none; }
.listing {
  position: relative; display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; min-width: 0;
  padding: 16px 22px 20px; border: 1px solid var(--line); border-radius: 18px; background: var(--surface); box-shadow: var(--shadow-sm);
}
/* Only a card new to the page rises in (listings.js enter): one drawn again stays put. */
.listing.entering, .made.entering { animation: rise 0.25s ease both; }
/* Its head: where it is, whose post, who pasted it and when; what it cost and Remove at the end. */
.listing-head { display: flex; align-items: center; gap: 10px; min-width: 0; min-height: 30px; }
.listing-head .lead { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 10px; min-width: 0; font-size: 13px; color: var(--muted); }
.listing-head .end { display: flex; align-items: center; gap: 6px; flex: none; margin-left: auto; font-size: 13px; color: var(--muted); }
.listing-head .cost, .made .cost { font-variant-numeric: tabular-nums; }
a.post-link { color: var(--fg-2); font-weight: 550; text-decoration: none; overflow-wrap: anywhere; }
a.post-link:hover { color: var(--fg); text-decoration: underline; text-underline-offset: 2px; }
/* This page's alone: the Team and My time pages have icon-only buttons of their own, and the Creatives
   cards have .done lines. :where() keeps the weight of the bare class, so nothing here changes. */
:where(.listings-page) button.icon-only { width: 30px; height: 30px; padding: 0; border-radius: 9px; color: var(--muted); }
:where(.listings-page) button.icon-only:hover:not(:disabled) { color: var(--fg); }

/* Where it is, in a word: waiting and reading quiet, ready inked in (it is someone's turn), live
   green, made but not finished amber (look at it), failed red. */
.phase {
  display: inline-flex; align-items: center; gap: 6px; height: 24px; padding: 0 10px 0 9px; border-radius: 999px;
  background: var(--sunken); color: var(--fg-2); font-size: 12px; font-weight: 600; white-space: nowrap;
}
.phase i { flex: none; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.phase[data-phase="waiting"] i { background: transparent; border: 1.5px solid currentColor; }
.phase[data-phase="reading"] i, .phase[data-phase="creating"] i { width: 10px; height: 10px; background: transparent; border: 2px solid var(--line-strong); border-top-color: var(--accent); animation: spin 0.8s linear infinite; }
.phase[data-phase="ready"] { background: var(--invert-bg); color: var(--invert-fg); }
.phase[data-phase="live"] { background: var(--ok-soft); color: var(--ok); }
.phase[data-phase="unfinished"] { background: var(--warn-soft); color: var(--warn); }
.phase[data-phase="failed"], .phase[data-phase="expired"] { background: var(--bad-soft); color: var(--bad); }

/* The title: the card's heading, edited where it stands. The box only shows on a hover or a click. */
.listing input.listing-title {
  width: calc(100% + 18px); min-height: 0; height: auto; margin: -6px -9px -4px; padding: 3px 8px;
  border-color: transparent; border-radius: 10px; background: transparent;
  font-size: 22px; line-height: 1.3; font-weight: 650; letter-spacing: -0.02em; text-overflow: ellipsis;
}
.listing input.listing-title:hover { background: var(--sunken); }
.listing input.listing-title:focus { background: var(--surface); }
.pick-note { margin: -6px 0 -4px; font-size: 13px; color: var(--muted); }
.alert.warn { border-color: var(--warn-line); border-left-color: var(--warn); background: var(--warn-soft); }
.alert.warn svg { color: var(--warn); }
.listing > .alert { margin-top: 0; }

/* The pictures: all one size, in rows that fill the card. The frame of the video (or the slide) a
   photo was drawn from comes before it, darker, with what it is in its corner. */
.shots { display: grid; grid-template-columns: repeat(auto-fill, minmax(172px, 1fr)); gap: 12px; align-items: start; }
.shot {
  position: relative; display: block; margin: 0; padding: 0; min-width: 0; aspect-ratio: 4 / 5; overflow: hidden; isolation: isolate;
  border: 1px solid var(--line); border-radius: 14px; background: var(--sunken); color: inherit; text-align: left;
}
.shot img { display: block; width: 100%; height: 100%; object-fit: cover; user-select: none; -webkit-user-drag: none; }
button.shot { height: auto; border-radius: 14px; font: inherit; cursor: zoom-in; }
button.shot.from, button.shot.from:hover:not(:disabled) { border-color: var(--line); background: #0b0c0f; }
button.shot.from img { transition: transform 0.35s ease, opacity 0.2s; opacity: 0.92; }
button.shot.from:hover img { transform: scale(1.03); opacity: 1; }
button.shot.from:active:not(:disabled) { transform: none; }
/* Words on a picture: always a dark veil and white letters, the pictures being any brightness. */
.shot .cap, .shot .src-tag {
  position: absolute; z-index: 1; left: 8px; bottom: 8px; max-width: calc(100% - 16px); padding: 3px 8px; border-radius: 999px;
  background: rgb(16 18 23 / 0.62); color: #fff; font-size: 11.5px; font-weight: 600; line-height: 1.35;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; pointer-events: none;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.shot .src-tag { display: inline-flex; align-items: center; gap: 5px; }
/* "See it bigger", in the other top corner: on a hover with a mouse, always on a touch screen. */
.shot .zoom {
  position: absolute; z-index: 2; top: 8px; right: 8px; width: 30px; height: 30px; padding: 0; border: 0; border-radius: 50%;
  background: rgb(16 18 23 / 0.5); color: #fff; opacity: 0; transition: opacity 0.15s, background-color 0.15s;
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.shot:hover .zoom, .shot .zoom:focus-visible { opacity: 1; }
.shot .zoom:hover:not(:disabled) { border: 0; background: rgb(16 18 23 / 0.78); }
@media (hover: none) { .shot .zoom { opacity: 1; } }

/* A photo to keep (a tick) or a look to pick (a round mark). The tick and the mark sit on a white
   disc so they show on any photo; picked, the accent; a look picked is ringed whole and the others
   step back. */
label.shot { cursor: pointer; transition: border-color 0.15s, box-shadow 0.15s; }
label.shot:hover { border-color: var(--line-strong); box-shadow: var(--shadow); }
label.shot:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
label.shot input { position: absolute; z-index: 2; top: 9px; left: 9px; margin: 0; }
label.shot input:focus-visible { outline: none; }
label.shot input[type="checkbox"] {
  width: 22px; height: 22px; border-radius: 7px; border-color: rgb(16 18 23 / 0.3);
  background-color: rgb(255 255 255 / 0.94); background-size: 14px; box-shadow: 0 1px 3px rgb(0 0 0 / 0.2);
}
label.shot input[type="checkbox"]:checked { border-color: var(--accent); background-color: var(--accent); }
label.shot input[type="radio"] {
  appearance: none; -webkit-appearance: none; flex: none; width: 24px; height: 24px; min-height: 0; padding: 0; border-radius: 50%; cursor: pointer;
  border: 1.5px solid rgb(16 18 23 / 0.3); background: rgb(255 255 255 / 0.94) center / 14px no-repeat; box-shadow: 0 1px 3px rgb(0 0 0 / 0.2);
  transition: background-color 0.12s, border-color 0.12s;
}
/* The base field rule rings a focused input; here the whole tile is ringed instead (above). */
label.shot input[type="radio"]:focus { border-color: rgb(16 18 23 / 0.3); box-shadow: 0 1px 3px rgb(0 0 0 / 0.2); }
label.shot input[type="radio"]:checked {
  border-color: var(--accent); background-color: var(--accent);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 6.2l2.4 2.4 4.6-5' fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
label.shot img { transition: opacity 0.15s, filter 0.15s; }
label.shot.off img { opacity: 0.4; }
label.shot.look.off img { opacity: 0.5; filter: saturate(0.6); }
label.shot.look.off:hover img { opacity: 0.85; filter: none; }
label.shot.look.on, label.shot.look.on:hover { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent), var(--shadow); }
/* A look of several colours: a picture each, side by side, two or more places wide. */
.look-photos { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1px; height: 100%; background: var(--line); }
.look-photo { position: relative; display: block; min-width: 0; height: 100%; background: var(--sunken); }
label.shot.look:not([data-n="1"]) { aspect-ratio: auto; }
label.shot.look:not([data-n="1"]) .look-photo { height: auto; aspect-ratio: 4 / 5; }
label.shot.look[data-n="2"] { grid-column: span 2; }
label.shot.look[data-n="3"] { grid-column: span 3; }
label.shot.look[data-n="4"] { grid-column: span 4; }
.look-photos[data-n="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.look-photos[data-n="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.look-photos[data-n="4"] { grid-template-columns: repeat(4, minmax(0, 1fr)); }
/* "3 more": the last tile, a dashed one the size of a photo. */
.looks-more {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; aspect-ratio: 4 / 5; min-width: 0;
  border: 1.5px dashed var(--line-strong); border-radius: 14px; color: var(--muted); font-size: 13px; font-weight: 550; text-align: center;
}
.looks-more button { flex-direction: column; gap: 8px; width: 100%; height: 100%; padding: 0; border: 0; border-radius: 12px; background: transparent; color: var(--fg-2); font-size: 13.5px; }
.looks-more button:hover:not(:disabled) { background: var(--sunken); color: var(--fg); }
.looks-more:has(button:hover) { border-color: var(--faint); }
.looks-more .spinner { width: 18px; height: 18px; }
/* Where the photos came from, under them. */
.shots-notes { display: grid; gap: 4px; margin-top: -6px; }
.shots-note { display: flex; align-items: flex-start; gap: 7px; font-size: 12.5px; color: var(--muted); overflow-wrap: anywhere; }
.shots-note svg { flex: none; margin-top: 2px; }
.shots-note a { color: var(--fg-2); text-decoration: underline; text-decoration-color: var(--line-strong); text-underline-offset: 2px; }
.shots-note a:hover { color: var(--fg); text-decoration-color: currentColor; }
.shots-note.warn { color: var(--warn); }

/* Where it goes, and the button that sends it: a bar across the card's foot. */
.create-row {
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px 22px; margin: 4px -22px -20px; padding: 14px 22px;
  border-top: 1px solid var(--line); border-radius: 0 0 17px 17px; background: color-mix(in srgb, var(--sunken) 55%, var(--surface));
}
.listing .field { display: inline-flex; align-items: center; gap: 9px; min-width: 0; }
.field-name { font-size: 13px; font-weight: 550; color: var(--fg-2); }
.listing .field select { min-width: 0; }
.listing .store-field select { max-width: 280px; }
/* Wide enough for "@hayden.cairns — 0 posts left, next at 7:51 PM": it was cut at 220px. */
.listing .creator-field select { max-width: 400px; }
.listing .was { font-size: 12.5px; color: var(--muted); white-space: nowrap; }
.create-row .go { margin-left: auto; height: 40px; padding: 0 20px; border-radius: 11px; }
.no-store { display: flex; align-items: flex-start; gap: 7px; flex-basis: 100%; font-size: 12.5px; color: var(--warn); }
.no-store svg { flex: none; margin-top: 2px; }
/* The names of a product's choices (its colours; a set's pieces sold one by one): a box each, sized
   for a short name, under the photos they name. */
.listing .variants { display: grid; gap: 10px; min-width: 0; }
.listing .names-field { display: flex; align-items: flex-start; gap: 9px; }
.listing .names-field[hidden] { display: none; }
.listing .names-field .field-name { padding-top: 9px; white-space: nowrap; }
.listing .names { display: flex; flex-wrap: wrap; gap: 6px; flex: 1 1 auto; min-width: 0; }
.listing input.variant-name { flex: 0 1 170px; min-width: 0; height: 36px; padding: 0 11px; border-radius: 10px; font-size: 14px; background: var(--surface); }
/* A set's pieces are named in full ("Cross Patch Zip-Up Hoodie"): their boxes share the line. */
.listing [data-names="pieceNames"] input.variant-name { flex: 1 1 220px; }
.piece.off .variants { opacity: 0.4; }

/* A post of several items: a piece each, one under the other, its name, its price and its photos. */
.pieces { display: grid; min-width: 0; margin-top: -2px; }
.piece { display: grid; gap: 14px; min-width: 0; padding: 18px 0; border-top: 1px solid var(--line); }
.piece:last-child { padding-bottom: 4px; }
.piece-head { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; min-width: 0; }
.piece-head > input[type="checkbox"] { width: 20px; height: 20px; border-radius: 6px; }
/* Up and down: where the piece goes among the others (the first is the product's first choice). */
.piece-order { display: flex; gap: 2px; margin-left: auto; }
.piece-order + .piece-x { margin-left: 0; }
.listing input.piece-title {
  flex: 1 1 240px; min-width: 0; min-height: 0; height: auto; margin: -4px 0; padding: 4px 8px;
  border-color: transparent; border-radius: 9px; background: transparent; font-size: 16px; font-weight: 600; letter-spacing: -0.01em;
}
.listing input.piece-title:hover { background: var(--sunken); }
.listing input.piece-title:focus { background: var(--surface); }
/* A phone has no hover to show that a piece's name is a box to type in: the box always shows. */
@media (hover: none) {
  .listing input.piece-title:not(:focus) { background: var(--sunken); }
}
.piece.off .shots, .piece.off .piece-title, .piece.off .field, .piece.off .shots-notes { opacity: 0.4; }
.piece-wait { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 12px; min-width: 0; }
.piece-name { font-weight: 600; overflow-wrap: anywhere; }
.piece-step { font-size: 13px; color: var(--muted); }
.piece-step.bad { flex-basis: 100%; color: var(--fg-2); }
.piece.waiting .bar, .piece.failed .row-actions { margin-top: -4px; }
.piece.failed .row-actions { margin-left: 0; }
.listing .bar { margin-top: 0; }

/* A card being read, made, or that failed: one short line, a small picture of the post first. */
.listing.slim { grid-template-columns: auto minmax(0, 1fr); align-items: start; column-gap: 16px; padding: 14px 18px 16px 14px; }
.slim .thumb { display: grid; place-items: center; width: 52px; aspect-ratio: 4 / 5; overflow: hidden; border-radius: 10px; background: var(--sunken); color: var(--muted); }
.slim .thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.slim.failed .thumb, .slim.expired .thumb { background: var(--bad-soft); color: var(--bad); }
.slim-body { display: grid; gap: 8px; min-width: 0; }
.slim-step { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; font-size: 14px; font-weight: 550; }
.slim-step .pct { color: var(--muted); font-size: 12.5px; font-weight: 500; font-variant-numeric: tabular-nums; }
.slim-error { font-size: 13.5px; color: var(--fg-2); overflow-wrap: anywhere; text-wrap: pretty; }
.slim-actions { display: flex; gap: 8px; }

/* ---- what was made: a line each ---- */
:where(.listings-page) .done { padding: 18px 22px 10px; }
.done-head { display: flex; align-items: baseline; gap: 10px; }
.done-head h2 { font-size: 16px; font-weight: 650; letter-spacing: -0.01em; }
.done-list { display: grid; margin-top: 6px; }
.made { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 18px; min-width: 0; padding: 14px 0; border-top: 1px solid var(--line); }
.made:first-child { border-top: 0; }
.made-main { display: grid; gap: 4px; flex: 1 1 360px; min-width: 0; }
.made-title { display: flex; align-items: baseline; gap: 10px; min-width: 0; }
.made-title b { min-width: 0; font-size: 14.5px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.made-meta { margin: 0; font-size: 12.5px; line-height: 1.55; color: var(--muted); }
.made-meta .post-link { font-weight: 500; }
.made .piece-prices { display: flex; flex-wrap: wrap; gap: 2px 14px; margin: 0; padding: 0; list-style: none; font-size: 12.5px; color: var(--fg-2); }
.made .alert { margin-top: 4px; }
/* Under a made line, and on a ready card whose press is on its way or failed. */
:where(.listings-page) .launch-state { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 4px 7px; margin-top: 4px; font-size: 12.5px; font-weight: 500; color: var(--fg-2); text-decoration: none; }
:where(.listings-page) .launch-state:hover { color: var(--fg); }
:where(.listings-page) .launch-state i { width: 8px; height: 8px; border-radius: 50%; background: var(--muted); flex: none; }
:where(.listings-page) .launch-state[data-status="preparing"] i, :where(.listings-page) .launch-state[data-status="waiting"] i, :where(.listings-page) .launch-state[data-status="running"] i { background: var(--warn); animation: breathe 1.1s ease-in-out infinite alternate; }
:where(.listings-page) .launch-state[data-status="done"] i { background: var(--ok); }
:where(.listings-page) .launch-state[data-status="failed"] i { background: var(--bad); }
/* Held for the admin's edit ("Edit before posting"): it waits on them, not on TikTok, so it is still. */
:where(.listings-page) .launch-state[data-status="editing"] i { background: var(--accent); }
:where(.listings-page) .edit-wait { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin-top: 8px; }
:where(.listings-page) .edit-wait-note { font-size: 12.5px; color: var(--muted); }
/* The pixel, the display card, the account and the time, after the words: a phone has no tooltip. */
.launch-state .launch-detail { font-weight: 450; color: var(--muted); }
.launch-state .launch-detail::before { content: '· '; }
.listing > .launch-state { justify-self: start; }
.made-actions { display: flex; align-items: center; gap: 4px; flex: none; margin-left: auto; }
.made-actions .button.small { gap: 5px; color: var(--fg-2); }
.done-more { margin: 2px 0 8px; }

/* ---- the viewer: a photo up close, beside the frame it was drawn from ---- */
.photo-viewer[open] { display: grid; grid-template-rows: minmax(0, 1fr) auto; justify-items: center; gap: 16px; width: 100vw; height: 100vh; height: 100dvh; max-height: none; padding: 64px 20px 22px; }
.pv-stage { display: flex; align-items: center; justify-content: center; gap: 18px; min-height: 0; max-width: 100%; }
.pv-from, .pv-photo { display: grid; justify-items: center; align-content: center; gap: 10px; min-width: 0; min-height: 0; max-height: 100%; margin: 0; }
.pv-from img { display: block; max-width: 30vw; max-height: calc(100dvh - 190px); border-radius: 14px; background: #000; }
.pv-photos { display: flex; gap: 10px; min-height: 0; }
.pv-photos img { display: block; max-width: min(52vw, 820px); max-height: calc(100dvh - 190px); border-radius: 14px; background: #fff; }
.pv-photos[data-n="2"] img { max-width: min(30vw, 560px); }
.pv-photos[data-n="3"] img, .pv-photos[data-n="4"] img { max-width: min(20vw, 420px); }
.photo-viewer figcaption { min-height: 18px; font-size: 12.5px; color: rgb(255 255 255 / 0.7); text-align: center; }
.pv-bar { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 12px; }
.pv-count { min-width: 60px; font-size: 13px; color: rgb(255 255 255 / 0.82); text-align: center; font-variant-numeric: tabular-nums; }
.photo-viewer button.round { flex: none; width: 40px; height: 40px; padding: 0; border-radius: 50%; border-color: transparent; background: rgb(255 255 255 / 0.14); color: #fff; }
.photo-viewer button.round:hover:not(:disabled) { border-color: transparent; background: rgb(255 255 255 / 0.26); }
.photo-viewer button.round:disabled { opacity: 0.3; }
.pv-act { height: 40px; margin-left: 8px; padding: 0 20px; border-radius: 999px; }
.pv-act:disabled { opacity: 1; background: rgb(255 255 255 / 0.14); border-color: transparent; color: #fff; }
.flip-x svg { transform: scaleX(-1); }

@media (max-width: 640px) {
  .intake-head { margin-bottom: 12px; }
  .intake-head h1 { font-size: 20px; }
  .paste { grid-template-columns: minmax(0, 1fr); }
  .paste-box, .asks-box, .listings-page .paste > button { grid-area: auto; }
  .listing { gap: 14px; padding: 14px 14px 16px; border-radius: 16px; }
  .listing input.listing-title { font-size: 19px; }
  .listing-head { align-items: flex-start; }
  .shots { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  label.shot.look[data-n="3"], label.shot.look[data-n="4"] { grid-column: 1 / -1; }
  .create-row { gap: 12px; margin: 2px -14px -16px; padding: 14px; border-radius: 0 0 15px 15px; }
  .listing .field { display: grid; grid-template-columns: 52px minmax(0, 1fr) auto; flex: 1 1 100%; }
  .listing .store-field select { max-width: none; }
  .listing .store-field, .listing .priced-field { grid-template-columns: 52px minmax(0, 1fr); }
  .create-row .go { flex: 1 1 100%; margin-left: 0; }
  .piece-head .piece-title { flex-basis: calc(100% - 76px); }
  .piece-head .piece-x { order: 1; }
  /* The name and the cross on the first line, the price with up and down on the next, then how a
     set is sold: the "For" choice came before the cross and left it on a line of its own. */
  .piece-head .price-field { order: 2; }
  .piece-head .piece-order { order: 3; }
  .piece-head .priced-field { order: 4; }
  /* Up alone (pressed again, it takes a piece to the top): with down too the price read "$19.". */
  .piece-head .piece-order .move-down { display: none; }
  .piece-head .price-field:has(~ .piece-order) { flex-basis: calc(100% - 42px); }
  .listing input.piece-title { font-size: 16px; }
  .listing .names-field { display: grid; grid-template-columns: 52px minmax(0, 1fr); }
  .listing input.variant-name { flex: 1 1 130px; height: 40px; font-size: 16px; }
  .listing.slim { column-gap: 12px; padding: 12px 12px 14px; }
  .slim .thumb { width: 44px; }
  :where(.listings-page) .done { padding: 16px 14px 8px; }
  /* Four buttons (Launch again, View on the store, Open in Shopify, the cross) came to 396px in a
     338px panel and the page scrolled sideways: they wrap, the cross at the line's end. */
  .made-actions { flex: 1 1 100%; flex-wrap: wrap; gap: 6px 4px; margin-left: -8px; }
  .made-actions .icon-only { margin-left: auto; }
  .made-title b { white-space: normal; }
  /* "More videos" and "Posted by" fit the first column; the account stretches like the price. */
  .launch-page .listing .field { grid-template-columns: 84px minmax(0, 1fr) auto; }
  .listing .more-field, .listing .creator-field { grid-template-columns: 84px minmax(0, 1fr); }
  /* A card still being read or made is narrower by its picture: the name over the box, which then
     has the card's whole width for a link. */
  .listing .slim-body .more-field { grid-template-columns: minmax(0, 1fr); gap: 6px; }
  .slim-body .more-field .field-name { padding-top: 0; }
  .listing .creator-field select { max-width: none; }
  /* "@mybrand — 15 posts left" is wider than the box beside "Posted by" (2026-10-29): the name over
     the box, which then has the row's whole width. */
  .listing .create-row .creator-field { grid-template-columns: minmax(0, 1fr); gap: 6px; }
  /* A message at the foot (an update to reload for, an error) would cover the last made line's
     buttons: the page is that much longer while one shows. */
  body:has(.toasts .toast) main { padding-bottom: 132px; }
  .photo-viewer[open] { padding: 60px 12px 16px; }
  /* The frame sits in the photo's corner: the stage is as tall as the photo, and the photo's
     caption (18px under a 10px gap) is stepped over. */
  .pv-stage { position: relative; align-self: center; }
  .pv-from { position: absolute; z-index: 1; left: 10px; bottom: 38px; }
  .pv-from img { max-width: 24vw; max-height: 26dvh; border: 2px solid rgb(255 255 255 / 0.85); border-radius: 10px; box-shadow: 0 4px 16px rgb(0 0 0 / 0.5); }
  .pv-from figcaption { display: none; }
  .pv-photos img, .pv-photos[data-n] img { max-width: calc(100vw - 24px); max-height: calc(100dvh - 170px); }
  .pv-photos[data-n="2"] img { max-width: calc(50vw - 17px); }
  .pv-act { flex: 1 1 100%; margin-left: 0; }
}

/* ---- the date-range picker: a chip that opens a calendar card under it (range-picker.js) ---- */
.chip.range svg { flex: none; }
.rp-backdrop { position: fixed; inset: 0; z-index: 30; }
.rp { position: fixed; z-index: 31; padding: 14px 16px 12px; border: 1px solid var(--line); border-radius: 16px; background: var(--surface); color: var(--fg); box-shadow: var(--shadow); }
.rp-presets { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.rp-presets button { border-color: var(--line-strong); color: var(--fg-2); }
.rp-months { display: flex; gap: 22px; }
.rp-month { width: 252px; }
.rp-head { display: flex; align-items: center; justify-content: space-between; height: 32px; margin-bottom: 4px; }
.rp-head b { font-size: 14px; font-weight: 650; letter-spacing: -0.01em; }
.rp-head button { width: 30px; padding: 0; }
.rp-head span { width: 30px; }
.rp-prev svg { transform: rotate(180deg); }
.rp-grid { display: grid; grid-template-columns: repeat(7, 36px); }
.rp-grid .wd { height: 28px; display: grid; place-items: center; font-size: 11.5px; font-weight: 550; color: var(--muted); }
.rp-day { position: relative; width: 36px; height: 36px; padding: 0; border: 0; border-radius: 10px; background: transparent; font-size: 13.5px; font-weight: 500; font-variant-numeric: tabular-nums; }
.rp-day:hover:not(:disabled) { background: var(--sunken); }
.rp-day:disabled { opacity: 1; color: var(--faint); cursor: default; }
.rp-day.in { border-radius: 0; background: var(--accent-soft); color: var(--accent-text); }
.rp-day.in:hover:not(:disabled) { background: var(--accent-line); }
.rp-day.end, .rp-day.end:hover:not(:disabled) { background: var(--accent); color: var(--accent-fg); }
.rp-day.first { border-radius: 10px 0 0 10px; }
.rp-day.last { border-radius: 0 10px 10px 0; }
.rp-day.today::after { content: ""; position: absolute; left: 50%; bottom: 4px; width: 4px; height: 4px; border-radius: 50%; background: var(--accent); transform: translateX(-50%); }
.rp-day.end.today::after { background: var(--accent-fg); }
.rp-day:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--accent); }
.rp-day.end:focus-visible { box-shadow: inset 0 0 0 2px var(--accent-fg); }
.rp-foot { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line); font-size: 13px; color: var(--muted); font-variant-numeric: tabular-nums; }
@media (max-width: 599px) {
  .rp-backdrop { background: rgb(0 0 0 / 0.4); }
  .rp { left: 10px !important; right: 10px; top: auto !important; bottom: 10px; padding: 14px 12px 12px; }
  .rp-months { justify-content: center; }
}

/* ---- phone: fields that still zoomed -----------------------------------------------------------
   iOS zooms the page into a focused field under 16 px. The phone rule far above sets 16 px, but
   these set a size of their own later or more exactly and kept it. Last in the file, so they yield. */
@media (max-width: 640px) {
  .dialog-field textarea, .rules-edit textarea, select.small, .listings-page .paste-box input, .listings-page .asks-box textarea, .listing .more-field textarea, :where(.listings-page) .change-box textarea { font-size: 16px; }
}
/* A finger, not a pointer: the made line's buttons and the crosses on the Listings and Launch
   pages are a size to tap (they are the page's presses — Launch, Retry — on a phone). */
@media (pointer: coarse) {
  .made-actions button.small, .made-actions .button.small { height: 34px; padding: 0 12px; }
  :where(.listings-page) button.icon-only { width: 36px; height: 36px; }
}

/* ---- "Edit video before uploading" ---------------------------------------------------------
   The editor is drawn over the page like the viewer: the video, the box that is kept, and under it
   the timeline and the few controls. White on dark whatever the theme, since it sits on a video.
   The one colour is the accent, on what is chosen: the part of the timeline that is kept, a pressed
   chip, the button that saves. */
.video .get.edit { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); cursor: pointer; }
.video .get.edit:hover { background: var(--accent-strong); border-color: var(--accent-strong); }
.video .get.edit svg { color: inherit; }
.editor { padding: 0; border: 0; background: transparent; max-width: 100vw; max-height: 100vh; max-height: 100dvh; overflow: visible; color: #fff; }
.editor::backdrop { background: rgb(0 0 0 / 0.9); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
.editor[open] { display: grid; justify-items: center; animation: toast-in 0.2s ease both; }
.editor-body { display: grid; justify-items: center; align-content: start; gap: 4px; width: min(94vw, 580px); max-height: 100vh; max-height: 100dvh; overflow-y: auto; overflow-x: hidden; padding: 10px 0 14px; }
/* Room around the picture for the handles of a box that reaches its edge. */
.editor-stage { padding: 14px; }
.editor-frame { position: relative; border-radius: 4px; background: #000; }
.editor-frame video { display: block; width: 100%; height: 100%; border-radius: inherit; }
.editor-frame video.mirrored { transform: scaleX(-1); }
.crop { position: absolute; inset: 0; touch-action: none; }
.crop-clip { position: absolute; inset: 0; overflow: hidden; border-radius: 4px; pointer-events: none; }
.crop-shade { position: absolute; box-shadow: 0 0 0 9999px rgb(0 0 0 / 0.64); }
.crop-box {
  position: absolute; box-sizing: border-box; border: 1.5px solid #fff; cursor: move; outline: none; touch-action: none;
  background-image: linear-gradient(rgb(255 255 255 / 0.22) 1px, transparent 1px), linear-gradient(90deg, rgb(255 255 255 / 0.22) 1px, transparent 1px);
  background-size: 100% 33.33%, 33.33% 100%; background-position: 0 -1px, -1px 0;
}
.crop-box:focus-visible { border-color: var(--accent); box-shadow: 0 0 0 3px var(--ring); }
/* A handle is a 30 px target around an 11 px dot, so a thumb finds it. */
.crop-box i { position: absolute; width: 30px; height: 30px; margin: -15px; touch-action: none; }
.crop-box i::after { content: ""; position: absolute; inset: 9.5px; border-radius: 50%; background: #fff; box-shadow: 0 0 0 1px rgb(0 0 0 / 0.45); }
.crop-box i[data-h="nw"] { left: 0; top: 0; cursor: nwse-resize; }
.crop-box i[data-h="n"] { left: 50%; top: 0; cursor: ns-resize; }
.crop-box i[data-h="ne"] { left: 100%; top: 0; cursor: nesw-resize; }
.crop-box i[data-h="e"] { left: 100%; top: 50%; cursor: ew-resize; }
.crop-box i[data-h="se"] { left: 100%; top: 100%; cursor: nwse-resize; }
.crop-box i[data-h="s"] { left: 50%; top: 100%; cursor: ns-resize; }
.crop-box i[data-h="sw"] { left: 0; top: 100%; cursor: nesw-resize; }
.crop-box i[data-h="w"] { left: 0; top: 50%; cursor: ew-resize; }
/* Held to a shape, only a corner resizes it. */
.crop.locked i[data-h="n"], .crop.locked i[data-h="e"], .crop.locked i[data-h="s"], .crop.locked i[data-h="w"] { display: none; }
.editor-panel { display: grid; gap: 10px; width: 100%; padding: 0 14px; }
.timeline-row { display: flex; align-items: center; gap: 10px; }
.editor button.round { flex: none; width: 40px; height: 40px; padding: 0; border-radius: 50%; border-color: transparent; background: rgb(255 255 255 / 0.14); color: #fff; }
.editor button.round:hover:not(:disabled) { background: rgb(255 255 255 / 0.26); border-color: transparent; }
.timeline { position: relative; flex: 1; min-width: 0; height: 52px; border-radius: 9px; background: #23262d center / 100% 100% no-repeat; touch-action: none; cursor: pointer; }
.timeline .out { position: absolute; top: 0; bottom: 0; background: rgb(0 0 0 / 0.68); pointer-events: none; }
.timeline .out.before { left: 0; border-radius: 9px 0 0 9px; }
.timeline .out.after { right: 0; border-radius: 0 9px 9px 0; }
.timeline .keep { position: absolute; top: 0; bottom: 0; box-sizing: border-box; border: 2px solid var(--accent); border-radius: 9px; pointer-events: none; }
.timeline .playhead { position: absolute; top: -4px; bottom: -4px; width: 2px; margin-left: -1px; border-radius: 1px; background: #fff; box-shadow: 0 0 0 1px rgb(0 0 0 / 0.35); pointer-events: none; }
.editor .timeline .grip { position: absolute; top: 0; bottom: 0; width: 30px; height: auto; margin-left: -15px; padding: 0; border: 0; border-radius: 0; background: transparent; box-shadow: none; cursor: ew-resize; touch-action: none; }
.timeline .grip::after { content: ""; position: absolute; top: 9px; bottom: 9px; left: 11px; width: 8px; border-radius: 4px; background: #fff; box-shadow: 0 0 0 1px rgb(0 0 0 / 0.4); }
.timeline .grip:focus-visible { outline: none; }
.timeline .grip:focus-visible::after { box-shadow: 0 0 0 3px var(--accent); }
.timeline .grip:disabled { opacity: 0.35; cursor: default; }
.editor-times { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 6px 18px; font-size: 12.5px; color: rgb(255 255 255 / 0.66); }
.editor-times span { display: inline-flex; align-items: center; gap: 5px; }
.editor-times b { min-width: 52px; text-align: center; font: 600 12.5px var(--mono); color: #fff; font-variant-numeric: tabular-nums; }
.editor button.step { width: 28px; height: 28px; padding: 0; border-radius: 8px; border-color: rgb(255 255 255 / 0.22); background: rgb(255 255 255 / 0.08); color: #fff; font-size: 15px; line-height: 1; }
.editor button.step:hover:not(:disabled) { background: rgb(255 255 255 / 0.2); border-color: rgb(255 255 255 / 0.4); }
.editor-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px; }
.editor-row .chips { margin: 0; justify-content: center; }
.editor-label { font-size: 12.5px; color: rgb(255 255 255 / 0.66); }
.editor .chip { border-color: rgb(255 255 255 / 0.24); background: rgb(255 255 255 / 0.09); color: #fff; }
.editor .chip:hover:not(:disabled) { border-color: rgb(255 255 255 / 0.5); background: rgb(255 255 255 / 0.16); }
.editor .chip[aria-pressed="true"], .editor .chip[aria-pressed="true"]:hover:not(:disabled) { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); }
.editor .chip:disabled { opacity: 0.4; }
.editor-result { text-align: center; font-size: 13.5px; font-weight: 600; font-variant-numeric: tabular-nums; }
.editor-note { text-align: center; font-size: 12.5px; color: rgb(255 255 255 / 0.62); }
.editor .alert { margin-top: 0; border-color: rgb(255 255 255 / 0.3); border-left-color: #fff; background: rgb(255 255 255 / 0.1); color: #fff; font-size: 13px; }
.editor .alert svg { color: #fff; }
.editor button.plain { border-color: rgb(255 255 255 / 0.24); background: rgb(255 255 255 / 0.09); color: #fff; }
.editor button.plain:hover:not(:disabled) { border-color: rgb(255 255 255 / 0.5); background: rgb(255 255 255 / 0.16); }
.editor button.plain:disabled { opacity: 0.4; }
/* The photo editor (editor-photos.js): the photo shown, with its box and text like a video's; under
   it a strip of every photo in the order they go out, the one shown edged in the accent and each
   kept one numbered; then a bar for the one shown: move it, leave it out, mirror every photo. A
   photo left out is faded and struck through. The strip scrolls by itself, never the page. */
.editor-frame img { display: block; width: 100%; height: 100%; border-radius: inherit; -webkit-user-select: none; user-select: none; -webkit-user-drag: none; }
.editor-frame img.mirrored { transform: scaleX(-1); }
.editor-frame.left-out img { opacity: 0.3; }
.editor-frame.left-out .crop, .editor-frame.left-out .text-layer { display: none; }
.photo-strip { display: flex; gap: 6px; justify-self: center; max-width: 100%; overflow-x: auto; padding: 3px 2px 6px; scrollbar-width: thin; }
.editor button.photo-thumb { position: relative; flex: none; width: 44px; height: 62px; padding: 0; border: 2px solid transparent; border-radius: 8px; overflow: hidden; background: #23262d; }
.editor button.photo-thumb:hover:not(:disabled) { border-color: rgb(255 255 255 / 0.5); background: #23262d; }
.editor button.photo-thumb[aria-pressed="true"], .editor button.photo-thumb[aria-pressed="true"]:hover:not(:disabled) { border-color: var(--accent); }
.photo-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; pointer-events: none; }
.photo-thumb img.mirrored { transform: scaleX(-1); }
.photo-thumb b { position: absolute; left: 3px; top: 3px; min-width: 16px; height: 16px; padding: 0 4px; box-sizing: border-box; border-radius: 8px; background: rgb(0 0 0 / 0.62); color: #fff; font: 600 10.5px/16px var(--mono); text-align: center; }
.photo-thumb b:empty { display: none; }
.photo-thumb.out img { opacity: 0.28; }
.photo-thumb.out::after { content: ""; position: absolute; inset: 0; background: linear-gradient(to top right, transparent calc(50% - 1px), rgb(255 255 255 / 0.85) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px)); }
.photo-bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px 10px; }
.photo-move { display: inline-flex; align-items: center; gap: 6px; }
.photo-move .where { min-width: 92px; text-align: center; font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums; }
.photo-tools { display: grid; gap: 10px; }
.editor-result .bit { white-space: nowrap; }
/* The close button stays over whatever scrolls under it; a picture that would start under it at
   rest starts below it (clearOfClose in editor-crop.js). */
.editor .viewer-close { z-index: 2; }
.editor-stage.below-close { padding-top: 62px; }
/* The editor's text (editor-text.js): drawn on a canvas the size of the crop box, over the video,
   with a box over each text that takes presses. The chosen one has a dashed edge, a handle at its
   corner that resizes and turns it, and an × that removes it. When it shows is a second bar under
   the timeline, the text's time in the accent; its tools sit under the crop row. */
.text-layer { position: absolute; pointer-events: none; }
.text-ink { position: absolute; inset: 0; width: 100%; height: 100%; }
.text-guide { position: absolute; background: var(--accent); pointer-events: none; }
.text-guide.across { left: 0; right: 0; top: 50%; height: 1px; margin-top: -0.5px; }
.text-guide.down { top: 0; bottom: 0; left: 50%; width: 1px; margin-left: -0.5px; }
.text-hit { position: absolute; box-sizing: border-box; transform-origin: 0 0; border: 1.5px dashed transparent; border-radius: 6px; pointer-events: auto; cursor: move; touch-action: none; outline: none; }
/* It follows its text at once. The reduced-motion rule's 1 ms transitions leave a box a frame
   behind, and a press in that frame missed it (headless Chrome, which asks for reduced motion). */
.text-hit, .text-ink { transition: none !important; }
.text-hit[hidden], .text-tools[hidden], .text-when[hidden] { display: none; }
.text-hit:hover { border-color: rgb(255 255 255 / 0.55); }
.text-hit.on { border-color: #fff; box-shadow: 0 0 0 1px rgb(0 0 0 / 0.3); }
.text-hit:focus-visible { border-color: var(--accent); box-shadow: 0 0 0 3px var(--ring); }
.text-hit .turn, .editor .text-hit .drop { display: none; position: absolute; width: 30px; height: 30px; margin: -15px; padding: 0; border: 0; border-radius: 50%; background: transparent; box-shadow: none; touch-action: none; }
.text-hit.on .turn, .editor .text-hit.on .drop { display: grid; place-items: center; }
.text-hit .turn { left: 100%; top: 100%; cursor: grab; }
.text-hit .drop { left: 0; top: 0; }
.editor .text-hit .drop:hover:not(:disabled) { background: transparent; }
.text-hit .turn span, .text-hit .drop span { display: grid; place-items: center; width: 20px; height: 20px; border-radius: 50%; background: #fff; color: #111; box-shadow: 0 0 0 1px rgb(0 0 0 / 0.45), 0 1px 4px rgb(0 0 0 / 0.35); }
.text-when { display: grid; gap: 6px; }
.text-span-row { padding-left: 50px; } /* under the timeline, past its play button */
.text-span { position: relative; height: 26px; border-radius: 7px; background: rgb(255 255 255 / 0.07); touch-action: none; cursor: pointer; }
.text-span .out { position: absolute; top: 0; bottom: 0; background: rgb(0 0 0 / 0.55); pointer-events: none; }
.text-span .out.before { left: 0; border-radius: 7px 0 0 7px; }
.text-span .out.after { right: 0; border-radius: 0 7px 7px 0; }
.text-span .on { position: absolute; top: 0; bottom: 0; box-sizing: border-box; padding: 0 14px; overflow: hidden; border-radius: 7px; background: var(--accent); color: var(--accent-fg); font-size: 11.5px; font-weight: 600; line-height: 26px; white-space: nowrap; text-overflow: ellipsis; pointer-events: none; }
.editor .text-span .grip { position: absolute; top: 0; bottom: 0; width: 30px; height: auto; margin-left: -15px; padding: 0; border: 0; border-radius: 0; background: transparent; box-shadow: none; cursor: ew-resize; touch-action: none; }
.text-span .grip::after { content: ""; position: absolute; top: 5px; bottom: 5px; left: 12px; width: 6px; border-radius: 3px; background: #fff; box-shadow: 0 0 0 1px rgb(0 0 0 / 0.4); }
.text-span .grip:focus-visible { outline: none; }
.text-span .grip:focus-visible::after { box-shadow: 0 0 0 3px var(--accent); }
.text-list .text-chip span { max-width: 150px; overflow: hidden; text-overflow: ellipsis; }
.text-tools { display: grid; gap: 10px; padding: 12px; border: 1px solid rgb(255 255 255 / 0.14); border-radius: 14px; background: rgb(255 255 255 / 0.05); }
.editor textarea.text-words { min-height: 0; max-height: calc(6lh + 20px); padding: 9px 12px; border-color: rgb(255 255 255 / 0.24); background: rgb(255 255 255 / 0.08); color: #fff; font-size: 16px; line-height: 1.4; resize: none; }
.editor textarea.text-words::placeholder { color: rgb(255 255 255 / 0.45); }
.editor textarea.text-words:focus { border-color: var(--accent); }
.text-bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px; }
.text-bar b { min-width: 44px; font: 600 12.5px var(--mono); font-variant-numeric: tabular-nums; }
.text-style canvas { width: 26px; height: 26px; }
.text-bin { margin-left: 14px; } /* apart from the look buttons beside it */
.swatches { display: flex; flex-wrap: wrap; justify-content: center; gap: 5px; }
.editor .swatch { position: relative; flex: none; box-sizing: border-box; width: 28px; height: 28px; padding: 0; border: 2px solid #fff; border-radius: 50%; background: var(--c); box-shadow: 0 0 0 1px rgb(0 0 0 / 0.25); }
.editor .swatch:hover:not(:disabled) { border-color: #fff; background: var(--c); }
.editor .swatch[aria-pressed="true"], .editor .swatch.own.on { box-shadow: 0 0 0 2px #111, 0 0 0 4px var(--accent); }
.editor .swatch:focus-visible, .swatch.own:focus-within { outline: 2px solid var(--accent); outline-offset: 3px; }
.swatch.own { display: inline-block; background: conic-gradient(#ea4040, #f2ce46, #77c25d, #00a8cd, #3496ef, #5756d5, #ea4040); cursor: pointer; }
.swatch.own::after { content: ""; position: absolute; inset: 4px; border-radius: 50%; background: var(--c, transparent); pointer-events: none; }
.editor .swatch.own input { position: absolute; inset: 0; width: 100%; height: 100%; min-height: 0; padding: 0; border: 0; border-radius: 50%; opacity: 0; cursor: pointer; }
.editor input.text-size { width: min(260px, 62%); min-height: 0; padding: 0; border: 0; background: transparent; box-shadow: none; accent-color: var(--accent); }

/* ---- check ----------------------------------------------------------------------------------- */
/* The Check page (check.js): the Listings page's paste bar, the four groups to show, and a row for
   each check: the post's picture, what the check says, and why. Green, amber and red tell the groups
   apart, always with an icon and a word as well. */
.vcheck-page .paste-box input { height: 48px; padding-left: 42px; border-radius: 13px; font-size: 15px; background: var(--surface); }
.vcheck-page .paste > button { grid-area: 1 / 2; height: 48px; padding: 0 22px; border-radius: 13px; font-size: 14.5px; }
/* What to show: the groups, then the day and (on the admin's page) the person, at the right. */
.vc-bar { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 16px; min-width: 0; }
.vc-groups { display: flex; flex-wrap: wrap; gap: 6px; }
button.vc-group { height: 34px; padding: 0 13px; border-radius: 999px; gap: 7px; font-size: 13.5px; }
.vc-group i { width: 8px; height: 8px; border-radius: 50%; }
.vc-group.pass i { background: var(--ok); }
.vc-group.unsure i { background: var(--warn); }
.vc-group.fail i { background: var(--bad); }
.vc-group b { font-weight: 600; color: var(--muted); font-variant-numeric: tabular-nums; }
.vc-group b:empty { display: none; }
button.vc-group[aria-pressed="true"], button.vc-group[aria-pressed="true"]:hover:not(:disabled) { background: var(--accent-soft); color: var(--accent-text); border-color: var(--accent-line); }
.vc-group[aria-pressed="true"] b { color: inherit; }
.vc-picks { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 14px; margin-left: auto; min-width: 0; }
.vc-pick { display: flex; align-items: center; gap: 8px; min-width: 0; }
.vc-pick[hidden] { display: none; }
.vc-pick select { min-height: 34px; max-width: 220px; padding-top: 4px; padding-bottom: 4px; font-size: 13px; }

/* The list, a day at a time, newest first. A day's heading stays under the bar while its checks
   go by: its name, how many links, how many in each group, and its links to copy. */
.vc-list { display: grid; gap: 22px; min-width: 0; }
.vc-list:empty { display: none; }
.vc-day { display: grid; gap: 10px; min-width: 0; }
.vc-day-rows { display: grid; gap: 10px; min-width: 0; }
.vc-day-head {
  position: sticky; top: var(--topbar-h); z-index: 5;
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px 14px; min-width: 0; min-height: 44px;
  margin: -6px -8px -4px; padding: 6px 8px;
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  -webkit-backdrop-filter: saturate(1.5) blur(12px); backdrop-filter: saturate(1.5) blur(12px);
}
.vc-day-name { margin: 0; font-size: 15px; font-weight: 700; letter-spacing: -0.01em; }
.vc-day-count { font-size: 13px; color: var(--muted); }
.vc-day-groups { display: inline-flex; align-items: center; gap: 12px; font-size: 12.5px; font-weight: 600; color: var(--fg-2); }
.vc-day-group { display: inline-flex; align-items: center; gap: 5px; }
.vc-day-group i { width: 7px; height: 7px; border-radius: 50%; }
.vc-day-group.pass i { background: var(--ok); }
.vc-day-group.unsure i { background: var(--warn); }
.vc-day-group.fail i { background: var(--bad); }
button.vc-copy { margin-left: auto; }

/* A check: its cover, then what the check says. The edge in the group's colour, so a long list
   reads at a glance; the word and the icon say it too. */
.vc-row {
  display: grid; grid-template-columns: 72px minmax(0, 1fr); align-items: start; column-gap: 16px; min-width: 0;
  padding: 14px 16px 10px 14px; border: 1px solid var(--line); border-radius: 14px; background: var(--surface);
  box-shadow: inset 3px 0 0 var(--edge, transparent), var(--shadow-sm);
}
/* Dark has no small shadow (--shadow-sm is none), and "none" in a list of shadows voids them all. */
@media (prefers-color-scheme: dark) { .vc-row { box-shadow: inset 3px 0 0 var(--edge, transparent); } }
.vc-row.pass { --edge: var(--ok); }
.vc-row.unsure { --edge: var(--warn); }
.vc-row.fail { --edge: var(--bad); }
.vc-row.busy { --edge: var(--accent); }
.vc-thumb { position: relative; display: flex; flex-direction: column; width: 72px; aspect-ratio: 9 / 16; overflow: hidden; border-radius: 10px; background: var(--sunken); color: var(--muted); }
.vc-thumb-pic { position: relative; display: grid; place-items: center; width: 100%; aspect-ratio: 9 / 16; }
.vc-thumb-pic img { position: absolute; inset: 0; display: block; width: 100%; height: 100%; object-fit: cover; }
.vc-thumb-blank { display: grid; place-items: center; }
/* The length on the cover, as TikTok shows it, or the pictures of a slideshow. */
.vc-len {
  position: absolute; left: 5px; bottom: 5px; display: inline-flex; align-items: center; gap: 3px;
  padding: 1px 5px; border-radius: 6px; background: rgb(0 0 0 / 0.62); color: #fff;
  font-size: 11px; font-weight: 650; line-height: 16px;
}
.vc-len:empty { display: none; }
.vc-len svg { stroke-width: 2.2; }
.vc-main { display: grid; gap: 7px; min-width: 0; }
.vc-head { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 10px; min-width: 0; min-height: 26px; }
.vc-verdict { display: inline-flex; align-items: center; gap: 6px; height: 26px; padding: 0 10px 0 8px; border-radius: 999px; background: var(--sunken); color: var(--fg-2); font-size: 13px; font-weight: 650; white-space: nowrap; }
.vc-verdict svg { stroke-width: 2.4; }
.vc-verdict.pass { background: var(--ok-soft); color: var(--ok); }
.vc-verdict.unsure { background: var(--warn-soft); color: var(--warn); }
.vc-verdict.fail { background: var(--bad-soft); color: var(--bad); }
.vc-verdict.busy { background: var(--accent-soft); color: var(--accent-text); }
.vc-step { font-size: 13px; color: var(--muted); }
/* A Send it's rating out of 10: a gold star, filled from 8 up. */
.vc-rating { --star: #d99a00; display: inline-flex; align-items: center; gap: 4px; height: 26px; padding: 0 9px 0 7px; border-radius: 999px; background: var(--sunken); color: var(--fg-2); font-size: 13px; white-space: nowrap; }
.vc-rating svg { color: var(--star); stroke-width: 2; }
.vc-rating.top svg { fill: currentColor; }
.vc-rating b { font-weight: 700; color: var(--fg); }
.vc-rating-of { font-size: 12px; color: var(--muted); }
@media (prefers-color-scheme: dark) { .vc-rating { --star: #f2c14e; } }
.vc-piece { min-width: 0; font-size: 14.5px; font-weight: 650; letter-spacing: -0.005em; overflow-wrap: anywhere; }
.vc-when { display: inline-flex; align-items: center; gap: 8px; margin-left: auto; font-size: 12.5px; color: var(--muted); white-space: nowrap; }
/* Whose it is, on the admin's page: initials in a colour of their own (none of the groups'). */
.vc-who { display: inline-grid; place-items: center; min-width: 26px; height: 20px; padding: 0 6px; border-radius: 6px; background: var(--sunken); color: var(--fg-2); font-size: 11.5px; font-weight: 700; letter-spacing: 0.02em; }
.vc-who.t0 { background: #e8efff; color: #2350c8; }
.vc-who.t1 { background: #f0e9ff; color: #6a35c9; }
.vc-who.t2 { background: #fde7f4; color: #b0256f; }
.vc-who.t3 { background: #e0f4f1; color: #0d7466; }
.vc-who.t4 { background: #e2f3fa; color: #0b6f8c; }
.vc-who.t5 { background: #ecebff; color: #4643b8; }
.vc-who.t6 { background: #f5ece4; color: #87502a; }
.vc-who.t7 { background: #eceff3; color: #47526a; }
@media (prefers-color-scheme: dark) {
  .vc-who.t0 { background: #172447; color: #9ab8ff; }
  .vc-who.t1 { background: #261a45; color: #c4a8ff; }
  .vc-who.t2 { background: #3a1430; color: #f5a3d2; }
  .vc-who.t3 { background: #0e2c29; color: #6fdcc9; }
  .vc-who.t4 { background: #0d2a36; color: #7fd3ee; }
  .vc-who.t5 { background: #1e1f47; color: #aeb0ff; }
  .vc-who.t6 { background: #2e2118; color: #e2b48c; }
  .vc-who.t7 { background: #22262e; color: #b4bdcc; }
}
/* What the rules are about: whose post, its likes and views, likes to views, its age. */
.vc-facts { display: flex; align-items: center; flex-wrap: wrap; gap: 3px 14px; min-width: 0; font-size: 13px; color: var(--fg-2); }
.vc-fact { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.vc-fact svg { color: var(--muted); }
.vc-author { min-width: 0; font-weight: 600; color: var(--fg); overflow-wrap: anywhere; }
.vc-ratio { padding: 1px 7px; border-radius: 999px; background: var(--sunken); color: var(--fg-2); font-size: 12px; font-weight: 650; white-space: nowrap; }
.vc-ratio.bad { background: var(--bad-soft); color: var(--bad); }
.vc-facts.vc-pasted { display: block; font-family: var(--mono); font-size: 12.5px; color: var(--muted); overflow-wrap: anywhere; }
.vc-reasons { display: grid; gap: 5px; margin: 1px 0 0; padding: 0; list-style: none; }
.vc-reason { display: flex; align-items: flex-start; gap: 7px; min-width: 0; font-size: 13.5px; line-height: 1.45; overflow-wrap: anywhere; }
.vc-reason svg { flex: none; margin-top: 2.5px; stroke-width: 2.2; }
.vc-reason.fail svg { color: var(--bad); }
.vc-reason.unsure svg { color: var(--warn); }
.vc-reason.ok svg { color: var(--ok); }
.vc-reason.note { color: var(--muted); }
.vc-reason.note svg { color: var(--faint); }
/* Somebody's own words, as they wrote them: in English on a page in Filipino too. */
.vc-q { padding: 0 3px; border-radius: 4px; background: var(--sunken); color: var(--fg); -webkit-box-decoration-break: clone; box-decoration-break: clone; }
.vc-reason.note .vc-q { color: inherit; }
.vc-at { color: var(--muted); }
.vc-about { display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical; -webkit-line-clamp: 2; font-size: 12.5px; color: var(--muted); overflow-wrap: anywhere; }
.vc-moved { font-size: 12.5px; color: var(--accent-text); }
.vc-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 2px 4px; margin-left: -10px; }
.vc-moves { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 2px; margin-left: 4px; padding-left: 10px; border-left: 1px solid var(--line); }
.vc-moves-label { margin-right: 2px; font-size: 12.5px; color: var(--muted); }
.vc-move.pass svg { color: var(--ok); }
.vc-move.unsure svg { color: var(--warn); }
.vc-move.fail svg { color: var(--bad); }
.vc-end { display: inline-flex; align-items: center; gap: 6px; margin-left: auto; font-size: 12.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
button.vc-more { justify-self: center; }
/* The page holds its own place in the list (check.js holdPlace). The browser's hold, left on, moved
   the page whenever the bar changed height (its live state, the clock), and the check at the top
   of the screen slid under the bar by as much. */
body.vcheck-page { overflow-anchor: none; }
/* Back to the top of the list (check.js markTop): a pill under the bar and the day's heading, there
   once the list is scrolled half a screen in. Hidden, it takes no tap and no Tab stop. Centred by
   its margins, so a press can still nudge it down. */
button.vc-top {
  position: fixed; z-index: 19; top: calc(var(--topbar-h) + 52px); left: 0; right: 0; width: max-content; margin: 0 auto;
  height: 34px; padding: 0 15px 0 11px; gap: 6px; border-color: var(--line); border-radius: 999px;
  background: var(--surface); color: var(--fg); box-shadow: var(--shadow-lg); font-size: 13px; font-weight: 600;
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity 0.18s, transform 0.18s, visibility 0s linear 0.18s, background-color 0.15s, border-color 0.15s;
}
button.vc-top.on { opacity: 1; visibility: visible; transform: none; transition: opacity 0.18s, transform 0.18s, visibility 0s, background-color 0.15s, border-color 0.15s; }
button.vc-top.on:active:not(:disabled) { transform: translateY(1px); }
button.vc-top svg { color: var(--accent); stroke-width: 2.2; }

/* The rules: a list for the team, a form for the admin. */
.vc-rule-list { display: grid; gap: 6px; margin: 0; padding-left: 18px; }
.vc-rule-list li::marker { color: var(--muted); }
.vc-rules-form { display: grid; gap: 14px; }
.vc-nums { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 10px 14px; }
.vc-num, .vc-area { display: grid; gap: 5px; min-width: 0; }
.vc-num input { font-variant-numeric: tabular-nums; }
.vc-area textarea { min-height: calc(2lh + 22px); font-size: 13.5px; }
.vc-area .hint { font-size: 12.5px; }
.vc-check { display: grid; grid-template-columns: auto 1fr; gap: 3px 8px; align-items: center; cursor: pointer; }
.vc-check input { margin: 0; }
.vc-check .hint { grid-column: 2; font-size: 12.5px; }
.vc-rules-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; }

@media (max-width: 640px) {
  .vcheck-page .paste > button { grid-area: auto; }
  /* 16px, or iOS zooms the page into the box on a tap: the phone rule further up comes before this
     page's 15px, so it lost. */
  .vcheck-page .paste-box input { font-size: 16px; }
  /* The cover big on the left, the whole picture in its own shape and nothing else, and every word
     in one column to its right (user, 2026-10-27: "stop making the thumbnails have some weird stuff
     just increase the size of the thumbnail like the green rectangle", drawn over two fifths of the
     card; then "keep all the text to the right of the thumbnail its going under it rn, keep
     everything clean symmetrical and neat"). With no picture, the small box as before. */
  .vc-row { grid-template-columns: min(42%, 200px) minmax(0, 1fr); column-gap: 12px; padding: 12px 12px 8px; }
  .vc-row.nopic { grid-template-columns: 72px minmax(0, 1fr); }
  .vc-thumb { width: 100%; }
  .vc-thumb, .vc-thumb-pic { aspect-ratio: var(--shape, 9 / 16); } /* the picture's own (check.js) */
  .vc-thumb-pic img { object-fit: contain; }
  .vc-picks { margin-left: 0; }
  /* The buttons in tidy rows in the narrow column, no word on a line alone: Open and Copy link, then
     the two moves side by side (their words say where to; "Move to" has no room here), then the
     cost and the bin at the right. A little less padding, and the row starts by as much to the left,
     so each icon lines up with the words above. */
  .vc-actions { margin-left: -8px; }
  .vc-actions button.small, .vc-actions .button.small { padding: 0 8px; }
  .vc-moves { flex-basis: 100%; margin-left: 0; padding-left: 0; border-left: 0; }
  .vc-moves-label { display: none; }
  .vc-day-head { gap: 2px 10px; }
  .vc-facts { column-gap: 11px; }
}
/* On a phone: the four groups two by two, each as wide as the other, and the pickers side by side
   under them; a day's button, its icon alone. */
@media (max-width: 480px) {
  .vc-groups { display: grid; grid-template-columns: 1fr 1fr; width: 100%; }
  .vc-picks { display: grid; grid-template-columns: 1fr 1fr; width: 100%; }
  .vc-pick { display: grid; gap: 4px; }
  .vc-pick .field-label { font-size: 12px; }
  .vc-pick select { width: 100%; max-width: none; }
  .vc-copy span { display: none; }
  button.vc-copy { width: 34px; padding: 0; justify-content: center; }
}

/* The Pixels page: each store behind its switch — its state, the day's figures, its pixels — then TikTok's
   own list of the pixels nothing here sends to — a row in use by an ad group but fed by nothing is the one
   that matters, and is tinted. */
.pixel-head { display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap; }
.pixel-head .grow { flex: 1; min-width: 0; }
.pixel-head > .switch { margin-top: 2px; }
.pixel-head .conv-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-left: auto; }
.pixel-head .status, .empties .status { margin-top: 3px; }
/* The Pixels page: a pixel is a line; its ledger waits behind Details. */
.pixel-list .dim { color: var(--muted); font-size: 12.5px; }
.pixel-list .dim.warn, .who-name .dim { font-weight: 500; }
.who-name .dim { color: var(--muted); font-size: 12.5px; }
.pixel-list .tag { display: inline-block; margin-left: 6px; padding: 1px 6px; border-radius: 6px; background: var(--sunken); color: var(--fg-2); font-size: 11px; font-weight: 500; vertical-align: 1px; white-space: nowrap; }
.pixel-list .state { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; font-weight: 500; white-space: nowrap; color: var(--muted); }
.pixel-list .state::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none; opacity: 0.9; }
.pixel-list .state.ok { color: var(--ok); }
.pixel-list .state.warn { color: var(--warn); }
.pixel-list .state.bad { color: var(--bad); }
.pixel-list.compact td { padding: 9px 12px 9px 0; }
.pixel-list.compact td:last-child { padding-right: 0; }
.pixel-list.compact .row-actions { gap: 10px; justify-content: flex-end; }
.pixel-list tr.open td { border-bottom: 0; }
.pixel-list tr.details td { padding: 0 0 10px; color: var(--muted); font-size: 12.5px; line-height: 1.5; text-wrap: pretty; }
.pixel-list tr.details td > div + div { margin-top: 3px; }
.pixel-list tr.details .status { margin-top: 0; }
.pixel-list.tt-list td:last-child { text-align: right; }
.pixel-list.tt-list .row-actions { justify-content: flex-end; }
.pixel-list select { padding: 3px 6px; border: 1px solid var(--line-strong); border-radius: 6px; background: var(--bg); font-size: 12.5px; max-width: 200px; }
button.link.more { margin-top: 10px; font-size: 13px; }
.empties { border-top: 0; margin-top: 10px; }
.empties .empty-store { display: flex; align-items: center; gap: 10px; padding: 7px 0; border-top: 1px solid var(--line); font-size: 13px; }
.empties .empty-store:first-of-type { margin-top: 8px; border-top: 0; }
.empties .empty-store .grow { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.empties .empty-store b { font-weight: 550; }

/* Phones: the Pixels page's table stacks each pixel as a small card — name and code, product, status,
   the buttons in a row. After the table's own rules, which these must beat. */
@media (max-width: 600px) {
  .pixel-list.compact thead { display: none; }
  .pixel-list.compact, .pixel-list.compact tbody, .pixel-list.compact tr, .pixel-list.compact td { display: block; }
  .pixel-list.compact tr[hidden] { display: none; }
  /* The day's count and last send keep their place on a phone too, named since there is no header row (health check 2026-11-01). */
  .pixel-list.compact td:nth-child(4), .pixel-list.compact td:nth-child(5) { display: inline-block; text-align: left; margin: 5px 14px 0 0; }
  .pixel-list.compact td[data-th]::before { content: attr(data-th) ": "; color: var(--muted); font-size: 12.5px; }
  .pixel-list.compact tr { padding: 10px 0; border-bottom: 1px solid var(--line); }
  .pixel-list.compact tr.open { border-bottom: 0; padding-bottom: 4px; }
  .pixel-list.compact tr.details { padding-top: 0; }
  .pixel-list.compact td, .pixel-list.compact tr.details td { padding: 0; border: 0; }
  .pixel-list.compact td.pixel-for { margin-top: 5px; max-width: none; }
  .pixel-list.compact td.pixel-for .dim:not(.warn) { display: none; } /* the empty dash goes; a product that could not be read stays said */
  .pixel-list.compact .state { margin-top: 6px; }
  .pixel-list.compact .row-actions { flex-direction: row; flex-wrap: wrap; justify-content: flex-start; gap: 6px 14px; margin-top: 8px; }
  .pixel-list.compact tr.details td { padding-bottom: 6px; }
}
