/* VadPosts Beta 2. Hand-written, no framework, no build step.
   Every colour, the radius, the density and the sidebar width come from
   config/theme.json via a <style> block the server emits. Nothing visual is
   hard-coded here, so the Design screen can change the look without a deploy. */

* { box-sizing: border-box; }

html { color-scheme: light dark; }

body {
  margin: 0;
  background: var(--surface);
  color: var(--ink);
  font: 15px/1.6 var(--font-stack);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

.skip {
  position: absolute; left: -9999px;
  background: var(--card); padding: 10px 14px; border-radius: var(--radius);
}
.skip:focus { left: 12px; top: 12px; z-index: 50; }

/* ---------- app shell ---------- */

body.app { display: grid; grid-template-columns: var(--sidebar-w) 1fr; min-height: 100vh; }

.side {
  background: var(--card);
  border-right: 1px solid var(--line);
  padding: 18px 14px;
  display: flex; flex-direction: column; gap: 16px;
  position: sticky; top: 0; height: 100vh;
}

/* The logo and the phone-width menu button share a row on a phone and do
   not exist as a group anywhere else, which is what display:contents is
   for: above 860 pixels the logo is a direct child of .side again. */
.sidetop { display: contents; }
.navbtn {
  display: none; align-items: center; gap: 8px;
  padding: 9px 13px; min-height: 42px;
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--surface); color: var(--ink);
  font: inherit; font-size: 14px; font-weight: 650; cursor: pointer;
}
.navbtn svg { width: 18px; height: 18px; flex: none; }

.logo { display: flex; align-items: center; gap: 10px; color: var(--ink); }
.logo:hover { text-decoration: none; }
.logo-mark {
  width: 32px; height: 32px; flex: none;
  display: grid; place-items: center;
  background: var(--accent); color: var(--accent-text);
  border-radius: 9px; font-weight: 800; font-size: 17px;
}
.logo-img { width: 32px; height: 32px; object-fit: contain; }
.logo-text { font-weight: 700; font-size: 15px; line-height: 1.2; letter-spacing: -0.2px; }
.logo-text em {
  display: block; font-style: normal; font-weight: 600;
  font-size: 10px; letter-spacing: 1.1px; text-transform: uppercase; color: var(--ink-muted);
}

.ws-switch select {
  width: 100%; padding: 8px 10px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); color: var(--ink); font: inherit; font-size: 13px;
}

.sidenav { display: flex; flex-direction: column; gap: 2px; }
.sidenav a {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: 8px;
  color: var(--ink-muted); font-weight: 600; font-size: 14px;
}
.sidenav a:hover { background: var(--surface); color: var(--ink); text-decoration: none; }
.sidenav a.on { background: var(--accent); color: var(--accent-text); }
.sidenav svg { width: 17px; height: 17px; flex: none; }

/* Terms and privacy, at the bottom of the sidebar with the rest of the small
   print. The three rules are one idea: exactly one auto margin in the group,
   so the whole block travels to the bottom together. Signed out there is no
   .side-who, so this one carries the auto; signed in, .side-who already has
   it and a second auto here would split the free space and strand the lines
   apart down the sidebar, which is what it did the first time. */
.side-legal { margin-top: auto; font-size: 11px; }
.side-who + .side-legal { margin-top: 6px; }
.side-legal + .side-foot { margin-top: 2px; }
.side-legal a { color: var(--ink-muted); }
.side-foot { margin-top: auto; font-size: 11px; color: var(--ink-muted); }

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

.pagehead {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 18px 28px; border-bottom: 1px solid var(--line); background: var(--card);
}
.pagehead h1 { margin: 0; font-size: 20px; letter-spacing: -0.3px; }

main { padding: 24px 28px 64px; max-width: 1180px; }

/* ---------- surfaces ---------- */

.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px;
  margin-bottom: 18px;
}
.card h2 { margin: 0 0 8px; font-size: 17px; letter-spacing: -0.2px; }
.card h3 { margin: 0 0 10px; font-size: 14px; letter-spacing: 0.1px; }
.card h4 { margin: 0 0 6px; font-size: 13px; }

.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; align-items: start; }
.grid .card { margin: 0; }
.grid .span2 { grid-column: span 2; }
@media (max-width: 980px) { .grid { grid-template-columns: 1fr 1fr; } .grid .span2 { grid-column: span 2; } }
@media (max-width: 680px) { .grid { grid-template-columns: 1fr; } .grid .span2 { grid-column: span 1; } }

.split { display: grid; grid-template-columns: 1.4fr 1fr; gap: 18px; align-items: start; }

/* A grid item will not shrink below its own content by default, so one wide
   table inside a column pushed the column - and the page with it - past the
   screen even after the columns had collapsed to one. This is what made the
   settings page 540 pixels wide on a 375-pixel phone and cut the right-hand
   side off every sentence on it. */
.grid > *, .split > *, .tworow > * { min-width: 0; }
@media (max-width: 900px) { .split { grid-template-columns: 1fr; } }

