/* ==========================================================================
   Transmit — 2026 design layer
   Loaded after app.css, so everything here is a deliberate override.

   Why a separate file: app.css is the original desk stylesheet and stays
   readable on its own. This layer carries the design system from
   docs/DESIGN-SYSTEM.md — the neutral #121212 surface stack, Signal teal as
   the one action colour, a real type scale, the accessibility floor, and the
   three breakpoints. Every contrast ratio in the comments was measured.
   ========================================================================== */

/* ---------------------------------------------------------------- fonts --- */
/* Self-hosted, not a CDN: the app must survive a dead uplink, and a font
   request that hangs would block first paint. Drop the three .woff2 files
   into app/static/fonts/ and this activates itself — until then every rule
   falls through to the platform stack below, so nothing breaks.
   Files (SIL Open Font License, free to redistribute):
     Inter-Variable.woff2          -> body + UI            rsms.me/inter
     Archivo-Variable.woff2        -> headings             fonts.google.com/specimen/Archivo
     JetBrainsMono-Variable.woff2  -> keys, IDs, timecodes jetbrains.com/lp/mono
   Without them the team sees Segoe on Windows, Roboto on Android, SF on iOS —
   three different products. With them, one. */
@font-face {
  font-family: "Transmit Text";
  src: url("../fonts/Inter-Variable.woff2") format("woff2-variations");
  font-weight: 100 900; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Transmit Display";
  src: url("../fonts/Archivo-Variable.woff2") format("woff2-variations");
  font-weight: 100 900; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Transmit Mono";
  src: url("../fonts/JetBrainsMono-Variable.woff2") format("woff2-variations");
  font-weight: 100 800; font-style: normal; font-display: swap;
}

/* --------------------------------------------------------------- tokens --- */
:root {
  color-scheme: dark;

  /* Surfaces. Neutral base, cool-tinted lift — pure grey stacks read muddy
     once three layers are on screen. Luminance: 0.6% / 1.1% / 1.7% / 2.6%. */
  --bg-canvas:     #121212;
  --bg-surface-1:  #1A1B1E;
  --bg-surface-2:  #212328;
  --bg-surface-3:  #2A2D32;
  --bg-inset:      #0E0F11;
  --scrim:         rgba(8, 9, 10, .64);

  /* Edges. Surface-to-surface contrast is only 1.09:1, so a hairline is what
     actually separates a card — not the fill, and not a shadow. */
  --edge-hairline: rgba(255, 255, 255, .07);
  --edge-strong:   rgba(255, 255, 255, .12);
  --edge-control:  #72787E;   /* 3.86:1 on surface-1 — WCAG 1.4.11 needs 3:1 */

  /* Text on surface-1: 14.29 / 7.34 / 5.47 : 1 */
  --text-primary:   #E8EAED;
  --text-secondary: #A2AAB4;
  --text-muted:     #8A929C;
  --text-disabled:  #6B7280;
  --text-on-accent: #0B1210;  /* 9.18:1 inside a Signal button */

  /* Signal teal, hue ~172° — the furthest usable point from Facebook blue
     (217°) and YouTube red (0°), so a button never reads as part of a logo. */
  --signal:       #35C9B5;
  --signal-hover: #4BD8C4;
  --signal-press: #23B4A1;
  --signal-text:  #7FE9DA;
  --signal-tint:  rgba(53, 201, 181, .14);
  --signal-edge:  rgba(53, 201, 181, .40);

  --brass:      #E2A33C;  --brass-text: #F5C877;
  --brass-tint: rgba(226, 163, 60, .14);
  --rose:       #FF6B6B;  --rose-text:  #FF9B9B;
  --rose-tint:  rgba(255, 107, 107, .14);
  --slate:      #8A929C;  --slate-text: #C3CAD2;
  --slate-tint: rgba(138, 146, 156, .14);

  /* Old names, remapped so the 1150 lines above inherit the new palette
     without being touched. --idle was a blue that clashed with the Facebook
     mark; --queue was doing double duty as "primary action" and "scheduled",
     which made a button look like a status. Both fixed here. */
  --ink:       var(--bg-canvas);
  --ink-deep:  var(--bg-inset);
  --panel:     var(--bg-surface-1);
  --panel-2:   var(--bg-surface-2);
  --raised:    var(--bg-surface-3);
  --line:      rgba(255, 255, 255, .08);
  --line-soft: rgba(255, 255, 255, .05);
  --text:      var(--text-primary);
  --text-dim:  var(--text-secondary);
  --text-mute: var(--text-muted);
  --live:      var(--signal);
  --queue:     var(--brass);
  --fail:      var(--rose);
  --idle:      var(--signal);
  --draft:     var(--slate);

  --space-1: 4px;  --space-2: 8px;  --space-3: 12px; --space-4: 16px;
  --space-5: 24px; --space-6: 32px; --space-7: 48px; --space-8: 64px;

  --radius-sm:   6px;
  --radius:      12px;
  --radius-lg:   16px;
  --radius-pill: 999px;

  --shadow: none;                                        /* cards: edge only */
  --shadow-menu:   0 12px 24px -8px rgba(0, 0, 0, .66);
  --shadow-dialog: 0 24px 48px -12px rgba(0, 0, 0, .72);
  --shadow-toast:  0 16px 32px -12px rgba(0, 0, 0, .70);

  --sans: "Transmit Text", "Segoe UI Variable Text", "Segoe UI", Inter, Roboto,
          system-ui, -apple-system, "Helvetica Neue", Arial,
          "Noto Sans Bengali", sans-serif;
  --display: "Transmit Display", "Segoe UI Variable Display", "Segoe UI Semibold",
             "Transmit Text", "Segoe UI", system-ui, -apple-system, Arial, sans-serif;
  /* How many characters a reader crosses in one line. The only width limit
     this design keeps, and it is in `ch` on purpose: it holds at any zoom,
     any font size and any screen, which a pixel cap on a container never
     does. Nothing else in the layout has a maximum width. */
  --measure: 66ch;
  --mono: "Transmit Mono", ui-monospace, "Cascadia Mono", "JetBrains Mono",
          "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace;

  /* Continuous, not stepped: narrow enough to leave the content room on a
     small laptop, wide enough to breathe on a large display, and in rem so
     it grows with the font rather than against it. */
  --rail: clamp(12.5rem, 13.5vw, 17rem);
  --measure: 68ch;    /* a line of prose never runs wider than this */
  --ease-out: cubic-bezier(.2, 0, 0, 1);
}

/* Light mirror. Offered because forced dark is an accessibility problem for
   astigmatism, and daytime editing on a bright screen is real. The teal has
   to darken for white, not merely invert: #12776C is 5.41:1 on white. */
[data-theme="light"] {
  color-scheme: light;
  --bg-canvas: #F6F7F8; --bg-surface-1: #FFFFFF; --bg-surface-2: #F0F2F4;
  --bg-surface-3: #FFFFFF; --bg-inset: #F0F2F4;
  --scrim: rgba(16, 20, 24, .40);
  --edge-hairline: rgba(16, 20, 24, .09);
  --edge-strong: rgba(16, 20, 24, .16);
  --edge-control: #767D84;
  --text-primary: #1B1F23; --text-secondary: #4A5259; --text-muted: #5E666D;
  --text-on-accent: #FFFFFF;
  --signal: #12776C; --signal-hover: #0F6459; --signal-press: #0B554C;
  --signal-text: #0C5C53; --signal-tint: rgba(18, 119, 108, .10);
  --signal-edge: rgba(18, 119, 108, .35);
  --brass-text: #7A5310; --rose-text: #A32020; --slate-text: #414A52;
  --line: rgba(16, 20, 24, .10); --line-soft: rgba(16, 20, 24, .06);
  --shadow-menu: 0 12px 24px -10px rgba(16, 20, 24, .18);
  --shadow-dialog: 0 24px 48px -16px rgba(16, 20, 24, .22);
}

/* ----------------------------------------------------------------- type --- */
body {
  background: var(--bg-canvas);
  font: 400 16px/1.6 var(--sans);
  color: var(--text-primary);
  background-image: none;
}

h1, h2, h3, h4 { font-family: var(--display); letter-spacing: -.015em; }
h1 { font-size: 28px; line-height: 1.2;  font-weight: 600; }
h2 { font-size: 23px; line-height: 1.3;  font-weight: 600; }
h3 { font-size: 19px; line-height: 1.35; font-weight: 600; }
h4 { font-size: 16px; line-height: 1.4;  font-weight: 600; }
p  { max-width: var(--measure); }

.mono, .value.mono, code, kbd, pre { font-family: var(--mono); }
.mono, code, kbd { font-variant-numeric: tabular-nums; }
.eyebrow, .rail-group {
  font: 600 12px/1.35 var(--sans); letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-muted);
}
.lede, .page-head .lede { font-size: 17px; color: var(--text-secondary); max-width: var(--measure); }
.hint { font-size: 14px; color: var(--text-secondary); max-width: var(--measure); }
a { color: var(--signal); }
a:hover { color: var(--signal-hover); }

/* -------------------------------------------------- accessibility floor --- */
/* One ring, everywhere, never removed. 8.34:1 against a card surface. */
:focus-visible,
.btn:focus-visible,
.sectab:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible,
a:focus-visible, button:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--signal);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
  transition: outline-color 160ms var(--ease-out);
}
.seg input:focus-visible + em { outline: 2px solid var(--signal); outline-offset: 4px; }

.skip-link {
  position: fixed; top: 8px; left: 8px; z-index: 200;
  transform: translateY(-160%);
  background: var(--signal); color: var(--text-on-accent);
  font-weight: 600; padding: 10px 16px; border-radius: var(--radius-sm);
}
.skip-link:focus { transform: translateY(0); text-decoration: none; }

