/* =========================================================================
   WSPR Curate — design tokens (on-brand with the interview archive)
   Palette and type pulled directly from the interview archive — the site
   moving to stories.wsprstudios.com: near-black sections,
   a pale blush-pink section, and a single coral/salmon accent, with a
   bold condensed all-caps display face and a soft geometric body face —
   matching their actual look rather than a generic template.
   The one deliberately near-black "sealed" treatment on THIS site is
   reserved for the Event/Result Key boxes, which now doubles as an echo
   of the archive's own black section rhythm rather than an invented contrast.
   ========================================================================= */
:root {
  --black: #0d0d0d;
  --black-raised: #171514;

  --blush: #f7ded9;
  --blush-raised: #fdf5f2;
  --blush-sunken: #f0d2cb;

  --line: #e6c9c0;
  --line-on-black: #332d2a;

  --ink: #201c1a;
  --ink-dim: #6b5f58;
  --ink-faint: #a3948b;

  --paper-text: #f5ede8;
  --paper-text-dim: #cabdb5;

  --coral: #e2967f;
  --coral-deep: #c97a62;
  --coral-tint: rgba(226, 150, 127, 0.14);

  --signal: #b3503c;
  --signal-bg: rgba(179, 80, 60, 0.1);

  /* Fit colours — green, yellow, red, at full strength.
     They are only ever shown ON BLACK. The same three against blush
     went muddy and read as tacky; against the black score block they
     read as indicators. That is why the block is black rather than
     tinted: the colour needs a dark ground to sit on, and it earns
     its loudness by occupying almost no area. */
  --fit-strong: #34a06a;
  --fit-cond: #e0a92e;
  --fit-low: #d94f3d;
  --amber: #b98330;
  --amber-bg: rgba(185, 131, 48, 0.15);
    --ok: #4c7a5c;
  --ok-bg: rgba(76, 122, 92, 0.12);

  --font-display: "Anton", "Archivo Black", sans-serif;
  --font-body: "Poppins", -apple-system, "Segoe UI", sans-serif;
  --font-mono: "IBM Plex Mono", "SFMono-Regular", Menlo, Consolas, monospace;

  --radius: 4px;
  --max-width: 880px;

  --shadow-panel: 0 1px 0 rgba(255, 255, 255, 0.5) inset, 0 10px 26px rgba(60, 30, 20, 0.08);
  --shadow-seal: 0 1px 0 rgba(255, 255, 255, 0.03) inset, 0 14px 32px rgba(0, 0, 0, 0.4);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; }
}

* { box-sizing: border-box; }
html { color-scheme: light; }

body {
  margin: 0;
  background: var(--blush);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;

  /* Short pages (the screening confirmation, error states) used to leave
     the footer floating partway down with bare background beneath it,
     which reads as a broken page rather than a deliberate end. */
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
}
body > main { flex: 1 0 auto; }
body > footer.site-footer { flex-shrink: 0; }

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

:focus-visible { outline: 2px solid var(--coral-deep); outline-offset: 2px; }

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  color: var(--ink);
  margin: 0 0 0.5em;
}

.eyebrow {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--coral-deep);
}

p { color: var(--ink-dim); }
.mono { font-family: var(--font-mono); }

/* ---------------------------------------------------------------------
   Shell / black header bar (matches the archive's nav treatment)
   --------------------------------------------------------------------- */
.shell { max-width: var(--max-width); margin: 0 auto; padding: 0 24px; }
/* The nav bar is not a column of prose. Capping it at the 880px reading
   width is what made a signed-in nav — wordmark, three links, a name and a
   button, about 930px of content — wrap onto a second row on a wide screen.
   Body content still reads at 880. */
header.nav .shell { max-width: 1240px; }
/* Same opt-out for a page whose content is tables rather than sentences. */
.shell-wide { max-width: 1240px; }

.nav {
  background: var(--black);
  padding: 22px 0;
  border-bottom: 3px solid var(--coral);
}

/* nowrap above the phone breakpoint. The signed-in name is the only
   flexible piece (see below), so a long name or a long button label
   shortens the name instead of dropping the whole action group onto a
   second row -- which is what happened to the owner, whose label and
   button are both longer than a curator's. The two media queries at
   680px put wrapping back, where the collapsible menu needs its own row. */
.nav-inner { display: flex; justify-content: space-between; align-items: center; min-height: 32px; gap: 20px; flex-wrap: nowrap; }

/* Wordmark lockup ----------------------------------------------------
   WSPR │ Curator
        │ Suite

   The name and the product, joined by a rule. WSPR keeps the coral and
   the display face; "Curator Suite" sits quieter beside it in the body
   face, stacked so the lockup stays compact enough for a nav bar.

   Sized against the mark on the archive — roughly 1.4x the cap height of
   what this was, with letter-spacing to close the width gap that Anton,
   being a condensed face, otherwise leaves. */
.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  text-decoration: none;
  cursor: pointer;
  line-height: 1;
}
.wordmark:hover { text-decoration: none; }

.wordmark-name {
  font-family: var(--font-display);
  /* The bar this sits in stops growing at --max-width (880px), so the
     wordmark has to stop growing too. Letting it keep scaling on vw meant
     that on a wide monitor the lockup got bigger while its container
     didn't, and the nav wrapped onto a second row once a signed-in
     curator had a name and two buttons beside it. 1.85rem is where it
     lands at the width the shell tops out. */
  font-size: clamp(1.75rem, 2.4vw, 1.85rem);
  letter-spacing: 0.14em;
  /* Trailing letter-spacing leaves a gap after the final R; pulling it
     back keeps the rule optically where it belongs. */
  margin-right: -0.14em;
  color: var(--coral);
  text-transform: uppercase;
  line-height: 1;
}
.wordmark:hover .wordmark-name { color: var(--coral-deep); }

.wordmark-rule {
  width: 1px;
  /* No height of its own: stretch to whatever the tallest thing in the
     lockup is (the WSPR name). Giving this an em height made it measure
     against .wordmark's font-size rather than the type next to it, which
     on a phone left a divider taller than both halves and pushed the
     whole header open. */
  align-self: stretch;
  background: var(--line-on-black);
}

.wordmark-suite {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.66rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--paper-text);
  line-height: 1.15;
}

/* On a light background the lockup has to invert or it disappears. */
.band:not(.band-dark) .wordmark-suite { color: var(--ink); }
.band:not(.band-dark) .wordmark-rule { background: var(--line); }

@media (max-width: 560px) {
  /* Keep the lockup, shrink it — the nav still has to hold a sign-in
     button and a menu toggle on one row. */
  .wordmark { gap: 9px; }
  .wordmark-name { font-size: 1.55rem; letter-spacing: 0.1em; margin-right: -0.1em; }
  .wordmark-suite { font-size: 0.56rem; letter-spacing: 0.12em; }
}

.nav-links { display: flex; align-items: center; gap: 22px; font-family: var(--font-body); font-weight: 500; font-size: 0.85rem; letter-spacing: 0.01em; flex-wrap: wrap; }

/* Mobile: collapse the nav into a hamburger toggle instead of letting
   everything wrap into two or three tall rows. Hidden entirely above
   the breakpoint, where the normal inline nav-links row is used. */
.nav-hamburger {
  display: none;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 5px;
  width: 34px;
  height: 34px;
  background: none;
  border: 1px solid var(--line-on-black);
  border-radius: var(--radius);
  cursor: pointer;
  padding: 0;
  flex-shrink: 0;
}
.nav-hamburger span { display: block; width: 18px; height: 2px; background: var(--paper-text); }

@media (max-width: 960px) {
  .nav-hamburger { display: flex; }
  .nav-inner { flex-wrap: wrap; }
  .nav-links {
    display: none;
    width: 100%;
    flex-direction: column;
    align-items: flex-start;
    gap: 16px;
    padding-top: 18px;
    margin-top: 14px;
    border-top: 1px solid var(--line-on-black);
  }
  .nav-links.nav-links-open { display: flex; }
  .nav-signed-in { flex-direction: column; align-items: flex-start; gap: 10px; }
}
.nav-links a { color: var(--paper-text-dim); }
.nav-links a.current { color: var(--coral); }
.nav-links a:hover { color: var(--paper-text); text-decoration: none; }

main { padding: 56px 0 96px; }

/* The landing page is nothing but full-bleed bands, and every band brings
   its own vertical padding. main's padding on top of that showed up as a
   strip of blush between the header and the hero (and again above the
   footer) that read as a rendering fault rather than spacing. */
main.bands { padding: 0; }

/* Same rhythm argument as .section: what breathes on a desktop is dead
   space on a phone. */
@media (max-width: 680px) {
  main { padding: 32px 0 56px; }
}

/* One sentence does not need a black slab under it. On a phone this was
   28px of padding above and 32px below a single line — most of a screen
   spent on a signpost. The sentence stays; the field it sat in does not. */
footer.site-footer {
  background: transparent;
  padding: 18px 0 26px;
  color: var(--ink-faint);
  font-size: 0.82rem;
}
footer.site-footer a { color: var(--coral-deep); }
footer.site-footer { border-top: 1px solid var(--line); }

/* ---------------------------------------------------------------------
   Hero (landing page)
   --------------------------------------------------------------------- */
/* Top padding is the hero's own now that main no longer supplies any on
   the landing page. */
.hero { padding: 56px 0 72px; }

.hero-grid {
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: 32px;
  align-items: center;
}
@media (max-width: 760px) {
  .hero-grid { grid-template-columns: 1fr; }
  /* The key exists to fill the second column. Once the grid stacks there
     is no second column, so all it does is put 250px between the sign-in
     button and the next thing worth reading. Its caption restates the
     lede directly above it, and the whole block is already aria-hidden,
     so nothing is lost by dropping it here. */
  .hero-visual { display: none; }
}

.hero h1 {
  font-size: clamp(2rem, 5.4vw, 3.3rem);
  line-height: 1.1;
  margin: 18px 0 22px;
}
.hero h1 em { color: var(--coral-deep); font-style: normal; }

.hero p.lede { max-width: 54ch; font-size: 1.05rem; }

.hero-visual svg { width: 100%; height: auto; display: block; }
.hero-visual-caption { font-size: 0.85rem; color: var(--ink-faint); text-align: center; margin-top: 16px; max-width: 26ch; margin-left: auto; margin-right: auto; }

/* The one deliberately dark, "sealed" element on the page. */
.token-demo {
  margin-top: 40px;
  border: 1px solid var(--line-on-black);
  background: var(--black);
  border-radius: var(--radius);
  padding: 20px 22px;
  box-shadow: var(--shadow-seal);
  max-width: 560px;
}
.token-demo .label { font-family: var(--font-body); font-weight: 500; font-size: 0.72rem; color: var(--paper-text-dim); letter-spacing: 0.04em; text-transform: uppercase; margin-bottom: 10px; }
.token-demo .line { font-family: var(--font-mono); font-size: 0.95rem; color: var(--paper-text); min-height: 1.4em; word-break: break-all; }
.token-demo .line .sealed { color: var(--coral); }

/* ---------------------------------------------------------------------
   Owner sign-in gate — the same "sealed" dark treatment as the key
   boxes and the token demo, since this genuinely is the one locked door
   in the whole product.
   --------------------------------------------------------------------- */
.seal-gate {
  display: flex;
  justify-content: center;
  /* 10vh read as generous on a laptop and as a wall of empty pink on a
     phone, where it stacked on main's own padding and pushed the one
     thing you came here to do most of a screen down. */
  padding: clamp(20px, 7vh, 72px) 0;
  min-height: 62vh;
  align-items: center;
}
@media (max-width: 680px) {
  /* On a phone the card is taller than the viewport anyway, so vertical
     centering has nothing to centre and min-height only adds slack. */
  .seal-gate { padding: 16px 0 36px; min-height: 0; }
  .seal-gate-card { padding: 32px 24px; }
}
.seal-gate-card {
  width: 100%;
  max-width: 440px;
  background: var(--black);
  border: 1px solid var(--line-on-black);
  border-radius: var(--radius);
  padding: 44px 40px;
  box-shadow: var(--shadow-seal);
  text-align: center;
}
.seal-gate-card.wide { max-width: 580px; }
.seal-gate-mark {
  font-family: var(--font-display);
  font-size: 1.5rem;
  color: var(--coral);
  letter-spacing: 0.14em;
  /* Tight to the eyebrow beneath it, so "WSPR" and "Curator Suite"
     read as one name rather than the eyebrow belonging to "Sign in". */
  margin-bottom: 6px;
}
/* ...and the heading gets its own air below the name. */
.seal-gate-card .eyebrow { margin-bottom: 22px; }
.seal-gate-card h1 {
  font-size: 1.7rem;
  margin: 6px 0 10px;
}
.seal-gate-card p {
  font-size: 0.92rem;
  margin-bottom: 26px;
}
.seal-gate-card .field { text-align: center; margin-bottom: 22px; }
.seal-gate-card input {
  background: #ffffff;
  border-color: #ffffff;
  color: var(--ink);
}
.seal-gate-card input:focus { border-color: var(--coral); }

/* Password fields: masked, with a reveal control sitting inside the box. */
.pw-wrap { position: relative; }
.pw-wrap input { padding-right: 96px; }
.pw-show {
  position: absolute; right: 10px; top: 50%; transform: translateY(-50%);
  display: inline-flex; align-items: center; gap: 5px;
  background: none; border: 0; cursor: pointer; padding: 4px 2px;
  font-family: var(--font-body); font-size: 0.68rem; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--coral-deep);
}
.pw-show:hover { color: var(--coral); }
.seal-gate-card .field { text-align: left; }

/* --- Invitation page ---------------------------------------------------- */
/* The gate card is near-black, so anything inheriting the page's ink colour
   disappears on it. Sign-in set these inline; the invitation page has more
   of them, so they belong here. */
.seal-gate-card h1 { color: var(--paper-text); }
.seal-gate-card p { color: var(--paper-text-dim); }
.seal-gate-card label { color: var(--paper-text-dim); }
.seal-gate-card .hint { color: var(--paper-text-dim); opacity: 0.8; }
.seal-gate-card .wordmark-suite { text-align: left; }
.invite-lead { color: var(--paper-text); font-weight: 600; font-size: 1.04rem; margin-bottom: 22px; }
.invite-box { color: var(--paper-text-dim); border-top: 1px solid var(--line-on-black);
  border-bottom: 1px solid var(--line-on-black); padding: 18px 0; margin: 22px 0; }
.invite-box strong { color: var(--paper-text); display: block; margin-bottom: 4px; }
/* Every control above it is full width; a narrower button reads as
   misaligned even when it is perfectly centred. */
.invite-cta { display: flex; width: 100%; }
.invite-cred { display: grid; grid-template-columns: auto 1fr; gap: 14px 20px; text-align: left;
  max-width: 360px; margin: 22px auto; padding: 20px; border: 1px solid var(--line-on-black);
  border-radius: var(--radius); background: rgba(226, 150, 127, 0.06); }