.muted { color: var(--ink-muted); }
.note { color: var(--ink-muted); font-size: 12.5px; margin: 8px 0 0; }

/* ---------- bits ---------- */

.stat-num { font-size: 34px; font-weight: 800; letter-spacing: -1px; display: block; line-height: 1.1; }
.stat h3 { margin: 2px 0 4px; }

.meter { height: 6px; background: var(--surface); border-radius: 99px; overflow: hidden; margin: 10px 0; }
.meter span { display: block; height: 100%; background: var(--accent); }

.pill {
  display: inline-block; padding: 2px 8px; border-radius: 99px;
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.2px;
  border: 1px solid var(--line); color: var(--ink-muted); background: var(--surface);
}
.pill.ok   { color: var(--ok);   border-color: color-mix(in srgb, var(--ok) 35%, transparent); }
.pill.bad  { color: var(--bad);  border-color: color-mix(in srgb, var(--bad) 35%, transparent); }
.pill.info { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 35%, transparent); }

.tagchip {
  display: inline-block; padding: 3px 9px; margin: 0 5px 5px 0;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 99px; font-size: 12.5px;
}
.tags { margin-bottom: 14px; }

code {
  font: 12.5px/1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 5px; padding: 1px 5px;
}

.btn, button.primary, .btn.primary {
  display: inline-block; padding: 8px 14px; border-radius: 8px;
  border: 1px solid var(--line); background: var(--card); color: var(--ink);
  font: inherit; font-size: 13.5px; font-weight: 650; cursor: pointer;
}
.btn:hover { text-decoration: none; background: var(--surface); }
.primary, .btn.primary { background: var(--accent); color: var(--accent-text); border-color: transparent; }
.primary:hover { filter: brightness(1.07); }

.banner { padding: 11px 14px; border-radius: var(--radius); margin-bottom: 16px; font-size: 14px; }
.banner.ok  { background: color-mix(in srgb, var(--ok) 12%, transparent); color: var(--ok); }
.banner.bad { background: color-mix(in srgb, var(--bad) 12%, transparent); color: var(--bad); }
/* The confirm-your-address banner. Amber rather than red: an unconfirmed
   address is a thing to finish, not a thing that went wrong. */
.banner.warn { background: color-mix(in srgb, var(--warn) 12%, transparent); color: var(--warn); }
.banner-act { display: inline; margin-left: 8px; }
.banner-act button {
  font: inherit; cursor: pointer; padding: 2px 10px; border-radius: 999px;
  border: 1px solid currentColor; background: transparent; color: inherit;
}
.warn-card { border-color: color-mix(in srgb, var(--warn) 40%, var(--line)); }

/* ---------- tables and lists ---------- */

table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
th, td { text-align: left; padding: var(--cell-pad); border-bottom: 1px solid var(--line); vertical-align: top; }
th { font-size: 11px; text-transform: uppercase; letter-spacing: 0.7px; color: var(--ink-muted); }
tbody tr:last-child td { border-bottom: 0; }

ul.plain { list-style: none; margin: 0; padding: 0; font-size: 13.5px; }
ul.plain li { padding: 6px 0; border-bottom: 1px solid var(--line); }
ul.plain li:last-child { border-bottom: 0; }
ul.plain li.bad { color: var(--bad); }

.facts { display: grid; grid-template-columns: max-content 1fr; gap: 5px 16px; margin: 0; font-size: 13.5px; }
.facts dt { color: var(--ink-muted); }
.facts dd { margin: 0; }

.tabs { display: flex; gap: 4px; flex-wrap: wrap; margin-bottom: 16px; }
.tabs a {
  padding: 6px 12px; border-radius: 99px; font-size: 13px; font-weight: 650;
  color: var(--ink-muted); border: 1px solid transparent;
}
.tabs a:hover { background: var(--card); text-decoration: none; }
.tabs a.on { background: var(--accent); color: var(--accent-text); }

.postlist { list-style: none; margin: 0; padding: 0; }
.postrow { margin-bottom: 10px; }
.postrow a {
  display: block; background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 14px 16px; color: var(--ink);
}
.postrow a:hover { text-decoration: none; border-color: var(--accent); }
.postrow .meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 7px; }
.postrow p { margin: 0; color: var(--ink-muted); font-size: 13.5px; }
.chips code { margin-right: 4px; }
.when { font-size: 12px; color: var(--ink-muted); }

ul.cards { list-style: none; margin: 0; padding: 0; }
ul.cards li {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 14px 16px; margin-bottom: 10px;
}
ul.cards li.off { opacity: 0.62; }
ul.cards h4 { margin: 6px 0 4px; font-size: 14.5px; }
ul.cards p { margin: 0; font-size: 13.5px; }

/* ---------- forms ---------- */

.field { margin-bottom: 14px; }
.field label { display: block; font-size: 12px; font-weight: 700; color: var(--ink-muted); margin-bottom: 4px; text-transform: uppercase; letter-spacing: 0.6px; }
.field .val { margin: 0; }