@media (prefers-contrast: more) {
  :root {
    --edge-hairline: rgba(255, 255, 255, .28);
    --edge-strong: rgba(255, 255, 255, .40);
    --edge-control: #A0A7AE;
    --text-muted: #A2AAB4;
    --signal-tint: transparent; --brass-tint: transparent;
    --rose-tint: transparent;   --slate-tint: transparent;
  }
  .badge, .pill, .tally-pill { border-width: 1px; border-style: solid; }
}

/* --------------------------------------------------------------- shell ---- */
.rail { background: var(--bg-surface-1); border-right: 1px solid var(--edge-hairline); }
.rail-brand { border-bottom: 1px solid var(--edge-hairline); padding: 20px 16px 16px; }
.rail-brand .mark {
  width: 30px; height: 30px; border-radius: 8px;
  background: var(--signal); color: var(--text-on-accent);
  font: 700 15px/1 var(--display);
}
.rail-brand b { font: 600 17px/1.2 var(--display); }
.rail-brand span { font: 600 11px/1.3 var(--sans); letter-spacing: .08em; }

.rail-nav { padding: 8px; gap: 2px; }
.rail-link {
  min-height: 44px; padding: 10px 12px; gap: 10px;
  border-radius: var(--radius-sm); font-size: 15px;
  border-left: 3px solid transparent;
  transition: background-color 200ms var(--ease-out), color 200ms var(--ease-out);
}
.rail-link:hover { background: var(--bg-surface-2); }
.rail-link.on {
  background: var(--signal-tint); color: var(--text-primary);
  border-left-color: var(--signal); font-weight: 600;
}
.rail-link .ico { width: 20px; height: 20px; opacity: 1; display: grid; place-items: center; }
.rail-link .ico svg { width: 20px; height: 20px; stroke: currentColor; fill: none;
  stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
.rail-link .tag { font-family: var(--mono); background: var(--bg-surface-3); }
.rail-link .tag.hot  { background: var(--rose-tint);  color: var(--rose-text); }
.rail-link .tag.warm { background: var(--brass-tint); color: var(--brass-text); }
.rail-foot { border-top: 1px solid var(--edge-hairline); padding: 12px; }

.topbar {
  background: color-mix(in srgb, var(--bg-canvas) 92%, transparent);
  border-bottom: 1px solid var(--edge-hairline);
  padding: 12px 24px; min-height: 56px;
}

/* Off on desktop, on below 768px — declared here so the button never flashes
   into view during load on a wide screen. */
.nav-toggle {
  display: none; place-items: center; flex: none;
  width: 44px; height: 44px; margin-left: -10px;
  background: transparent; border: 1px solid transparent; border-radius: var(--radius-sm);
  color: var(--text-secondary); cursor: pointer;
  transition: background-color 200ms var(--ease-out), color 200ms var(--ease-out);
}
.nav-toggle:hover { background: var(--bg-surface-2); color: var(--text-primary); }
.nav-scrim { display: none; }

.crumb { font: 600 14px/1.2 var(--sans); letter-spacing: 0; color: var(--text-secondary); }
.crumb b { font-family: var(--display); font-size: 15px; }
.clock b { font-family: var(--mono); }
.clock span { font: 600 11px/1 var(--sans); letter-spacing: .07em; }
.worker-lamp { font: 600 11px/1 var(--sans); letter-spacing: .07em;
  border-color: var(--edge-hairline); border-radius: var(--radius-pill); min-height: 32px; }
.lamp.ok  { background: var(--signal); box-shadow: 0 0 0 3px var(--signal-tint); }
.lamp.off { background: var(--rose);   box-shadow: 0 0 0 3px var(--rose-tint); }

/* No maximum width. This 1200px cap was the one actually deciding how much of
   a wide screen the app used — theme.css loads after app.css, so it won `.content`
   outright, and raising the number in the other file changed nothing. The limit
   that belongs here is the reading measure, in `ch`, on the text itself. */
.content { width: 100%;
  padding: clamp(0.875rem, 1.4vw, 2rem) clamp(0.875rem, 1.4vw, 2rem)
           clamp(1.5rem, 4vw, 4rem); }
.page-head { margin-bottom: 24px; }

/* -------------------------------------------------------------- panels ---- */
.panel {
  background: var(--bg-surface-1);
  border: 1px solid var(--edge-hairline);
  border-radius: var(--radius);
  box-shadow: none;
}
.panel + .panel { margin-top: 24px; }
.panel-head { background: transparent; border-bottom: 1px solid var(--edge-hairline);
  padding: 18px 24px; }
.panel-head h2, .panel-head h3 { font-family: var(--display); }
.panel-body { padding: 24px; }
.panel-foot { background: var(--bg-surface-2); border-top: 1px solid var(--edge-hairline);
  padding: 14px 24px; }
.grid { gap: 24px; }

/* ------------------------------------------------------------- buttons ---- */
.btn {
  font: 500 15px/1 var(--sans);
  min-height: 40px; padding: 0 16px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--edge-control);
  background: var(--bg-surface-2);
  transition: background-color 200ms var(--ease-out), border-color 200ms var(--ease-out),
              color 200ms var(--ease-out);
}
.btn:hover { background: var(--bg-surface-3); }
.btn:active { transform: none; background: var(--bg-surface-3); }
.btn[disabled] { opacity: .45; }

.btn--primary {
  background: var(--signal); border-color: var(--signal);
  color: var(--text-on-accent); font-weight: 600;
}
.btn--primary:hover { background: var(--signal-hover); border-color: var(--signal-hover); }
.btn--primary:active { background: var(--signal-press); border-color: var(--signal-press); }

.btn--go { background: var(--signal-tint); border-color: var(--signal-edge); color: var(--signal-text); }
.btn--go:hover { background: rgba(53, 201, 181, .22); }
.btn--danger { background: transparent; border-color: rgba(255, 107, 107, .45); color: var(--rose-text); }
.btn--danger:hover { background: var(--rose-tint); }
.btn--ghost { background: transparent; border-color: transparent; color: var(--text-secondary); }
.btn--ghost:hover { background: var(--bg-surface-2); color: var(--text-primary);
  border-color: var(--edge-hairline); }
.btn--tiny { min-height: 32px; padding: 0 12px; font-size: 13px; }
.btn-row { gap: 12px; }
.btn svg { width: 18px; height: 18px; stroke: currentColor; fill: none; stroke-width: 1.75;
  stroke-linecap: round; stroke-linejoin: round; }

/* --------------------------------------------------------------- forms ---- */
.label {
  font: 600 13px/1.4 var(--sans); letter-spacing: .02em; text-transform: none;
  color: var(--text-secondary); margin-bottom: 8px;
}
.field { margin-bottom: 20px; }

.input, .textarea, select.input {
  font: 400 16px/1.5 var(--sans);          /* 16px stops iOS zooming on focus */
  background: var(--bg-surface-2);
  border: 1px solid var(--edge-control);   /* 3.52:1 — a filled box alone fails */
  border-radius: var(--radius-sm);
  min-height: 40px; padding: 8px 12px;
  color: var(--text-primary);
  transition: border-color 200ms var(--ease-out), box-shadow 160ms var(--ease-out);
}
.input:focus, .textarea:focus, select.input:focus {
  outline: none;
  border-color: var(--signal);
  box-shadow: 0 0 0 3px var(--signal-tint);
}
.input::placeholder, .textarea::placeholder { color: var(--text-muted); }
.input.mono, .textarea.mono { font-family: var(--mono); font-size: 15px; }
.input[aria-invalid="true"] { border-color: var(--rose); }
.input[aria-invalid="true"]:focus { box-shadow: 0 0 0 3px var(--rose-tint); }
.check input { accent-color: var(--signal); width: 18px; height: 18px; }
.check { min-height: 44px; align-items: center; font-size: 15px; }

.seg { background: var(--bg-surface-2); border-color: var(--edge-control);
  border-radius: var(--radius-sm); padding: 4px; }
.seg label { min-height: 36px; display: inline-flex; align-items: center; font-size: 14px; }
.seg label:has(input:checked) { background: var(--signal); color: var(--text-on-accent); }
.seg input:checked + em { color: var(--text-on-accent); }

.dest { background: var(--bg-surface-2); border-color: var(--edge-hairline);
  border-radius: var(--radius-sm); min-height: 56px; }
.dest:hover { border-color: var(--edge-control); }
.dest:has(input:checked) { border-color: var(--signal-edge); background: var(--signal-tint); }
.dest input { accent-color: var(--signal); }
.drop { border-color: var(--edge-control); background: var(--bg-surface-2);
  border-radius: var(--radius); }

/* -------------------------------------------------------------- badges ---- */
.badge {
  font: 600 12px/1 var(--sans); letter-spacing: .04em; text-transform: none;
  padding: 5px 10px; border-radius: var(--radius-sm);
  background: var(--slate-tint); color: var(--slate-text);
  border: 1px solid transparent;
}
.badge--published  { background: var(--signal-tint); color: var(--signal-text);
  border-color: var(--signal-edge); }
.badge--scheduled  { background: var(--brass-tint); color: var(--brass-text);
  border-color: rgba(226, 163, 60, .4); }
.badge--publishing { background: var(--brass-tint); color: var(--brass-text);
  border-color: rgba(226, 163, 60, .4); }
.badge--failed     { background: var(--rose-tint); color: var(--rose-text);
  border-color: rgba(255, 107, 107, .4); }
.badge--partial    { background: var(--brass-tint); color: var(--brass-text); }
.badge--draft, .badge--canceled, .badge--skipped {
  background: var(--slate-tint); color: var(--slate-text);
  border-color: rgba(138, 146, 156, .35);
}
.badge--plain { border-color: var(--edge-hairline); color: var(--text-secondary); }
.avatar { background: var(--signal); color: var(--text-on-accent); }
.health--ok .lamp { background: var(--signal); }
.health--warning .lamp { background: var(--brass); }
.health--error .lamp { background: var(--rose); }
.health--unknown .lamp { background: var(--slate); }