.invite-cred dt { font-size: 0.7rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--coral); align-self: center; font-weight: 600; }
.invite-cred dd { margin: 0; font-family: var(--font-mono); font-size: 1.05rem;
  color: var(--paper-text); display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.cred-show { background: none; border: 0; cursor: pointer; padding: 0; font-family: var(--font-body);
  font-size: 0.64rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--coral-deep);
  font-weight: 700; display: inline-flex; align-items: center; gap: 5px; }
.seal-gate-card #loginAlert .alert { text-align: left; }

.gate-steps { text-align: left; margin-top: 8px; display: flex; flex-direction: column; gap: 16px; }
.gate-step { display: flex; gap: 14px; align-items: baseline; }
.gate-step-num { font-family: var(--font-display); color: var(--coral); font-size: 1.1rem; flex: 0 0 auto; min-width: 1.4em; }
.gate-step-text { font-size: 0.92rem; color: var(--paper-text-dim); }
.gate-step-text strong { color: var(--paper-text); font-weight: 600; }

.gate-manual { margin-top: 28px; padding-top: 24px; border-top: 1px solid var(--line-on-black); text-align: left; }
.gate-manual-label { font-size: 0.85rem; color: var(--paper-text-dim); margin-bottom: 10px; }
.gate-manual input { background: #ffffff; border-color: #ffffff; color: var(--ink); }
.gate-manual input:focus { border-color: var(--coral); }
.gate-manual-alert { font-size: 0.82rem; color: var(--signal); margin-top: 8px; min-height: 1.2em; }

/* ---------------------------------------------------------------------
   Steps band
   --------------------------------------------------------------------- */
.steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
@media (max-width: 720px) { .steps { grid-template-columns: 1fr; } }
.step-card { background: var(--blush-raised); padding: 28px 26px; display: flex; flex-direction: column; gap: 10px; transition: background 0.15s ease; }
.step-card:hover { background: var(--coral-tint); }
.step-numeral { font-family: var(--font-display); color: var(--coral-deep); font-size: 1.6rem; }
.step-card h3 { font-size: 1.05rem; margin-bottom: 2px; }
.step-card p { font-size: 0.92rem; margin: 0; }
.step-card .enter { margin-top: 8px; font-family: var(--font-body); font-weight: 600; font-size: 0.85rem; color: var(--coral-deep); }

.principles { margin-top: 64px; display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
@media (max-width: 720px) { .principles { grid-template-columns: 1fr; } }
.principle dt { font-family: var(--font-body); font-weight: 600; font-size: 0.85rem; text-transform: none; color: var(--coral-deep); margin-bottom: 6px; }
.principle dd { margin: 0; font-size: 0.92rem; color: var(--ink-dim); }

/* ---------------------------------------------------------------------
   Page headers
   --------------------------------------------------------------------- */
/* The suite bar.

   Every signed-in page used to open with a 2rem name and a coral rule —
   about 158px, and the first real content began 455px down a phone
   screen. The name was also the second time you were told it: the nav
   already says "Signed in as …".

   So identity is one line, and the access date rides on the end of it,
   because that is the only thing here a curator actually needs to act
   on. Pages that carry real explanatory copy keep it as a lede below. */
.suite-bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px 18px; flex-wrap: wrap;
  padding-bottom: 9px; margin-bottom: 16px;
  border-bottom: 1px solid var(--line);
}
.suite-who { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.13em; text-transform: uppercase; color: var(--ink-dim); }
.suite-exp { font-size: 0.64rem; font-weight: 600; letter-spacing: 0.09em; text-transform: uppercase; color: var(--ink-faint); }
/* Access does not expire, so this is usually empty. An empty flex child
   still claims a slot and pushes the name off the left edge. */
.suite-exp:empty { display: none; }
.suite-exp.is-closing { color: var(--signal); }
.suite-lede { font-size: 0.9rem; color: var(--ink-dim); margin: 0 0 22px; max-width: 66ch; }
.sx-short { display: none; }
@media (max-width: 560px) {
  .suite-bar { gap: 8px 12px; }
  .suite-who { font-size: 0.66rem; letter-spacing: 0.1em; }
  .suite-exp { font-size: 0.6rem; letter-spacing: 0.06em; }
  .sx-long { display: none; }
  .sx-short { display: inline; }
}

.page-head { margin-bottom: 40px; max-width: 62ch; }
.page-head h1 {
  font-size: 2rem;
  margin-top: 10px;
  display: inline-block;
  border-bottom: 4px solid var(--coral);
  padding-bottom: 8px;
}
.page-head p { font-size: 1rem; margin-top: 16px; }

/* ---------------------------------------------------------------------
   Panels & cards
   --------------------------------------------------------------------- */
.panel {
  background: var(--blush-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 28px;
  margin-bottom: 24px;
  box-shadow: var(--shadow-panel);
}
.panel h2 { font-size: 1.2rem; display: flex; align-items: center; gap: 10px; letter-spacing: 0; }
.panel h2 .numeral { color: var(--coral-deep); font-family: var(--font-display); }
.hint { font-size: 0.85rem; color: var(--ink-faint); margin-top: 4px; }

/* ---------------------------------------------------------------------
   Forms
   --------------------------------------------------------------------- */
label { display: block; font-size: 0.9rem; color: var(--ink); margin-bottom: 6px; font-weight: 500; }

input[type="text"], input[type="password"], input[type="search"], input[type="date"], textarea, select {
  width: 100%;
  background: var(--blush-sunken);
  border: 1px solid var(--line);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 0.95rem;
  padding: 10px 12px;
  border-radius: var(--radius);
}
textarea { resize: vertical; min-height: 72px; }
input[type="text"].mono-input, input[type="password"].mono-input, textarea.mono-input { font-family: var(--font-mono); font-size: 0.88rem; }
input:focus, textarea:focus, select:focus { border-color: var(--coral); }

.field { margin-bottom: 20px; }
.char-count { font-size: 0.75rem; color: var(--ink-faint); text-align: right; margin-top: 4px; font-family: var(--font-mono); }
.field-row { display: flex; gap: 14px; flex-wrap: wrap; }
.field-row > * { flex: 1 1 200px; }

fieldset { border: none; padding: 0; margin: 0; }
legend { padding: 0; margin-bottom: 12px; font-size: 0.95rem; color: var(--ink); font-weight: 500; }

.radio-group { display: flex; flex-direction: column; gap: 8px; }
.radio-option {
  display: flex; align-items: flex-start; gap: 10px; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: var(--radius); cursor: pointer;
  background: var(--blush-sunken); transition: border-color 0.12s ease, background 0.12s ease;
}
.radio-option:hover { border-color: var(--coral); }
.radio-option input { margin-top: 3px; accent-color: var(--coral-deep); }
.radio-option.selected { border-color: var(--coral); background: var(--coral-tint); }
.radio-option span { font-size: 0.92rem; }

/* Dimension rows: label + 1-5 box picker */
.dim-row {
  display: grid;
  grid-template-columns: 1fr 2fr;
  gap: 16px;
  align-items: center;
  padding: 16px 0;
  border-bottom: 1px solid var(--line);
}
.dim-row:last-child { border-bottom: none; }
@media (max-width: 640px) { .dim-row { grid-template-columns: 1fr; gap: 10px; } }
.dim-label { font-size: 0.92rem; font-weight: 500; }
.dim-readout { font-family: var(--font-body); font-size: 0.88rem; color: var(--coral-deep); margin-top: 6px; min-height: 1.2em; line-height: 1.4; }

.pick-boxes { display: flex; gap: 8px; }
.pick-box {
  flex: 1;
  aspect-ratio: 1;
  max-width: 52px;
  border: 1px solid var(--line);
  background: var(--blush-sunken);
  color: var(--ink-dim);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 1.05rem;
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color 0.12s ease, background 0.12s ease, color 0.12s ease;
}
.pick-box:hover { border-color: var(--coral); }

/* Neutral is quiet; only a real choice is coral.
   ---------------------------------------------------------------------
   Eleven qualities, all defaulting to the neutral 3. When every one of
   those 3s was filled coral — the colour that means "chosen" everywhere
   else on this site — eleven untouched rows all announced that they had
   been answered, and a first-timer read the section as eleven questions
   they were behind on and dutifully clicked through all of them.

   No sentence fixes that; the colour was the instruction and it was
   saying the wrong thing. So the untouched 3 is an outline — clearly the
   current position, obviously not a decision — and coral is spent only
   where the curator actually moved something. The section now reports
   its own state without a word: two rows lit out of eleven means two
   things matter and the other nine are fine as they are. */
.pick-box.selected {
  border-color: var(--coral); background: var(--coral);
  color: #fff; font-weight: 700;
}
.pick-box.selected.is-moved {
  border-color: var(--coral-deep); background: var(--coral-deep); color: #fff;
}
/* The readout follows the same rule: coral once it describes a choice. */
.dim-row .dim-readout { color: var(--ink-faint); }
.dim-row.is-moved .dim-readout { color: var(--coral-deep); }
/* Named on the label so a moved row is scannable on a wide screen, where
   the picker sits far to the right of the words. */
.dim-row.is-moved .dim-label::after {
  content: "set"; margin-left: 8px; vertical-align: 2px;
  font-size: 0.56rem; font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--coral-deep);
}

.weight-select { width: auto; min-width: 160px; }

/* Custom question builder */
.cq-block { border: 1px solid var(--line); border-radius: var(--radius); padding: 20px; margin-bottom: 16px; background: var(--blush-sunken); position: relative; }
.cq-block .cq-remove { position: absolute; top: 14px; right: 14px; font-family: var(--font-body); font-weight: 500; font-size: 0.8rem; color: var(--signal); background: none; border: none; cursor: pointer; }
.cq-conditional { margin-top: 14px; padding-top: 14px; border-top: 1px dashed var(--line); }
.option-row { display: flex; gap: 8px; margin-bottom: 8px; }
.option-row input { flex: 1; }
.option-row button { flex: 0 0 auto; }

/* ---------------------------------------------------------------------
   Buttons
   --------------------------------------------------------------------- */
.btn {
  /* justify-content matters here: the moment a button is wider than its
     label — a min-width, width:100%, or a grid cell stretching it — a flex
     container with no justification pins the text to the left edge. Every
     "width:100%;justify-content:center" written inline around this codebase
     was a workaround for its absence. */
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-family: var(--font-body); font-weight: 600; font-size: 0.9rem; letter-spacing: 0.01em;
  padding: 12px 22px; border-radius: var(--radius);
  border: 1px solid var(--coral); background: transparent; color: var(--coral-deep);
  cursor: pointer; transition: background 0.12s ease, color 0.12s ease;
}
/* A button label never wraps. Anywhere.

   Wrapped labels have been the single most persistent defect in this
   build — Change date splitting in two, Next dropping below the pager,
   Revoke and settle events folding inside its own modal. Each looked
   like a one-off; they were the same bug, and the page never complained.

   nowrap makes the failure LOUD instead of silent: a label that will not
   fit now pushes its container wide, where the overflow sweep catches it
   at 360/390/768/1200 and dev-tools/wrap-check.js fails the build. The
   fix then has to be a shorter label or a wider slot — a decision — and
   never a quiet second line nobody chose. */
.btn { white-space: nowrap; }
.btn:hover { background: var(--coral); color: var(--black); }
.btn:disabled { opacity: 0.4; cursor: not-allowed; }
.btn-primary { background: var(--coral); color: var(--black); font-weight: 600; }
.btn-primary:hover { background: var(--coral-deep); color: var(--black); }
.btn-ghost { border-color: var(--line); color: var(--ink-dim); }
.btn-ghost:hover { background: var(--blush-sunken); color: var(--ink); }
/* The header bar is always near-black, so ANY ghost button inside it needs
   the light treatment -- not just the ones in the collapsible link list.
   Scoping this to .nav-links left the persistent "Sign out" button with
   dark ink on a dark bar, i.e. invisible. */
.nav .btn-ghost { border-color: var(--line-on-black); color: var(--paper-text-dim); }
.nav .btn-ghost:hover { background: var(--black-raised); color: var(--paper-text); }
.nav-signed-in { display: flex; align-items: center; gap: 14px; }
.nav-signed-in-name { font-family: var(--font-body); font-size: 0.85rem; color: var(--paper-text-dim); }
.nav-signed-in-name strong { color: var(--paper-text); font-weight: 600; }
.btn-small { padding: 7px 12px; font-size: 0.75rem; }

/* ---------------------------------------------------------------------
   Key display — deliberately "sealed" dark, echoing the archive's black bands
   --------------------------------------------------------------------- */
.key-output {
  background: var(--black); border: 1px solid var(--line-on-black); border-radius: var(--radius);
  padding: 16px; font-family: var(--font-mono); font-size: 0.85rem; color: var(--paper-text);
  word-break: break-all; margin-bottom: 10px;
}
.key-id { font-family: var(--font-mono); font-size: 1.4rem; letter-spacing: 0.08em; color: var(--coral-deep); }
.key-actions { display: flex; gap: 10px; align-items: center; margin-top: 10px; }
.copy-feedback { font-size: 0.8rem; color: var(--ok); font-family: var(--font-body); font-weight: 500; opacity: 0; transition: opacity 0.15s ease; }
.copy-feedback.show { opacity: 1; }

/* ---------------------------------------------------------------------
   Alerts / status
   --------------------------------------------------------------------- */
.alert { border-radius: var(--radius); padding: 14px 16px; font-size: 0.9rem; margin-bottom: 20px; border: 1px solid transparent; }
.alert-error { background: var(--signal-bg); border-color: var(--signal); color: var(--signal); }
.alert-ok { background: var(--ok-bg); border-color: var(--ok); color: var(--ok); }
.alert-info { background: var(--coral-tint); border-color: var(--coral); color: var(--coral-deep); }

.status-badge {
  display: inline-block; font-family: var(--font-body); font-weight: 600; font-size: 0.75rem; letter-spacing: 0.01em;
  text-transform: none; padding: 4px 10px; border-radius: 999px; border: 1px solid currentColor;
}
.status-compatible, .status-met { color: var(--ok); }
.status-mismatch { color: var(--ink-faint); }
.status-failed { color: var(--signal); }
.status-info { color: var(--coral-deep); }

.dashboard-tabs { display: flex; gap: 4px; margin-bottom: 20px; border-bottom: 1px solid var(--line); }
.dashboard-tab {
  background: none; border: none; padding: 10px 18px; cursor: pointer;
  font-family: var(--font-body); font-weight: 600; font-size: 0.9rem;
  color: var(--ink-faint); border-bottom: 2px solid transparent; margin-bottom: -1px;
  white-space: nowrap;
}
.dashboard-tab:hover { color: var(--ink); }

/* Four tabs at desktop padding are wider than a phone.
 *
 * Squeezing them into equal thirds was the first fix, and it broke
 * "Event Links" onto two lines — the exact defect this file's sibling
 * check now fails on. Labels do not wrap; the strip scrolls instead, so
 * a name is never cut in half and the page still does not move sideways.
 */
@media (max-width: 520px) {
  .dashboard-tabs {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .dashboard-tabs::-webkit-scrollbar { display: none; }
  .dashboard-tab {
    flex: 0 0 auto;
    padding-left: 12px;
    padding-right: 12px;
    font-size: 0.8rem;
    text-align: center;
  }
}
.dashboard-tab.active { color: var(--coral-deep); border-bottom-color: var(--coral); }

/* ---------------------------------------------------------------------
   Report (decoder)
   --------------------------------------------------------------------- */
.report-hero { border: 1px solid var(--line); background: var(--blush-raised); border-radius: var(--radius); padding: 28px; margin-bottom: 24px; box-shadow: var(--shadow-panel); }
.report-hero.fit-strong { border-color: var(--ok); }
.report-hero.fit-conditional { border-color: var(--coral); }
.report-hero.fit-low { border-color: var(--line); }
.report-hero.fit-failed { border-color: var(--signal); }

.overall-number { font-family: var(--font-display); font-size: 2.8rem; color: var(--ink); }
.overall-label { font-family: var(--font-body); font-weight: 600; font-size: 0.95rem; margin-top: 6px; color: var(--ink-dim); }

.vector-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px 20px; margin-top: 16px; }
.vector-item { font-size: 0.85rem; }
.vector-item .k { color: var(--ink-faint); }
.vector-item .v { font-family: var(--font-mono); color: var(--coral-deep); margin-left: 6px; }

.archetype-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
@media (max-width: 640px) { .archetype-pair { grid-template-columns: 1fr; } }

/* --- Archetype comparison ------------------------------------------------
   One row per dimension instead of two stacked columns of numbers: the
   curator sees where the prospect sits against what they asked for without
   doing the subtraction, and the card stays balanced either way. */
.archetype-side h3 { margin: 6px 0 0; }
.archetype-desc { font-size: 0.88rem; color: var(--ink-dim); margin: 10px 0 0; }
.overall-row { display: flex; align-items: baseline; gap: 16px; flex-wrap: wrap; }
.overall-row .overall-label { margin-top: 0; }
.level-meter { display: flex; align-items: flex-end; gap: 3px; height: 34px; margin-top: 18px; }
.level-meter i { flex: 1; height: 20px; border-radius: 2px; background: var(--blush-sunken); }
.level-meter i.on { height: 34px; background: var(--coral); }
.level-meter i.edge { height: 27px; background: var(--coral); opacity: 0.45; }
@media (max-width: 480px) { .level-meter { gap: 2px; height: 28px; } .level-meter i { height: 16px; } .level-meter i.on { height: 28px; } .level-meter i.edge { height: 22px; } }
.room-read { margin-top: 26px; padding-top: 20px; border-top: 1px solid var(--line); }
.room-read p { margin: 8px 0 0; font-size: 0.92rem; color: var(--ink-dim); max-width: 70ch; }
.score-split { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 12px; }

.cmp-table { margin-top: 20px; border-top: 1px solid var(--line); }
.cmp-row { display: grid; grid-template-columns: minmax(120px, 1.1fr) minmax(90px, 2fr) auto 46px; align-items: center; gap: 14px; padding: 9px 0; border-bottom: 1px solid var(--line); font-size: 0.85rem; }
.cmp-row.cmp-head { border-bottom: 1px solid var(--line); font-size: 0.68rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-faint); padding: 8px 0; }
.cmp-head .cmp-bar-head { letter-spacing: 0.04em; text-transform: none; font-size: 0.66rem; }
.cmp-label { color: var(--ink-dim); }
.cmp-bar { position: relative; height: 8px; border-radius: 4px; background: var(--blush-sunken); }
.cmp-fill { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 4px; background: var(--coral); }
.cmp-tick { position: absolute; top: -3px; bottom: -3px; width: 2px; margin-left: -1px; background: var(--ink); border-radius: 1px; }
.cmp-nums { font-family: var(--font-mono); font-size: 0.8rem; color: var(--ink-faint); white-space: nowrap; }
.cmp-nums b { color: var(--ink); font-weight: 600; }
.cmp-gap { font-family: var(--font-mono); font-size: 0.8rem; text-align: right; color: var(--ink-faint); }
.cmp-gap.gap-close { color: var(--ok); }
.cmp-gap.gap-mid { color: var(--coral-deep); }
.cmp-gap.gap-wide { color: var(--signal); font-weight: 600; }