input[type=text], input[type=url], input[type=number], select, textarea {
  width: 100%; padding: 9px 11px;
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--surface); color: var(--ink); font: inherit; font-size: 14px;
}
textarea.caption { font-size: 15px; line-height: 1.65; resize: vertical; }
/* The brand profile boxes hold prose. Dragged sideways on the default
   `resize: both` they push out of the card, which on a 375-pixel screen takes
   the whole page with them. Vertical only. */
.brandfield textarea { resize: vertical; line-height: 1.55; }
input[type=range] { width: 100%; accent-color: var(--accent); }
input[type=checkbox] { accent-color: var(--accent); width: 16px; height: 16px; }

/* Inputs inside a settings table need room; without this the label column
   collapses to a single character. Caught by looking at the rendered page. */
td input[type=text] { min-width: 9rem; padding: 6px 9px; font-size: 13px; }
td input[type=number] { width: 5rem; padding: 6px 9px; font-size: 13px; }
table th:last-child, table td:last-child { width: 1%; white-space: nowrap; }

.urlform { display: flex; gap: 8px; flex-wrap: wrap; }
.urlform input { flex: 1 1 260px; }

.formbar {
  position: sticky; bottom: 0; display: flex; align-items: center; gap: 12px;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 12px 16px; font-size: 13px;
}

/* auto-fit rather than a fixed pair: inside the narrow settings column the two
   columns squeezed the hex field down to "#1f". Caught by looking at it. */
.colorgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(158px, 1fr)); gap: 10px; }
.colorfield { display: grid; grid-template-columns: 1fr auto; gap: 6px; align-items: center; }
.colorfield label { grid-column: 1 / -1; font-size: 11.5px; font-weight: 700; color: var(--ink-muted); text-transform: capitalize; }
.colorfield input[type=color] { grid-column: 2; width: 38px; height: 34px; padding: 2px; border: 1px solid var(--line); border-radius: 7px; background: var(--surface); }
.colorfield input[type=text] { grid-column: 1; font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12.5px; }

/* ---------- checks, palettes, media ---------- */

.checks { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 620px) { .checks { grid-template-columns: 1fr; } }
.checkcol ul { list-style: none; margin: 0; padding: 0; font-size: 12.5px; }
.checkcol li { padding: 3px 0; }
.checkcol li.pass { color: var(--ok); }
.checkcol li.fail { color: var(--bad); }