/* -------------------------------------------------------------- tables ---- */
.table thead th, table thead th {
  background: var(--bg-surface-2);
  font: 600 12px/1.35 var(--sans); letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-muted);
  border-bottom: 1px solid var(--edge-hairline);
}
.table tbody td, table tbody td {
  border-bottom: 1px solid var(--edge-hairline);
  font-size: 15px;
}
.table tbody tr:hover, table tbody tr:hover { background: var(--bg-surface-2); }
.table td.num, .table th.num { text-align: right; font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------------- flash ---- */
.flash {
  border-radius: var(--radius); border: 1px solid var(--edge-hairline);
  background: var(--bg-surface-3); box-shadow: var(--shadow-toast);
  border-left: 4px solid var(--signal);
  padding: 16px; margin-bottom: 24px; font-size: 15px;
  animation: flash-in 240ms var(--ease-out);
}
.flash--warn { border-left-color: var(--brass); }
.flash--err  { border-left-color: var(--rose); }
@keyframes flash-in { from { opacity: 0; transform: translateY(12px); } }

/* =========================================================== connections ==
   Keys & Settings, rebuilt around one question: is this reachable right now?
   A saved key proves nothing, so the terminal state is "verified 4 min ago",
   never "Saved". Same tally vocabulary as the queue, so one visual language
   covers both content and credentials.
   ========================================================================= */

.settings-split { display: grid; grid-template-columns: var(--rail) minmax(0, 1fr);
  gap: 32px; align-items: start; }
/* min-width:0 is load-bearing: without it a long unbroken value in a .readout
   pushes the grid column wider than the viewport and the whole page scrolls
   sideways — which is exactly what a Drive folder ID or a client secret is. */
.settings-panes { min-width: 0; }
.settings-rail { position: sticky; top: 80px; display: grid; gap: 2px; }
.settings-rail a {
  display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 10px 12px;
  border-radius: var(--radius-sm); color: var(--text-secondary); font-size: 15px;
  border-left: 3px solid transparent;
  transition: background-color 200ms var(--ease-out);
}
.settings-rail a:hover { background: var(--bg-surface-2); text-decoration: none; }
.settings-rail a[aria-current="true"] {
  background: var(--signal-tint); color: var(--text-primary);
  border-left-color: var(--signal); font-weight: 600;
}
.settings-rail .keystrip {
  margin-top: 24px; padding: 16px; border-radius: var(--radius);
  background: var(--bg-surface-1); border: 1px solid var(--edge-hairline);
}
.settings-rail .keystrip b { display: block; font: 600 12px/1.4 var(--sans);
  letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted); }
.settings-rail a .ico { display: grid; place-items: center; width: 20px; height: 20px; flex: none; }
.settings-rail a .flag { margin-left: auto; width: 8px; height: 8px; border-radius: 50%; flex: none; }
.settings-rail a .flag.is-fault { background: var(--rose); }
.settings-rail a .flag.is-wait  { background: var(--brass); }

.settings-pane > .pane-head { margin-bottom: 20px; }
.settings-pane > .pane-head h2 { margin: 0; }
.settings-pane > .pane-head .lede { margin: 6px 0 0; }
.pane-back { display: none; margin-bottom: 12px; }

.conn { padding: 24px; }
.conn + .conn { margin-top: 24px; }
.conn--fault { border-left: 3px solid var(--rose); }
.conn--attention { border-left: 3px solid var(--brass); }
.conn-top { display: flex; align-items: flex-start; gap: 16px; flex-wrap: wrap; }
.conn-mark { width: 28px; height: 28px; flex: none; }
.conn-mark svg, .conn-mark img { width: 28px; height: 28px; }
.conn-id { min-width: 0; flex: 1 1 220px; }
.conn-id h3 { font-size: 19px; }
.conn-id p { margin: 4px 0 0; font-size: 15px; color: var(--text-secondary); }