@media (max-width: 640px) {
  .cmp-row { grid-template-columns: 1fr auto 40px; grid-template-areas: "label nums gap" "bar bar bar"; gap: 6px 12px; }
  .cmp-label { grid-area: label; }
  .cmp-nums { grid-area: nums; }
  .cmp-gap { grid-area: gap; }
  .cmp-bar { grid-area: bar; }
  .cmp-row.cmp-head .cmp-bar-head { display: none; }
  .score-split { grid-template-columns: 1fr; }
}

.cq-report-item { border: 1px solid var(--line); border-radius: var(--radius); padding: 16px 18px; margin-bottom: 12px; background: var(--blush-raised); }
.cq-report-item .q-text { font-size: 0.95rem; margin-bottom: 8px; }
.cq-report-item .meta { font-size: 0.82rem; color: var(--ink-faint); display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 8px; }
.cq-report-item .answer { font-family: var(--font-body); font-weight: 600; color: var(--ink); }

.linkback { margin-top: 32px; font-size: 0.88rem; }
.skeleton { color: var(--ink-faint); font-family: var(--font-body); font-size: 0.9rem; }

/* ---------------------------------------------------------------------
   v2 — event dashboard, applicant tables, admin controls

   Same restraint as the rest of the site: one accent, flat surfaces, no
   new colour vocabulary. Fit states reuse the ok/coral/signal roles the
   report already uses, so "strong" means the same thing everywhere a
   curator sees it.
   --------------------------------------------------------------------- */

/* Event cards -------------------------------------------------------

   Pale ground, coral rail for live, dashed outline for closed.

   These were solid black for a while. One live event looked sharp; five
   was a wall, and it spent the page's whole colour budget on a list.
   Coral stays an accent here — the job it already has everywhere else —
   rather than becoming a second background, and the fit dots keep a
   pale ground where green, yellow and red all read without help.

   It also protects the arrival: with no black in the list, clicking a
   card and landing on the black event hero is a real transition.
   ------------------------------------------------------------------- */
/* A row, not a card.
   ---------------------------------------------------------------------
   The card spent most of its height on two horizontal rules and the
   ~29px of margin and padding each one carried. That bought separation
   between an event's name, its status and its actions — separation a
   single hairline between rows gives for a fraction of the space. On a
   phone this is three events where there used to be one and a half, and
   the list is read on a phone far more than anywhere else.

   The whole row is still the click target, exactly as the card was. */
.ev-row {
  display: block;
  padding: 15px 0;
  border-top: 1px solid var(--line);
  cursor: pointer;
}
.ev-row:first-child { border-top: 0; }
/* Bleeding the hover past the panel padding keeps the highlight reading
   as a full-width row rather than a floating band inside one. */
.ev-row:hover,
.ev-row:focus-visible {
  background: var(--blush-sunken);
  margin: 0 -12px; padding-left: 12px; padding-right: 12px;
}

.ev-main { min-width: 0; }
/* Name left, count hard right, one line, at every width.
   
   An earlier pass made this `display: contents` on desktop so the count
   could rejoin the row's own flex as a right-hand column. It did not:
   the head's children became blocks inside .ev-main instead, so the
   count dropped onto its own line with the deadline pushed beneath it —
   the "weird gap" in the middle of every desktop row. One flex row here
   does the same job at both sizes and cannot come apart. */
.ev-head {
  display: flex; align-items: baseline; gap: 14px; min-width: 0;
}
.ev-head .ev-name { flex: 1 1 auto; min-width: 0; }
.ev-head .ev-side { flex: none; }
.ev-name {
  font-size: 1.02rem; font-weight: 600; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ev-meta { font-size: 0.78rem; color: var(--ink-dim); margin-top: 3px; }
.ev-side { flex: none; text-align: right; }
.ev-count { font-family: var(--font-display); font-size: 1.5rem; line-height: 1; color: var(--coral-deep); }
.ev-unit { font-size: 0.52rem; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-faint); }

/* Copy link as text, not a boxed button. A pill here rebuilds the card
   this row replaced — the box was most of what made the old one heavy. */
.ev-copy {
  display: inline-flex; align-items: center; gap: 5px;
  background: none; border: 0; padding: 4px 0 0; margin-top: 5px;
  font-family: var(--font-body); font-size: 0.76rem; font-weight: 600;
  color: var(--ink-dim); cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px;
}
.ev-copy:hover { color: var(--coral-deep); }
.ev-copy:disabled { color: var(--ok); cursor: default; text-decoration: none; }
.ev-copy svg { width: 12px; height: 12px; stroke: currentColor; stroke-width: 2; fill: none; stroke-linecap: round; stroke-linejoin: round; }

/* Closed and purged: a step quieter. The two states also sit in their
   own panels with their own headings, which is what carries the
   distinction the card's coral rail used to carry on its own. */
.ev-row.is-past .ev-name { color: var(--ink-dim); font-weight: 500; }
.ev-row.is-past .ev-count { color: var(--ink-faint); }

/* The dot itself, shared by the list rows and the event header. The
   container rule that used to sit here belonged to the card the list
   was built from before it became rows; .ev-dots replaced it and this
   one had no remaining user, so it is gone rather than parked. */
.ev-fit { display: flex; align-items: center; gap: 6px; font-size: 0.63rem; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-dim); white-space: nowrap; }
.ev-fit i { width: 7px; height: 7px; border-radius: 50%; display: block; flex: none; }
.ev-fit.s i { background: var(--fit-strong); }
.ev-fit.c i { background: var(--fit-cond); }
.ev-fit.l i { background: var(--fit-low); }
.ev-fit.u i { background: var(--ink-faint); }

/* Retired with the card: the boxed action row, the dashed past-card
   treatment and its phone overrides. Their jobs moved to .ev-copy and
   .ev-row.is-past above, and the row needs no width-specific padding —
   it has no box to pad. */
/* On a phone the count rides up beside the name instead of holding its
   own column. Pinned right it was taking about 40% of the width, which
   left the deadline — the one line that decides whether you open the
   event — wrapping across three. Beside the name it costs nothing and
   the meta gets the full width back. */
/* On a phone the count sits on the name's baseline rather than stacked
   above its own caption. The deadline line no longer needs a narrow
   variant — it is short enough at every width now. */
@media (max-width: 699px) {
  .ev-head { gap: 10px; }
  .ev-head .ev-side { display: flex; align-items: baseline; gap: 5px; }
  .ev-head .ev-count { font-size: 1.25rem; }
  .ev-head .ev-unit { font-size: 0.5rem; }
}

@media (max-width: 560px) {
  .ev-name { white-space: normal; }
}

/* Fit pills --------------------------------------------------------- */
.fit-pill {
  display: inline-block;
  font-family: var(--font-body);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid currentColor;
  white-space: nowrap;
}
.fit-pill.fit-strong { color: var(--ok); }
.fit-pill.fit-conditional { color: var(--coral-deep); }
.fit-pill.fit-low { color: var(--ink-faint); }
.fit-pill.fit-failed { color: var(--signal); }

/* Data tables ------------------------------------------------------- */
/* Wide tables scroll inside their own container rather than pushing the
   page sideways on a phone. */
.data-table-wrap { overflow-x: auto; }
.data-table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
.data-table th {
  text-align: left;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  padding: 0 14px 10px 0;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
.data-table td { padding: 13px 14px 13px 0; border-bottom: 1px solid var(--line); vertical-align: middle; }
.data-table td.num, .data-table th.num { text-align: right; font-family: var(--font-mono); }
.data-table th.num { font-family: var(--font-body); }
.data-table tbody tr[data-open-applicant] { cursor: pointer; }
.data-table tbody tr[data-open-applicant]:hover { background: var(--blush-sunken); }
.data-table .row-actions { display: flex; gap: 6px; justify-content: flex-end; flex-wrap: wrap; }

/* Activity log ------------------------------------------------------ */
.activity-list { list-style: none; margin: 0; padding: 0; }
.activity-item {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 11px 0;
  border-bottom: 1px solid var(--line);
  font-size: 0.88rem;
  color: var(--ink-dim);
}
.activity-item:last-child { border-bottom: none; }
.activity-when { font-family: var(--font-mono); font-size: 0.78rem; color: var(--ink-faint); white-space: nowrap; }
.activity-item.actor-system .activity-what { color: var(--ink-faint); font-style: italic; }

@media (max-width: 560px) {
  .activity-item { flex-direction: column; gap: 3px; }
}

/* Retention status --------------------------------------------------- */
/* Deliberately prominent. A deletion promise is only worth as much as
   the job behind it, and a sweep that quietly stopped running looks
   exactly like one with nothing to do. */
.retention-status {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  border: 1px solid var(--line);
  border-left: 3px solid var(--ok);
  background: var(--blush-raised);
  border-radius: var(--radius);
  padding: 14px 18px;
  margin-bottom: 20px;
  font-size: 0.86rem;
  color: var(--ink-dim);
}
.retention-status.stale { border-left-color: var(--signal); color: var(--signal); }
.retention-status .k {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* Inline transfer control ------------------------------------------- */
.transfer-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 10px; }
.transfer-row select { max-width: 240px; }

/* Diagnostics output ------------------------------------------------ */
.alert-detail {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid currentColor;
  opacity: 0.8;
  word-break: break-word;
}
.diag-output {
  margin-top: 14px;
  padding: 16px 18px;
  background: var(--black);
  color: var(--paper-text);
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-size: 0.78rem;
  line-height: 1.55;
  overflow-x: auto;
  white-space: pre;
}

/* Modals ------------------------------------------------------------ */
/* Replaces window.prompt() for anything with a fixed set of right
   answers — a picker can't be mistyped, and it keeps admin dialogs
   inside the site's own design rather than the browser's. */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(13, 13, 13, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  z-index: 100;
}
.modal-card {
  background: var(--blush-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-panel);
  padding: 28px;
  width: 100%;
  max-width: 460px;
  max-height: 90vh;
  overflow-y: auto;
}
.modal-title {
  font-family: var(--font-display);
  font-size: 1.25rem;
  text-transform: uppercase;
  margin: 0 0 8px;
}
.modal-description { margin-bottom: 20px; }
.modal-body .field { margin-bottom: 16px; }
.modal-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  margin-top: 24px;
  flex-wrap: wrap;
}

@media (max-width: 480px) {
  .modal-actions { flex-direction: column-reverse; }
  .modal-actions .btn { width: 100%; justify-content: center; }
}

/* Two-line table cells ---------------------------------------------- */
/* Lets a table carry a name and its context in one column instead of
   spending a whole column on each, which is what made the event table
   wrap onto three lines per row. */
.cell-primary { color: var(--ink); }
.cell-sub { color: var(--ink-faint); font-size: 0.78rem; margin-top: 2px; white-space: nowrap; }
/* The curator column carries two lines of text and was being squeezed to
   the point of hyphenating mid-word by the action buttons opposite.

   The ACTIONS column takes the table's slack. A row here is two separate
   things — what the event is, and what you can do about it — and they
   should not be interleaved. width:100% on the last cell is the standard
   way to say "all the leftover width goes here": every fact then packs
   against the left edge in reading order, and the buttons collect in one
   block on the right. Giving that slack to the name column instead (the
   previous attempt) pushed the facts into the middle of the row, where
   the screening count read as though it belonged to the date beside it. */