.palette { margin-bottom: 14px; }
.swatches { display: flex; flex-wrap: wrap; gap: 6px; }
.swatch {
  width: 86px; height: 52px; border-radius: 8px; border: 1px solid var(--line);
  display: flex; align-items: flex-end; justify-content: center; padding-bottom: 4px;
}
.swatch code { font-size: 10.5px; background: rgba(255,255,255,.88); color: #111; border: 0; }

.tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 14px; }
.tile { margin: 0; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.tile .thumb { aspect-ratio: 4 / 5; }
/* The picture itself, shown whole rather than cropped: a card is words, and a
   crop that eats the headline is worse than letterboxing. */
.tile .thumb img { width: 100%; height: 100%; object-fit: contain; display: block;
                   background: var(--bg, #0e1116); }
.tile figcaption { padding: 9px 11px; font-size: 12.5px; }
.tile figcaption span { display: block; color: var(--ink-muted); font-size: 11.5px; margin-top: 2px; }

.placeholder {
  display: grid; place-items: center;
  background: repeating-linear-gradient(45deg, var(--surface), var(--surface) 9px,
              color-mix(in srgb, var(--line) 55%, transparent) 9px,
              color-mix(in srgb, var(--line) 55%, transparent) 18px);
  color: var(--ink-muted); font-size: 11.5px; min-height: 100px;
}

.dot {
  display: inline-block; width: 13px; height: 13px; border-radius: 4px;
  border: 1px solid var(--line); margin-right: 6px; vertical-align: -2px;
}

.findings td:first-child { width: 1%; }
.findings td { font-size: 13px; }

ul.quotes { list-style: none; margin: 0 0 4px; padding: 0; }
ul.quotes li {
  border-left: 3px solid var(--accent); padding: 4px 0 4px 11px;
  margin-bottom: 7px; font-size: 13.5px; color: var(--ink-muted);
}

.empty { text-align: center; padding: 40px 20px; }
.empty .placeholder, .empty img {
  width: 100%; max-width: 420px; aspect-ratio: 16 / 9;
  margin: 0 auto 18px; border-radius: var(--radius); object-fit: cover;
}
.empty h3 { margin: 0 0 6px; font-size: 17px; }
.empty p { margin: 0 auto 14px; color: var(--ink-muted); max-width: 46ch; }

/* ---------- signing in ----------
   The sign-in page and the "connect an app" approval screen sit outside the
   app shell, because the shell draws a workspace switcher and there is
   nothing to switch between before anyone has signed in. They take their
   colours from the same theme, so they follow the skin like every other page.
   Nothing here resembles any other product's sign-in page; the layout is a
   centred card because that is what a single form wants. */
.auth-page {
  display: grid; place-items: center; min-height: 100vh;
  padding: 24px 16px; background: var(--surface);
}
.auth-card {
  width: 100%; max-width: 27rem; background: var(--card);
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 28px 26px 24px;
}
.auth-brand { margin-bottom: 18px; }
.auth-brand span { font-size: 19px; font-weight: 700; letter-spacing: -0.3px; }
.auth-brand em {
  display: block; font-style: normal; font-size: 12px; color: var(--ink-muted); margin-top: 2px;
}
.auth-h2 { margin: 0 0 8px; font-size: 17px; letter-spacing: -0.2px; }
.auth-card p { margin: 0 0 12px; font-size: 14px; }
.auth-fine { font-size: 12.5px; color: var(--ink-muted); }
/* Under the sign-in card rather than inside it, so it reads as site
   furniture and not as part of whichever form is on screen. */
.auth-legal { text-align: center; font-size: 12.5px; margin: 18px auto 32px; }
.auth-legal a { color: var(--ink-muted); }
.auth-err { color: var(--bad); font-weight: 600; }

.auth-tabs { display: flex; gap: 2px; margin-bottom: 18px; }
.auth-tabs a {
  flex: 1; text-align: center; padding: 8px 10px; font-size: 13px; font-weight: 600;
  border: 1px solid var(--line); color: var(--ink-muted); text-decoration: none;
}
.auth-tabs a:first-child { border-radius: var(--radius) 0 0 var(--radius); }
.auth-tabs a:last-child  { border-radius: 0 var(--radius) var(--radius) 0; }
.auth-tabs a.on { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }

.auth-label {
  display: block; font-size: 11.5px; font-weight: 700; color: var(--ink-muted);
  margin: 14px 0 4px; text-transform: uppercase; letter-spacing: 0.6px;
}
.auth-input {
  width: 100%; padding: 9px 11px; font: inherit; font-size: 14px;
  color: var(--ink); background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius);
}
.auth-input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.auth-btn {
  width: 100%; margin-top: 18px; padding: 11px 14px; font: inherit; font-size: 14px;
  font-weight: 600; cursor: pointer; color: var(--accent-text);
  background: var(--accent); border: 1px solid var(--accent);
  border-radius: var(--radius); text-align: center; text-decoration: none; display: block;
}
.auth-btn-quiet {
  margin-top: 8px; color: var(--ink); background: transparent; border-color: var(--line);
}
.auth-check { display: block; font-size: 13.5px; margin: 4px 0; }

.auth-google {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  padding: 10px 14px; font-size: 14px; font-weight: 600;
  color: var(--ink); background: var(--card);
  border: 1px solid var(--line); border-radius: var(--radius); text-decoration: none;
}
.auth-google:hover { background: var(--surface); text-decoration: none; }
.auth-or { position: relative; text-align: center; margin: 16px 0 4px; }
.auth-or::before {
  content: ''; position: absolute; top: 50%; left: 0; right: 0; height: 1px; background: var(--line);
}
.auth-or span {
  position: relative; padding: 0 10px; font-size: 12px;
  color: var(--ink-muted); background: var(--card);
}
.auth-warn {
  padding: 11px 13px; margin: 0 0 14px; font-size: 13px; border-radius: var(--radius);
  background: color-mix(in srgb, var(--warn) 12%, transparent); color: var(--warn);
}

/* who is signed in, at the foot of the sidebar */
.side-who {
  margin-top: auto; padding-top: 12px; border-top: 1px solid var(--line); font-size: 12px;
}
.side-who b { display: block; font-size: 12.5px; }
.side-who span { display: block; color: var(--ink-muted); word-break: break-all; }
/* The two flags are pills and have to shrink to their words. The rule above
   is more specific than .side-flag's own display, so they were stretching
   to the full width of the sidebar - barely visible in a 220-pixel column,
   obvious the moment the sidebar became a full-width drawer on a phone. */
.side-who .side-flag { display: inline-block; }
.side-who a { display: inline-block; margin-top: 6px; font-size: 12px; }
.side-flag {
  display: inline-block; margin-top: 5px; padding: 1px 6px; font-size: 10.5px;
  font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px;
  border-radius: 999px; background: color-mix(in srgb, var(--warn) 16%, transparent); color: var(--warn);
}
.side-flag-staff { background: color-mix(in srgb, var(--accent) 16%, transparent); color: var(--accent); }

/* the grant grid, where a tick is one workspace for one login */
.tbl td input[type=checkbox] { width: 17px; height: 17px; }
.plainlist { list-style: none; padding: 0; margin: 0; font-size: 13.5px; }
.plainlist li { padding: 7px 0; border-bottom: 1px solid var(--line); }
.plainlist li:last-child { border-bottom: 0; }
form.inline { display: inline; }

/* ---------------------------------------------------------------------------
   The composer, and the two views of what is scheduled. Added 2026-10-23.

   Hand-written like the rest of this file: no framework and no build step,
   because the server has no Node and cannot have one. The month grid is a
   plain CSS grid of seven columns, which is why it needs the width warning on
   a phone rather than a media query that squeezes it into something unusable.
   --------------------------------------------------------------------------- */

.composer .lbl { display:block; font-weight:600; margin:14px 0 6px; font-size:14px }
.composer .lbl:first-child { margin-top:0 }
.composer textarea, .composer input[type=text], .composer input[type=url],
.composer input[type=datetime-local], .composer input[type=number], .composer select,
.card form input[type=text], .card form input[type=url], .card form input[type=number],
.card form input[type=file], .card form select {
  width:100%; box-sizing:border-box; padding:9px 11px; border:1px solid var(--line);
  border-radius:calc(var(--radius) - 4px); background:var(--card); color:var(--ink);
  font:inherit;
}
.composer textarea { line-height:1.5; resize:vertical }
.counter { text-align:right; font-size:13px; color:var(--ink-muted); margin-top:4px }
.counter.low { color:var(--bad); font-weight:600 }
.tworow { display:grid; grid-template-columns:1fr 1fr; gap:18px }
.btnbar { display:flex; flex-wrap:wrap; gap:10px; align-items:center; margin:18px 0 6px }
.btnbar form { margin:0 }
.btn.warn { border-color:var(--warn); color:var(--warn) }
.btn.quiet { background:transparent; border-color:transparent; color:var(--ink-muted) }
.err-note { border-left:3px solid var(--bad) }
.warn-note { border-left:3px solid var(--warn) }

/* the platform picker */
.platgrid { display:grid; grid-template-columns:repeat(auto-fill,minmax(210px,1fr)); gap:8px }
.platpick {
  display:grid; grid-template-columns:auto 1fr; gap:4px 9px; align-items:baseline;
  border:1px solid var(--line); border-radius:calc(var(--radius) - 4px);
  padding:9px 11px; cursor:pointer;
}
.platpick.on { border-color:var(--accent); box-shadow:inset 0 0 0 1px var(--accent) }
.platpick input { margin:0; grid-row:1 / span 3 }
.platname { font-weight:600 }
.platlimit, .plat-flag { font-size:12px; color:var(--ink-muted); grid-column:2 }
.plat-flag { font-style:normal; display:block }
.plat-unproven { color:var(--warn) }
.plat-bad { color:var(--bad) }
.plat-warn { color:var(--warn) }
.plat-ok { color:var(--ok) }

/* the media picker: library rows and nothing else */
.medgrid { display:grid; grid-template-columns:repeat(auto-fill,minmax(150px,1fr)); gap:10px }
.medpick {
  display:grid; grid-template-columns:auto 1fr auto; gap:4px 8px; align-items:center;
  border:1px solid var(--line); border-radius:calc(var(--radius) - 4px); padding:8px; cursor:pointer;
}
.medpick.on { border-color:var(--accent) }
.medpick img { grid-column:1 / -1; width:100%; height:84px; object-fit:cover; border-radius:4px }
.medfilm {
  grid-column:1 / -1; height:84px; display:grid; place-items:center; border-radius:4px;
  background:var(--surface); color:var(--ink-muted); font-size:12px; letter-spacing:.08em;
  text-transform:uppercase;
}
.medname { font-size:13px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.medkind { font-size:11px; color:var(--ink-muted); grid-column:2 }
.medpos { width:52px !important; grid-row:2 / span 2; grid-column:3 }
.medmini { display:inline-block; font-size:12px; border:1px solid var(--line); border-radius:999px;
  padding:3px 9px; margin:0 5px 5px 0; cursor:pointer }
.medmini.on { border-color:var(--accent) }
.medmini input { margin-right:5px }

/* per-platform rewrites */
details.pcap > summary { cursor:pointer; font-weight:600 }
.pcap-row { border-top:1px solid var(--line); padding-top:12px; margin-top:12px }
.pmedia { margin-top:10px }

/* the month grid */
.monthbar { display:flex; gap:12px; align-items:center; flex-wrap:wrap; margin:14px 0 }
.monthbar strong { font-size:17px }
.cal { display:grid; grid-template-columns:repeat(7,1fr); gap:6px }
.cal .dow { font-size:12px; text-transform:uppercase; letter-spacing:.06em;
  color:var(--ink-muted); padding:2px 4px }
.cal .cell { position:relative; min-height:108px; border:1px solid var(--line);
  border-radius:calc(var(--radius) - 4px); background:var(--card); padding:4px }
.cal .cell.off { background:transparent; border-style:dashed; opacity:.4 }
.cal .cell.today { border-color:var(--accent); box-shadow:inset 0 0 0 1px var(--accent) }
.cal .dnum { font-size:12px; color:var(--ink-muted); padding:1px 3px }
.cal .pcard { display:block; text-decoration:none; color:inherit; background:var(--surface);
  border-radius:4px; padding:4px 5px; margin-bottom:4px; font-size:12px }
.cal .pcard:hover { outline:1px solid var(--accent) }
/* A slot Post For Me is already holding, which this product did not create and
   cannot change. Hatched and dimmed so a free day and a taken one are not the
   same shape at a glance, and no hover, because there is nothing to click. */
.cal .pcard.held { background:repeating-linear-gradient(135deg,
    var(--surface), var(--surface) 6px, transparent 6px, transparent 12px);
  border:1px dashed var(--line); opacity:.75; cursor:default }
.cal .pcard.held:hover { outline:0 }
/* Ours, with a time, that nobody is holding: it will not go out. */
.cal .pcard.limp { border-left:3px solid var(--bad) }
.daylist .rowline.held { opacity:.75 }
.cal .ptime { font-weight:600; margin-right:5px }
.cal .ptext { display:block; color:var(--ink-muted); margin-top:2px }
.cal .more { font-size:12px; padding:0 4px }
.cal .ghost-add { position:absolute; right:4px; top:2px; width:20px; height:20px;
  display:grid; place-items:center; border-radius:4px; color:var(--ink-muted);
  text-decoration:none; opacity:0 }
.cal .cell:hover .ghost-add { opacity:1; background:var(--surface) }
.mobile-hint { display:none; font-size:14px }

/* the list of the same month */
.daylist .rowline { display:flex; gap:9px; align-items:baseline; flex-wrap:wrap;
  padding:6px 0; border-top:1px solid var(--line) }
.daylist .rowline:first-child { border-top:0 }
.daylist .rtime { font-weight:600; min-width:46px }

@media (max-width:860px) {
  .tworow { grid-template-columns:1fr }
  .cal { display:none }
  .mobile-hint { display:block }
}

/* ---------- the results dashboard ----------
   Built 2026-10-23. Two things here earn their lines rather than being
   decoration: `.nodata` is the dash that stands for "the platform does not
   report this number", which has to look different from a 0 at a glance, and
   `.num` right-aligns every figure so a column can be read down. */

.rfilters { display:flex; flex-direction:column; gap:8px; margin-bottom:14px }
.rchips { display:flex; gap:6px; flex-wrap:wrap; align-items:center }
.rchip {
  display:inline-block; padding:4px 11px; border:1px solid var(--line);
  border-radius:999px; font-size:12.5px; color:var(--ink-muted);
  background:var(--card); white-space:nowrap;
}
.rchip:hover { text-decoration:none; color:var(--ink); border-color:var(--ink-muted) }
.rchip.on { color:var(--ink); border-color:var(--accent); font-weight:600;
  background:color-mix(in srgb, var(--accent) 12%, var(--card)) }
.rchip.export { border-style:dashed }
.rsep { width:1px; height:18px; background:var(--line); margin:0 4px }

.rstats { display:grid; grid-template-columns:repeat(auto-fit, minmax(118px, 1fr));
  gap:10px; margin:14px 0 }
.rstat { background:var(--card); border:1px solid var(--line);
  border-radius:var(--radius); padding:12px 14px }
.rstat .n { display:block; font-size:25px; font-weight:800; letter-spacing:-0.8px;
  line-height:1.15 }
.rstat .l { display:block; font-size:12px; color:var(--ink-muted); margin-top:2px }

/* A dash, not a zero. Deliberately quiet, so it reads as absent rather than
   as a number that happens to be small. */
.nodata { color:var(--ink-muted); opacity:0.55; font-weight:400 }

.tablewrap { overflow-x:auto }
table th.num, table td.num { text-align:right; white-space:nowrap }
table td.num, table th.num { width:1% }
.rsub { display:block; font-size:11.5px; color:var(--ink-muted); margin-top:2px }
.rcap { max-width:430px }

/* "Start from this post", on every post in the best-posts table.
   It sits inside `.rsub`, which is deliberately quiet, so it takes its own
   colour and weight back - a link that inherits muted grey reads as another
   piece of the timestamp. The padding is there to make it worth tapping on a
   phone, where this is the main thing on that row somebody wants to press. */
.rmore { color:var(--accent); font-weight:600; font-size:12.5px;
  display:block; padding:4px 0 1px }

/* The post a run is being written from, quoted on the write screen so the
   person can see which one they clicked before anything is written. */
.seedpost { margin:0 0 12px; padding:10px 14px; border-left:3px solid var(--accent);
  background:var(--surface); border-radius:0 6px 6px 0; font-size:14.5px;
  line-height:1.5; white-space:normal; overflow-wrap:anywhere }
.rtrend { font-size:22px; font-weight:700; margin:4px 0 0 }
.rtrend.up { color:var(--ok) }
.rtrend.down { color:var(--bad) }

/* ---------- the following, per account ----------
   Added 2026-10-26 with follower history. `.spark` inherits currentColor on
   purpose: the line and its dot are drawn in the text colour of the cell, so
   there is no second set of colours to keep in step with the dark theme. */

.rdelta { font-size:15px; font-weight:600; opacity:0.85 }
.fup   { color:var(--ok) }
.fdown { color:var(--bad) }
.fspark { width:1%; padding-right:4px }
.spark { display:block; color:var(--accent); opacity:0.9 }
/* The sentence that stands where a number would be. Narrow enough to read as
   a note rather than as data, which is what it is. */
.fwhy { display:block; font-size:12.5px; max-width:340px; line-height:1.45;
         white-space:normal }
/* A reading older than yesterday. Quiet rather than alarming - it is a number
   that needs checking, not an error - but it must not read as "Today". */
.fstale { color:var(--warn, #d9a441) }

/* A rendered card, shown on the post screen. Max-width rather than a fixed one,
   so a narrow column scales it down instead of pushing the page sideways. */
.cardshot { display:block; width:100%; max-width:270px; height:auto; border-radius:6px;
            border:1px solid var(--line, rgba(255,255,255,.12)) }

/* Every slide of a carousel, in posting order, under the cover. Small on
   purpose: these are there to show how many there are and roughly what they
   look like, not to be read. */
.cardstrips { display:flex; flex-wrap:wrap; gap:8px }
.cardstrip { width:64px; height:auto; border-radius:4px;
             border:1px solid var(--line, rgba(255,255,255,.12)) }

/* The plan screen: what you are on, what is left, and what the tiers cost.
   Every number on it is read from plan_limits and usage_meter, so nothing here
   assumes a particular count or a particular price. */
.planbars { display: grid; gap: 14px; margin: 14px 0 4px; }
.planbar { display: grid; gap: 2px; }
.planbar b { font-size: 13px; }
.planbar span { font-size: 13px; }
.planbar .meter { margin: 4px 0 2px; }
.card.plan { display: flex; flex-direction: column; gap: 8px; }
.card.plan.cur { border-color: var(--accent); }
.card.plan .price { margin: 0; font-size: 26px; font-weight: 700; letter-spacing: -0.5px; }
.card.plan .price small { font-size: 13px; font-weight: 500; color: var(--ink-muted); }
.card.plan ul { margin: 6px 0 0; padding-left: 18px; line-height: 1.6; font-size: 13.5px; }
.card.plan form { margin-top: auto; display: flex; gap: 8px; flex-wrap: wrap; }
.card.plan .tag { margin-top: auto; font-size: 12.5px; font-weight: 600; color: var(--accent); }
.stack { display: grid; gap: 14px; margin-top: 14px; }
.stack label { display: grid; gap: 4px; font-size: 13px; font-weight: 600; }
.stack label .note { font-weight: 400; margin: 0; }
.stack button { justify-self: start; }


/* ---------- setting up, the first time ----------
   The strip under the page heading that says where a new account is up to.
   It is drawn by src/FirstRun.php from what is actually in the database and
   disappears the moment there is nothing left to do, so most accounts never
   see it and no account has a flag saying it is finished.

   The pills are the live console's pattern, kept deliberately: it has been
   in front of real customers, it is small, and a row of short words reads
   as progress in a way a list of sentences does not. */

.firstrun { margin-bottom: 18px; }
.setup-steps {
  list-style: none; display: flex; flex-wrap: wrap; gap: 8px; padding: 0; margin: 0 0 10px;
}
.setup-steps li {
  display: flex; align-items: center; gap: 8px;
  background: var(--card); border: 1px solid var(--line); border-radius: 99px;
  padding: 6px 15px 6px 7px; font-size: 13px; font-weight: 600; color: var(--ink-muted);
}
.setup-steps li i {
  width: 20px; height: 20px; border-radius: 50%; flex: none;
  display: grid; place-items: center; font-style: normal; font-size: 11px; font-weight: 700;
  background: var(--surface); color: var(--ink-muted);
}
.setup-steps li.done i { background: var(--ok); color: var(--accent-text); }
.setup-steps li.now { border-color: var(--accent); color: var(--ink); }
.setup-steps li.now i { background: var(--accent); color: var(--accent-text); }
.setup-steps li.now a { color: var(--ink); }
.setup-steps li.now a:hover { text-decoration: none; }

.firstrun-why {
  margin: 0; font-size: 13.5px; color: var(--ink-muted); max-width: 62ch;
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
}

/* ====================================================================
   PHONE WIDTHS LIVE AT THE END OF THIS FILE, ON PURPOSE.

   They sat up beside the shell rules at first, and half of them did
   nothing: a media query carries no extra weight, so `.facts` two
   hundred lines further down simply won. Anything width-conditional
   goes below every rule it has to beat.
   ==================================================================== */

/* ---------- the shell below 860 pixels ----------
   Rewritten 2026-10-27, because this is where the customer actually is: a
   coach is not at a desk.

   What it used to do was turn the sidebar into a wrapping row of fourteen
   links. Measured on staging at 375 wide, that row plus the workspace
   switcher and the who-is-signed-in block pushed <main> to y=522 on an
   812-pixel screen, on every signed-in screen. Two thirds of the first
   thing a person sees was navigation.

   Now the sidebar is a bar - the logo and one Menu button - and the rest
   folds behind it. The folding is gated on `html.js`, which a line in the
   <head> adds, so with scripting off nothing folds and the page is what it
   was before the button existed. */
@media (max-width: 860px) {
  /* Two rows now rather than two columns, and the second one takes the
     slack. Without `auto 1fr` the grid shares the leftover height of
     `min-height:100vh` between both rows, so on a short page - Topics with
     nothing in it - the bar quietly grew to 267 pixels and pushed the
     heading two thirds of the way down the screen. */
  body.app { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }

  .side {
    position: sticky; top: 0; z-index: 30;
    height: auto; max-height: 100vh; overflow-y: auto;
    flex-direction: column; align-items: stretch; gap: 12px;
    padding: 10px 16px;
    border-right: 0; border-bottom: 1px solid var(--line);
  }
  /* Sticky inside the drawer, which scrolls: fourteen links are taller
     than a phone, and the way out has to still be there at the bottom of
     them. */
  .sidetop {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    position: sticky; top: -10px; z-index: 2;
    background: var(--card); padding: 10px 0; margin: -10px 0 0;
  }
  .navbtn { display: inline-flex; }
  body.nav-open .navbtn {
    background: var(--accent); color: var(--accent-text); border-color: transparent;
  }

  html.js .side > :not(.sidetop) { display: none; }
  html.js body.nav-open .side > .ws-switch { display: block; }
  html.js body.nav-open .side > .sidenav { display: flex; }
  html.js body.nav-open .side > .side-who,
  html.js body.nav-open .side > .side-legal,
  html.js body.nav-open .side > .side-foot { display: block; }

  /* Open, it is a list rather than a wrapping row. Fourteen links read
     down far better than across, and 11 pixels of padding makes each one a
     finger target instead of a mouse target. */
  .sidenav { flex-direction: column; gap: 2px; }
  .sidenav a { padding: 11px 10px; font-size: 15px; }

  /* These three travelled to the bottom of a full-height sidebar on their
     auto margins. There is no bottom to travel to in a drawer. */
  .side-who, .side-legal, .side-foot { margin-top: 0; }
  .side-who { padding-top: 10px; }
  /* Across a full-width drawer the flag and the way out end up on one
     line, which reads as one control. */
  .side-who a { display: block; }

  main, .pagehead { padding-left: 16px; padding-right: 16px; }
}

/* ---------- phones proper ----------
   375 pixels across, less a 16-pixel gutter each side, which is what an
   iPhone SE or a mini actually gives you. */
@media (max-width: 600px) {
  .pagehead { flex-wrap: wrap; gap: 10px; padding-top: 14px; padding-bottom: 14px; }
  .pagehead h1 { font-size: 18px; }
  .pagehead .actions { display: flex; flex-wrap: wrap; gap: 8px; width: 100%; }
  main { padding-top: 18px; }

  /* 16 pixels is not a design choice. Under it, Safari zooms the whole page
     in when a field takes focus, and the person is then reading a
     sideways-scrolling form they never asked for. */
  input[type=text], input[type=url], input[type=number], input[type=email],
  input[type=password], select, textarea, .auth-input { font-size: 16px; }

  /* A table too wide to fit scrolls inside itself instead of taking the
     page sideways with it. Measured before this: the settings table made
     the page 540 pixels wide and the "who can sign in" table 568, on a
     375-pixel screen, which cut whole sentences off the right-hand edge of
     every card on those pages. Tables already sitting in a .tablewrap keep
     the scroller they have. */
  main table { display: block; width: 100%; overflow-x: auto; }
  .tablewrap table { display: table; }

  /* The scroller above only does anything if something stops the table
     shrinking to fit the screen, and nothing did, so it never scrolled -
     it squeezed. Every column fell to its narrowest and the words came
     apart with it. Opened at 375 pixels on 2026-10-30: the queue read one
     word per line, five lines to say "Sat 31 Oct 16:27 UTC"; the connected
     accounts table on Settings broke "facebook" into "faceboo" and "k" and
     spread one Post For Me id down eleven lines of four characters. A floor
     under each cell puts the words back together and lets the table do what
     the rule above meant: scroll inside itself. Number columns and the last
     column keep the tight sizing they already have, so this does not widen
     a table that was already readable. */
  main table th:not(.num):not(:last-child),
  main table td:not(.num):not(:last-child) { min-width: 7rem; }

  /* And the one cell carrying a sentence gets more than the floor, or the
     queue still reads three words to a line and a row stands 195 pixels
     tall to say one thing. A link is the only thing in this product's
     tables that holds a sentence, so it is the handle to grab. 87 pixels
     a row after this. A browser too old for :has() ignores the line and
     keeps the floor above, which is still the right way up. */
  main table td:not(.num):not(:last-child):has(> a) { min-width: 13rem; }

  .facts { grid-template-columns: 1fr; gap: 0; }
  .facts dt { margin-top: 8px; }

  /* A URL or an identifier in a code span has nowhere to break, and one of
     them is enough to carry the whole page sideways. Inside a table it has
     a scroller to go sideways in, so there it keeps its words whole: this
     rule is what turned a platform name into "faceboo" and "k". */
  code { overflow-wrap: anywhere; }
  main table code { overflow-wrap: normal; }
  .formbar { flex-wrap: wrap; }
  .banner-act { display: inline-block; margin-top: 6px; }
}