/* the tally: lamp + word, never colour alone */
.tally-pill {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  font: 600 13px/1 var(--sans); letter-spacing: .02em;
  padding: 5px 10px; border-radius: var(--radius-sm);
  border: 1px solid transparent; white-space: nowrap;
}
.tally-pill i { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.tally-pill.is-idle { background: var(--slate-tint); color: var(--slate-text);
  border-color: rgba(138, 146, 156, .35); }
.tally-pill.is-idle i { background: transparent; box-shadow: inset 0 0 0 2px var(--slate); }
.tally-pill.is-wait { background: var(--brass-tint); color: var(--brass-text);
  border-color: rgba(226, 163, 60, .4); }
.tally-pill.is-wait i { background: linear-gradient(90deg, var(--brass) 50%, transparent 50%);
  box-shadow: inset 0 0 0 2px var(--brass); }
.tally-pill.is-live { background: var(--signal-tint); color: var(--signal-text);
  border-color: var(--signal-edge); }
.tally-pill.is-live i { background: var(--signal); }
.tally-pill.is-fault { background: var(--rose-tint); color: var(--rose-text);
  border-color: rgba(255, 107, 107, .4); }
.tally-pill.is-fault i { background: var(--rose); }
.tally-pill.is-checking { background: var(--bg-surface-3); color: var(--text-secondary);
  border-color: var(--edge-hairline); }
.tally-pill.is-checking i { background: var(--text-secondary); animation: tally-pulse 1400ms infinite ease-in-out; }
@keyframes tally-pulse { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }

/* the well: configured values, deliberately quiet — reference material */
.conn-well {
  margin-top: 16px; padding: 16px; border-radius: var(--radius-sm);
  background: var(--bg-surface-2);
}
.conn-well dl { display: grid;
  grid-template-columns: minmax(min(45%, 7.5rem), auto) minmax(0, 1fr);
  gap: 10px 20px; margin: 0; align-items: center; }
.conn-well dt { font: 600 13px/1.4 var(--sans); color: var(--text-secondary); }
.conn-well dd { margin: 0; font: 400 15px/1.4 var(--mono); color: var(--text-primary);
  overflow-x: auto; white-space: nowrap; scrollbar-width: thin; }
.conn-well dd.with-copy { display: flex; align-items: center; gap: 10px; }

.conn-fault {
  margin-top: 16px; padding: 16px; border-radius: var(--radius-sm);
  background: var(--rose-tint); border-left: 3px solid var(--rose);
}
.conn-fault b { display: block; font: 600 15px/1.4 var(--sans); color: var(--rose-text);
  font-family: var(--sans); }
.conn-fault code { font-family: var(--mono); font-size: 14px; }
.conn-fault p { margin: 6px 0 0; font-size: 15px; color: var(--text-primary); }
.conn-attention {
  margin-top: 16px; padding: 16px; border-radius: var(--radius-sm);
  background: var(--brass-tint); border-left: 3px solid var(--brass);
}
.conn-attention b { color: var(--brass-text); display: block; font-weight: 600; }
.conn-attention p { margin: 6px 0 0; font-size: 15px; }
/* A provider's own error text can appear here too, not only in .conn-fault —
   an amber warning is the right home for a failure that is not a breakage. */
.conn-attention code { font-family: var(--mono); font-size: 14px;
  display: block; margin-top: 6px; overflow-wrap: anywhere; }

.conn-foot { margin-top: 20px; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.conn-when { font: 600 12px/1 var(--sans); letter-spacing: .05em; color: var(--text-muted);
  margin-right: auto; }

/* the checklist: numbered because these steps genuinely must happen in order */
.conn-steps { margin: 16px 0 0; padding: 0; list-style: none; counter-reset: step; }
.conn-steps li {
  counter-increment: step; position: relative; padding: 10px 0 10px 40px;
  font-size: 15px; border-top: 1px solid var(--edge-hairline);
}
.conn-steps li:first-child { border-top: 0; }
.conn-steps li::before {
  content: counter(step); position: absolute; left: 0; top: 10px;
  width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-items: center;
  font: 600 12px/1 var(--mono); color: var(--text-secondary);
  background: var(--bg-surface-2); border: 1px solid var(--edge-hairline);
}
.conn-steps li.done::before { content: "✓"; background: var(--signal-tint);
  color: var(--signal-text); border-color: var(--signal-edge); }
.conn-steps code { font-family: var(--mono); font-size: 14px; }

/* paste validation, before anything is sent to a provider */
.verdict { margin-top: 8px; font-size: 14px; display: flex; gap: 8px; align-items: flex-start; }
.verdict.ok   { color: var(--signal-text); }
.verdict.bad  { color: var(--rose-text); }
.verdict.info { color: var(--text-secondary); }

/* danger zone: outlines, not filled red blocks — a red slab reads "press me" */
.danger-zone { margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--edge-strong); }
.danger-zone h2 { color: var(--rose-text); }
.danger-zone .lede { color: var(--text-secondary); }

/* ==================================================== responsive layers ==
   Three thresholds, matching the spec. Mobile first in intent even though
   these read as overrides of the desktop rules above.
   ======================================================================= */

/* ------------------------------------------------- mobile: below 768px --- */
@media (max-width: 767px) {
  .shell { grid-template-columns: minmax(0, 1fr); }

  /* the rail becomes a drawer: off-canvas, over a scrim, 84% / max 320px */
  .rail {
    position: fixed; inset: 0 auto 0 0; z-index: 60;
    width: 84%; max-width: 320px; height: 100%;
    flex-direction: column; align-items: stretch;
    border-right: 1px solid var(--edge-hairline); border-bottom: 0;
    background: var(--bg-surface-1);
    transform: translateX(-100%);
    transition: transform 240ms var(--ease-out);
    overflow-y: auto; overscroll-behavior: contain;
    padding-bottom: env(safe-area-inset-bottom);
  }
  body.nav-open .rail { transform: translateX(0); }
  .rail-nav { display: grid; }
  .rail-group { display: block; }
  .rail-link .ico { display: grid; }
  .rail-brand span { display: block; }
  .rail-foot { margin-top: auto; }
  .rail-user .who { display: block; }

  .nav-scrim {
    display: block;
    position: fixed; inset: 0; z-index: 55; background: var(--scrim);
    opacity: 0; pointer-events: none; transition: opacity 240ms var(--ease-out);
  }
  body.nav-open .nav-scrim { opacity: 1; pointer-events: auto; }
  body.nav-open { overflow: hidden; }

  .nav-toggle { display: inline-grid; }
  .topbar { padding: 8px 16px; gap: 12px; min-height: 56px; }
  .crumb { display: block; font-size: 15px; min-width: 0; overflow: hidden;
    text-overflow: ellipsis; white-space: nowrap; }
  .clocks { gap: 0; }
  .clocks .clock, .worker-lamp span { display: none; }
  .clocks .clock.audience { display: block; border-left: 0; padding-left: 0; }

  .content { padding-bottom: calc(clamp(1.5rem, 4vw, 4rem)
                                 + env(safe-area-inset-bottom)); }
  h1 { font-size: 23px; }
  .panel-head, .panel-body { padding: 16px; }
  .panel-foot { padding: 12px 16px; }
  .grid { gap: 16px; }
  .panel + .panel { margin-top: 16px; }

  /* every control is thumb-sized */
  .btn { min-height: 44px; width: 100%; }
  .btn--tiny, .btn-row .btn { width: auto; }
  .input, .textarea, select.input { min-height: 48px; font-size: 16px; }
  .field-row > * { flex: 1 1 100%; }

  /* tables become record cards; labels come from each table's own headers,
     stamped onto the cells by app.js so no template needs editing */
  table.responsive, .table { border: 0; }
  table.responsive thead, .table thead { position: absolute; width: 1px; height: 1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  table.responsive tbody tr, .table tbody tr {
    display: block; margin-bottom: 12px; padding: 16px;
    background: var(--bg-surface-1); border: 1px solid var(--edge-hairline);
    border-radius: var(--radius);
  }
  table.responsive tbody td, .table tbody td {
    display: flex; justify-content: space-between; gap: 16px;
    padding: 6px 0; border: 0; text-align: right;
  }
  table.responsive tbody td::before, .table tbody td::before {
    content: attr(data-label);
    font: 600 13px/1.4 var(--sans); color: var(--text-secondary);
    text-align: left; flex: none;
  }
  table.responsive tbody td[data-label=""]::before, .table tbody td:empty { display: none; }

  /* Keys & Settings: a list that pushes into sections, not tabs — six labels
     do not fit legibly on a 360px screen */
  .settings-split { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .settings-rail { position: static; }
  .settings-rail a { background: var(--bg-surface-1); border: 1px solid var(--edge-hairline);
    border-left-width: 3px; min-height: 56px; }
  .settings-split.drilled .settings-rail { display: none; }
  .pane-back { display: inline-flex; }
  .conn { padding: 16px; }
  .conn-top { gap: 12px; }
  .conn-id { flex: 1 1 100%; order: 2; }
  .conn-mark { order: 1; }
  .tally-pill { order: 3; flex: 0 0 auto; }
  .conn-well dl { grid-template-columns: minmax(0, 1fr); gap: 4px 0; }
  .conn-well dt { margin-top: 8px; }
  .conn-foot .btn { width: 100%; }
  .conn-when { margin: 0 0 8px; flex: 1 1 100%; }

  /* a submit bar you can reach with a thumb */
  .sticky-actions {
    position: sticky; bottom: 0; z-index: 30;
    margin: 24px -16px calc(-24px - env(safe-area-inset-bottom));
    padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
    background: var(--bg-surface-1); border-top: 1px solid var(--edge-hairline);
    display: flex; gap: 12px;
  }
}

/* ------------------------------------------- tablet: 768px to 1024px ----- */
@media (min-width: 768px) and (max-width: 1024px) {
  .shell { grid-template-columns: minmax(0, 1fr); }
  /* the rail lies down as a scrollable tab strip, 44px tall */
  .rail {
    position: sticky; top: 0; z-index: 40; height: auto; width: auto;
    flex-direction: row; align-items: center; transform: none;
    border-right: 0; border-bottom: 1px solid var(--edge-hairline);
    overflow-x: auto; overflow-y: hidden; scrollbar-width: none;
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 24px,
                        #000 calc(100% - 24px), transparent);
  }
  .rail::-webkit-scrollbar { display: none; }
  .rail-brand { border-bottom: 0; padding: 12px 16px; flex: none; }
  .rail-brand span { display: none; }
  .rail-nav { display: flex; padding: 6px; gap: 4px; flex: none; }
  .rail-group { display: none; }
  .rail-link {
    border-left: 0; border-bottom: 3px solid transparent;
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    white-space: nowrap; min-height: 44px;
  }
  /* app.css hides the rail icons below 900px, which would make this strip
     change shape halfway through its own band. Keep them at every width. */
  .rail-link .ico { display: grid; }
  .rail-link.on { border-left: 0; border-bottom-color: var(--signal); background: transparent; }
  .rail-foot { margin-left: auto; border-top: 0; flex: none; display: flex; gap: 8px;
    align-items: center; }
  .rail-user .who { display: none; }
  .nav-toggle { display: none; }


  /* settings keeps the strip and shows cards full width */
  .settings-split { grid-template-columns: minmax(0, 1fr); gap: 20px; }
  .settings-rail {
    position: sticky; top: 60px; z-index: 20;
    display: flex; gap: 4px; overflow-x: auto; scrollbar-width: none;
    background: var(--bg-canvas); padding: 8px 0;
    border-bottom: 1px solid var(--edge-hairline);
  }
  .settings-rail::-webkit-scrollbar { display: none; }
  .settings-rail a { border-left: 0; border-bottom: 3px solid transparent;
    border-radius: var(--radius-sm) var(--radius-sm) 0 0; white-space: nowrap; }
  .settings-rail a[aria-current="true"] { border-left: 0; border-bottom-color: var(--signal);
    background: transparent; }
  .settings-rail .keystrip { display: none; }
  /* the group labels only make sense in a vertical list */
  .settings-rail > .eyebrow { display: none; }
  .conn-foot { gap: 8px; }
  .conn-foot .conn-when { flex: 1 1 100%; margin: 0 0 4px; }
}

/* ------------------------------------------------ desktop: above 1024 --- */
@media (min-width: 1025px) {
  .nav-toggle, .nav-scrim { display: none; }
  .content > .panel, .content > form > .panel { max-width: 100%; }
  /* prose and forms stay readable however wide the window gets */
  .measured { max-width: var(--measure-wide, 88ch); }
}

/* The 1440px block that used to live here is gone. It stepped the rail width
   and re-stated the padding, and both are now continuous: --rail is a clamp()
   and the padding scales with the viewport, so there is no width at which
   either jumps. */

/* ------------------------------------------------------------- motion ---- */
.panel, .btn, .rail-link, .settings-rail a, .conn, .dest, tbody tr {
  transition-timing-function: var(--ease-out);
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 120ms !important;
    transition-property: opacity, color, background-color, border-color !important;
  }
  .rail { transition: none; }
}

/* --------------------------------------------------------------- print --- */
@media print {
  .rail, .topbar, .nav-toggle, .nav-scrim, .settings-rail, .sticky-actions { display: none !important; }
  .shell, .settings-split { grid-template-columns: minmax(0, 1fr); }
  .panel, .conn { border-color: #ccc; }
}

/* ==========================================================================
   Chat
   --------------------------------------------------------------------------
   Two panes: every conversation on the left, the open one on the right. The
   room the whole team shares is pinned to the top of that list and everything
   else is a topic, so one screen covers both "say something to everyone" and
   "this problem needs its own thread".

   The screen is the height of the window and never the height of the content:
   only the two inner panes scroll. --chat-top is the topbar's real height,
   measured by app.js on load and resize; the value here is the fallback for a
   browser with JavaScript switched off, where being a pixel out costs nothing
   because the page can still scroll.
   ========================================================================== */
:root { --chat-top: 57px; --chat-aside: 300px; }

.content--chat {
  padding: 0; max-width: none;
  display: flex; flex-direction: column;
  height: calc(100vh - var(--chat-top));
  min-height: 420px;
}
.content--chat .flash { margin: 10px 18px 0; }
.chat-shell {
  flex: 1 1 auto; min-height: 0;
  display: grid; grid-template-columns: var(--chat-aside) minmax(0, 1fr);
  background: var(--bg-canvas);
}

/* ------------------------------------------------------- the conversations */
.chat-list {
  display: flex; flex-direction: column; min-height: 0;
  background: var(--bg-surface-1);
  border-right: 1px solid var(--edge-hairline);
}
.chat-list-head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 13px 16px; border-bottom: 1px solid var(--edge-hairline);
}
.chat-list-head b { font: 600 14px/1 var(--display); letter-spacing: .01em; }
.chat-list-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 6px; }

.chat-row {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 10px; align-items: center;
  padding: 8px 10px; border-radius: var(--radius);
  color: var(--text-secondary); text-decoration: none;
}
.chat-row:hover { background: var(--bg-surface-2); color: var(--text-primary); }
.chat-row.on {
  background: var(--signal-tint); color: var(--text-primary);
  box-shadow: inset 2px 0 0 var(--signal);
}
.chat-row-main { min-width: 0; display: grid; gap: 2px; }
.chat-row-top { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.chat-row-top b { font-size: 13.5px; font-weight: 500; }
.chat-row-when { flex: none; font-size: 10.5px; color: var(--text-muted); }
.chat-row-line { font-size: 12.5px; color: var(--text-muted); }
.chat-row-line i { font-style: normal; color: var(--text-secondary); }
.chat-row.unread .chat-row-top b { font-weight: 700; color: var(--text-primary); }
.chat-row.unread .chat-row-line { color: var(--text-secondary); }
.chat-row-count {
  flex: none; min-width: 20px; padding: 0 6px; border-radius: var(--radius-pill);
  background: var(--signal); color: var(--text-on-accent);
  font: 600 11px/20px var(--mono); text-align: center;
}
.chat-face { flex: none; display: inline-flex; }
.chat-face .avatar { width: 34px; height: 34px; font-size: 14px; }
.chat-face.room {
  width: 34px; height: 34px; border-radius: var(--radius-sm);
  display: grid; place-items: center;
  background: var(--signal-tint); color: var(--signal);
  border: 1px solid var(--signal-edge);
}

/* Starting a topic is deliberate, so it sits behind a fold rather than
   competing with the message box for attention. */
.chat-new { border-top: 1px solid var(--edge-hairline); }
.chat-new > summary {
  list-style: none; cursor: pointer; padding: 12px 16px;
  font-size: 13px; font-weight: 500; color: var(--text-secondary);
}
.chat-new > summary::-webkit-details-marker { display: none; }
.chat-new > summary::before { content: "+ "; color: var(--signal); font-weight: 700; }
.chat-new > summary:hover { color: var(--text-primary); background: var(--bg-surface-2); }
.chat-new[open] > summary { color: var(--text-primary); border-bottom: 1px solid var(--edge-hairline); }
.chat-new > form { padding: 12px 16px 16px; display: grid; gap: 10px; }

.chat-people { border-top: 1px solid var(--edge-hairline); padding: 10px 16px 12px; }
.chat-faces { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
.chat-face-one { position: relative; display: inline-flex; cursor: default; }
.chat-face-one .avatar { width: 24px; height: 24px; font-size: 10px; }
.chat-face-one .avatar { filter: grayscale(.7); opacity: .55; }
.chat-face-one.live .avatar { filter: none; opacity: 1; }
.chat-face-one.live::after {
  content: ""; position: absolute; right: -1px; bottom: -1px;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--live); box-shadow: 0 0 0 2px var(--bg-surface-1);
}

/* ------------------------------------------------------------- the open room */
.chat-room { display: flex; flex-direction: column; min-height: 0; background: var(--bg-canvas); }
.chat-room-head {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 18px; border-bottom: 1px solid var(--edge-hairline);
  background: var(--bg-surface-1);
}
.chat-room-who { min-width: 0; display: grid; gap: 2px; }
.chat-room-who b { font: 600 15px/1.2 var(--display); }
.chat-room-sub {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
  font-size: 11.5px; color: var(--text-muted);
}
.chat-room-sub .pill { font-size: 10.5px; }

.chat-back {
  display: none; position: relative; flex: none;
  width: 36px; height: 36px; border-radius: var(--radius-sm);
  border: 1px solid var(--edge-hairline); background: var(--bg-surface-2);
  color: var(--text-secondary); place-items: center; cursor: pointer;
}
.chat-back-count {
  position: absolute; top: -5px; right: -5px; min-width: 17px; padding: 0 4px;
  border-radius: var(--radius-pill); background: var(--rose); color: #fff;
  font: 600 10px/17px var(--mono); text-align: center;
}

.chat-menu { position: relative; margin-left: auto; flex: none; }
.chat-menu > summary {
  list-style: none; cursor: pointer;
  width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid var(--edge-hairline); background: var(--bg-surface-2);
  color: var(--text-secondary);
}
.chat-menu > summary::-webkit-details-marker { display: none; }
.chat-menu > summary:hover { color: var(--text-primary); border-color: var(--edge-strong); }
.chat-menu[open] > summary { color: var(--signal); border-color: var(--signal-edge); }
.chat-menu[open] > summary svg { transform: rotate(180deg); }
.chat-menu-body {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 40;
  width: min(320px, calc(100vw - 32px));
  display: grid; gap: 12px;
  padding: 14px; border-radius: var(--radius);
  background: var(--bg-surface-2); border: 1px solid var(--edge-strong);
  box-shadow: 0 18px 44px rgba(0, 0, 0, .5);
}
.chat-menu-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }

/* --------------------------------------------------------------- the stream */
.chat-scroll {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  display: flex; flex-direction: column;
  padding: 14px 18px 6px;
  overflow-anchor: none;
}
.chat-older { min-height: 4px; text-align: center; }
/* A short conversation sits on the message box instead of floating at the top
   of an empty field. */
.chat-stream { margin-top: auto; }

.chat-day { display: flex; justify-content: center; margin: 16px 0 8px; }
.chat-day span {
  padding: 3px 11px; border-radius: var(--radius-pill);
  background: var(--bg-surface-2); border: 1px solid var(--edge-hairline);
  font: 600 10.5px/1.5 var(--mono); letter-spacing: .04em;
  color: var(--text-muted); text-transform: uppercase;
}
.chat-fresh { display: flex; align-items: center; gap: 10px; margin: 14px 0 6px; }
.chat-fresh::before, .chat-fresh::after {
  content: ""; flex: 1; height: 1px; background: var(--signal-edge);
}
.chat-fresh span {
  font: 700 10px/1 var(--sans); letter-spacing: .1em; text-transform: uppercase;
  color: var(--signal);
}

.bub {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  gap: 8px; margin-top: 10px;
}
.bub.run { margin-top: 2px; }
/* A run of messages from one person shows one avatar and one name. Both are
   always in the markup and hidden by this rule, so app.js can regroup a
   stream after new messages arrive by toggling a single class. */
.bub.run .bub-face .avatar, .bub.run .bub-who { display: none; }
.bub.me { grid-template-columns: minmax(0, 1fr); justify-items: end; }
.bub-face { width: 28px; flex: none; align-self: end; }
.bub-face .avatar { width: 28px; height: 28px; font-size: 11px; }
.bub-col { min-width: 0; max-width: min(76%, 620px); display: grid; gap: 4px; }
.bub.me .bub-col { justify-items: end; }
.bub-who {
  display: flex; align-items: center; gap: 6px;
  padding-left: 3px; font-size: 11.5px; color: var(--text-muted);
}
.bub-art {
  position: relative;
  padding: 8px 13px 6px; border-radius: var(--radius-lg);
  background: var(--bg-surface-3); border: 1px solid var(--edge-hairline);
}
/* The tail marks who is speaking and where a run of messages begins — the only
   corner in the whole screen that is not the same radius as its neighbours. */
.bub:not(.run) .bub-art { border-top-left-radius: var(--radius-sm); }
.bub.me:not(.run) .bub-art {
  border-top-left-radius: var(--radius-lg); border-top-right-radius: var(--radius-sm);
}
.bub.me .bub-art { background: var(--signal); border-color: transparent; color: var(--text-on-accent); }
.bub-text { white-space: pre-wrap; overflow-wrap: anywhere; font-size: 14.5px; line-height: 1.55; }
.bub-meta {
  display: block; text-align: right; margin-top: 2px;
  font: 500 10px/1.4 var(--mono); color: var(--text-muted);
}
.bub.me .bub-meta { color: color-mix(in srgb, var(--text-on-accent) 60%, transparent); }
.bub.sending .bub-art { opacity: .6; }
.bub.failed .bub-art { background: var(--rose-tint); border-color: var(--rose); color: var(--rose-text); }

/* A correction is admitted, not advertised: small, quiet, next to the time. */
.bub-edited {
  margin-left: 5px; font-style: normal; opacity: .75;
}
.bub-edited::before { content: "· "; }

.chat-empty { display: grid; gap: 4px; place-items: center; text-align: center; padding: 36px 20px; }
.chat-empty b { font: 600 15px/1.3 var(--display); }
.chat-empty span { font-size: 13px; color: var(--text-muted); max-width: 40ch; }

.chat-seen { display: flex; align-items: center; flex-wrap: wrap; gap: 5px; padding: 10px 2px 6px; min-height: 18px; }
.chat-seen .avatar { width: 18px; height: 18px; font-size: 9px; }

/* ------------------------------------------------------------ the composer */
.chat-compose {
  display: grid; gap: 8px; padding: 10px 18px 12px;
  border-top: 1px solid var(--edge-hairline); background: var(--bg-surface-1);
}
/* Three columns, not two: clip, box, send. With only two named columns the clip
   took the 1fr and the textarea fell into an implicit auto column, which is what
   shrank the writing box to a stub. The box is the one thing that must be wide. */
.chat-compose-row {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 10px; align-items: end;
}
.chat-input {
  width: 100%; resize: none; min-height: 44px; max-height: 180px;
  padding: 11px 14px; border-radius: var(--radius-lg);
  border: 1px solid var(--edge-control); background: var(--bg-inset);
  color: var(--text-primary); font: 400 14.5px/1.5 var(--sans);
}
.chat-input::placeholder { color: var(--text-muted); }
.chat-input:focus-visible {
  outline: none; border-color: var(--signal);
  box-shadow: 0 0 0 3px var(--signal-tint);
}
.chat-send {
  flex: none; width: 44px; height: 44px; border-radius: 50%; border: 0; cursor: pointer;
  display: grid; place-items: center;
  background: var(--signal); color: var(--text-on-accent);
  transition: background 120ms var(--ease-out);
}
.chat-send:hover { background: var(--signal-hover); }
.chat-send[disabled] { background: var(--bg-surface-3); color: var(--text-muted); cursor: default; }
.chat-hint { font-size: 11px; color: var(--text-muted); }
.chat-hint b { color: var(--text-secondary); font-weight: 600; }
.chat-quiet { margin-bottom: 2px; }

/* --------------------------------------------------------------- narrow --- */
/* Below this the list becomes a drawer over the room, the way a phone chat
   works: one pane at a time, and the toggle carries the unread count so the
   badge is still visible with the list shut. */
@media (max-width: 900px) {
  .chat-shell { grid-template-columns: minmax(0, 1fr); position: relative; overflow: hidden; }
  .chat-list {
    position: absolute; inset: 0; z-index: 30;
    transform: translateX(-101%); transition: transform 220ms var(--ease-out);
    box-shadow: 0 0 44px rgba(0, 0, 0, .55);
  }
  .chat-shell.list-open .chat-list { transform: none; }
  .chat-back { display: inline-grid; }
  .chat-room-head { padding: 8px 12px; }
  .chat-scroll { padding: 12px 12px 4px; }
  .chat-compose { padding: 8px 12px 10px; }
  .chat-hint { display: none; }
  .bub-col { max-width: 86%; }
  /* No hover on a touch screen, so the actions stay visible. */
  .bub-acts { opacity: 1; }
}
@media (max-width: 560px) {
  .chat-menu-body { position: fixed; left: 12px; right: 12px; top: auto; width: auto; }
  .bub-col { max-width: 90%; }
}
@media (prefers-reduced-motion: reduce) {
  .chat-list { transition: none; }
  .bub-act { transition: none; }
}

/* --------------------------------------------------------------------------
   Screenshots, screen recordings and replies in the chat
   --------------------------------------------------------------------------
   A picture of the actual error is the fastest way to explain a problem, so
   these are sized to be readable in the stream without a click — but capped, so
   one tall phone screenshot cannot push the whole conversation off screen. */

.quote {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0 0 var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-left: 3px solid var(--signal);
  border-radius: var(--radius-sm);
  background: var(--bg-inset);
  color: inherit;
  text-decoration: none;
  max-width: 100%;
  overflow: hidden;
}
.quote b {
  font-size: 12px;
  font-weight: 600;
  color: var(--signal);
  letter-spacing: .01em;
}
.quote span {
  font-size: 13px;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
a.quote:hover { background: var(--signal-tint); }
.quote--gone {
  border-left-color: var(--edge-strong);
  font-style: italic;
}
.quote--gone span { color: var(--text-muted); }
.bub.me .quote { border-left-color: var(--text-on-accent); background: rgba(0, 0, 0, .14); }
.bub.me .quote b { color: var(--text-on-accent); }
.bub.me .quote span { color: var(--text-on-accent); opacity: .82; }

/* The bubble a reply points at, flashed after the jump so the eye lands on it. */
@keyframes tx-found {
  0%, 70% { background: var(--signal-tint); }
  100%    { background: transparent; }
}
.bub.found .bub-art { animation: tx-found 1.6s var(--ease-out); }

.shots {
  display: grid;
  gap: 3px;
  margin-bottom: var(--space-2);
  border-radius: var(--radius-sm);
  overflow: hidden;
  max-width: 340px;
}
.shots--many { grid-template-columns: 1fr 1fr; }
.shot {
  display: block;
  position: relative;
  margin: 0;
  background: var(--bg-inset);
  line-height: 0;
}
.shot img {
  display: block;
  width: 100%;
  max-height: 320px;
  object-fit: cover;
  cursor: zoom-in;
}
.shots:not(.shots--many) .shot img { object-fit: contain; }
.shots--many .shot img { aspect-ratio: 1; }

.shot--film {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 132px;
  padding: var(--space-4);
  line-height: 1.4;
  text-align: center;
}
.shot--film video { width: 100%; max-height: 320px; border-radius: var(--radius-sm); }
.shot-play {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--signal);
  color: var(--text-on-accent);
  cursor: pointer;
  transition: transform .15s var(--ease-out);
}
.shot-play:hover { transform: scale(1.06); }
.shot-cap { font-size: 12px; color: var(--text-secondary); word-break: break-all; }

/* Full size, because half the point of a screenshot is the small print in it. */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  padding: var(--space-5);
  background: rgba(0, 0, 0, .86);
}
.lightbox img { max-width: 100%; max-height: 88vh; border-radius: var(--radius-sm); }
.lightbox-x {
  position: absolute;
  top: var(--space-4);
  right: var(--space-4);
  width: 40px;
  height: 40px;
  border: 1px solid var(--edge-strong);
  border-radius: var(--radius-pill);
  background: var(--bg-surface-2);
  color: var(--text-primary);
  font-size: 18px;
  cursor: pointer;
}
.lightbox-name {
  position: absolute;
  bottom: var(--space-4);
  left: 50%;
  transform: translateX(-50%);
  font-size: 12px;
  color: var(--text-secondary);
}