.data-table td:first-child,
.data-table th:first-child { min-width: 190px; }
.data-table td:last-child,
.data-table th:last-child { width: 100%; }
/* Room between columns, not just under them. 14px was tight enough that
   a right-aligned number and the next column's left edge nearly touched. */
.data-table th { padding-right: 24px; }
.data-table td { padding-right: 24px; }
.data-table th:last-child,
.data-table td:last-child { padding-right: 0; }
.data-table .row-actions { flex-wrap: nowrap; white-space: nowrap; }
/* Actions stay on one line at every width. The table already scrolls
   horizontally in .data-table-wrap, so wrapping only stacked the buttons
   on top of each other and made every row taller on a phone. */
.cell-sub code { font-family: var(--font-mono); font-size: 0.76rem; color: var(--coral-deep); }
.cell-secondary { font-size: 0.8rem; color: var(--ink-faint); margin-top: 2px; }

.data-table td { white-space: nowrap; }
.data-table td:first-child { white-space: normal; }

/* An event link as a card, for phones ---------------------------------
   The event table is 790px of content. In a 284px column that is a
   sideways scroll, and what sits off the right edge is Copy link,
   Transfer and Cancel — the entire reason for opening the page. Below
   620px the rows are rendered as cards instead (in JS, because the page
   size changes with the breakpoint too), so nothing is off screen and
   nothing has to be swiped for.
   Same clothes as the event cards on /events: pale, coral rail, and the
   rail goes grey once the event is not live. */
.lk-list { display: grid; gap: 10px; }
.lk {
  position: relative; overflow: hidden;
  background: var(--blush-raised); border: 1px solid var(--line);
  border-radius: 12px; padding: 14px 14px 12px 16px;
}
.lk::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; background: var(--coral); }
.lk.is-off::before { background: var(--line); }
.lk-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.lk-name { font-weight: 600; font-size: 0.95rem; line-height: 1.3; }
.lk-who { font-size: 0.76rem; color: var(--ink-faint); margin-top: 2px; }
/* A wrapped badge reads as a rendering fault; a wrapped event name is
   just a long name. So the badge holds its line and the name gives way. */
.lk-top .status-badge { white-space: nowrap; flex: none; }
.lk-meta { display: flex; flex-wrap: wrap; gap: 4px 14px; margin: 10px 0 12px; font-size: 0.78rem; color: var(--ink-dim); }
.lk-meta b { font-family: var(--font-mono); font-weight: 500; color: var(--ink); }
/* One column per button, however many there are: a lone Copy link on a
   settled event should span the card rather than sit in a third of it
   looking like two buttons failed to render. */
.lk-acts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.lk-acts[data-n="1"] { grid-template-columns: 1fr; }
.lk-acts[data-n="2"] { grid-template-columns: repeat(2, 1fr); }
.lk-acts .btn { width: 100%; justify-content: center; }

/* Collapsed system section ------------------------------------------- */
/* Diagnostics belong within reach, not on screen. Closed by default,
   with a one-line status so a healthy system says so quietly and a
   broken one still gets a banner at the top of the page. */
.system-details {
  margin-top: 40px;
  border-top: 1px solid var(--line);
  padding-top: 8px;
}
.system-details summary {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  cursor: pointer;
  padding: 12px 0;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.78rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
  list-style: none;
}
.system-details summary::-webkit-details-marker { display: none; }
.system-details summary::before {
  content: "▸";
  margin-right: 8px;
  font-size: 0.7rem;
  transition: transform 0.15s ease;
  display: inline-block;
}
.system-details[open] summary::before { transform: rotate(90deg); }
.system-details summary:hover { color: var(--ink-dim); }
.system-summary-status {
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: none;
  font-size: 0.82rem;
  margin-left: auto;
}
.system-summary-status.state-ok { color: var(--ok); }
.system-summary-status.state-problem { color: var(--signal); }
.system-summary-status.state-unknown { color: var(--ink-faint); }
.system-details-body { padding: 8px 0 24px; }

/* =========================================================================
   Landing page — sales-page depth

   Same palette and type as everywhere else; what changes is rhythm.
   Full-bleed strips break up long stretches of prose, comparison and
   retention blocks carry meaning in their structure, and section
   spacing is wide enough that thirteen sections read as a considered
   argument rather than a wall.
   ========================================================================= */

.section { padding: 78px 0; }
/* Vertical rhythm that reads as generous on a desktop reads as dead space
   on a phone, where 78px top and bottom stacks into 156px of empty band
   between every section. */
@media (max-width: 680px) {
  .section { padding: 52px 0; }
  .strip { padding: 26px 0; }
  .hero { padding: 34px 0 44px; }
}
.section > .eyebrow { margin-bottom: 10px; }
.section h2 { font-size: clamp(1.5rem, 3.2vw, 2.1rem); line-height: 1.15; max-width: 20ch; }
.section-lede { max-width: 66ch; font-size: 1.02rem; margin-bottom: 18px; }
.section-lede em { color: var(--ink); font-style: italic; }

.hero-actions { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 26px; }

/* Credibility strip -------------------------------------------------- */
/* Exactly three. A fourth wrapped onto its own row and read as a
   mistake rather than a list. */
.strip { padding: 34px 0; }
.strip-inner {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px 32px;
}
@media (max-width: 700px) { .strip-inner { grid-template-columns: 1fr; gap: 18px; } }
.strip-item { display: flex; flex-direction: column; gap: 3px; }
.strip-item strong {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--coral);
}
.strip-item span { font-size: 0.84rem; color: var(--paper-text-dim); }

/* Comparison --------------------------------------------------------- */
.compare {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  margin-top: 32px;
}
@media (max-width: 720px) { .compare { grid-template-columns: 1fr; } }
.compare-col {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 24px 26px;
  background: var(--blush-raised);
}
.compare-col h3 { font-size: 1rem; margin-bottom: 16px; }
.compare-col ul { list-style: none; margin: 0; padding: 0; }
.compare-col li {
  position: relative;
  padding-left: 26px;
  margin-bottom: 13px;
  font-size: 0.92rem;
  color: var(--ink-dim);
  line-height: 1.5;
}
.compare-col li::before {
  position: absolute;
  left: 0;
  top: 0;
  font-weight: 700;
  font-family: var(--font-body);
}
.compare-without { border-left: 3px solid var(--signal); }
.compare-without li::before { content: "✕"; color: var(--signal); }
.compare-with { border-left: 3px solid var(--ok); }

/* --- Pricing ------------------------------------------------------------
   Two cards, not a tier table: there is only one product and one future
   price, and a three-column tier grid would imply choices that don't
   exist. The pilot card leads because it is the one that applies today. */
.price-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; }
@media (max-width: 760px) { .price-pair { grid-template-columns: 1fr; } }
.price-card { background: var(--blush-raised); border: 1px solid var(--line); border-radius: var(--radius); padding: 28px; box-shadow: var(--shadow-panel); }
.price-card-now { border-color: var(--coral); }
.price-figure { font-family: var(--font-display); font-size: 2.6rem; line-height: 1; margin: 10px 0 6px; color: var(--ink); }
.price-unit { font-family: var(--font-body); font-size: 0.9rem; font-weight: 600; color: var(--ink-dim); letter-spacing: 0; }
.price-tbd { color: var(--ink-faint); }
.price-sub { font-size: 0.88rem; color: var(--ink-dim); margin: 0 0 18px; }
.price-list { list-style: none; margin: 0; padding: 0; }
.price-list li { position: relative; padding-left: 20px; margin-bottom: 12px; font-size: 0.9rem; color: var(--ink-dim); }
.price-list li::before { content: "—"; position: absolute; left: 0; color: var(--coral); }
.band-dark .price-card { background: var(--black-raised); border-color: var(--line-on-black); box-shadow: none; }
.band-dark .price-card-now { border-color: var(--coral); }
.band-dark .price-figure { color: var(--paper-text); }
.band-dark .price-sub,
.band-dark .price-list li { color: var(--paper-text-dim); }
.band-dark .price-unit { color: var(--paper-text-dim); }
.compare-with li::before { content: "✓"; color: var(--ok); }

/* Four-across steps -------------------------------------------------- */
.steps-four { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }

