/* Mobile first. No build step, no framework. Read top to bottom.
   The goal here is that someone who has never seen the code can tell what
   each control does and what it will change. */

:root {
  --navy: #0b1b2b;
  --ink: #16232f;
  --paper: #f4f6f8;
  --card: #ffffff;
  --line: #dfe5ec;
  --muted: #667585;
  --good: #1c7a4f;
  --good-bg: #e6f4ec;
  --warn: #8a5a00;
  --warn-bg: #fdf3dd;
  --bad: #9c2230;
  --bad-bg: #fbe9eb;
  --accent: #14568f;
  --accent-soft: #e8f0f9;
  --radius: 12px;
  --shadow: 0 1px 2px rgba(16, 34, 51, .06), 0 4px 14px rgba(16, 34, 51, .05);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font: 16px/1.55 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: var(--ink);
  background: var(--paper);
  -webkit-text-size-adjust: 100%;
}

main { padding: 1rem 1rem 4rem; max-width: 760px; margin: 0 auto; }

h1 { font-size: 1.5rem; margin: 0 0 .25rem; letter-spacing: -.01em; }
h2 { font-size: 1.15rem; margin: 0; letter-spacing: -.01em; }
h3 { font-size: 1rem; margin: 0; }
a { color: var(--accent); }

.lede { color: var(--muted); margin: .1rem 0 0; font-size: .95rem; }
.pagehead { margin-bottom: 1.1rem; }
.section-head { margin: 1.75rem 0 .5rem; }
.hint { color: var(--muted); font-size: .85rem; margin: .3rem 0 0; }
/* A missed slot is the one hint on the schedule that is not just guidance. */
.hint.warn { color: #6b4600; background: var(--warn-bg); padding: .35rem .5rem; border-radius: 4px; }
.quiet { color: var(--muted); }
/* When a post entered review, was approved, and left. Two columns so the times
   line up down the page and a gap in the sequence is visible at a glance. */
.stamps { display: grid; grid-template-columns: auto 1fr; gap: .15rem .6rem;
          margin: .5rem 0 0; font-size: .82rem; color: var(--muted); }
.stamps dt { font-weight: 600; }
.stamps dd { margin: 0; }
.note { color: var(--muted); font-size: .85rem; margin-top: 1rem; }

/* ---- Top bar ---- */

/* The bar wraps rather than scrolling sideways. A menu item hidden behind a
   horizontal scroll may as well not exist on a phone, and "Add a post" was
   landing 130px off the right edge of a 375px screen. */
.bar {
  display: flex; align-items: center; gap: .5rem .75rem; flex-wrap: wrap;
  padding: .55rem 1rem; padding-top: max(.55rem, env(safe-area-inset-top));
  background: var(--navy); color: #fff;
  position: sticky; top: 0; z-index: 20;
}
.bar .brand { font-weight: 700; font-size: .9rem; letter-spacing: .01em; white-space: nowrap; order: 0; }
.bar nav { display: flex; gap: .4rem .85rem; flex-wrap: wrap; align-items: center;
  order: 2; flex: 1 1 100%; }
.bar a { color: #b9c7d6; text-decoration: none; font-size: .9rem; white-space: nowrap; padding: .15rem 0; }
.bar a.on { color: #fff; box-shadow: inset 0 -2px 0 #fff; }
.bar .who { font-size: .8rem; color: #8fa1b4; white-space: nowrap; order: 1; margin-left: auto; }

/* ---- Flash and banners ---- */

.flash {
  display: flex; align-items: flex-start; gap: .75rem;
  max-width: 760px; margin: .75rem auto 0; padding: .75rem 1rem;
  background: var(--good-bg); border: 1px solid #b6ddc6; border-radius: var(--radius);
  color: #14502f; font-size: .9rem;
}
.flash span { flex: 1; }
.flash-close { background: none; border: 0; font-size: 1.2rem; line-height: 1; color: inherit;
  cursor: pointer; padding: 0 .2rem; min-height: auto; }

.banner { padding: .85rem 1rem; border-radius: var(--radius); margin: 0 0 1.1rem; font-size: .9rem; }
.banner strong { display: block; margin-bottom: .15rem; }
.banner.shadow { background: var(--warn-bg); border: 1px solid #e8cf92; color: #6b4600; }
.banner.info { background: var(--accent-soft); border: 1px solid #b9cfe6; color: #123f68; }
.banner.danger { background: var(--bad-bg); border: 1px solid #e3aeb5; color: #7d1a26; }
.banner ul { margin: .5rem 0 .25rem 1rem; padding: 0; }

.notice { padding: .5rem .7rem; border-radius: 8px; font-size: .85rem; margin: .5rem 0; }
.notice.warn { background: var(--warn-bg); color: #6b4600; }
.notice.small { display: block; margin: .35rem 0 0; }
/* The claims the model made on its own. Kept legible line by line, because the
   reviewer is meant to read each one rather than skim a paragraph. */
.notice.claims { white-space: pre-wrap; line-height: 1.6; }
.banner.warnbox { background: var(--warn-bg); border: 1px solid #e8cf92; color: #6b4600; }
.banner.warnbox ul { margin: .5rem 0 0 1.1rem; padding: 0; }

.empty-state {
  background: var(--card); border: 1px dashed var(--line); border-radius: var(--radius);
  padding: 2rem 1.25rem; text-align: center; color: var(--muted);
}
.empty-state h2 { color: var(--ink); margin-bottom: .4rem; }

/* ---- Idea card ---- */

.idea {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  margin-bottom: 1.25rem; overflow: hidden; box-shadow: var(--shadow);
}
.idea-head { padding: 1rem; background: linear-gradient(180deg, #fbfcfd, #f5f7fa); border-bottom: 1px solid var(--line); }
.idea-head h2 { margin-bottom: .5rem; }

.tags { display: flex; gap: .4rem; flex-wrap: wrap; }
.tag {
  font-size: .72rem; font-weight: 600; padding: .2rem .55rem; border-radius: 999px;
  background: #eef2f6; color: #47586a; white-space: nowrap;
}
.tag.tool { background: var(--accent-soft); color: #14568f; }
.tag.quiet { background: transparent; color: var(--muted); font-weight: 400; padding-left: .1rem; }
/* A post for a particular day. It expires the day after, so the date is the most
   important thing on the card — a Memorial Day post approved on the 26th is waste. */
.tag.dated { background: var(--warn-bg); color: #6b4600; }

/* ---- One platform's draft ---- */

.draft { padding: 1rem; border-top: 1px solid var(--line); }
.draft:first-of-type { border-top: 0; }
.draft-head { display: flex; align-items: center; gap: .5rem; }
.status-meaning { color: var(--muted); font-size: .85rem; margin: .15rem 0 .75rem; }

.plat-instagram { border-left: 3px solid #c1358a; }
.plat-facebook  { border-left: 3px solid #1877f2; }
.plat-linkedin  { border-left: 3px solid #0a66c2; }

.pill {
  font-size: .7rem; font-weight: 700; text-transform: uppercase; letter-spacing: .03em;
  padding: .18rem .5rem; border-radius: 999px; white-space: nowrap;
}
.pill.good { background: var(--good-bg); color: var(--good); }
.pill.wait { background: var(--warn-bg); color: var(--warn); }
.pill.bad  { background: var(--bad-bg);  color: var(--bad); }
.pill.off  { background: #eceff3; color: var(--muted); }

/* ---- Journey strip ---- */

.journey { display: flex; list-style: none; margin: 0 0 1rem; padding: 0; gap: .25rem; }
.journey li {
  flex: 1; text-align: center; font-size: .68rem; font-weight: 600; color: var(--muted);
  padding: .3rem .2rem; background: #eef1f5; border-radius: 6px; text-transform: uppercase;
  letter-spacing: .02em;
}
.journey li.done { background: var(--good-bg); color: var(--good); }
.journey li.now  { background: var(--accent); color: #fff; }
.journey.stalled li.now { background: var(--bad); }

/* ---- Media ---- */

.section-label {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--muted); margin: 1rem 0 .45rem; font-weight: 700;
}

.media { display: flex; gap: .6rem; overflow-x: auto; padding-bottom: .5rem; scroll-snap-type: x mandatory; }
.media figure { margin: 0; flex: 0 0 62%; max-width: 250px; scroll-snap-align: start; }
.media img { width: 100%; border-radius: 8px; display: block; background: var(--navy); }
.media figcaption { font-size: .78rem; margin-top: .4rem; }
.media .role { display: block; font-weight: 600; }
.media .result { display: block; color: var(--muted); }

.fit { display: flex; gap: .25rem; margin-top: .4rem; flex-wrap: wrap; }
.fit button {
  font-size: .72rem; padding: .3rem .5rem; min-height: 34px;
  border: 1px solid var(--line); background: #fff; border-radius: 6px; color: var(--muted); cursor: pointer;
}
.fit button.on { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }

.explain { margin-top: .5rem; font-size: .85rem; }
.explain summary { color: var(--accent); cursor: pointer; }
.explain p { color: var(--muted); margin: .5rem 0 0; }

.collab { margin: 0; font-size: .88rem; }
.handle { display: inline-block; background: #eef2f6; padding: .15rem .5rem;
  border-radius: 999px; margin-right: .3rem; font-weight: 600; }

/* ---- Caption ---- */

textarea {
  width: 100%; font: inherit; padding: .7rem; border: 1px solid var(--line);
  border-radius: 8px; resize: vertical; background: #fff; color: var(--ink);
}
textarea:focus { outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent); }

.counter { font-size: .78rem; color: var(--muted); margin: .35rem 0 0; }
.counter.tight { color: var(--warn); font-weight: 600; }
.counter.over { color: var(--bad); font-weight: 700; }

.actions { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: .75rem; }
.consequence { font-size: .82rem; color: var(--muted); margin: .5rem 0 0; }

/* ---- Buttons ---- */

button {
  font: inherit; padding: .6rem 1rem; border-radius: 8px;
  border: 1px solid var(--line); background: #fff; color: var(--ink); cursor: pointer;
  min-height: 44px; /* thumbs, on a boat, in the sun */
}
button:hover { border-color: #b9c4d0; }
button.primary { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }
button.primary:hover { background: #10456f; }
button.danger { background: #fff; border-color: #dda6ad; color: var(--bad); }
button.danger:hover { background: var(--bad-bg); }
button.big { width: 100%; font-size: 1.05rem; min-height: 54px; }
button[disabled] { background: #eef1f5; color: var(--muted); cursor: not-allowed; border-color: var(--line); }
button.toggle { min-height: 36px; padding: .25rem .8rem; font-size: .8rem; font-weight: 600; }
button.toggle.on { background: var(--good); border-color: var(--good); color: #fff; }

form.inline { display: inline-flex; gap: .35rem; align-items: center; }
form.inline button { min-height: 38px; padding: .35rem .7rem; font-size: .85rem; }

/* ---- Schedule ---- */

.day {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: .85rem 1rem; margin-bottom: .75rem; box-shadow: var(--shadow);
}
.day.empty { background: #fafbfc; box-shadow: none; }
.day > header { display: flex; align-items: baseline; gap: .5rem; margin-bottom: .35rem; }
.daysub { color: var(--muted); font-size: .85rem; }

.row { display: flex; gap: .75rem; align-items: flex-start; padding: .7rem 0;
  border-top: 1px solid var(--line); flex-wrap: wrap; }
.day .row:first-of-type { border-top: 0; }
.row .thumb { width: 52px; height: 65px; object-fit: cover; border-radius: 6px; background: var(--navy); flex: none; }
.row .thumb.placeholder { background: #e6eaef; }
.row .meta { flex: 1 1 55%; min-width: 180px; font-size: .9rem; display: flex; flex-direction: column; gap: .1rem; }
.row .meta .sub { color: var(--muted); font-size: .82rem; }
.row .meta time { color: var(--ink); font-size: .82rem; font-weight: 600; }
.row .state { display: flex; flex-direction: column; gap: .35rem; align-items: flex-start; }
.rowactions { display: flex; gap: .35rem; }
.row.locked { background: #f6f8fa; border-radius: 8px; padding: .7rem; }
.row.reserved { background: var(--accent-soft); border-radius: 8px; padding: .7rem; }
.gap { color: var(--muted); font-size: .85rem; margin: .2rem 0; }
.slotform { flex-wrap: wrap; }
.slotform input { font: inherit; padding: .5rem; border: 1px solid var(--line); border-radius: 8px; }

.viewlink { font-size: .82rem; text-decoration: none; }
.viewlink:hover { text-decoration: underline; }
.backlink { font-size: .88rem; margin: 0 0 .5rem; }
.backlink a { text-decoration: none; }

/* The caption exactly as written, newlines and all. */
.caption-readout { white-space: pre-wrap; background: #f7f9fb; border: 1px solid var(--line);
  border-radius: 8px; padding: .8rem; font-size: .95rem; line-height: 1.55; }

.facts { display: grid; grid-template-columns: max-content 1fr; gap: .3rem .9rem;
  margin: 0; font-size: .87rem; }
.facts dt { color: var(--muted); }
.facts dd { margin: 0; word-break: break-word; }

/* ---- History ---- */

.history { list-style: none; padding: 0; margin: 0; }
.history li {
  background: var(--card); border: 1px solid var(--line); border-left: 3px solid var(--line);
  border-radius: var(--radius); padding: .8rem 1rem; margin-bottom: .6rem; box-shadow: var(--shadow);
}
.history li.tone-good { border-left-color: var(--good); }
.history li.tone-wait { border-left-color: var(--warn); }
.history li.tone-bad  { border-left-color: var(--bad); }
.hrow { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.history .sub { color: var(--muted); font-size: .82rem; margin: .25rem 0 0; }
.history .meaning { font-size: .88rem; margin: .35rem 0 0; }
.history .detail { font-size: .8rem; color: var(--muted); margin: .35rem 0 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; word-break: break-word; }

/* ---- Tables ---- */

table { width: 100%; border-collapse: collapse; font-size: .85rem;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; display: block; overflow-x: auto; }
th { text-align: left; font-size: .72rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted); background: #f7f9fb; }
th, td { padding: .55rem .7rem; border-bottom: 1px solid var(--line); white-space: nowrap; }
tr:last-child td { border-bottom: 0; }
td.detail { white-space: normal; color: var(--muted); font-size: .8rem; }

/* ---- Settings ---- */

.killswitch { border: 2px solid; border-radius: var(--radius); padding: 1.1rem;
  background: var(--card); box-shadow: var(--shadow); }
.killswitch.on { border-color: var(--good); }
.killswitch.off { border-color: var(--warn); }
.killswitch .state { font-weight: 600; margin: .35rem 0 .1rem; }
.killswitch form { margin-top: .9rem; }

.heartbeat { list-style: none; padding: 0; margin: 0; }
.heartbeat li { padding: .55rem .8rem; border-radius: 8px; margin-bottom: .35rem;
  background: var(--card); border: 1px solid var(--line); font-size: .88rem; }
.heartbeat li.bad { background: var(--bad-bg); border-color: #e3aeb5; color: var(--bad); font-weight: 600; }

/* ---- Add a post form ---- */

.btnlink { display: inline-block; font-size: .88rem; text-decoration: none; padding: .5rem .9rem;
  border: 1px solid var(--line); border-radius: 8px; background: #fff; color: var(--accent); }
.btnlink:hover { border-color: var(--accent); }

.card-form { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.1rem; box-shadow: var(--shadow); margin-bottom: 1rem; }
.card-form select { width: 100%; font: inherit; padding: .6rem; border: 1px solid var(--line);
  border-radius: 8px; background: #fff; }

/* The reason for the post, and the one extra thing that reason needs.
   Hidden only once the script has said it can do the showing — with scripting
   off every follow-up field stays on screen and labelled, and the server reads
   only the one the chosen angle asks for. */
[data-angle-ready] .followup:not(.on) { display: none; }
.followup { animation: followup-in .16s ease-out; }
@keyframes followup-in { from { opacity: 0; transform: translateY(-3px); } }
@media (prefers-reduced-motion: reduce) { .followup { animation: none; } }

/* Two ways to build a post, side by side rather than buried in a menu. */
.tabs { display: flex; gap: .3rem; margin-bottom: 1rem; border-bottom: 1px solid var(--line); }
.tabs a { padding: .55rem .9rem; text-decoration: none; color: var(--muted); font-size: .9rem;
  border: 1px solid transparent; border-bottom: 0; border-radius: 8px 8px 0 0; margin-bottom: -1px; }
.tabs a.on { background: var(--card); border-color: var(--line); color: var(--ink); font-weight: 600; }
.tabs a:hover { color: var(--ink); }

.boatcard { background: var(--accent-soft); border-radius: 8px; padding: .8rem 1rem; margin-bottom: 1.2rem; }
.boatcard h2 { margin: 0 0 .1rem; }
.boatcard .sub { margin: 0; font-size: .88rem; color: #123f68; }

/* Photo chooser. The number shows the order they'll appear in. */
.photogrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: .5rem; }
.photo { position: relative; margin: 0; cursor: pointer; display: block; }
.photo input { position: absolute; opacity: 0; width: 0; height: 0; }
.photo img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 8px;
  display: block; background: var(--navy); outline: 3px solid transparent; outline-offset: -3px;
  transition: outline-color .12s ease, opacity .12s ease; opacity: .62; }
.photo input:checked + img { outline-color: var(--accent); opacity: 1; }
.photo input:focus-visible + img { outline-color: var(--warn); }
.photo .tick { position: absolute; top: .3rem; left: .3rem; min-width: 1.35rem; height: 1.35rem;
  border-radius: 999px; background: rgba(16, 34, 51, .55); color: #fff; font-size: .7rem;
  font-weight: 700; display: none; align-items: center; justify-content: center; }
.photo input:checked ~ .tick { display: inline-flex; background: var(--accent); }
/* What a picture is, and whether it has been out before. The yards send files
   called `GS44_0117_RGB.jpg`, so the folder it was filed in is the only thing
   that says what it shows — and that is also what decides whether she may be
   cropped, which is worth seeing before you pick. */
.photo .cap { position: absolute; left: .3rem; right: .3rem; bottom: .3rem;
  background: rgba(16, 34, 51, .68); color: #fff; font-size: .6rem; font-weight: 600;
  line-height: 1.15; padding: .22rem .35rem; border-radius: 5px; text-align: center;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* A button that has started slow work. The spinner is on the button rather than
   over the page, so it is obvious which action is running. */
button.busy { position: relative; padding-left: 2.2rem; cursor: progress; }
button.busy::before {
  content: ""; position: absolute; left: .85rem; top: 50%; width: .85rem; height: .85rem;
  margin-top: -.45rem; border-radius: 50%;
  border: 2px solid currentColor; border-right-color: transparent;
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  button.busy::before { animation-duration: 2.4s; }
}
button[disabled].busy { opacity: 1; color: var(--muted); }

.writerow { display: flex; gap: .75rem; align-items: center; flex-wrap: wrap; margin-bottom: 1.2rem; }
.writerow .hint { flex: 1 1 240px; margin: 0; }
.rule { border: 0; border-top: 1px solid var(--line); margin: 1.4rem 0; }
.field { display: block; margin-bottom: 1.4rem; }
.field .label { display: block; font-weight: 600; margin-bottom: .1rem; }
.field .label em { font-weight: 400; color: var(--muted); font-style: normal; }
.field .hint { display: block; margin: 0 0 .45rem; }
.field input[type="text"], .field input[type="file"], .field textarea {
  width: 100%; font: inherit; padding: .6rem; border: 1px solid var(--line);
  border-radius: 8px; background: #fff; }
.checks { display: flex; gap: 1rem; flex-wrap: wrap; }
.check { display: inline-flex; align-items: center; gap: .4rem; font-weight: 400;
  margin-top: .5rem; cursor: pointer; }
.check input { width: auto; min-height: 20px; }

/* ---- Login ---- */

.login { max-width: 380px; margin: 3rem auto; padding: 1.5rem;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); }
.login h1 { text-align: center; margin-bottom: 1.25rem; font-size: 1.25rem; }
/* The mark sits above the name, on a dark panel.
   The logo is white with a transparent background — it is drawn to sit on a
   photograph or the foot of a broker card, and on the white login panel it is
   invisible. The band is what makes it legible, not decoration. Capped by
   height so a wide logo and a square one carry the same weight. */
.loginmark { display: block; width: 100%; max-height: 96px; object-fit: contain;
             background: #0b1b2b; border-radius: 6px; padding: 1rem .9rem;
             margin: 0 0 1.15rem; }
.login label { display: block; margin-bottom: .85rem; font-size: .9rem; font-weight: 600; }
.login select, .login input { width: 100%; font: inherit; font-weight: 400; padding: .65rem;
  border: 1px solid var(--line); border-radius: 8px; margin-top: .3rem; background: #fff; }
.login button { width: 100%; margin-top: .3rem; }
.error { color: var(--bad); font-weight: 600; }

/* ---- Toasts, pending and offline states, all set by app.js ---- */

.toasts { position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  display: flex; flex-direction: column; align-items: center; gap: .4rem;
  padding: 0 1rem 1rem; padding-bottom: max(1rem, env(safe-area-inset-bottom)); pointer-events: none; }
.toast { pointer-events: auto; cursor: pointer; max-width: 520px; width: 100%;
  background: var(--ink); color: #fff; padding: .7rem 1rem; border-radius: 10px;
  font-size: .9rem; box-shadow: 0 6px 24px rgba(16, 34, 51, .28);
  animation: toast-in .18s ease-out; }
.toast.going { opacity: 0; transition: opacity .55s ease; }
@keyframes toast-in { from { transform: translateY(8px); opacity: 0; } to { transform: none; opacity: 1; } }

/* A card that just changed gets a brief outline, so a tap that updates one
   part of a long page is visible without hunting for what moved. */
.just-changed { animation: settle 1.2s ease-out; }
@keyframes settle {
  0%   { box-shadow: inset 0 0 0 2px var(--accent); background: var(--accent-soft); }
  100% { box-shadow: inset 0 0 0 2px transparent; background: transparent; }
}

[data-pending] { opacity: .5; pointer-events: none; }
.offline-note { position: fixed; bottom: 0; left: 0; right: 0; padding: .7rem;
  background: var(--warn); color: #fff; text-align: center; font-size: .85rem; z-index: 30; }

@media (min-width: 620px) {
  .media figure { flex-basis: 40%; }

  /* Room for one row again: brand, the four views, the action, then the name. */
  .bar nav { order: 1; flex: 1 1 auto; }
  .bar .who { order: 2; margin-left: 0; }
}

/* Choosing a different photograph. The grid is the one from the listing form;
   here each tile is its own submit button rather than a checkbox, because
   picking a photo is the action rather than a step towards one. */
.photo button.photopick { padding: 0; border: 0; background: none; width: 100%; cursor: pointer;
  display: block; border-radius: 8px; }
.photo button.photopick img { opacity: .82; }
.photo button.photopick:hover img,
.photo button.photopick:focus-visible img { opacity: 1; outline-color: var(--accent); }
.photo .tick.on { display: inline-flex; background: var(--accent); width: auto; padding: 0 .5rem;
  border-radius: 999px; font-size: .62rem; letter-spacing: .02em; }
.photo button.photopick.inuse img { outline-color: var(--accent); opacity: 1; }

/* On the photograph, not under it. This started life as a text link at the
   bottom of the caption, below three other buttons in a 250px column, where it
   was rendered, reachable and invisible. You look at the picture you do not
   like, so the way to change it belongs on the picture. */
.media figure { position: relative; }
a.swap { position: absolute; top: .4rem; right: .4rem; z-index: 1;
  background: rgba(11, 27, 43, .82); color: #fff; text-decoration: none;
  font-size: .7rem; font-weight: 600; line-height: 1; letter-spacing: .01em;
  padding: .38rem .6rem; border-radius: 999px; backdrop-filter: blur(2px); }
a.swap:hover, a.swap:focus-visible { background: var(--accent); color: #fff; outline: none; }
a.swap:focus-visible { box-shadow: 0 0 0 2px #fff, 0 0 0 4px var(--accent); }

/* Uploading your own picture, on the chooser. */
.uploadrow { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; margin: .6rem 0 .2rem; }
.uploadrow input[type=file] { flex: 1 1 14rem; font-size: .82rem; }

/* "The system is working."
 *
 * Every manual change here is a round trip: an upload copies a file and rebuilds
 * three derivatives, writing captions is ten to twenty seconds at Claude. The
 * page used to sit there looking untouched, which invites a second click — and a
 * second click on Approve is a second post.
 *
 * A dimmed screen rather than a spinner tucked into one button, because the
 * point is that the whole page is unavailable until this finishes. It waits a
 * moment before appearing, so anything that returns quickly never flashes grey.
 */
.working { position: fixed; inset: 0; z-index: 60; display: none;
  flex-direction: column; align-items: center; justify-content: center; gap: .9rem;
  background: rgba(244, 246, 248, .78); backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px); }
.working.on { display: flex; }
.working .spinner { width: 2.6rem; height: 2.6rem; border-radius: 50%;
  border: 3px solid rgba(11, 27, 43, .16); border-top-color: var(--accent);
  animation: spin .8s linear infinite; }
.working .working-text { font-size: .92rem; font-weight: 600; color: var(--ink);
  background: var(--card); border: 1px solid var(--line); border-radius: 999px;
  padding: .45rem .95rem; box-shadow: var(--shadow); }

@media (prefers-reduced-motion: reduce) {
  /* Still obviously alive, without anything rotating. */
  .working .spinner { animation: breathe 1.6s ease-in-out infinite; }
}
@keyframes breathe { 0%, 100% { opacity: 1; } 50% { opacity: .3; } }