/* The in-app player. Clips are shot 2160×3840, so height is the constraint and
   width follows — a portrait video sized by width would run off the screen top
   and bottom. The stage is what a click counts as "on the video", which is why
   it wraps rather than the video standing bare in the backdrop. */
.viewer-stage {
  position: relative;
  display: grid;
  place-items: center;
  max-width: 100%;
  max-height: 88vh;
}
.viewer-media {
  display: block;
  max-height: 88vh;
  max-width: 100%;
  width: auto;
  border-radius: var(--radius-sm);
  background: #000;
}
/* Pulling a 4K file back out of Drive is not instant, and an unexplained black
   rectangle reads as broken. This says which of the two it is. */
.viewer-wait {
  position: absolute;
  z-index: 1;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--edge-strong);
  border-radius: var(--radius-pill);
  background: var(--bg-surface-2);
  color: var(--text-secondary);
  font-size: 13px;
}
.viewer-wait.bad {
  max-width: 34ch;
  border-radius: var(--radius-sm);
  color: var(--fail);
  text-align: center;
}

/* Files chosen but not sent yet. */
.tray {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  padding: var(--space-2) 0 0;
}
.tray-item {
  position: relative;
  width: 68px;
  height: 68px;
  border: 1px solid var(--edge-hairline);
  border-radius: var(--radius-sm);
  background: var(--bg-inset);
  overflow: hidden;
}
.tray-item img { width: 100%; height: 100%; object-fit: cover; }
.tray-film {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  height: 100%;
  padding: var(--space-2);
  font-size: 10px;
  line-height: 1.25;
  color: var(--text-secondary);
  word-break: break-all;
}
.tray-x {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 20px;
  height: 20px;
  border: 0;
  border-radius: var(--radius-pill);
  background: rgba(0, 0, 0, .68);
  color: #fff;
  font-size: 12px;
  line-height: 1;
  cursor: pointer;
}
.tray-size {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 1px 4px;
  background: rgba(0, 0, 0, .6);
  font-size: 9px;
  color: #fff;
  text-align: center;
}