/* Prospect flow ------------------------------------------------------ */
.prospect-flow {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px;
  margin-top: 28px;
  counter-reset: prospect;
}
.prospect-step {
  border-top: 2px solid var(--coral);
  padding-top: 14px;
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.prospect-step .k {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.92rem;
  color: var(--ink);
}
.prospect-step span:last-child { font-size: 0.86rem; color: var(--ink-faint); line-height: 1.5; }

/* Dimensions --------------------------------------------------------- */
.dimension-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 2px;
  margin-top: 28px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.dimension {
  background: var(--blush-raised);
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.dimension .k {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.88rem;
  color: var(--coral-deep);
}
.dimension span:last-child { font-size: 0.84rem; color: var(--ink-faint); line-height: 1.45; }

/* Retention table ---------------------------------------------------- */
.retention-table {
  margin-top: 28px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.retention-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 20px;
  padding: 18px 22px;
  border-bottom: 1px solid var(--line);
  background: var(--blush-raised);
  align-items: baseline;
  font-size: 0.92rem;
}
.retention-row:last-child { border-bottom: none; }
.retention-row > span:last-child {
  font-family: var(--font-body);
  font-weight: 600;
  color: var(--coral-deep);
  white-space: nowrap;
  font-size: 0.88rem;
}
.retention-head {
  background: var(--blush-sunken);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.retention-head > span:last-child { color: var(--ink-faint); font-size: 0.72rem; }
@media (max-width: 560px) {
  .retention-row { grid-template-columns: 1fr; gap: 6px; }
  .retention-row > span:last-child { white-space: normal; }
}

/* Fit / not-fit ------------------------------------------------------ */
.fit-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 28px; }
@media (max-width: 720px) { .fit-grid { grid-template-columns: 1fr; } }
.fit-col h3 { font-size: 1rem; margin-bottom: 14px; }
.check-list, .cross-list { list-style: none; margin: 0; padding: 0; }
.check-list li, .cross-list li {
  position: relative;
  padding-left: 26px;
  margin-bottom: 12px;
  font-size: 0.92rem;
  color: var(--ink-dim);
  line-height: 1.5;
}
.check-list li::before { content: "✓"; position: absolute; left: 0; color: var(--ok); font-weight: 700; }
.cross-list li::before { content: "✕"; position: absolute; left: 0; color: var(--ink-faint); font-weight: 700; }

/* FAQ ---------------------------------------------------------------- */
.faq-item { border-bottom: 1px solid var(--line); }
.faq-item summary {
  cursor: pointer;
  padding: 18px 30px 18px 0;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.98rem;
  color: var(--ink);
  list-style: none;
  position: relative;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
  content: "+";
  position: absolute;
  right: 4px;
  top: 15px;
  font-size: 1.3rem;
  font-weight: 400;
  color: var(--coral-deep);
  line-height: 1;
}
.faq-item[open] summary::after { content: "–"; }
.faq-item summary:hover { color: var(--coral-deep); }
.faq-item p { margin: 0 0 20px; max-width: 68ch; font-size: 0.94rem; }

.closing { text-align: left; }
.closing h2 { max-width: 24ch; }

/* Footer ------------------------------------------------------------- */
.footer-grid {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  gap: 32px;
  padding-bottom: 28px;
}
@media (max-width: 640px) { .footer-grid { grid-template-columns: 1fr; gap: 24px; } }
.footer-grid > div { display: flex; flex-direction: column; gap: 8px; }
.footer-grid strong {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--paper-text);
  margin-bottom: 2px;
}
.footer-grid p { color: var(--paper-text-dim); font-size: 0.86rem; margin: 0; max-width: 34ch; }
.footer-grid a { color: var(--paper-text-dim); font-size: 0.86rem; }
.footer-grid a:hover { color: var(--coral); }
.footer-grid .hint { color: var(--ink-faint); font-size: 0.8rem; }
.footer-wordmark {
  font-family: var(--font-display);
  font-size: 1.9rem;
  color: var(--coral);
  letter-spacing: 0.14em;
  line-height: 1;
}
.footer-base {
  border-top: 1px solid var(--line-on-black);
  padding-top: 20px;
  font-size: 0.82rem;
  color: var(--ink-faint);
}


/* =========================================================================
   Alternating bands

   The page reads as blocks rather than one unbroken field of blush,
   matching the rhythm of the rest of the brand. A dark band doesn't get
   its own component styles — it redefines the surface tokens locally,
   so every card, table and border inside it inverts automatically and
   nothing can be left behind when a new component is added.
   ========================================================================= */
.band { background: var(--blush); }

.band-dark {
  --blush: var(--black);
  --blush-raised: var(--black-raised);
  --blush-sunken: #221f1d;
  --ink: var(--paper-text);
  --ink-dim: var(--paper-text-dim);
  --ink-faint: #8d827a;
  --line: var(--line-on-black);
  --shadow-panel: var(--shadow-seal);
  background: var(--black);
  color: var(--paper-text);
}
.band-dark h1, .band-dark h2, .band-dark h3 { color: var(--paper-text); }
.band-dark p { color: var(--paper-text-dim); }
.band-dark a:not(.btn) { color: var(--coral); }
.band-dark .btn-ghost { border-color: var(--line-on-black); color: var(--paper-text-dim); }
.band-dark .btn-ghost:hover { background: var(--black-raised); color: var(--paper-text); }
.band-dark .hint { color: #8d827a; }

/* The closing sits one step lighter than the footer it leads into, so
   the two dark blocks stay legible as two blocks. */
.band-closing { background: var(--black-raised); }
.band-closing h2 { max-width: 24ch; }

.band-hero { padding-bottom: 0; }

/* Four-up grids ------------------------------------------------------ */
/* A 2×2 square rather than a row of three with a lonely fourth
   underneath — which is what auto-fit produced at this width. */
.steps-quad { grid-template-columns: repeat(2, 1fr); gap: 18px; }
@media (max-width: 640px) { .steps-quad { grid-template-columns: 1fr; } }

.prospect-quad {
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
}
@media (max-width: 640px) { .prospect-quad { grid-template-columns: 1fr; } }
.prospect-quad .prospect-step {
  border: 1px solid var(--line);
  border-top: 2px solid var(--coral);
  border-radius: var(--radius);
  background: var(--blush-raised);
  padding: 20px 22px;
}
.prospect-step .n {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--coral);
  letter-spacing: 0.08em;
}

/* Sign-in overlay ---------------------------------------------------- */
.signin-backdrop { align-items: flex-start; padding-top: 8vh; }
.signin-overlay-card { position: relative; max-width: 440px; width: 100%; }
.signin-close {
  position: absolute;
  top: 14px;
  right: 16px;
  background: none;
  border: none;
  color: var(--paper-text-dim);
  font-size: 1.6rem;
  line-height: 1;
  cursor: pointer;
  padding: 4px 8px;
}
.signin-close:hover { color: var(--paper-text); }
@media (max-width: 480px) { .signin-backdrop { padding: 16px; align-items: center; } }

/* A centred column needs its header centred too, or the value reads as
   belonging to the column beside it. */
.data-table th.center, .data-table td.center { text-align: center; }


/* =========================================================================
   Touch devices — stop iOS zooming the page on focus

   Safari on iOS zooms the viewport whenever a focused input's text is
   smaller than 16px. The site's fields were 14–15px, so tapping "Your
   key" on a phone blew the page up and left the person pinching back
   out before they could type. Nothing was actually broken; it just felt
   broken, which is the same thing to whoever is holding the phone.

   16px on touch widths is the whole fix. maximum-scale=1 in the
   viewport tag would also stop it, and is the wrong answer — it takes
   pinch-zoom away from everyone who needs it.
   ========================================================================= */
@media (max-width: 768px) {
  input[type="text"],
  input[type="password"],
  input[type="search"],
  input[type="date"],
  textarea,
  select,
  input[type="text"].mono-input,
  input[type="password"].mono-input,
  textarea.mono-input {
    font-size: 16px;
  }
}

/* Sign-in overlay on a small screen: sit near the top, keep breathing
   room at the edges, and scroll inside itself rather than off-screen. */
@media (max-width: 560px) {
  .signin-backdrop { padding: 20px 16px; align-items: flex-start; }
  .signin-overlay-card {
    padding: 28px 22px;
    max-height: calc(100vh - 40px);
    overflow-y: auto;
  }
  .seal-gate-card { padding: 30px 22px; }
}


/* Nav actions that never collapse ------------------------------------ */
/* The hamburger hides navigation, not the primary action. */
.nav-persistent { display: flex; align-items: center; gap: 10px; order: 3; }

/* The signed-in name is context, not an action. It's hidden until the
   page knows who you are, and it's the first thing dropped when the bar
   gets tight -- the two buttons and the menu toggle have to keep their
   row on a phone, and the name is the only one of the four that isn't
   something you click. Toggled by class rather than an inline style so
   the media query below can still override it. */
.nav-persistent .nav-signed-in-name { display: none; }
.nav-persistent .nav-signed-in-name.is-visible {
  display: inline;
  /* The one part of the bar allowed to give: it shrinks and ellipsises so
     the buttons keep their full labels and the row never breaks. */
  flex: 0 1 auto;
  min-width: 0;
  max-width: 18ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.nav-persistent > .btn { flex-shrink: 0; }


}
/* Brighter and heavier than the section links beside it, so the name
   reads as who you are rather than as one more thing to click. */
.nav-persistent .nav-signed-in-name { color: var(--paper-text); font-weight: 600; }

/* Long/short label pair for the signed-in destination button. Below 430px
   the full word ("Administration") pushes the wordmark and menu toggle
   onto a second row, so the abbreviation takes over. */
.lbl-short { display: none; }
@media (max-width: 430px) {
  .lbl-full { display: none; }
  .lbl-short { display: inline; }
}
@media (max-width: 900px) {
  .nav-persistent .nav-signed-in-name.is-visible { display: none; }
}

/* Sign out exists twice in the landing markup -- once in the persistent
   row, once inside the collapsible menu -- because on a phone the row
   can't hold the wordmark, two buttons and the menu toggle without
   wrapping onto a second line. Both start hidden; signing in reveals
   them; these two rules make sure only one is ever on screen. */
.js-signout { display: none; }
.js-signout.is-visible { display: inline-flex; }
#landingSignOutBtnMenu.is-visible { display: none; }
@media (max-width: 680px) {
  #landingSignOutBtn.is-visible { display: none; }
  #landingSignOutBtnMenu.is-visible { display: inline-flex; }
}
.nav-persistent .nav-hamburger { display: none; }

@media (max-width: 680px) {
  .nav-persistent .nav-hamburger { display: flex; }
  .nav-inner { flex-wrap: wrap; }
  .nav-links { order: 4; }
}

/* Access codes ------------------------------------------------------- */
/* Meant to be read aloud and typed, so it's set large, spaced, and in
   the mono face where every character is unambiguous. */
.access-code-display {
  font-family: var(--font-mono);
  font-size: 1.5rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  color: var(--coral-deep);
  background: var(--blush-sunken);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px 20px;
  text-align: center;
  word-break: break-all;
}
.code-inline {
  font-family: var(--font-mono);
  font-size: 0.92rem;
  letter-spacing: 0.06em;
  color: var(--coral-deep);
}
@media (max-width: 480px) {
  .access-code-display { font-size: 1.2rem; letter-spacing: 0.08em; padding: 14px; }
}

/* Ready-to-send message --------------------------------------------- */
.message-preview {
  background: var(--blush-sunken);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px 20px;
  font-family: var(--font-body);
  font-size: 0.88rem;
  line-height: 1.6;
  color: var(--ink-dim);
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 320px;
  overflow-y: auto;
  margin: 0 0 12px;
}

/* Grouped copy actions ----------------------------------------------- */
/* Buttons that belong together sit together. A per-button "Copied"
   label holds its space even at zero opacity, which spaced these out
   like gapped teeth — so they share one confirmation instead. */
.key-actions-tight { gap: 8px; flex-wrap: wrap; }
.key-actions-tight .copy-feedback { margin-left: 6px; }


/* The nav bar has to stay comfortable now the wordmark carries weight. */
.nav { padding: 20px 0; }
.nav-inner { gap: 18px; }

/* The phone-size reduction lives with the rest of the lockup rules now
   (see .wordmark-name / .wordmark-suite above). The old rule here set a
   font-size on .wordmark itself, which stopped meaning anything once the
   lockup made it a flex container. */


/* Hero eyebrow -------------------------------------------------------
   Coral everywhere else, black here — and the rule behind that is
   worth stating rather than treating as a one-off:

   THE EYEBROW GOES BLACK ONLY WHERE IT SITS DIRECTLY ABOVE CORAL
   HEADLINE TEXT.

   Every other section has a black headline, so a coral eyebrow gives
   contrast and there's nothing to compete with. In the hero the
   headline itself carries the accent, and two coral elements stacked
   on top of each other blur into one another — the eye can't tell
   where the label ends and the headline begins. One accent per view;
   here it belongs to the headline. */
.hero .eyebrow { color: var(--ink); }


/* ---------------------------------------------------------------------
   Screening intro — the sealed card an applicant lands on

   Same black seal card as the invitation and the sign-in gate, for the
   same reason: this is a door, and a door should look like one. The
   applicant meets the close date on the way in, because a window that
   closes is the curator's policy working as intended, not a dead link
   to be discovered later.

   The counter is ONE readout, not a row of tiles. Split into boxes it
   reads as a checkout timer; set as a single line of type it reads as a
   time, which is what it is.
   --------------------------------------------------------------------- */

.deadline-box { text-align: center; }

/* Label, date, time — three deliberate lines. Set as one sentence the
   date wrapped wherever the box ran out, which landed mid-date and read
   as an accident rather than a layout. */
.deadline-label {
  display: block;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--coral);
}
.deadline-date {
  display: block;
  font-size: 1rem;
  font-weight: 600;
  color: var(--paper-text);
  margin-top: 7px;
  text-wrap: balance;
}
.deadline-time {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--paper-text-dim);
  margin-top: 2px;
}

/* The byline sits under the title like a credit. Centred by default;
   .byline-right pushes it to the edge instead. */
.intro-byline {
  font-size: 0.92rem;
  color: var(--paper-text-dim);
  margin: -8px 0 0;
}
.intro-byline strong { color: var(--paper-text); font-weight: 600; }

/* The date sits with the name and the host, the way it does on any
   invitation. Brighter than the byline because it is a hard fact about
   the night rather than an attribution. */
.intro-eventdate {
  font-size: 0.95rem;
  color: var(--paper-text);
  font-weight: 500;
  margin: 2px 0 18px;
}

/* The card is 580px on a desktop, which is wider than this sentence
   wants to be. Hold it to a readable measure and let it centre inside
   the card rather than stretching to the edges. */
#introFootnote,
.intro-kicker {
  max-width: 40ch;
  margin-left: auto;
  margin-right: auto;
  text-wrap: balance;
}

/* Same problem on the closed card, where the whole message is one
   sentence sitting alone in the box. */
#linkGateMessage {
  max-width: 34ch;
  margin-left: auto;
  margin-right: auto;
  text-wrap: balance;
}
.seal-gate-card.byline-right .intro-byline { text-align: right; }

.countdown {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 0.12em;
  margin: 24px 0 20px;
  font-family: var(--font-mono);
  font-size: clamp(1.3rem, 6.4vw, 1.75rem);
  font-weight: 500;
  line-height: 1.1;
  color: var(--paper-text);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.cd-pair { display: inline-flex; align-items: baseline; }

/* Coral at rest. The counter is the one thing on this card that is
   actually running, so it takes the accent and keeps it. */
.cd-num { letter-spacing: 0.01em; color: var(--coral); }

.cd-unit {
  font-size: 0.44em;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--paper-text-dim);
  margin-left: 0.12em;
}

.cd-sep {
  color: var(--paper-text-dim);
  opacity: 0.45;
  margin: 0 0.14em;
}

/* Label on one line, the date on its own beneath it — the date is the
   fact worth reading, and it should not have to be picked out of a
   sentence. */
.deadline-eventdate {
  display: block;
  margin-bottom: 18px;
  font-size: 0.82rem;
  color: var(--paper-text-dim);
}
.deadline-eventdate-label {
  display: block;
  font-size: 0.68rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  opacity: 0.75;
  margin-bottom: 3px;
}
.deadline-eventdate strong {
  display: block;
  font-size: 0.9rem;
  margin: 0;
  color: var(--paper-text);
}

/* The readout warms as it runs out. Nothing moves and nothing blinks —
   the number falling is the urgency, and a pulsing timer would drag the
   page down-market exactly where it can least afford it. */
/* There is no separate 24-hour tint any more: coral became the resting
   colour, so a "soon" state set to coral would repaint the same value.
   Two steps is the whole ladder — coral, then red in the last hour. */
.countdown.is-closed .cd-num,
.countdown.is-closed .cd-sep { color: var(--paper-text-dim); opacity: 0.55; }

/* ---------------------------------------------------------------------
   The event name, at whatever length a curator gives it

   Curators name their own events and some of those names are long.
   The size steps down by character count so a three-word name stays
   commanding and a twelve-word one still fits the card instead of
   running off it or shrinking every name to suit the worst case.
   --------------------------------------------------------------------- */

.intro-kicker {
  color: var(--paper-text-dim);
  font-size: 0.9rem;
  /* auto, not 0 — this shorthand runs after the measure-capping rule
     below and a plain 0 here silently cancels its centring. */
  margin: 0 auto 6px;
}

#introEventName {
  font-size: clamp(1.55rem, 7.6vw, 2.05rem);
  line-height: 1.08;
  margin: 0 0 18px;
  overflow-wrap: break-word;
  text-wrap: balance;
}
#introEventName.is-long { font-size: clamp(1.25rem, 5.9vw, 1.6rem); }
#introEventName.is-very-long { font-size: clamp(1.05rem, 4.7vw, 1.28rem); line-height: 1.2; }

/* The questions themselves sit on the ordinary pink page — the card is
   the threshold, not the whole experience. */
#introPanel .btn { margin-top: 6px; }

/* Counting toward an opening, not a closing. The border picks up the
   accent because this is an invitation to come back, not a warning. */
.deadline-box.is-preopen { border-color: var(--coral); }



/* ---------------------------------------------------------------------
   The deletion notice

   True fine print. It is here because it has to be — a data promise
   belongs on the page where the data is collected — but it is not part
   of the card's design and must not compete with the button above it.
   Small, faint, and legible to anyone who goes looking; invisible to
   anyone who is not.
   --------------------------------------------------------------------- */

#introCuratedLine {
  font-size: 0.66rem;
  line-height: 1.55;
  color: var(--paper-text-dim);
  opacity: 0.5;
  /* Full content width, which is the button's width. Capping the measure
     made it three narrow lines under a wide button, which reads as a
     block; letting it run the same width reads as a caption. */
  max-width: none;
  margin: 26px auto 0;
  /* balance, not pretty: pretty only fixes the last line, which left a
     long line above a short one. balance evens every line instead, so
     two lines come out the same length under a centred button. */
  text-wrap: balance;
}


/* The screening page is centred end to end — a left-aligned footer under
   a centred card reads as a loose end. Opt-in rather than global: the
   landing, pricing, events, authority and create pages are left-aligned
   by design and their footers should stay that way.

   balance evens the lines too, so the last word cannot end up alone. */
footer.site-footer-centred .shell {
  text-align: center;
  text-wrap: balance;
}


/* ---------------------------------------------------------------------
   Create form — the window picker and the schedule it produces

   The curator learns the model by filling in the form: pick a night,
   pick a window, and every date it implies appears underneath before
   anything is committed. Cheaper than explaining it on another page,
   and it means the limit on moving the event is never a surprise.
   --------------------------------------------------------------------- */

.win-picker { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
@media (max-width: 560px) { .win-picker { grid-template-columns: repeat(2, 1fr); } }

.win-opt {
  display: block; margin: 0; cursor: pointer; text-align: center;
  padding: 14px 10px; border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--blush-raised);
}
.win-opt input { position: absolute; opacity: 0; width: 0; height: 0; }
.win-opt:hover { border-color: var(--coral-deep); }
.win-opt.is-on { border-color: var(--coral-deep); background: var(--coral-tint); }
.win-opt:focus-within { outline: 2px solid var(--coral-deep); outline-offset: 2px; }
.win-num { display: block; font-family: var(--font-display); font-size: 1.9rem; line-height: 1; color: var(--ink); }
.win-lab { display: block; font-size: 0.66rem; font-weight: 700; letter-spacing: 0.13em; text-transform: uppercase; color: var(--coral-deep); margin-top: 3px; }

/* A window longer than the time until the event is legal — screening
   just opens immediately and you get the shorter run. Marked, not
   disabled, because it is a choice rather than a mistake. */
.win-opt.is-capped { border-style: dashed; }
.win-cap { display: block; font-size: 0.5rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--fit-cond); margin-top: 4px; }

/* The move-by limit lives in the fine print rather than in a row of its
   own. It was the only row that needed a footnote to be understood,
   which is a sign it was a sentence pretending to be data. The date
   inside the sentence keeps the red so it is still findable at a glance. */
/* Before a date exists the panel is one sentence. The rows and the fine
   print arrive together, filled in, the moment there is something true to
   put in them. */
.date-preview.is-empty .dp-row,
.date-preview.is-empty .dp-fine { display: none; }
.date-preview.is-empty .dp-note { margin: 0; }
.dp-fine { font-size: 0.76rem; line-height: 1.5; color: var(--ink-faint); margin: 9px 0 0; }
.dp-fine b { color: var(--signal); font-weight: 600; }
/* Black, not coral: red already means "required" and marks the ceiling
   date in this very sentence, and a chip here would sit beside the
   Pilot chip and read as a row of badges. */
.dp-fine .fn-rate { color: var(--black); font-weight: 600; }

/* Marks a price that is real but not being charged yet. Green because it
   is good news, and a chip rather than a sentence because it sits beside
   several different prices and should read identically every time. */
