/* Dispatch Studio — the design system, as tokens.
 *
 * Light is written first and is the source of truth; dark redefines the same
 * token NAMES with different values. No component ever names a colour, so
 * adding a theme never touches a layout.
 *
 * The two are not inverses. Amber darkens to #a86a04 on paper to stay legible
 * and lightens to #f7bd52 on ink; green and teal likewise. Inverting
 * mechanically fails contrast in both directions.
 *
 * Three theme states, not two: an explicit choice stamps data-theme, and the
 * default "system" setting stamps nothing — so the media query has to be
 * guarded against an explicit light choice on a dark OS.
 */

:root {
  --bg:        #f2ede1;
  --nav:       #faf7ef;
  --surface:   #fffdf8;
  --sunk:      #efe9db;
  --input:     #fffdf8;
  --line:      #ded5c4;
  --line-soft: #e4dbc9;

  --text:   #1a1712;
  --text-2: #4d453a;
  --muted:  #6b6153;
  --muted-2:#94897a;
  --faint:  #c2b6a0;

  /* Print colours. The spectrum, the burgundy action and the amber rule are
   * constant across themes — they were designed for ink on paper and hold on
   * either ground. Only the small-text variants move. */
  --amber:      #a86a04;
  --amber-full: #ec9b04;
  --amber-soft: #fdf0d5;
  --amber-line: #dfa93b;
  --amber-ink:  #8a5602;

  --teal:      #02596e;
  --teal-soft: #ddeef1;
  --teal-line: #9fd0d8;

  --green:      #1c7d55;
  --green-soft: #e0f0e6;
  --green-line: #7fc4a2;
  --green-ink:  #14663f;

  --burg:      #9d2227;
  --burg-soft: #fae4e4;
  --burg-line: #e0a0a3;
  --burg-ink:  #8d1f24;

  --neutral-soft: #f0eade;
  --neutral-line: #e4dbc9;
  --chip-idle:    #e7dfd0;

  --avatar-bg: #015d72;
  --avatar-fg: #f2f8f9;

  --shadow:     0 1px 2px rgba(60, 45, 20, .05);
  --shadow-lift:0 8px 20px -12px rgba(60, 45, 20, .34);
  --sel-shadow: 0 4px 14px -8px rgba(168, 106, 4, .5);

  --tile: radial-gradient(70% 70% at 50% 42%, #f6f1e6 0%, #eae3d5 100%);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:        #0c0c0b;
    --nav:       #131310;
    --surface:   #171714;
    --sunk:      #101010;
    --input:     #0e0e0c;
    --line:      #2b2b26;
    --line-soft: #23231e;

    --text:   #fbf8f2;
    --text-2: #b8b3a7;
    --muted:  #918d82;
    --muted-2:#6b675e;
    --faint:  #3d3d33;

    --amber:      #f7bd52;
    --amber-soft: #2e2409;
    --amber-line: #5e4a10;
    --amber-ink:  #f7bd52;

    --teal:      #96d1bd;
    --teal-soft: #0c2a2b;
    --teal-line: #135a5c;

    --green:      #49c48d;
    --green-soft: #14301f;
    --green-line: #2ea36b;
    --green-ink:  #86e2b4;

    --burg:      #9d2227;
    --burg-soft: #2c1517;
    --burg-line: #6d2328;
    --burg-ink:  #e2888c;

    --neutral-soft: #1a1a17;
    --neutral-line: #2f2f28;
    --chip-idle:    #1e1e1a;

    --avatar-bg: #1d2740;
    --avatar-fg: #cfd6e9;

    --shadow:      inset 0 1px 0 rgba(251, 248, 242, .035);
    --shadow-lift: 0 14px 30px -16px rgba(0, 0, 0, .95);
    --sel-shadow:  0 0 22px -10px #ec9b04;

    --tile: radial-gradient(70% 70% at 50% 40%, #16160f 0%, #0e0e0c 100%);
  }
}

:root[data-theme="dark"] {
  --bg:#0c0c0b; --nav:#131310; --surface:#171714; --sunk:#101010; --input:#0e0e0c;
  --line:#2b2b26; --line-soft:#23231e;
  --text:#fbf8f2; --text-2:#b8b3a7; --muted:#918d82; --muted-2:#6b675e; --faint:#3d3d33;
  --amber:#f7bd52; --amber-soft:#2e2409; --amber-line:#5e4a10; --amber-ink:#f7bd52;
  --teal:#96d1bd; --teal-soft:#0c2a2b; --teal-line:#135a5c;
  --green:#49c48d; --green-soft:#14301f; --green-line:#2ea36b; --green-ink:#86e2b4;
  --burg:#9d2227; --burg-soft:#2c1517; --burg-line:#6d2328; --burg-ink:#e2888c;
  --neutral-soft:#1a1a17; --neutral-line:#2f2f28; --chip-idle:#1e1e1a;
  --avatar-bg:#1d2740; --avatar-fg:#cfd6e9;
  --shadow:inset 0 1px 0 rgba(251,248,242,.035);
  --shadow-lift:0 14px 30px -16px rgba(0,0,0,.95);
  --sel-shadow:0 0 22px -10px #ec9b04;
  --tile:radial-gradient(70% 70% at 50% 40%, #16160f 0%, #0e0e0c 100%);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  /* body must paint its own ground: a transparent body borrows the host's */
  background: var(--bg);
  color: var(--text);
  font-family: "Archivo", system-ui, -apple-system, sans-serif;
  font-size: 14px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--amber); text-decoration: none; }
a:hover { opacity: .8; }

:focus-visible { outline: 2px solid var(--amber-full); outline-offset: 2px; border-radius: 4px; }

.mono { font-family: "JetBrains Mono", ui-monospace, monospace; font-variant-numeric: tabular-nums; }

/* ── the spectrum. The one sacred brand asset — nine stops, in order. ── */
.spectrum { display: flex; height: 4px; flex: none; }
.spectrum span { flex: 1; }
.s1{background:#015d72}.s2{background:#0a7a82}.s3{background:#099298}
.s4{background:#96d1bd}.s5{background:#e7d9a8}.s6{background:#ec9b04}
.s7{background:#ca6702}.s8{background:#ba3e02}.s9{background:#9d2227}

/* ── shell ── */
.page { min-height: 100vh; display: flex; flex-direction: column; }

.topbar {
  display: flex; align-items: stretch; gap: 24px;
  height: 58px; padding: 0 22px; flex: none;
  border-bottom: 1px solid var(--line); background: var(--nav);
}
.brand { display: flex; align-items: center; gap: 10px; }
.brand .bar { width: 9px; height: 24px; border-radius: 2px;
  background: linear-gradient(var(--amber-full), var(--burg)); }
.brand .name { font-weight: 800; font-size: 12.5px; letter-spacing: .17em;
  text-transform: uppercase; line-height: 1.1; white-space: nowrap; }
.brand .name span { color: var(--muted-2); font-weight: 600; }

.scene-pick {
  display: flex; align-items: center; gap: 9px; align-self: center;
  background: var(--surface); border: 1px solid var(--line); border-radius: 8px;
  padding: 7px 12px; cursor: pointer; box-shadow: var(--shadow);
  font: inherit; color: inherit;
}
.dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.dot.live { background: var(--green); }
.dot.building { background: var(--amber-full); }

.tabs { display: flex; gap: 3px; align-items: flex-end; }
.tabs a {
  border-bottom: 2.5px solid transparent; color: var(--muted-2);
  padding: 10px 13px 12px; font-weight: 600; font-size: 13px;
  margin-bottom: -1px; white-space: nowrap;
}
.tabs a:hover { color: var(--text); opacity: 1; }
.tabs a.on { border-bottom-color: var(--amber); color: var(--text); }

.topbar .right { margin-left: auto; display: flex; align-items: center; gap: 12px; }
.icon-btn {
  display: flex; align-items: center; justify-content: center;
  width: 31px; height: 31px; border-radius: 8px; cursor: pointer;
  background: var(--surface); border: 1px solid var(--line); color: var(--muted);
}
.avatar {
  display: flex; align-items: center; justify-content: center;
  width: 31px; height: 31px; border-radius: 50%;
  background: var(--avatar-bg); color: var(--avatar-fg);
  font-weight: 700; font-size: 11px; flex: none;
}

.wrap { flex: 1 1 auto; min-height: 0; padding: 20px 22px 28px; }

/* ── banner: the app works with a piece missing, and says which ── */
.banner {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 12px 15px; border-radius: 10px; margin-bottom: 16px;
  font-size: 13.5px; line-height: 1.5;
}
.banner.warn { background: var(--amber-soft); border: 1px solid var(--amber-line); color: var(--amber-ink); }
.banner.bad  { background: var(--burg-soft);  border: 1px solid var(--burg-line);  color: var(--burg-ink); }
.banner b { font-weight: 700; }

/* ── controls ── */
.head { display: flex; align-items: baseline; gap: 13px; margin-bottom: 14px; flex-wrap: wrap; }
h1 { font-weight: 800; font-size: 23px; letter-spacing: -.018em; margin: 0; }
.sub { font-size: 11px; color: var(--muted-2); }

.pills { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.pill {
  background: var(--surface); border: 1px solid var(--line); color: var(--muted);
  border-radius: 99px; padding: 7px 15px; font-weight: 600; font-size: 11.5px;
  cursor: pointer; box-shadow: var(--shadow); font-family: inherit;
}
.pill:hover { color: var(--text); }
.pill.on {
  background: var(--amber-soft); border-color: var(--amber-line);
  color: var(--amber-ink); box-shadow: var(--sel-shadow);
}
.pill.win.on { background: var(--teal-soft); border-color: var(--teal-line); color: var(--teal); }

.note { display: flex; align-items: center; gap: 9px; margin-bottom: 16px; min-height: 18px; }
.note .rule { width: 15px; height: 2px; background: var(--amber); border-radius: 99px; flex: none; }
.note span { font-size: 12.5px; color: var(--muted); font-style: italic; }

/* ── feed rows ── */
.rows { display: flex; flex-direction: column; gap: 9px; }
.row {
  display: flex; gap: 16px; align-items: flex-start;
  padding: 15px 17px; border: 1px solid var(--line-soft); border-radius: 11px;
  background: var(--surface); box-shadow: var(--shadow);
  transition: transform .16s ease, border-color .16s ease, box-shadow .16s ease;
}
.row:hover { transform: translateY(-1px); border-color: var(--faint); box-shadow: var(--shadow-lift); }
.row .rank {
  flex: 0 0 32px; text-align: center; padding-top: 2px;
  font-weight: 700; font-size: 14px; color: var(--faint);
}
.row:first-child .rank { color: var(--amber); font-size: 17px; }
.row .body { flex: 1 1 auto; min-width: 0; }
.row .side { flex: 0 0 auto; display: flex; align-items: center; }

.meta { display: flex; align-items: center; gap: 9px; margin-bottom: 7px; flex-wrap: wrap; }
a.title { display: block; color: inherit; text-decoration: none; }
a.title:hover { color: var(--amber-ink); }
.title { font-weight: 600; font-size: 15.5px; letter-spacing: -.006em; margin-bottom: 6px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.headline { display: flex; align-items: center; gap: 9px; margin-bottom: 10px; min-width: 0; }
.headline .rule { width: 2px; height: 16px; background: var(--amber-full); border-radius: 99px; flex: none; }
.headline span { font-size: 13.5px; color: var(--text-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.facts { display: flex; gap: 15px; flex-wrap: wrap; font-size: 10.5px; color: var(--muted-2); }
.facts .why { color: var(--amber); }

.tag { padding: 2px 9px; border-radius: 5px; font-weight: 700; font-size: 9.5px;
  text-transform: uppercase; letter-spacing: .07em; white-space: nowrap; }
.tag.breaking { background: var(--burg-soft);   color: var(--burg-ink);  border: 1px solid var(--burg-line); }
.tag.edge     { background: var(--amber-soft);  color: var(--amber-ink); border: 1px solid var(--amber-line); }
.tag.source   { background: var(--teal-soft);   color: var(--teal);      border: 1px solid var(--teal-line); }
.tag.trending,
.tag.other    { background: var(--neutral-soft);color: var(--muted);     border: 1px solid var(--neutral-line); }

.btn {
  background: var(--surface); color: var(--text); border: 1px solid var(--line);
  border-radius: 8px; padding: 9px 18px; font-weight: 700; font-size: 11px;
  letter-spacing: .08em; text-transform: uppercase; cursor: pointer;
  white-space: nowrap; box-shadow: var(--shadow); font-family: inherit;
  transition: all .14s ease;
}
.btn:hover { background: var(--burg); border-color: var(--burg); color: #fbf8f2; }

.state {
  display: flex; align-items: center; gap: 7px; padding: 8px 14px;
  border-radius: 8px; font-weight: 700; font-size: 10px;
  letter-spacing: .09em; text-transform: uppercase; white-space: nowrap;
}
.state.mine { background: var(--green-soft); border: 1px solid var(--green-line); color: var(--green-ink); }
.state.taken{ background: var(--chip-idle);  border: 1px solid var(--neutral-line); color: var(--muted); }

/* ── empty ── */
.empty {
  border: 1px dashed var(--line); border-radius: 12px; background: var(--sunk);
  padding: 44px 28px; text-align: center; color: var(--muted);
}
.empty h2 { font-size: 17px; color: var(--text); margin: 0 0 8px; }
.empty p { margin: 0 auto; max-width: 48ch; font-size: 14px; line-height: 1.6; }

.footnote { margin-top: 18px; font-size: 10.5px; color: var(--muted-2); }

@media (prefers-reduced-motion: reduce) { * { transition: none !important; animation: none !important; } }

/* The phone's navigation. The top tabs cannot survive a 375px bar next to a
   brand mark and a scene picker, and hiding them without a replacement leaves a
   phone with no way to reach any other page — which is most of how this tool is
   actually used. Fixed to the bottom because that is where a thumb rests. */
.tabbar {
  display: none; position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
  background: var(--nav); border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.tabbar a {
  flex: 1 1 0; min-width: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 3px; height: 56px;
  text-decoration: none; color: var(--muted-2);
  font-weight: 600; font-size: 10px; letter-spacing: .04em;
}
.tabbar a.on { color: var(--amber-ink); }
.tabbar a.on svg { stroke: var(--amber); }
.tabbar svg { stroke: currentColor; }

/* ── phone: parity, not a subset ── */
@media (max-width: 700px) {
  .wrap { padding: 16px 14px 22px; }
  .topbar { gap: 14px; padding: 0 14px; }
  .tabs { display: none; }          /* replaced by .tabbar, defined above */
  .tabbar { display: flex; }
  /* Clear the fixed bar, and the home indicator under it. */
  .page { padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px)); }
  .row { flex-wrap: wrap; }
  .row .side { flex: 1 1 100%; justify-content: flex-end; }
  .btn { min-height: 44px; }        /* thumb target */
}

/* ── Story ─────────────────────────────────────────────────────────────── */

/* Story is the one page that owns the whole viewport: two independently
   scrolling columns, so choosing a picture never scrolls the headline you are
   choosing it for out of sight. */
.wrap.flush { padding: 0; display: flex; min-height: 0;
              /* Flex items default to min-width:auto, so an oversized child
                 (the generator on a phone) would widen the whole document
                 instead of scrolling inside its own box — stretching the tab
                 bar past the screen and leaving the top bar behind. */
              min-width: 0; }

.split { flex: 1 1 auto; display: flex; min-width: 0; min-height: 0; }
.pane-l {
  flex: 0 0 452px; min-width: 0; overflow-y: auto; padding: 20px;
  background: var(--sunk); border-right: 1px solid var(--line);
}
.pane-r { flex: 1 1 auto; min-width: 0; overflow-y: auto; padding: 20px; }

.backlink {
  display: inline-flex; align-items: center; gap: 7px; background: none;
  border: 0; padding: 0; color: var(--muted-2); cursor: pointer;
  font: 700 10.5px/1 "Archivo", system-ui, sans-serif;
  letter-spacing: .09em; text-transform: uppercase;
}
.backlink:hover { color: var(--text); }

.storynav { display: flex; align-items: center; gap: 6px; margin-left: auto; }
.storynav a, .storynav span {
  display: grid; place-items: center; width: 26px; height: 26px;
  border-radius: 7px; border: 1px solid var(--line); background: var(--surface);
  color: var(--muted); text-decoration: none;
}
.storynav a:hover { color: var(--text); border-color: var(--faint); }
.storynav span { opacity: .35; }

.pane-l h2 {
  font-weight: 600; font-size: 18px; line-height: 1.35;
  letter-spacing: -.012em; margin: 0 0 11px;
}
.pane-l h3, .pane-r h3 {
  font-weight: 700; font-size: 15px; letter-spacing: -.01em; margin: 0;
}
.sechead { display: flex; align-items: baseline; gap: 11px; margin-bottom: 12px; }
.sechead .sub { flex: 0 1 auto; }
.hr { height: 1px; background: var(--line); margin: 20px 0; }
a.ext { font-size: 11px; color: var(--amber); text-decoration: none; }
a.ext:hover { text-decoration: underline; }

.hl-box {
  background: var(--surface); border: 1px solid var(--line-soft);
  border-radius: 11px; padding: 7px; margin-bottom: 20px;
  box-shadow: var(--shadow);
}
.hl {
  display: flex; gap: 11px; align-items: flex-start; width: 100%;
  padding: 10px 12px; border: 0; border-radius: 8px; background: none;
  cursor: pointer; text-align: left; color: var(--text-2);
  font: 400 13.5px/1.45 "Archivo", system-ui, sans-serif;
}
.hl:hover { background: var(--neutral-soft); }
.hl .dot {
  width: 6px; height: 6px; border-radius: 50%; flex: none; margin-top: 7px;
  background: var(--line);
}
.hl.on {
  background: var(--amber-soft); color: var(--text);
  box-shadow: inset 2px 0 0 var(--amber-full);
}
.hl.on .dot { background: var(--amber-full); }
.hl-ask { display: flex; gap: 8px; align-items: center;
          margin: 9px 5px 5px; padding-top: 11px;
          border-top: 1px solid var(--line-soft); }
.hl-ask input {
  flex: 1 1 auto; min-width: 0; background: var(--input); color: var(--text);
  border: 1px solid var(--line); border-radius: 7px; padding: 8px 11px;
  font: 400 12.5px "Archivo", system-ui, sans-serif;
}
.hl-ask input:focus { outline: 2px solid var(--amber-line); outline-offset: -1px; }

.build {
  background: var(--burg); color: #fbf8f2; border: 0; padding: 13px 24px;
  border-radius: 8px; cursor: pointer;
  font: 700 13px "Archivo", system-ui, sans-serif;
  letter-spacing: .07em; text-transform: uppercase;
}
.build:hover:not(:disabled) { filter: brightness(1.1); transform: translateY(-1px); }
.build:disabled { opacity: .45; cursor: not-allowed; }

.tiles {
  display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 28px;
}
.tile {
  flex: 1 1 200px; max-width: 260px; padding: 0;
  border: 1px solid var(--line-soft); border-radius: 11px; overflow: hidden;
  background: var(--surface); cursor: pointer; position: relative;
  box-shadow: var(--shadow); text-align: left;
  transition: transform .16s ease, border-color .16s ease, box-shadow .16s ease;
}
.tile:hover:not(.dead) { transform: translateY(-2px); border-color: var(--faint); }
.tile.on { border-color: var(--green-line); box-shadow: var(--shadow-lift); }
.tile.dead { opacity: .34; cursor: default; }
.tile .thumb {
  position: relative; aspect-ratio: 1; display: grid; place-items: center;
  background: var(--tile); border-bottom: 1px solid var(--line-soft);
}
.tile .thumb img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block;
}
.tile .foot {
  padding: 9px 11px; display: flex; justify-content: space-between;
  gap: 6px; align-items: center;
}
.tile .kind {
  font-family: "JetBrains Mono", ui-monospace, monospace; font-size: 9.5px;
  text-transform: uppercase; letter-spacing: .07em; color: var(--amber);
}
.tile.dead .kind { color: var(--burg-ink); }
.tile .kind.src { color: var(--teal); }
.tile .play {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -60%);
  width: 50px; height: 50px; border-radius: 50%; padding-left: 4px;
  background: rgba(26, 23, 18, .66); border: 2px solid rgba(251, 248, 242, .9);
  display: grid; place-items: center;
}
.tile .tick {
  position: absolute; top: 9px; right: 9px; width: 23px; height: 23px;
  border-radius: 50%; background: var(--green); display: none;
  place-items: center; color: var(--bg);
}
.tile.on .tick { display: grid; }
/* An unverified photo is how the wrong person's face reaches a published post,
   so it is marked on the tile rather than buried in a tooltip. */
.tile .warn {
  position: absolute; top: 9px; left: 9px; padding: 2px 7px; border-radius: 5px;
  background: var(--amber-soft); border: 1px solid var(--amber-line);
  color: var(--amber-ink); font: 700 9px "Archivo", system-ui, sans-serif;
  letter-spacing: .06em; text-transform: uppercase;
}

.card-note {
  display: flex; gap: 10px; align-items: flex-start; padding: 13px 15px;
  border: 1px solid var(--line-soft); border-radius: 10px;
  background: var(--surface); font-size: 12px; color: var(--muted);
  line-height: 1.55; box-shadow: var(--shadow); margin-top: 18px;
}

/* Phone: the two columns become one page. Post first, because deciding whether
   this is even worth making comes before choosing a picture for it. */
@media (max-width: 900px) {
  .split { flex-direction: column; overflow-y: auto; }
  .pane-l { flex: 0 0 auto; border-right: 0; border-bottom: 1px solid var(--line); }
  .pane-l, .pane-r { overflow-y: visible; }
  .tile { max-width: none; flex-basis: 140px; }
}

/* Only the desktop split pins the viewport. On a phone the two panes are one
   ordinary scrolling page, so pinning would trap the content. */
@media (min-width: 901px) {
  .page:has(.wrap.flush) { height: 100vh; overflow: hidden; }
}

/* The desktop split pins the viewport; the phone bar is fixed over a normally
   scrolling page, so the pinned height has to go or the panes scroll under it. */
@media (max-width: 700px) {
  .wrap.flush { padding-bottom: 0; }
  .pane-l { padding-bottom: 24px; }
}

/* A note whose text runs to more than one line wants a vertical rule beside it,
   not the horizontal dash that suits a single line. */
.note.upright { align-items: stretch; }
.note.upright .rule { width: 2px; height: auto; align-self: stretch; }

/* ── Studio ────────────────────────────────────────────────────────────── */

/* The generator is an iframe, not a rewrite. It keeps its own dark control
   chrome, which is the convention for editors inside light apps anyway, and it
   keeps working — reskinning a 127 KB file that already does 73 buttons' worth
   of work would risk all of that to gain a colour. */
.studio { flex: 1 1 auto; display: flex; flex-direction: column;
          min-height: 0; min-width: 0; }
.studio-bar {
  flex: none; display: flex; align-items: center; gap: 14px;
  padding: 9px 18px; border-bottom: 1px solid var(--line);
  background: var(--sunk); min-width: 0;
}
.studio-scroll { flex: 1 1 auto; display: flex; min-height: 0; min-width: 0; }
.studio-frame {
  flex: 1 1 auto; width: 100%; border: 0; display: block; min-height: 0;
  background: #0c0c0b;   /* the generator's own ground, so no white flash */
}

@media (max-width: 700px) {
  /* The generator has NO media queries and no width checks — it was drawn for a
     desktop and never told about phones. Squeezed to 375px it half-reflows and
     the Export button falls off the right edge, which is the one control the
     whole page exists for.

     So on a phone it is given the width it was built for and the page pans.
     Panning a wide editor is not good; an unreachable Export is worse. A real
     phone layout is R3 — it means either porting the deck handoff into the
     phone variant (which does not have it) or teaching this file to reflow, and
     neither is a CSS tweak. */
  .studio-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch;
                   max-width: 100%; }
  /* The SAFE layout, in CSS, so it holds with no JavaScript at all: the
     generator gets the width it was drawn for and the page pans. Studio then
     injects a real phone layout into the frame and clears this inline on
     success. If that injection never runs, or throws, or finds markup it does
     not recognise, this is what you are left with — which is usable. */
  .studio-frame { min-width: 1120px; min-height: calc(100vh - 190px); }
  .studio-bar .sub { display: none; }
}

/* ── Library ───────────────────────────────────────────────────────────── */

/* Posts keep their real 4:5 shape. A square crop would show a different
   picture from the one that actually went out, which is the one thing this
   page exists to show. */
.lib { display: flex; flex-wrap: wrap; gap: 16px; }
.libcard {
  flex: 1 1 210px; max-width: 280px; text-decoration: none; color: inherit;
  border: 1px solid var(--line-soft); border-radius: 12px; overflow: hidden;
  background: var(--surface); box-shadow: var(--shadow);
  transition: transform .16s ease, border-color .16s ease, box-shadow .16s ease;
}
.libcard:hover { transform: translateY(-2px); border-color: var(--faint);
                 box-shadow: var(--shadow-lift); }
.shot {
  position: relative; aspect-ratio: 4 / 5; display: grid; place-items: center;
  background: var(--tile); border-bottom: 1px solid var(--line-soft);
}
.shot img { position: absolute; inset: 0; width: 100%; height: 100%;
            object-fit: cover; display: block; }
.pin {
  position: absolute; top: 9px; left: 9px; padding: 2px 8px; border-radius: 5px;
  font: 700 9px "Archivo", system-ui, sans-serif; letter-spacing: .07em;
  text-transform: uppercase;
  background: var(--neutral-soft); border: 1px solid var(--neutral-line);
  color: var(--muted);
}
.pin.ready    { background: var(--amber-soft); border-color: var(--amber-line); color: var(--amber-ink); }
.pin.approved { background: var(--teal-soft);  border-color: var(--teal-line);  color: var(--teal); }
.pin.posted   { background: var(--green-soft); border-color: var(--green-line); color: var(--green-ink); }
.libfoot { padding: 11px 12px 12px; }
.libhead {
  font-weight: 600; font-size: 13.5px; line-height: 1.4; margin-bottom: 7px;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
}

/* One saved post: the picture at a readable size, the fields beside it. */
.detail { display: flex; gap: 24px; align-items: flex-start; flex-wrap: wrap; }
.shotbig { flex: 1 1 360px; max-width: 480px; min-width: 0; }
.shotbig img {
  width: 100%; height: auto; display: block; border-radius: 12px;
  border: 1px solid var(--line-soft); box-shadow: var(--shadow-lift);
}
.side-col { flex: 1 1 340px; min-width: 0; max-width: 560px; }
.detail textarea, .detail input[type="url"], .detail input[type="text"] {
  width: 100%; background: var(--input); color: var(--text);
  border: 1px solid var(--line); border-radius: 8px; padding: 10px 12px;
  font: 400 13px/1.5 "Archivo", system-ui, sans-serif; resize: vertical;
}
.detail textarea:focus, .detail input:focus {
  outline: 2px solid var(--amber-line); outline-offset: -1px;
}

/* ── Feed · Cards (masonry) ────────────────────────────────────────────── */

.head { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.viewtabs { margin-left: auto; display: flex; gap: 2px; padding: 2px;
            background: var(--sunk); border: 1px solid var(--line);
            border-radius: 8px; }
.viewtabs a {
  padding: 5px 13px; border-radius: 6px; text-decoration: none;
  font-weight: 600; font-size: 11.5px; color: var(--muted);
}
.viewtabs a:hover { color: var(--text); }
.viewtabs a.on { background: var(--surface); color: var(--text);
                 box-shadow: var(--shadow); }

/* The columns are built by JS so cards can be PACKED rather than dealt out.
   CSS columns and a round-robin both read as fixed shelves — the eye follows a
   column instead of the ranking. Here each card goes to whichever column is
   shortest at that moment, walking in rank order, so the best bets still land
   near the top and the bottom edge stays roughly level. */
.masonry { display: flex; align-items: flex-start; gap: 14px; }
.mcol { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 14px; }

.card {
  position: relative; display: block; text-decoration: none; color: inherit;
  border: 1px solid var(--line-soft); border-radius: 12px; overflow: hidden;
  background: var(--surface); box-shadow: var(--shadow);
  transition: transform .16s ease, border-color .16s ease, box-shadow .16s ease;
}
.card:hover { transform: translateY(-2px); border-color: var(--faint);
              box-shadow: var(--shadow-lift); }
/* aspect-ratio reserves the right space before the image arrives, so the pack
   is correct on first paint instead of jumping when pictures land. */
.card .pic { position: relative; width: 100%; background: var(--tile);
             border-bottom: 1px solid var(--line-soft); }
.card .pic img { width: 100%; height: 100%; object-fit: cover; display: block; }
.card .vid {
  position: absolute; bottom: 8px; right: 8px; width: 26px; height: 26px;
  border-radius: 50%; display: grid; place-items: center; padding-left: 2px;
  background: rgba(26, 23, 18, .66); border: 1px solid rgba(251, 248, 242, .85);
}
.cbody { padding: 11px 12px 12px; }
.cbody .meta { margin-bottom: 6px; }
.ctitle {
  font-weight: 600; font-size: 13.5px; line-height: 1.4; margin-bottom: 7px;
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical;
  overflow: hidden;
}
/* A text post is deliberately plainer. That is honest rather than a fallback:
   a story with nothing to show really is worth less to you. */
.card.plain { background: var(--neutral-soft); }
.card.plain .ctitle { -webkit-line-clamp: 6; }
.cstate {
  position: absolute; top: 9px; right: 9px; padding: 3px 9px; border-radius: 6px;
  font: 700 9px "Archivo", system-ui, sans-serif; letter-spacing: .06em;
  text-transform: uppercase;
}
.cstate.mine  { background: var(--green-soft); border: 1px solid var(--green-line); color: var(--green-ink); }
.cstate.taken { background: var(--chip-idle);  border: 1px solid var(--neutral-line); color: var(--muted); }

@media (max-width: 700px) {
  .masonry { gap: 10px; }
  .mcol { gap: 10px; }
  .viewtabs { margin-left: 0; }
}

/* ── Today ─────────────────────────────────────────────────────────────── */

/* Sections are separated by space rather than boxes. Each one is already a
   list of bordered rows, so wrapping them in panels too would be two frames
   around the same thing. */
.tsec { margin-bottom: 26px; }
.tsec .sechead { align-items: baseline; gap: 10px; margin-bottom: 10px; }
.tsec .sechead .sub { text-align: right; font-style: italic; }
.tempty {
  margin: 0; padding: 13px 15px; border: 1px dashed var(--line);
  border-radius: 10px; font-size: 12.5px; color: var(--muted-2);
}
.tsec .row .side .btn { white-space: nowrap; }

@media (max-width: 700px) {
  /* The hint reads as a caption under the title rather than squeezed beside it. */
  .tsec .sechead { flex-wrap: wrap; }
  .tsec .sechead .sub { text-align: left; flex-basis: 100%; }
}

/* ── the scan control ──────────────────────────────────────────────────── */

/* Sits on both Today and the Feed, because those are the two places the
   staleness is visible and the complaint should be next to its remedy. */
.scanbar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px 14px; margin-bottom: 16px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface); box-shadow: var(--shadow);
}
.sinfo { display: flex; align-items: center; gap: 9px; min-width: 0; flex: 1 1 auto; }
.sinfo .mono { font-size: 11px; color: var(--muted); min-width: 0;
               overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sdot { width: 8px; height: 8px; border-radius: 50%; flex: none;
        background: var(--faint); }
.sdot.done { background: var(--green); }
.sdot.failed { background: var(--burg); }
.sdot.never { background: var(--faint); }
/* Running is the one state worth animating — it is the only one that is
   genuinely still changing. */
.sdot.running, .sdot.queued { background: var(--amber-full); animation: sblink 1.1s ease-in-out infinite; }
@keyframes sblink { 0%, 100% { opacity: 1 } 50% { opacity: .25 } }

@media (max-width: 700px) { .scanbar .btn { flex: 1 1 100%; } }

/* A picture reddit has already deleted. The box STAYS at its reserved size —
   collapsing it would change the card's height after the wall was packed, and
   re-packing mid-scroll is what used to throw you back up the page. The mark is
   also more honest than a silent gap: this post had an image and it is gone. */
.card .pic.gone::after {
  content: "media gone";
  position: absolute; inset: auto 0 8px 0; text-align: center;
  font-family: "JetBrains Mono", ui-monospace, monospace; font-size: 9px;
  letter-spacing: .07em; text-transform: uppercase; color: var(--muted-2);
}
.card .pic.gone {
  display: grid; place-items: center;
  background: var(--tile); opacity: .6;
}

/* A claim that was refused because somebody else has the story. Amber, not
   red: nothing failed, and the second press is a deliberate takeover. */
.btn.taken-warn {
  background: var(--amber-soft); border-color: var(--amber-line);
  color: var(--amber-ink);
}
.btn.taken-warn:hover { background: var(--amber-line); color: var(--text); }
.btn.done { background: var(--green-soft); border-color: var(--green-line);
            color: var(--green-ink); cursor: default; }

/* A refused approval. Burgundy because it is a stop, not a warning — but it is
   the gate working, so the wording next to it does the explaining. */
#msg.blocked { color: var(--burg-ink); font-weight: 600; }

/* The scene control. A <details> rather than JS: it is a menu, the browser
   already knows how to open and close one, and it keeps working if a script
   fails. `.static` is the one-scene case — same shape, no affordance, because
   nothing is clickable there. */
.scene-pick-wrap { position: relative; display: flex; align-items: center; }
.scene-pick-wrap summary::-webkit-details-marker { display: none; }
.scene-pick-wrap summary { list-style: none; }
.scene-pick.static { cursor: default; }
.scene-menu {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 40;
  min-width: 180px; padding: 5px; border-radius: 10px;
  background: var(--surface); border: 1px solid var(--line);
  box-shadow: var(--shadow-lift);
}
.scene-menu a {
  display: flex; align-items: center; gap: 8px; padding: 8px 10px;
  border-radius: 7px; text-decoration: none; color: var(--text);
  font-size: 13px; font-weight: 500;
}
.scene-menu a:hover { background: var(--neutral-soft); }
.scene-menu a.on { background: var(--amber-soft); color: var(--amber-ink); }

/* ── phone: the things measuring found ─────────────────────────────────── */

@media (max-width: 700px) {
  /* iOS Safari ZOOMS THE PAGE when you focus an input whose font-size is under
     16px, and does not zoom back out. Every field here was 12.5-13px, so
     tapping the caption box threw the whole layout sideways. This is the one
     mobile rule that is not a matter of taste. */
  input, textarea, select { font-size: 16px !important; }

  /* The type scale came off a 1440px mockup: 46 elements on Today were 10.5px
     or smaller and 51 more were 11px. Legible on a monitor at arm's length,
     not on a handset. The hierarchy is kept — everything moves up together
     rather than flattening into one size. */
  .facts, .facts.mono { font-size: 12px; }
  .sub, .sub.mono { font-size: 12px; }
  /* Badges are bold, uppercase and letter-spaced, so they read at a smaller
     size than body text does — but 9.5px was still a squint. */
  .tag { font-size: 11px; padding: 3px 9px; }
  .state, .cstate, .pin { font-size: 11px; }
  .mono { font-size: 12px; }
  .footnote { font-size: 11.5px; }
  .ctitle { font-size: 14px; }
  .libhead { font-size: 14px; }

  /* A 31px control is under every published minimum for a thumb. */
  .icon-btn { width: 40px; height: 40px; }
  .avatar { width: 36px; height: 36px; }
  .pill { padding: 9px 14px; }

  /* Library cards were capped at 280px, so on a 375px screen one sat per row
     with 67px of dead space beside it. Two up, using the width. */
  .libcard { flex-basis: 45%; max-width: none; }
  .lib { gap: 12px; }
}

/* The two small-mono metadata sizes, as classes rather than inline styles
   repeated seventeen times across five templates. Inline styles cannot be
   overridden by a media query, which is exactly why the phone type scale
   could not reach them. */
.mono.sm { font-size: 11px; color: var(--muted); }
.mono.xs { font-size: 10px; color: var(--muted-2); }
@media (max-width: 700px) {
  .mono.sm { font-size: 12.5px; }
  .mono.xs { font-size: 12px; }
}

@media (max-width: 700px) {
  /* A one-line title with an ellipsis works on a wide row and not on a phone:
     "Ken Carson Disses Nine "Pussy bitch y…" tells you nothing about the story
     you are being asked to take. Wrap to a few lines instead — a list you
     cannot read is not a shorter list, it is a broken one. */
  .title { white-space: normal; overflow: visible; text-overflow: clip;
           display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
           overflow: hidden; }
  .headline { align-items: flex-start; }
  .headline .rule { height: auto; align-self: stretch; }
  .headline span { white-space: normal; overflow: visible; text-overflow: clip;
                   display: -webkit-box; -webkit-line-clamp: 3;
                   -webkit-box-orient: vertical; overflow: hidden; }

  /* The action sits under the text rather than squeezed beside it, and is
     wide enough to hit without aiming. */
  .row { flex-wrap: wrap; }
  .row .side { flex: 1 1 100%; }
  .row .side .btn { flex: 1 1 auto; text-align: center; }
}