/* The strip above the composer while a reply is queued. */
.quote-bar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  margin-bottom: var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--bg-inset);
}
.quote-bar-mark {
  flex: 0 0 3px;
  align-self: stretch;
  border-radius: 2px;
  background: var(--signal);
}
.quote-bar-text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.quote-bar-text b { font-size: 12px; color: var(--signal); }
.quote-bar-text i {
  font-style: normal;
  font-size: 13px;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.quote-bar-x, .chat-clip {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  transition: background .15s var(--ease-out), color .15s var(--ease-out);
}
.quote-bar-x:hover, .chat-clip:hover { background: var(--bg-surface-3); color: var(--text-primary); }
.chat-clip { flex: 0 0 auto; align-self: flex-end; }

/* Reply and delete sit together, revealed on hover — a toolbar on every bubble
   would make a busy room look like a control panel. */
/* Actions sit on the inside edge, toward the middle of the screen: to the right
   of somebody else's bubble, to the left of your own. Against the outer edge
   they get cramped by the window and read as belonging to nothing. */
.bub-acts {
  position: absolute;
  top: 2px;
  left: 100%;
  display: flex;
  align-items: center;
  gap: 2px;
  margin-left: var(--space-2);
  opacity: 0;
  transition: opacity .15s var(--ease-out);
}
.bub.me .bub-acts { left: auto; right: 100%; margin: 0 var(--space-2) 0 0; }
.bub:hover .bub-acts, .bub-acts:focus-within { opacity: 1; }
.bub-act {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: 1px solid var(--edge-hairline);
  border-radius: var(--radius-pill);
  background: var(--bg-surface-2);
  color: var(--text-secondary);
  font-size: 12px;
  cursor: pointer;
}
.bub-act:hover { color: var(--text-primary); border-color: var(--edge-control); }
/* Editing happens in place, so the box borrows the bubble's own colours rather
   than looking like a form dropped on top of the conversation. */
.bub-edit {
  display: block; width: 100%; min-width: 220px; resize: none;
  margin: 2px 0 0; padding: 6px 8px;
  border: 1px solid var(--edge-control); border-radius: var(--radius-sm);
  background: var(--bg-inset); color: var(--text-primary);
  font: 400 14.5px/1.5 var(--sans);
}
.bub.me .bub-edit {
  background: rgba(0, 0, 0, .18); color: var(--text-on-accent);
  border-color: rgba(255, 255, 255, .35);
}
.bub-edit:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--signal-tint); }
.bub-edit-hint {
  display: block; margin-top: 3px;
  font: 500 10px/1.4 var(--mono); color: var(--text-muted);
}
.bub.me .bub-edit-hint { color: color-mix(in srgb, var(--text-on-accent) 65%, transparent); }
/* While a message is being corrected its own buttons would only get in the way. */
.bub.editing .bub-acts { display: none; }


/* Drag a screenshot anywhere over the conversation. */
.chat-scroll.dropping { outline: 2px dashed var(--signal); outline-offset: -6px; }