.pilot-chip {
  display: inline-block; white-space: nowrap;
  font-size: 0.58rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  color: #1f6b45; background: rgba(52, 160, 106, 0.14);
  border: 1px solid rgba(52, 160, 106, 0.4);
  padding: 2px 7px; border-radius: 20px;
}
/* The ladder, on the rung being chosen. Mono so the numbers line up down
   the row; faint so the day count stays the thing read first. */
/* The tiles hold days only. Price moved to the schedule panel's header:
   a price inside each tile made the row read as four offers instead of
   one choice, and it put mono type in a checkout. */
.dp-head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 16px; padding: 2px 0 13px; margin-bottom: 4px;
  border-bottom: 1px solid var(--line);
}
.dp-head-label { font-size: 0.95rem; font-weight: 500; color: var(--ink); white-space: nowrap; }
.dp-head-price {
  font-size: 1.3rem; font-weight: 700; color: var(--ink);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.date-preview.is-empty .dp-head { display: none; }

.dp-note.bad { background: rgba(179, 80, 60, 0.1); color: var(--signal); font-weight: 500; }
.dp-note.warn { background: rgba(224, 169, 46, 0.14); color: #7a5a15; }

.field-err { display: flex; gap: 8px; align-items: flex-start; font-size: 0.78rem; line-height: 1.45; color: var(--signal); font-weight: 500; margin: 7px 0 0; }
input.is-bad,
.cal-field.is-bad { border-color: var(--signal) !important; background: rgba(179, 80, 60, 0.06) !important; }

/* The dates dock.

   Black, not coral. Coral is already carrying two jobs on this page —
   the selected window and every button — and a coral strip pinned under
   a coral-selected option reads as one more control rather than a
   readout. Black is the colour this product uses when it is telling you
   something rather than offering you something. */

/* What you're building -------------------------------------------------

   The payoff. Eleven qualities used to produce a number nobody sees and a
   link; this reads the whole thing back before the curator commits to it.

   The archetype and its sentence come from schema.nearestArchetype() —
   the same eight archetypes the report uses, so a curator sees one name
   here and the same name later. It is a mirror, not a horoscope: the
   label is read off the shape of the vector they built, so it can never
   describe a room they did not describe.

   The "left open" line is the half people forget they decided, and it is
   where a mistake gets caught before a link goes to forty people. */
.built {
  position: relative; overflow: hidden;
  background: var(--blush-raised); border: 1px solid var(--line);
  border-radius: 16px; padding: 26px 26px 22px 30px; margin-top: 26px;
}
.built::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 5px; background: var(--coral); }
.built-eyebrow { font-size: 0.6rem; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-faint); }
.built-name { font-family: var(--font-display); font-size: 1.9rem; line-height: 1.05; margin: 6px 0 2px; text-transform: uppercase; }
/* The night this archetype belongs to. Plain text under the display
   line — enough to tell three events in flight apart without competing
   with the thing being bought. */
.built-for { font-size: 0.86rem; color: var(--ink-faint); margin: 4px 0 16px; }
.built-for b { color: var(--ink); font-weight: 600; }
/* Nothing moved means there is no archetype. Grey rather than the
   engine's fallback answer, which would name a room nobody described. */
.built-name.is-unset { color: var(--ink-faint); }
.built-says { font-size: 0.95rem; line-height: 1.62; color: var(--ink-dim); margin: 0 0 8px; max-width: 64ch; }
.built-says b { color: var(--ink); font-weight: 600; }
.built-open { font-size: 0.86rem; line-height: 1.55; color: var(--ink-faint); margin: 0 0 18px; max-width: 64ch; }
.built-open b { color: var(--ink-dim); }
.built-open:empty { display: none; }

.built-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px 34px; padding-top: 16px; border-top: 1px solid var(--line); }
@media (max-width: 720px) { .built-grid { grid-template-columns: 1fr; } }
.built-k { font-size: 0.58rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-faint); margin-bottom: 8px; }

/* What they value, in words. No numbers — see VALUE_PHRASES in the schema. */
.val-list { list-style: none; margin: 0; padding: 0; }
.val-list li { position: relative; padding: 4px 0 4px 16px; font-size: 0.88rem; color: var(--ink); line-height: 1.45; }
.val-list li::before { content: ""; position: absolute; left: 0; top: 12px; width: 6px; height: 6px; border-radius: 50%; background: var(--coral); }
.val-list li.none { padding-left: 0; color: var(--ink-faint); }
.val-list li.none::before { display: none; }

.pkg { list-style: none; margin: 0; padding: 0; }
.pkg li { display: flex; justify-content: space-between; gap: 12px; font-size: 0.86rem; padding: 4px 0; color: var(--ink-dim); }
/* The receipt.
   The pilot line sits in a tinted band because a discount you can see land
   is worth more than one you have to work out — the way a promo code looks
   once it has taken. The amounts stay in a plain column down the right so
   the arithmetic still lines up and reads as an invoice rather than a
   marketing claim. */
.rcpt { list-style: none; margin: 16px 0 0; padding: 0; }
.rcpt:empty { display: none; }
.rcpt li { display: flex; justify-content: space-between; align-items: baseline; gap: 14px; font-size: 0.88rem; padding: 5px 0; color: var(--ink-dim); }
.rcpt li b { color: var(--ink); font-weight: 600; }
.rcpt li .amt { font-weight: 600; color: var(--ink); white-space: nowrap; }
.rcpt li.off {
  color: var(--fit-strong); background: rgba(52, 160, 106, 0.10);
  border-radius: 8px; padding: 8px 12px; margin: 4px -12px;
}
.rcpt li.off b, .rcpt li.off .amt { color: var(--fit-strong); }
/* Listed, priced, not sold here. */
.rcpt li.muted, .rcpt li.muted .amt { color: var(--ink-faint); font-weight: 400; }

/* The badge the bar wears, since one line has no room for a receipt. */
.saved-chip {
  display: inline-flex; align-items: center; white-space: nowrap;
  font-size: 0.66rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: #1f6b45; background: rgba(52, 160, 106, 0.14);
  border: 1px solid rgba(52, 160, 106, 0.4);
  padding: 4px 10px; border-radius: 20px;
}
.saved-chip[hidden] { display: none; }

/* The total continues the column it totals: package, then receipt, then
   this. Nothing is stranded on the far left of the card. */
.built-foot { margin-top: 16px; padding-top: 16px; border-top: 2px solid var(--line); }
.built-ttop { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; }
.built-total { font-size: 1.25rem; font-weight: 600; color: var(--ink); white-space: nowrap; }
.built-now {
  font-family: var(--font-display); font-size: 2rem; line-height: 1; color: var(--ink);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.built-foot .btn { width: 100%; margin-top: 14px; }
/* Under the button, centred. Between the total and the action it read as
   a caveat on the number rather than reassurance about the payment. */
.built-fine { font-size: 0.76rem; color: var(--ink-faint); margin-top: 10px; text-align: center; }
@media (max-width: 560px) {
  .built-foot .btn { width: 100%; justify-content: center; }
  .built-money { margin-left: 0; }
}
.pkg li span:last-child { color: var(--ink); font-weight: 600; text-align: right; }

/* The cart ------------------------------------------------------------

   The builder is a purchase, so it gets a receipt rather than a form
   button. It is sticky at the bottom on a phone — where it also carries
   the schedule the old date dock used to show, because two black bars
   fighting over the same edge is one bar too many — and sits in the flow
   on a laptop, where there is room for it to simply be the last thing.

   Prices always render, struck through beside the zero. That is the
   whole point of the thing: a curator who watches $45 be waived four
   times knows what WSPR costs, and one who has only ever read "free"
   finds out from an invoice.

   Pale card + coral rail, like every other card on the site. It was black
   first, which was wrong twice over: it put a third visual language on a
   page we had already de-blacked once, and on a laptop it stacked
   directly against the black site footer so the two merged into one slab
   and the total stopped reading as a total. The money carries the
   emphasis instead — bigger, coral — and the coral button stays the
   loudest thing in the box, which is right, because it is the thing to
   press. */
.cart {
  position: relative; overflow: hidden;
  background: var(--blush-raised); color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 12px; padding: 11px 14px; margin-top: 26px;
  display: flex; align-items: center; gap: 12px;
}
/* The rail runs along the top: this is a bar, and a stripe down one end
   of a wide short box reads as an accident. */
.cart::before { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 3px; background: var(--coral); }
.cart-money { flex: 1 1 auto; min-width: 0; display: flex; align-items: baseline; gap: 8px; }
.cart-was { font-size: 0.86rem; color: var(--ink-faint); text-decoration: line-through; }
.cart-was[hidden] { display: none; }
.cart-now { font-family: var(--font-display); font-size: 1.35rem; line-height: 1; color: var(--ink); }
.cart .btn { flex: none; }
/* Retired once the real total is on screen. */
.cart.is-done { display: none; }

/* On a phone it pins to the foot of the screen. Everything it used to
   carry — three dates, two receipt lines, a waiver tag — lives on the page
   above it, and repeating all of it here cost a third of the screen. */
@media (max-width: 699px) {
  .cart-sticky {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
    margin: 0; border-radius: 0; border-left: 0; border-right: 0; border-bottom: 0;
    padding: 11px 14px calc(11px + env(safe-area-inset-bottom, 0px));
    box-shadow: 0 -4px 16px rgba(13, 13, 13, 0.12);
  }
  /* Only the form's shell. The selector used to be body.has-cart .shell,
     which caught the header's shell and the footer's too — so a page with
     a cart grew 96px of dead space inside its own nav bar and another
     inside its footer, which is where the "big black gap" under the
     header and the empty band at the foot both came from. */
  body.has-cart main .shell { padding-bottom: 96px; }
}

/* On a laptop it follows you down rather than waiting at the end.
   position:sticky pins it until the page scrolls far enough for its real
   position to arrive; no JS decides when. */
@media (min-width: 700px) {
  .cart-sticky {
    position: sticky; bottom: 18px; z-index: 30;
    box-shadow: 0 12px 34px rgba(13, 13, 13, 0.16);
  }
}
.cart-anchor { height: 1px; }

/* Inside the modal the receipt is an itemised block, not a one-line bar:
   there it is describing a purchase being made, not tracking one. */
.modal-card .cart { margin: 4px 0 16px; display: block; }
.modal-card .cart-money { display: block; text-align: right; }
.modal-card .cart-foot { display: flex; align-items: center; gap: 16px; }
.cart-items { list-style: none; margin: 0 0 12px; padding: 0 0 12px; border-bottom: 1px solid var(--line); }
.cart-items:empty { display: none; }
.cart-items li { display: flex; justify-content: space-between; align-items: baseline; gap: 14px; font-size: 0.84rem; padding: 5px 0; color: var(--ink-dim); }
.cart-items li b { color: var(--ink); font-weight: 600; }
.cart-items li .m { font-size: 0.82rem; color: var(--ink); white-space: nowrap; flex: none; }
.cart-items li.muted, .cart-items li.muted .m { color: var(--ink-faint); }
.cart-what { flex: 1 1 auto; min-width: 0; }
.cart-line { font-size: 0.92rem; font-weight: 600; color: var(--ink); }
.cart-sub { font-size: 0.78rem; color: var(--ink-faint); margin-top: 3px; }

/* Only the builder's cart pins itself to the bottom of a phone. The same
   receipt appears inside the change-date modal, and a modal's contents
   pinning themselves to the viewport is a dialog coming apart — hence the
   modifier rather than styling every .cart. */
@media (max-width: 699px) {
  .cart-sticky {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
    margin: 0; border-radius: 0; border-left: 0; border-right: 0; border-bottom: 0;
    padding: 12px 14px calc(12px + env(safe-area-inset-bottom, 0px));
    box-shadow: 0 -6px 18px rgba(13, 13, 13, 0.18);
  }
  /* The rail runs along the top when the card is a full-width bar: a
     5px stripe down the left edge of the screen reads as an accident. */
  .cart-sticky::before { left: 0; right: 0; top: 0; bottom: auto; width: auto; height: 4px; }
  .cart-items { margin-bottom: 8px; padding-bottom: 8px; }
  .cart-items li { font-size: 0.74rem; padding: 2px 0; }
  .cart-items li span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .ci-long { display: none; }
  .ci-short { display: inline; }
  .cart-foot { gap: 12px; }
  .cart-line { font-size: 0.82rem; }
  .cart-now { font-size: 1.2rem; }
  .cart-tag { margin-top: 2px; }
  .cart .btn { padding: 11px 16px; }
  /* Room for a fixed bar at the foot of a long form — the form's shell
     only, for the reason given above. At this width the stray copies were
     210px each: a third of a phone screen inside the header, and the same
     again under the footer's one line of text. */
  body.has-cart main .shell { padding-bottom: 210px; }
}

/* On a laptop it follows you down instead of waiting at the end.
   position:sticky with bottom:0 pins it to the foot of the viewport until
   the page scrolls far enough for its real position to arrive, at which
   point it simply stops — no JS deciding when to pin.

   The sentinel immediately after it is how the page knows the difference.
   While the sentinel is off screen the bar is floating, so it drops its
   itemised list and runs as one line; when the sentinel scrolls into view
   the bar is home and the full receipt comes back. Otherwise a curator
   reading step III has a four-line invoice sitting over their work. */
@media (min-width: 700px) {
  .cart-sticky {
    position: sticky; bottom: 18px; z-index: 30;
    box-shadow: 0 12px 34px rgba(13, 13, 13, 0.16);
  }
  .cart-sticky.is-floating .cart-items { display: none; }
  .cart-sticky.is-floating { padding-top: 13px; padding-bottom: 13px; }
}
.cart-anchor { height: 1px; }

/* The schedule strip inside the cart, phone only. On a laptop the date
   preview panel is already on screen, so repeating it here would be a
   second copy of a visible thing. */
.cart-when { display: none; }
@media (max-width: 699px) {
  .cart-when { display: flex; justify-content: space-between; gap: 10px; margin-bottom: 10px; padding-bottom: 9px; border-bottom: 1px solid var(--line); }
  .cart-when .dd-i { flex: 0 1 auto; }
}

/* .dd-i / .dd-k / .dd-v are the schedule strip. They used to belong to a
   .date-dock element of their own, pinned to the bottom of a phone screen
   next to — and then underneath — the cart. Two black bars fighting over
   one edge is one bar too many, so the strip moved inside the cart and the
   dock is gone. The classes stayed; only their home changed. */
.dd-i { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
/* Ink, not white. These were written for a black bar; the cart went pale
   and left them invisible against it. */
.dd-k { font-size: 0.48rem; font-weight: 700; letter-spacing: 0.13em; text-transform: uppercase; color: var(--ink-faint); }
.dd-v { font-size: 0.74rem; font-weight: 600; white-space: nowrap; color: var(--ink); }

/* The calendar ------------------------------------------------------

   Shared by the create form and the change-date modal, so the one place
   a curator makes a scheduling decision looks like the product rather
   than like whichever popup the browser felt like drawing.
   ------------------------------------------------------------------ */
.cal-field {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 12px 14px; border: 1px solid var(--line); border-radius: 12px;
  background: var(--blush); cursor: pointer; text-align: left;
  font-family: var(--font-body); color: var(--ink);
  /* Same rule as .btn: a date that folds onto three lines is the thing we
     keep having to fix. The JS shortens the format on narrow screens so
     nowrap here truncates almost never. */
  white-space: nowrap;
}
.cal-field:hover { border-color: var(--coral); }
.cal-field svg { width: 17px; height: 17px; stroke: var(--coral-deep); stroke-width: 2; fill: none; flex: none; }
.cal-val { flex: 1 1 auto; min-width: 0; font-size: 0.92rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cal-cue { flex: none; white-space: nowrap; font-size: 0.62rem; font-weight: 700; letter-spacing: 0.11em; text-transform: uppercase; color: var(--ink-faint); }

.cal-pop { margin-top: 10px; border: 1px solid var(--line); border-radius: 12px; background: var(--blush-raised); padding: 12px; }
.cal-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 10px; }
.cal-top b { font-size: 0.86rem; }
.cal-step {
  border: 1px solid var(--line); background: transparent; border-radius: 100px;
  width: 28px; height: 28px; cursor: pointer; color: var(--ink-dim); font-size: 1rem; line-height: 1; flex: none;
}
.cal-step:hover:not(:disabled) { border-color: var(--coral); color: var(--coral-deep); }
.cal-step:disabled { opacity: 0.3; cursor: default; }

.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; text-align: center; }
.cal-dow { font-size: 0.55rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-faint); padding: 3px 0; }
.cal-d {
  padding: 7px 0; font-size: 0.8rem; border-radius: 8px; border: 1px solid transparent;
  background: transparent; color: var(--ink); font-family: var(--font-body); cursor: pointer;
}
button.cal-d:hover { background: var(--blush-sunken); }
.cal-d.is-out { color: var(--ink-faint); opacity: 0.4; cursor: default; }
.cal-d.is-today { border-color: var(--coral); }
.cal-d.is-on { background: var(--black); color: #fff; font-weight: 700; border-color: var(--black); }
/* Struck through, not hidden: the limit is easier to trust when you can
   see exactly where it falls. */
.cal-d.is-blocked { color: var(--ink-faint); text-decoration: line-through; opacity: 0.5; cursor: not-allowed; }
.cal-note { font-size: 0.74rem; color: var(--ink-dim); margin: 10px 0 0; line-height: 1.45; }
.cal-note b { color: var(--signal); }

.date-preview {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--blush-raised); padding: 18px 20px; margin-top: 6px;
}
.dp-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  padding: 9px 0; border-bottom: 1px solid var(--line); font-size: 0.88rem;
}
.dp-row:last-of-type { border-bottom: 0; }
.dp-k { flex: none; color: var(--ink-dim); white-space: nowrap; }
.dp-v { flex: 1 1 auto; min-width: 0; color: var(--ink); font-weight: 600; text-align: right; white-space: nowrap; }
.dp-k-short { display: none; }