@media (max-width: 700px) {
  .shots { max-width: 100%; }
  /* No hover on a phone, so the actions have to be permanently visible. */
  .bub-acts { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .bub.found .bub-art { animation: none; background: var(--signal-tint); }
  .shot-play, .quote-bar-x, .chat-clip, .bub-acts { transition: none; }
}

/* --------------------------------------------------------- upload meter --- */
/* Two states that must look different at a glance, because they mean different
   things: "sending" is counting bytes and can be cancelled; "filing" has no
   number to report and cannot. The travelling sheen is the only animation in
   the component and it exists solely to carry that distinction — a bar frozen
   at 100% is what made people think the app had died. */

.upmeter {
  margin: 18px auto 0; max-width: 460px; text-align: left;
  padding: 16px; border-radius: var(--radius-sm);
  background: var(--bg-surface-2); border: 1px solid var(--edge-hairline);
}
.upmeter-head { display: flex; align-items: baseline; gap: 12px; }
.upmeter-head b { font: 600 15px/1.3 var(--sans); color: var(--text-primary); }
.upmeter-pct {
  margin-left: auto; font-size: 20px; font-weight: 600; color: var(--signal-text);
  /* Tabular, or every digit change nudges the whole readout sideways. */
  font-variant-numeric: tabular-nums;
}
.upbar {
  margin-top: 12px; height: 8px; border-radius: 999px; overflow: hidden;
  background: var(--bg-inset); border: 1px solid var(--edge-hairline);
}
.upbar-fill {
  display: block; height: 100%; width: 0; border-radius: 999px;
  background: var(--signal); transition: width .25s ease-out;
}
.upmeter-foot {
  margin-top: 8px; display: flex; gap: 12px; justify-content: space-between;
  font-size: 13px; color: var(--text-muted); font-variant-numeric: tabular-nums;
}
.upmeter-note { margin: 10px 0 0; font-size: 14px; color: var(--text-secondary); }
.upmeter-note:empty { display: none; }
.upmeter [data-up-cancel] { margin-top: 12px; }

/* Nothing left to count — so say so with movement instead of a number. */
.upmeter--filing .upbar-fill {
  background: linear-gradient(90deg,
    var(--signal-press) 0%, var(--signal-hover) 45%, var(--signal-press) 100%);
  background-size: 220% 100%;
  animation: upmeter-sheen 1.5s linear infinite;
}
@keyframes upmeter-sheen {
  from { background-position: 100% 0; }
  to   { background-position: -120% 0; }
}

.upmeter--failed { border-color: var(--rose); background: var(--rose-tint); }
.upmeter--failed .upmeter-head b { color: var(--rose-text); }
.upmeter--failed .upbar-fill { background: var(--rose); }
.upmeter--failed .upmeter-note { color: var(--text-primary); }

@media (max-width: 420px) {
  .upmeter-foot { flex-direction: column; gap: 2px; }
}
@media (prefers-reduced-motion: reduce) {
  .upbar-fill { transition: none; }
  /* Keep the two states distinguishable without motion: a flat, dimmer fill. */
  .upmeter--filing .upbar-fill { animation: none; background: var(--signal-press); }
}

/* Chat attachment progress, on the bubble it belongs to. Deliberately thinner
   and quieter than the Studio meter: one screenshot is not a batch of videos,
   and the bubble is small. */
.bub-up { margin-top: 8px; display: flex; align-items: center; gap: 8px; }
.bub-up-track {
  flex: 1; height: 4px; border-radius: 999px; overflow: hidden;
  background: rgba(255, 255, 255, .12);
}
.bub-up-track i {
  display: block; height: 100%; width: 0; border-radius: 999px;
  background: var(--signal); transition: width .2s linear;
}
.bub-up-pct { font-size: 11px; color: var(--text-secondary); min-width: 4ch; text-align: right; }
.bub-up--filing .bub-up-track i {
  background: linear-gradient(90deg,
    var(--signal-press) 0%, var(--signal-hover) 45%, var(--signal-press) 100%);
  background-size: 220% 100%;
  animation: upmeter-sheen 1.5s linear infinite;
}
/* Sits under .bub-art rather than in it, because .bub.sending dims .bub-art
   with opacity and that cannot be undone from inside. See meterOn() in app.js. */
.bub.me .bub-up { flex-direction: row-reverse; }
.bub.me .bub-up-pct { text-align: left; }
@media (prefers-reduced-motion: reduce) {
  .bub-up-track i { transition: none; }
  .bub-up--filing .bub-up-track i { animation: none; background: var(--signal-press); }
}

/* ==========================================================================
   Who is here — the topbar crowd control
   Ten people share this tool and nothing on screen ever said so. The count is
   the whole feature; the panel is only there because a number without names
   invites the question it cannot answer.

   Deliberately quiet: it sits beside the clocks, in the same small uppercase
   register, so it reads as another instrument on the shelf rather than a
   notification. Presence is inferred from the last few minutes of requests, so
   it must never look as authoritative as a live connection would.
   ========================================================================== */
.crowd { position: relative; margin-left: auto; }
.crowd + .clocks { margin-left: 14px; padding-left: 14px;
  border-left: 1px solid var(--line); }

.crowd-btn {
  display: flex; align-items: center; gap: 9px;
  padding: 4px 9px; border-radius: var(--radius-pill);
  background: transparent; border: 1px solid transparent;
  color: var(--text-mute); cursor: pointer;
  font: inherit; line-height: 1;
  transition: background .14s ease, border-color .14s ease, color .14s ease;
}
.crowd-btn:hover { background: var(--bg-surface-2); border-color: var(--edge-hairline);
  color: var(--text); }
.crowd-btn:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; }
.crowd-btn[aria-expanded="true"] { background: var(--bg-surface-2);
  border-color: var(--edge-hairline); color: var(--text); }

/* Overlapped faces, newest-active first. Four is the point where the stack
   stops reading as a group of people and starts reading as a texture. */
.crowd-faces { display: flex; align-items: center; }
.crowd-face {
  width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center;
  font: 600 10px/1 var(--sans, inherit); font-style: normal;
  color: #0B0C0E; letter-spacing: 0;
  border: 2px solid var(--bg-surface);
  margin-left: -7px; flex: none;
}
.crowd-face:first-child { margin-left: 0; }
.crowd-faces:empty { display: none; }

.crowd-word { font: 500 10px/1 var(--mono); letter-spacing: .1em;
  text-transform: uppercase; white-space: nowrap; }
.crowd-word b { font-size: 15px; letter-spacing: 0; color: var(--text);
  font-variant-numeric: tabular-nums; }
/* Nobody else is here. Still true, still worth saying — just not in the
   colour reserved for things that are happening. */
.crowd--alone .crowd-word b { color: var(--text-mute); }

.crowd-panel {
  position: absolute; top: calc(100% + 9px); right: 0; z-index: 40;
  width: 268px; max-width: min(268px, calc(100vw - 32px));
  padding: 12px; border-radius: var(--radius);
  background: var(--bg-surface-2); border: 1px solid var(--line);
  box-shadow: var(--shadow-menu);
}
.crowd-panel[hidden] { display: none; }
.crowd-head { padding: 0 2px 9px; border-bottom: 1px solid var(--edge-hairline);
  margin-bottom: 8px; }
.crowd-head b { display: block; font-size: 13px; color: var(--text); }
.crowd-head span { display: block; margin-top: 3px; font-size: 11px; line-height: 1.4;
  color: var(--text-mute); }

.crowd-list { list-style: none; margin: 0; padding: 0;
  max-height: min(52vh, 340px); overflow: auto; }
.crowd-row { display: flex; align-items: center; gap: 9px; padding: 5px 2px; }
.crowd-row .avatar { flex: none; }
.crowd-name { min-width: 0; flex: 1; }
.crowd-name b { display: block; font-size: 12.5px; font-weight: 600; color: var(--text); }
.crowd-name > span { display: block; font-size: 10.5px; color: var(--text-mute); }
/* A green dot on the avatar, not a word in the row: at this size the eye finds
   the dots in one pass and would have to read every line otherwise. */
.crowd-row .avatar { position: relative; }
.crowd-row:not(.out) .avatar::after {
  content: ""; position: absolute; right: -1px; bottom: -1px;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--live); border: 2px solid var(--bg-surface-2);
}
.crowd-row.out .avatar { opacity: .5; }
.crowd-row.out .crowd-name b { color: var(--text-mute); font-weight: 500; }

@media (max-width: 720px) {
  /* The faces go first: on a phone the count is the part that matters. */
  .crowd-faces { display: none; }
}

/* ==========================================================================
   Read receipts on your own messages
   Two ticks and a number, inside the bubble's meta line — the same place the
   clock already lives, so nothing grows a new row. The number is the honest
   part: it counts people whose read mark has passed this exact message, which
   is why it can differ from one bubble to the next in the same conversation.
   ========================================================================== */
.bub-seen {
  display: inline-flex; align-items: center; gap: 3px;
  margin-left: 2px; padding: 1px 4px 1px 3px;
  background: transparent; border: 0; border-radius: 5px;
  color: var(--text-mute); cursor: pointer; font: inherit;
  transition: background .12s ease, color .12s ease;
}
.bub-seen:hover { background: var(--bg-inset); color: var(--text); }
.bub-seen:focus-visible { outline: 2px solid var(--signal); outline-offset: 1px; }
.bub-seen b { font: 600 11px/1 var(--mono); font-variant-numeric: tabular-nums; }
.bub-seen svg { flex: none; }
/* Sent, and nobody has caught up yet. One tick's worth of certainty. */
.bub-seen.none { opacity: .45; }
.bub-seen.none b { display: none; }
/* Everybody. The one state worth a colour, because it is the one that means
   you can stop wondering. */
.bub-seen.all { color: var(--signal-text); }

.seenpop {
  position: fixed; z-index: 60; min-width: 190px; max-width: 260px;
  padding: 9px 10px; border-radius: var(--radius);
  background: var(--bg-surface-2); border: 1px solid var(--line);
  box-shadow: var(--shadow-menu); font-size: 12px;
}
.seenpop-head { font: 500 10px/1 var(--mono); letter-spacing: .09em;
  text-transform: uppercase; color: var(--text-mute); margin-bottom: 7px; }
.seenpop-row { display: flex; align-items: center; gap: 8px; padding: 3px 0; }
.seenpop-row .avatar { flex: none; }
.seenpop-row b { font-size: 12px; font-weight: 600; color: var(--text); }
.seenpop-row span { margin-left: auto; font-size: 10.5px; color: var(--text-mute);
  white-space: nowrap; }
.seenpop-none { color: var(--text-mute); line-height: 1.45; }

/* ==========================================================================
   The four counts on a post
   Views, reactions, shares, comments — the only question anybody opens this
   page to ask, so they are the first thing on it and they are big enough to
   read from across the room. Equal columns rather than a table: these are
   four peers, not a ranked list, and a table header would make them look
   like data to scan instead of a result to take in at a glance.
   ========================================================================== */
.postnums {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px;
  background: var(--line-soft);            /* the gap becomes the hairlines */
  border: 1px solid var(--line-soft); border-radius: var(--radius);
  overflow: hidden;
}
.postnums-one {
  display: flex; flex-direction: column; gap: 4px; align-items: center;
  padding: 15px 8px 13px; background: var(--bg-surface-1); text-align: center;
}
.postnums-one b {
  font-size: 25px; line-height: 1; letter-spacing: -.02em;
  color: var(--text-primary); font-variant-numeric: tabular-nums;
}
.postnums-one span {
  font: 600 10px/1 var(--sans); letter-spacing: .09em; text-transform: uppercase;
  color: var(--text-mute);
}

/* Two by two on a phone. Four 25px numbers side by side would shrink to
   nothing, and these are the numbers he checks on a phone most of all. */
@media (max-width: 560px) {
  .postnums { grid-template-columns: repeat(2, 1fr); }
  .postnums-one b { font-size: 21px; }
}

/* ==========================================================================
   The two public documents — /privacy and /terms
   The only pages here a stranger ever sees, and the audience that matters most
   is a Google reviewer deciding whether this project may leave testing. So
   these read as documents, not as screens: one column at a comfortable
   measure, real vertical rhythm, and headings that can be skimmed in one pass
   to find "what data, why, and how do I get rid of it".

   Built only on tokens that theme.css redefines for light mode
   (--bg-canvas, --bg-surface-*, --text-*, --line, --signal), because a
   reviewer's browser may well be in light mode and --text-mute is only ever
   set by app.css.
   ========================================================================== */
.legal {
  min-height: 100vh;
  background: var(--bg-canvas);
  display: flex; flex-direction: column;
}

/* ---- header ------------------------------------------------------------ */
.legal-top {
  display: flex; align-items: center; gap: 20px; flex-wrap: wrap;
  padding: 18px 28px;
  border-bottom: 1px solid var(--line);
  background: var(--bg-surface-1);
}
.legal-brand {
  display: inline-flex; align-items: center; gap: 11px;
  font: 600 16px/1 var(--sans); color: var(--text-primary); text-decoration: none;
}
.legal-brand:hover { text-decoration: none; }
.legal-brand .mark {
  width: 30px; height: 30px; flex: none; border-radius: 8px;
  display: grid; place-items: center;
  background: var(--signal); color: #06231F;
  font: 700 14px/1 var(--mono);
}
.legal-nav {
  margin-left: auto; display: flex; align-items: center; gap: 4px;
  font: 500 13px/1 var(--sans);
}
.legal-nav a {
  padding: 7px 11px; border-radius: var(--radius-sm);
  color: var(--text-secondary); text-decoration: none;
}
.legal-nav a:hover { background: var(--bg-surface-2); color: var(--text-primary);
  text-decoration: none; }
.legal-nav a:focus-visible { outline: 2px solid var(--signal); outline-offset: 1px; }
/* You are already reading this one. Marked, not hidden — a nav that silently
   drops the current page makes the other document harder to find. */
.legal-nav a[aria-current="page"] {
  background: var(--bg-surface-2); color: var(--text-primary);
  box-shadow: inset 0 0 0 1px var(--line);
}

/* ---- the document ------------------------------------------------------ */
/* 68ch, not a pixel width: the measure should follow the type, and this is the
   band where a long clause still tracks back to the right line. */
.legal-doc {
  flex: 1; width: 100%; max-width: 68ch;
  margin: 0 auto; padding: 56px 28px 72px;
}
.legal-eyebrow {
  margin: 0 0 14px;
  font: 500 11px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase;
  color: var(--signal);
}
.legal-doc h1 {
  margin: 0 0 18px;
  font-size: clamp(28px, 4.5vw, 38px); line-height: 1.15; letter-spacing: -.02em;
  color: var(--text-primary);
}
.legal-lede {
  margin: 0 0 18px;
  font-size: 17px; line-height: 1.6; color: var(--text-secondary);
}
.legal-dates {
  margin: 0 0 44px; padding-bottom: 26px;
  border-bottom: 1px solid var(--line);
  font-size: 13px; line-height: 1.6; color: var(--text-muted);
}
.legal-host { font-family: var(--mono); font-size: 12.5px; color: var(--text-secondary); }

/* A hairline in the left margin instead of a number: these sections are not a
   sequence and numbering them would imply an order that carries no meaning. */
.legal-doc h2 {
  margin: 44px 0 14px; padding-left: 15px;
  border-left: 2px solid var(--signal);
  font-size: 19px; line-height: 1.3; letter-spacing: -.01em;
  color: var(--text-primary);
}
.legal-doc h2:first-of-type { margin-top: 0; }
.legal-doc p {
  margin: 0 0 16px; font-size: 15.5px; line-height: 1.72;
  color: var(--text-secondary);
}
.legal-doc ul {
  margin: 0 0 18px; padding: 0; list-style: none;
}
.legal-doc li {
  position: relative; margin-bottom: 12px; padding-left: 18px;
  font-size: 15.5px; line-height: 1.7; color: var(--text-secondary);
}
.legal-doc li::before {
  content: ""; position: absolute; left: 2px; top: .72em;
  width: 5px; height: 5px; border-radius: 50%; background: var(--signal);
}
.legal-doc li strong, .legal-doc p strong { color: var(--text-primary); font-weight: 600; }
.legal-doc code {
  font: 500 13px/1.4 var(--mono);
  padding: 2px 6px; border-radius: 5px;
  background: var(--bg-surface-2); border: 1px solid var(--line);
  color: var(--text-primary); white-space: nowrap;
}
.legal-doc a { color: var(--signal); text-underline-offset: 3px; }
.legal-doc a:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; }

/* The one emphasised block on either page, and it earns it: this exact sentence
   is what Google's policy requires, and its absence is the usual reason a
   verification submission comes back. Treated as a quotation, because that is
   what it is. */
.legal-callout {
  margin: 26px 0 20px !important;
  padding: 18px 20px; border-radius: var(--radius);
  background: var(--bg-surface-1);
  border: 1px solid var(--line); border-left: 3px solid var(--signal);
  color: var(--text-primary) !important;
  font-size: 15px !important;
}
.legal-seealso {
  margin-top: 34px !important; padding-top: 22px;
  border-top: 1px solid var(--line);
  font-size: 14px !important;
}

/* ---- footer ------------------------------------------------------------ */
.legal-foot {
  padding: 26px 28px 34px;
  border-top: 1px solid var(--line);
  background: var(--bg-surface-1);
  text-align: center;
}
.legal-foot p {
  max-width: 62ch; margin: 0 auto 8px;
  font-size: 13px; line-height: 1.6; color: var(--text-muted);
}
.legal-foot p:last-child { margin-bottom: 0; }
.legal-foot a { color: var(--text-secondary); }

@media (max-width: 640px) {
  .legal-top { padding: 14px 18px; gap: 12px; }
  /* The brand and the nav each take a full row rather than the nav wrapping to
     a ragged second line under a left-aligned mark. */
  .legal-brand { width: 100%; }
  .legal-nav { margin-left: -11px; }
  .legal-doc { padding: 36px 18px 56px; }
  .legal-doc h2 { margin-top: 36px; }
  .legal-foot { padding: 22px 18px 28px; }
}

/* A reviewer may well print or PDF these pages. Worth the six lines. */
@media print {
  .legal-nav, .skip-link { display: none; }
  .legal, .legal-top, .legal-foot { background: #fff; }
  .legal-doc { max-width: none; padding: 0; }
  .legal-doc h2 { break-after: avoid; }
  .legal-callout { break-inside: avoid; }
}

/* ------------------------------------------------------------------ *
 * Instagram accounts found on the Facebook Pages (page_form.html).
 * Every Page that was searched appears here, including the ones that
 * cannot offer an account — those are dimmed and carry their reason,
 * because a Page missing from the list is indistinguishable from a
 * Page with no Instagram, and that is exactly what is being asked.
 * ------------------------------------------------------------------ */
.igfind {
  display: grid;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}
.igfind-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
  padding: var(--space-3);
  border: 1px solid var(--edge-hairline);
  border-radius: var(--radius-sm);
  background: var(--bg-surface-2);
}
.igfind-row > div { min-width: 0; }
.igfind-row b { display: block; }
.igfind-meta {
  display: block;
  color: var(--text-muted);
  font-size: .82rem;
  line-height: 1.45;
}
.igfind-off {
  background: transparent;
  border-style: dashed;
}
.igfind-off b { color: var(--text-secondary); }

/* Send to Instagram: now, or at a time. A <details> rather than a menu of its
   own, so the choice appears under the button that was already there and works
   with the keyboard and with JavaScript off. The marker is removed because the
   summary is dressed as a button, and a button with a disclosure triangle in it
   reads as neither one thing nor the other. */
.sendpick > summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
}
.sendpick > summary::-webkit-details-marker { display: none; }
.sendpick[open] > summary {
  border-color: var(--signal-edge);
  color: var(--signal-text);
}
.sendpick-menu {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-2);
  padding: var(--space-2);
  border: 1px solid var(--edge-hairline);
  border-radius: var(--radius-sm);
  background: var(--bg-surface-1);
}
/* Two ways to send, so two forms — see the template for why they are not one.
   Each keeps its own controls on one line, and the pair wraps together on a
   narrow screen rather than splitting the date away from its button. */
.sendpick-menu > form {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.sendpick-at {
  width: auto;
  padding: 4px 8px;
  font-size: .82rem;
}