/* On a phone "Screening closes" and "Friday, September 18" cannot share
   a line, and the row broke into four stacked fragments. Both halves
   shorten together — the label to one word, the date to "Fri, Sep 18" —
   so every row stays a single line. Both forms sit in the DOM and CSS
   picks one, so rotating the phone cannot strand the wrong version. */
@media (max-width: 560px) {
  .date-preview { padding: 14px 15px; }
  .dp-row { gap: 10px; font-size: 0.82rem; }
  .dp-k-long { display: none; }
  .dp-k-short { display: inline; }
}
.dp-note { font-size: 0.82rem; color: var(--ink-faint); margin: 14px 0 0; }
.dp-note strong { color: var(--signal); }


/* ---------------------------------------------------------------------
   The event screen: header, review queue, settled lists, guest list

   The suite carries the same sealed treatment as the applicant's door,
   so the two halves of the product read as one thing. The queue empties
   as decisions are made, which is what turns forty names into a task
   with an end rather than a wall to scroll.
   --------------------------------------------------------------------- */

/* The event hero wears the same clothes as its card in the list.

   It was black, which made opening an event feel like arriving
   somewhere — but it also meant the same event looked like two different
   objects depending on which screen you were on. The rail is what ties
   them together: the card you clicked and the panel you land on are
   plainly the same thing. */
.ev-hero {
  position: relative; overflow: hidden;
  background: var(--blush-raised); border: 1px solid var(--line);
  border-radius: 16px;
  padding: 30px 28px 26px; text-align: center; margin-bottom: 22px;
}
/* The rail is gone. It marked an event as live, paired with the dashed
   border a closed card carried — but the card list became hairline rows,
   so the other half of that language no longer exists and a lone coral
   edge was a leftover rather than a signal. The hero says it in words
   instead: "Screening closes Sep 26" on a live one, "Applicant records
   removed" on a closed one, which needs no legend. */
.ev-hero .eyebrow { color: var(--coral-deep); margin-bottom: 10px; }
.ev-hero h1 { color: var(--ink); font-size: clamp(1.7rem, 7vw, 2.4rem); margin: 0 0 8px; line-height: 1.05; }
.ev-when { font-size: 0.85rem; color: var(--ink-dim); }
.ev-stats {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; margin-top: 24px;
  background: var(--line); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden;
}
.ev-stat { background: var(--blush-raised); padding: 16px 8px; }
.ev-stat b { display: block; font-family: var(--font-mono); font-size: 1.7rem; line-height: 1; color: var(--coral-deep); }
.ev-stat.tbd b { color: var(--ink); }
.ev-stat span { display: block; margin-top: 6px; font-size: 0.58rem; letter-spacing: 0.13em; text-transform: uppercase; color: var(--ink-faint); }
/* An event with no date says so, rather than showing a bare dash that
   reads as a rendering fault. */
.ev-hero .eyebrow.is-unset { color: var(--signal); }

/* Section headers: coral label, rule, count on the end. */
.sec-head { display: flex; align-items: baseline; gap: 14px; margin-bottom: 18px; }
.sec-label { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.17em; text-transform: uppercase; color: var(--coral-deep); }
.sec-rule { flex: 1; height: 1px; background: var(--line); }
.sec-count { font-family: var(--font-mono); font-size: 1.05rem; color: var(--ink); font-variant-numeric: tabular-nums; }
.sec-count.yes { color: var(--ok); }
.sec-count.no { color: var(--signal); }

/* Review queue.

   The score is a solid black block down the LEFT of every card, with a
   4px rule across its top in the fit colour and the label beneath in
   the same hue. Working down a queue of forty is scanning a column of
   green, yellow and red rather than reading forty names.

   The block keeps its side position at every width. On a phone it
   narrows and the type shrinks with it rather than rotating to a bar,
   so a card looks like the same object on a laptop and in a hand.

   Accept sits on the left and is the black button; decline is an
   outline. Two solid buttons compete, and the accepted list is the one
   being built.

   There is no swipe. A decision about who enters someone's room is made
   by pressing a button, never by a gesture a scroll can imitate. */
/* The queue: one column on a phone, two on a wide screen.

   A single column on a laptop left roughly half the row empty, and the
   cards ran far longer than their content needed. Two-up halves the
   scroll. The tradeoff is real and worth naming: this list is RANKED,
   strongest first, so two columns are read in a Z rather than straight
   down, and deciding someone reflows the grid — the next card slides
   into the space the last one left. Accept and Decline are the only way
   to act, and they are labelled, so a reflow costs a glance rather than
   a mistake. */
.queue { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; align-items: start; }
@media (min-width: 900px) {
  .queue { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.acard { display: flex; min-width: 0; background: #fff; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }

.acard-score { position: relative; flex: none; width: 94px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; padding: 16px 8px; color: #fff; text-align: center; background: var(--black); }
.acard-score::after { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 4px; background: var(--ink-faint); }
.acard-score.f-strong::after { background: var(--fit-strong); }
.acard-score.f-cond::after { background: var(--fit-cond); }
.acard-score.f-low::after { background: var(--fit-low); }
.acard-score.f-unmet::after { background: var(--ink-faint); }
.acard-score b { font-family: var(--font-display); font-size: 1.75rem; line-height: 1; letter-spacing: 0.01em; font-weight: 400; }
.acard-score b i { font-style: normal; font-family: var(--font-body); font-size: 0.7rem; font-weight: 600; opacity: 0.55; margin-left: 1px; }
.acard-score span { font-size: 0.55rem; font-weight: 700; letter-spacing: 0.13em; text-transform: uppercase; line-height: 1.25; white-space: nowrap; color: var(--ink-faint); }
.acard-score.f-strong span { color: var(--fit-strong); }
.acard-score.f-cond span { color: var(--fit-cond); }
.acard-score.f-low span { color: var(--fit-low); }

.acard-body { flex: 1 1 auto; min-width: 0; padding: 15px 16px; }
.acard-name { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 1.06rem; font-weight: 600; color: var(--ink); cursor: pointer; }
.acard-name:hover { color: var(--coral-deep); }
.acard-meta { font-size: 0.76rem; color: var(--ink-faint); margin: 3px 0 13px; }

.dec { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; }
.dec button { font-family: var(--font-body); font-size: 0.79rem; font-weight: 600; padding: 11px 8px; border-radius: 100px; border: 1px solid transparent; cursor: pointer; white-space: nowrap; }
.dec .b-yes { background: var(--black); color: #fff; }
.dec .b-yes:hover { background: #2a2a2a; }
.dec .b-no { background: transparent; border-color: var(--line); color: var(--ink-dim); }
.dec .b-no:hover { border-color: var(--signal); color: var(--signal); }

/* Narrow: the rail stays on the left and gets out of the way instead —
   less width, smaller type, tighter padding. Measured at 360 so the
   buttons keep their labels on one line. */
@media (max-width: 560px) {
  .acard-score { width: 72px; padding: 14px 6px; gap: 2px; }
  .acard-score b { font-size: 1.4rem; }
  .acard-score b i { font-size: 0.6rem; }
  .acard-score span { font-size: 0.5rem; letter-spacing: 0.1em; white-space: normal; }
  .acard-body { padding: 13px 13px 14px; }
  .acard-name { font-size: 1rem; }
  .dec { gap: 7px; }
  .dec button { font-size: 0.75rem; padding: 10px 6px; }
}

/* Pager. Empty when the queue fits on one page, so the control only
   exists once there is something to page through. */
.pager { display: flex; align-items: center; justify-content: center; gap: 8px; flex-wrap: wrap; }
.pager:empty { display: none; }
.pager { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line); }
.pager button { font-family: var(--font-body); font-size: 0.76rem; font-weight: 600; min-width: 38px; padding: 9px 13px; border-radius: 100px; border: 1px solid var(--line); background: transparent; color: var(--ink-dim); cursor: pointer; white-space: nowrap; }
.pager button:hover:not(:disabled) { border-color: var(--coral); color: var(--coral-deep); }
.pager button.on { background: var(--black); border-color: var(--black); color: #fff; }
.pager button:disabled { opacity: 0.35; cursor: default; }
.pg-gap { color: var(--ink-faint); padding: 0 2px; }
.pg-of { font-size: 0.72rem; color: var(--ink-faint); margin-left: 6px; }
.pg-step { display: inline-flex; align-items: center; gap: 6px; }

/* On a phone the words push Next onto a second line, and a control that
   stacks is the thing this build keeps having to fix. Arrows alone are
   unambiguous next to numbered pages; the words stay in aria-label. */
@media (max-width: 560px) {
  .pager { gap: 6px; }
  .pager button { min-width: 34px; padding: 9px 11px; }
  .pg-word { display: none; }
  .pg-of { flex: 1 0 100%; text-align: center; margin: 4px 0 0; }
}

/* Overflow out of a capped settled list, into the screen that does the
   whole job rather than a second copy of it here. */
.settled-rest { display: block; width: 100%; margin-top: 12px; font-family: var(--font-body); font-size: 0.78rem; font-weight: 600; padding: 12px; border-radius: 100px; border: 1px solid var(--coral); background: transparent; color: var(--coral-deep); cursor: pointer; text-align: center; }
.settled-rest:hover { background: var(--coral); color: var(--black); }

/* Empty and finished states are messages about the whole queue, not
   cards in it, so they span both columns rather than sitting in one. */
.queue > .hint, .queue > .queue-done { grid-column: 1 / -1; }
.queue-done { text-align: center; padding: 34px 20px; color: var(--ink-faint); font-size: 0.88rem; }
.queue-done b { display: block; font-family: var(--font-display); font-size: 1.3rem; color: var(--ink); text-transform: uppercase; letter-spacing: 0.02em; margin-bottom: 8px; white-space: nowrap; }

/* Settled lists — rows butt together as one block. */
.settled { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0; min-width: 0; }
.settled-row { display: flex; align-items: center; min-width: 0; gap: 12px; padding: 13px 16px; border: 1px solid var(--line); border-radius: 0; margin-top: -1px; background: var(--blush-raised); }
.settled-row:first-child { margin-top: 0; border-top-left-radius: var(--radius); border-top-right-radius: var(--radius); }
.settled-row:last-child { border-bottom-left-radius: var(--radius); border-bottom-right-radius: var(--radius); }
.settled-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.98rem; font-weight: 500; color: var(--ink); cursor: pointer; }
.settled-name:hover { color: var(--coral-deep); }
.settled-score { flex: none; font-family: var(--font-mono); font-size: 0.82rem; color: var(--ink-faint); }
.settled-row .back { flex: none; font-size: 0.68rem; font-weight: 600; padding: 6px 12px; border-radius: 100px; border: 1px solid var(--line); background: transparent; color: var(--ink-dim); cursor: pointer; white-space: nowrap; }
.settled-row .back:hover { border-color: var(--ink-faint); color: var(--ink); }
.settled-row.is-out .settled-name { color: var(--ink-faint); text-decoration: line-through; }

/* Manage block */
.manage { margin-top: 26px; }
.manage-row { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin-bottom: 10px; }
.manage-row:last-child { margin-bottom: 0; }
.manage-foot { margin-top: 18px; font-size: 0.75rem; color: var(--ink-faint); text-align: center; }

/* Access is about to lapse. Only set in the final week — see
   renderSuiteHeader — so the colour still means something when it appears. */
#curatorHeaderExpiry.is-closing { color: var(--signal); }

/* "Copy screening link" is long enough that pairing it with anything on
   a phone wraps the neighbour onto two lines. One button per row below
   560 — a stack of full-width buttons, never a squeezed pair. */
@media (max-width: 560px) {
  .manage-row { grid-template-columns: 1fr; }
}
.btn-dark { background: var(--black); border-color: var(--black); color: #fff; }
.btn-dark:hover { background: #2a2a2a; border-color: #2a2a2a; color: #fff; }
.btn-dark:disabled { background: var(--black); border-color: var(--black); color: #fff; opacity: 1; cursor: default; }
.btn-icon { width: 14px; height: 14px; stroke: currentColor; stroke-width: 2; fill: none; stroke-linecap: round; stroke-linejoin: round; flex: none; }
.manage-row .btn { width: 100%; justify-content: center; }
.manage-row .btn-wide { grid-column: 1 / -1; }
.btn-danger { border-color: var(--signal); color: var(--signal); background: transparent; }
.btn-danger:hover { background: var(--signal); color: #fff; }
.manage-danger { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line); }

/* Guest list */
.gl-topbar { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.gl-print { margin-left: auto; font-size: 0.66rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-dim); border: 1px solid var(--line); border-radius: 100px; padding: 6px 13px; background: transparent; cursor: pointer; white-space: nowrap; }
/* Light, matching the event hero it is reached from. This was the one
   screen in the suite that opened on a black card, so tapping through
   from the event page read as arriving somewhere else entirely. */
.gl-hero { background: var(--blush-raised); border: 1px solid var(--line); border-radius: 16px; padding: 28px 26px 24px; text-align: center; margin-bottom: 22px; }
.gl-kicker { font-size: 0.64rem; font-weight: 700; letter-spacing: 0.15em; text-transform: uppercase; color: var(--coral-deep); margin-bottom: 9px; }
.gl-title { font-family: var(--font-display); font-size: clamp(1.6rem, 6.5vw, 2.1rem); text-transform: uppercase; color: var(--ink); line-height: 1.05; }
.gl-sub { font-size: 0.85rem; color: var(--ink-dim); margin-top: 7px; }
.gl-stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px; margin-top: 22px; background: var(--line); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.gl-stat { background: var(--blush-raised); padding: 16px 8px; }
.gl-stat b { display: block; font-family: var(--font-mono); font-size: 1.7rem; line-height: 1; color: var(--coral-deep); }
.gl-stat.exp b { color: var(--ink); }
.gl-stat span { display: block; margin-top: 6px; font-size: 0.58rem; letter-spacing: 0.13em; text-transform: uppercase; color: var(--ink-faint); }
.gl-search { width: 100%; padding: 12px 14px; margin-bottom: 14px; border: 1px solid var(--line); border-radius: var(--radius); background: #fff; color: var(--ink); font-size: 0.95rem; font-weight: 500; }
.gl-search::placeholder { color: var(--ink-faint); font-weight: 400; }
.gl-list { display: grid; grid-template-columns: minmax(0, 1fr); min-width: 0; gap: 0; align-content: start; max-height: 420px; overflow-y: auto; }
.gl-row { display: flex; align-items: center; min-width: 0; gap: 14px; padding: 14px 16px; border: 1px solid var(--line); border-radius: 0; margin-top: -1px; background: var(--blush-raised); cursor: pointer; }
.gl-row.r-first { margin-top: 0; border-top-left-radius: var(--radius); border-top-right-radius: var(--radius); }
.gl-row.r-last { border-bottom-left-radius: var(--radius); border-bottom-right-radius: var(--radius); }
.gl-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 1.05rem; font-weight: 500; color: var(--ink); }
.gl-btn { flex: none; margin-left: auto; font-family: var(--font-body); font-size: 0.72rem; font-weight: 600; padding: 8px 15px; border-radius: 100px; border: 1px solid var(--line); background: transparent; color: var(--ink-dim); cursor: pointer; white-space: nowrap; }
.gl-btn:hover { border-color: var(--coral-deep); color: var(--coral-deep); }
.gl-row.in { background: var(--coral-tint); }
.gl-row.in .gl-btn { background: var(--coral); border-color: var(--coral); color: var(--black); }
.gl-row.in .gl-name { font-weight: 600; }
.gl-row.out { cursor: default; }
.gl-row.out .gl-name { color: var(--ink-faint); text-decoration: line-through; }
.gl-foot { font-size: 0.8rem; color: var(--ink-faint); text-align: center; margin-top: 16px; }

/* Modals */
.modal-veil {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(13, 13, 13, 0.62);
  display: flex; align-items: center; justify-content: center;
  padding: 24px 16px; overflow-y: auto;
}
/* Same clothes as the hero and the list card. A black dialog floating
   over a blush page was a third visual language on one screen. */
.modal-card {
  position: relative; overflow: hidden;
  background: var(--blush-raised); border: 1px solid var(--line);
  border-radius: 16px; box-shadow: 0 18px 50px rgba(13, 13, 13, 0.28);
  padding: 26px 26px 26px 30px; max-width: 460px; width: 100%; margin: auto;
  /* overflow:hidden above is what keeps the coral rail inside the rounded
     corner — but it also kills the earlier max-height:90vh + overflow-y:auto
     pair, which would clip the card with no way to scroll it. With the
     calendar open this card can outgrow a phone screen, so the veil does
     the scrolling and the card is free to be as tall as it needs.
     margin:auto keeps the top reachable: a centred flex child taller than
     its scroll container otherwise has its head cut off. */
  max-height: none;
}
.modal-card::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 5px; background: var(--coral); }
.modal-card h3 { margin: 0 0 8px; font-size: 1.2rem; color: var(--ink); }
.modal-card p { font-size: 0.88rem; color: var(--ink-dim); margin: 0 0 16px; line-height: 1.5; }
.modal-card strong { color: var(--ink); }
.modal-limit { font-size: 0.8rem; color: var(--ink-dim); margin: 12px 0 20px; }
.modal-limit b { color: var(--signal); }
/* Cancel takes only what its short label needs; the confirm button gets
   the rest, because it is the one carrying a sentence. Equal halves is
   what folded "Revoke and settle events" onto two lines. */
.modal-actions { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 10px; }
@media (max-width: 480px) { .modal-actions { grid-template-columns: minmax(0, 1fr); } }
.modal-actions .btn { width: 100%; justify-content: center; }
.loss { border-left: 2px solid var(--signal); padding: 2px 0 2px 15px; margin-bottom: 18px; }
.loss ul { margin: 0; padding-left: 16px; font-size: 0.85rem; color: var(--ink-dim); }
.loss li { margin-bottom: 6px; }

/* The guest list is the one screen that means something on paper. */
@media print {
  header.nav, .site-footer, .gl-topbar, .gl-search, .gl-stats, .gl-btn,
  #eventsView, #applicantsView, #reportView, #glDeclinedPanel { display: none !important; }
  body { background: #fff; }
  .gl-hero { background: #fff; border: 0; box-shadow: none; padding: 0 0 14px; text-align: left; border-bottom: 2px solid #000; }
  .gl-title, .gl-name { color: #000; }
  .gl-kicker { color: #666; }
  .gl-sub, .gl-foot { color: #555; }
  .panel { border: 0; box-shadow: none; padding: 14px 0 0; }
  .gl-list { max-height: none; overflow: visible; }
  .gl-row { background: #fff !important; border: 0; border-bottom: 1px solid #ccc; border-radius: 0; padding: 11px 0; }
  .gl-row::before { content: ""; width: 16px; height: 16px; border: 1.5px solid #000; border-radius: 2px; display: inline-block; flex: none; margin-right: 10px; }
}


/* ---------------------------------------------------------------------
   Pricing ladder and the landing page's new sections
   --------------------------------------------------------------------- */

.tier-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin: 28px 0 24px; }
@media (max-width: 780px) { .tier-row { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 420px) { .tier-row { grid-template-columns: 1fr; } }
.tier { border: 1px solid var(--line); border-radius: var(--radius); background: var(--blush-raised); padding: 20px 18px; text-align: center; }
.tier-days { font-size: 0.68rem; font-weight: 700; letter-spacing: 0.13em; text-transform: uppercase; color: var(--coral-deep); }
.tier-price { font-family: var(--font-display); font-size: 2.1rem; line-height: 1.05; color: var(--ink); margin: 8px 0 6px; }
.tier-note { font-size: 0.8rem; color: var(--ink-faint); }
.tier-note-block { display: grid; gap: 14px; margin-top: 8px; }
.tier-note-block p { margin: 0; font-size: 0.92rem; max-width: 68ch; }
.tier-note-block strong { color: var(--ink); }
/* The postponement add-on. Two small tiers rather than a fifth window
   tile, because it is not a window you buy instead — it is weeks you add
   to one you already have. */
.addon-row { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; margin: 6px 0; max-width: 520px; }
@media (max-width: 420px) { .addon-row { grid-template-columns: 1fr; } }
.addon { border: 1px solid var(--line); border-radius: var(--radius); background: var(--blush-raised); padding: 16px 14px; text-align: center; }
.addon-d { font-size: 0.66rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--coral-deep); }
.addon-p { font-family: var(--font-display); font-size: 1.6rem; margin: 6px 0 4px; color: var(--ink); }
.addon-n { font-size: 0.76rem; color: var(--ink-faint); }

.outcome-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; margin-top: 28px; }
@media (max-width: 860px) { .outcome-row { grid-template-columns: 1fr; } }
/* Four across on a laptop, two on a tablet — never three and an orphan. */
.outcome-row.is-quad { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1000px) { .outcome-row.is-quad { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) { .outcome-row.is-quad { grid-template-columns: 1fr; } }
.outcome { border-top: 2px solid var(--coral); padding-top: 16px; }
.outcome h3 { font-size: 1rem; margin: 0 0 7px; letter-spacing: 0; }
.outcome p { font-size: 0.9rem; color: var(--ink-dim); margin: 0; }

.window-strip { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-top: 28px; }
@media (max-width: 860px) { .window-strip { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 460px) { .window-strip { grid-template-columns: 1fr; } }
.win { border: 1px solid var(--line-on-black); border-radius: var(--radius); padding: 18px 16px; }
.win-n { font-family: var(--font-mono); font-size: 0.72rem; color: var(--coral); letter-spacing: 0.1em; margin-bottom: 8px; }
.win h3 { font-size: 0.95rem; margin: 0 0 7px; color: var(--paper-text); letter-spacing: 0; }
.win p { font-size: 0.85rem; color: var(--paper-text-dim); margin: 0; }
.win.is-end { border-color: var(--coral); }

/* Credits ------------------------------------------------------------
   The count in the suite bar, and the ledger page it opens.

   Everything here renders only when there is something to render. A
   curator with no credits sees no chip, no balance and no control:
   a feature that announces its own emptiness is worse than one that
   waits until it has something to say. The chip is therefore absent
   from the DOM at zero rather than hidden, so there is no empty slot
   pushing the suite bar around either.
   ------------------------------------------------------------------- */

/* Pressable, and the only coral in that strip, which is what says so
   without needing an arrow or a caret to explain itself. Tapping it
   never spends anything — it opens the ledger. */
.suite-credits {
  font-family: var(--font-body); cursor: pointer;
  font-size: 0.64rem; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--coral-deep); background: var(--coral-tint);
  border: 1px solid var(--coral); border-radius: 20px; padding: 4px 10px;
  text-decoration: none; white-space: nowrap;
}
.suite-credits:hover { background: var(--coral); color: var(--black); }

.credit-head { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; margin: 6px 0 2px; }
.credit-figure { font-family: var(--font-display); font-size: 2.6rem; line-height: 1; color: var(--ink); }
.credit-unit { font-size: 1rem; color: var(--ink-dim); font-weight: 500; }
.credit-worth { font-size: 0.85rem; color: var(--ink-faint); }

/* Rows, not a table. A table implies columns you would sort, and there
   are only ever two things to know: what happened, and whether it has
   landed yet. */
.credit-row { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-top: 1px solid var(--line); }
.credit-row:first-child { border-top: 0; }
.credit-who { flex: 1 1 auto; min-width: 0; }
.credit-who strong { display: block; font-size: 0.95rem; color: var(--ink); }
.credit-who span { font-size: 0.82rem; color: var(--ink-faint); }
/* State and amount travel together. Loose in the row, a name that wraps
   to two lines on a phone pushed the badge into the middle of the block
   and the column stopped reading as a column. */
.credit-tail { flex: none; display: flex; align-items: baseline; gap: 10px; }
.credit-amt { font-family: var(--font-display); font-size: 1.1rem; color: var(--ink); }
.credit-amt.is-pending { color: var(--ink-faint); }
.credit-state { font-size: 0.7rem; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 600; }
.state-earned { color: var(--ok); }
.state-pending { color: var(--coral-deep); }

@media (max-width: 430px) {
  .credit-figure { font-size: 2.2rem; }
}

/* Fit dots, back on the event rows ------------------------------------
   Taken off once on the argument that they answer "what will I find"
   while the list only asks "should I look". True as far as it goes, and
   wrong in practice: without them the row had nothing beneath the
   status line and floated. They give it a floor, and the colours are
   the same three the review queue uses, so they are learned once. */
/* The breakdown sits directly under the figure it breaks down, and the
   schedule closes the row. Putting the date between the count and its
   own dots wedged a fact about the calendar in the middle of two facts
   about the queue. */
.ev-dots { display: flex; flex-wrap: wrap; gap: 5px 13px; margin-top: 6px; }
.ev-dots + .ev-meta { margin-top: 4px; }

/* Giving a credit, in the curator table -------------------------------
   The balance is the control. It has to look pressable without being
   hovered — a bare number reads as data, and a phone has no hover to
   discover it with — so it wears the same coral pill a curator sees for
   their own balance. One rule: a credit count in a pill is pressable.

   Its column sits second, right after the name, because this table
   scrolls sideways on a phone and a control past the third column is one
   nobody finds. */
.cred-cell { white-space: nowrap; }
.cred-btn {
  font-family: var(--font-body);
  font-size: 0.64rem; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase;
  cursor: pointer; white-space: nowrap;
  color: var(--coral-deep); background: var(--coral-tint);
  border: 1px solid var(--coral); border-radius: 20px; padding: 4px 11px;
}
.cred-btn:hover { background: var(--coral); color: var(--black); }
/* Zero is pressable too: it is how a first credit gets given. */
.cred-btn.zero { color: var(--ink-dim); background: transparent; border-color: var(--line); }
.cred-btn.zero:hover { border-color: var(--coral); color: var(--coral-deep); background: var(--coral-tint); }

/* The suite-bar chip at zero. Kept visible rather than hidden: it is the
   way through to the page that explains how credits are earned, and a
   door that only appears once you are already inside is not a door. */
.suite-credits.is-zero { color: var(--ink-faint); background: transparent; border-color: var(--line); }
.suite-credits.is-zero:hover { border-color: var(--coral); color: var(--coral-deep); background: var(--coral-tint); }

/* Progressive unlock on /create ---------------------------------------
   A locked section is dimmed and inert, and says what opens it. A lock
   with no reason attached is just a wall — the curator is left guessing
   whether the page is broken or they are. */
.panel.is-locked { opacity: 0.45; pointer-events: none; }
.panel.is-locked .lock-note { opacity: 1; }
.lock-note {
  font-size: 0.76rem; font-weight: 600; color: var(--coral-deep);
  letter-spacing: 0.04em; margin-top: 6px;
}
.panel.is-done > h2::after {
  content: "✓"; color: var(--ok); font-family: var(--font-body);
  font-size: 0.9rem; margin-left: 8px; font-weight: 700;
}

/* The count on the event builder: shown, not pressable. Every other
   place a credit count appears it opens the ledger — here it must not,
   because this page is a half-filled form and navigating away from one
   to look something up is how work gets lost. */
.suite-credits.is-static { cursor: default; }
.suite-credits.is-static:hover { background: var(--coral-tint); color: var(--coral-deep); }
.suite-credits.is-static.is-zero:hover { background: transparent; color: var(--ink-faint); border-color: var(--line); }
