/* ============================================================================
   Dynamic Auctioneers Marketing Platform (M8) - Design System v2 (Dark/Mint)
   "Obsidian + mint glow": cool charcoal surfaces, a mint accent,
   a soft glow on every interactive hover, crisp transform/shadow motion.
   Recolour in ONE place: change --accent* (hex) and --accent-rgb (the same
   colour as "r, g, b"); every glow, border and fill follows. Every class name
   is unchanged, so all Jinja templates render without edits.
   Motion follows emilkowal rules: transform/opacity/shadow only, ease-out,
   <=240ms, behind prefers-reduced-motion. Anti-slop: one cohesive cool palette,
   a restrained mint (not neon green-on-black), motion is motivated.
   ============================================================================ */

/* ---- Tokens ------------------------------------------------------------- */
:root {
  /* cool violet-charcoal surface ramp (darkest -> most lifted) */
  --ground:    #0C0B12;
  --ground-2:  #100E17;
  --surface:   #16131F;
  --surface-2: #1E1A2A;
  --surface-3: #262135;
  --sidebar:   #0A0910;

  --hairline:      #2A2539;
  --hairline-soft: #1F1B2B;
  --hairline-ink:  #2A2539;   /* legacy alias (sidebar dividers) */

  /* text ramp (cool off-white) */
  --text:        #E9E6F2;
  --text-strong: #F7F5FD;
  --muted:       #A19AB4;      /* ~6:1 on --surface */
  --faint:       #6F6885;

  /* mint accent -- change these + --accent-rgb to reskin the whole app */
  --accent:        #6EE7B7;
  --accent-bright: #A7F3D0;
  --accent-deep:   #10B981;
  --accent-ink:    #05271E;    /* text on solid accent fills */
  --accent-rgb:         110, 231, 183;
  --accent-bright-rgb:  167, 243, 208;
  --accent-bg:  rgba(var(--accent-rgb), .12);
  --accent-bd:  rgba(var(--accent-rgb), .34);

  /* legacy gold aliases (kept so any stray reference resolves) */
  --gold: var(--accent); --gold-bright: var(--accent-bright);
  --gold-deep: var(--accent-deep); --gold-ink: var(--accent-ink);
  --gold-bg: var(--accent-bg); --gold-bd: var(--accent-bd); --gold-pale: var(--accent-bg);

  /* semantic (brightened to read on dark) */
  --block: #E8735F;
  --note:  #E4B65C;
  --ok:    #82CE8C;
  --info:  #7CB8DA;
  --block-bg: rgba(232,115,95,.13);  --block-bd: rgba(232,115,95,.34);
  --note-bg:  rgba(228,182,92,.13);  --note-bd:  rgba(228,182,92,.32);
  --ok-bg:    rgba(130,206,140,.13); --ok-bd:    rgba(130,206,140,.30);
  --info-bg:  rgba(124,184,218,.13); --info-bd:  rgba(124,184,218,.30);

  /* legacy surface/state aliases */
  --ink: var(--surface); --ink-soft: var(--surface-2); --body: var(--text);
  --sheet: var(--surface);
  --block-pale: var(--block-bg); --note-pale: var(--note-bg);
  --ok-pale: var(--ok-bg); --info-pale: var(--info-bg);

  /* glow + elevation */
  --glow-ring:   0 0 0 1px rgba(var(--accent-rgb), .32);
  --glow-soft:   0 0 0 1px rgba(var(--accent-rgb), .22), 0 8px 26px -8px rgba(var(--accent-rgb), .35);
  --glow-strong: 0 0 0 1px rgba(var(--accent-rgb), .50), 0 12px 36px -8px rgba(var(--accent-rgb), .50);
  --shadow-1: 0 1px 2px rgba(0,0,0,.5);
  --shadow-2: 0 18px 48px -16px rgba(0,0,0,.85);

  --sidebar-w: 230px;
  --content-max: 1200px;

  /* motion */
  --ease: cubic-bezier(0.23, 1, 0.32, 1);
  --dur-1: 130ms;
  --dur-2: 190ms;
  --dur-3: 240ms;

  --font: 'Montserrat', 'Avenir Next', 'Helvetica Neue', system-ui, -apple-system,
          'Segoe UI', Roboto, Arial, sans-serif;

  color-scheme: dark;
}

/* ---- Reset / base ------------------------------------------------------- */
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background:
    radial-gradient(120% 90% at 100% -10%, rgba(var(--accent-rgb), .08), transparent 55%),
    radial-gradient(90% 70% at -10% 0%, rgba(124,92,224,.05), transparent 50%),
    var(--ground);
  background-attachment: fixed;
  color: var(--text);
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
h1, h2, h3, h4, p, ul, ol { margin: 0; }
ul, ol { padding: 0; list-style: none; }
a { color: var(--accent); text-decoration: none; transition: color var(--dur-1) var(--ease); }
/* scope link-hover colour to real links: a filled .btn keeps its own text
   colour on hover (accent-on-accent would otherwise disappear). */
a:not(.btn):hover { color: var(--accent-bright); text-decoration: underline; }
button { font-family: inherit; }
img { max-width: 100%; }
.num, .tnum { font-variant-numeric: tabular-nums; }
.muted { color: var(--muted); }

/* Visible focus everywhere (WCAG AA keyboard operability) */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---- App shell (glass command bar over full-width canvas) --------------- */
.app { display: flex; flex-direction: column; min-height: 100vh; }

.appbar {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; gap: 22px;
  height: 58px; padding: 0 22px;
  background: rgba(12, 11, 18, .82);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  backdrop-filter: blur(14px) saturate(1.3);
  border-bottom: 1px solid var(--hairline);
  box-shadow: 0 10px 34px -22px rgba(0,0,0,.95);
}
.appbar__brand { display: inline-flex; align-items: center; gap: 10px; flex: none; }
.appbar__brand:hover { text-decoration: none; }
.appbar__mark {
  width: 15px; height: 15px; border-radius: 4px; flex: none;
  background: linear-gradient(140deg, var(--accent-bright), var(--accent-deep));
  box-shadow: 0 0 14px rgba(var(--accent-rgb), .7);
  transform: rotate(45deg);
  transition: transform var(--dur-3) var(--ease), box-shadow var(--dur-2) var(--ease);
}
.appbar__brand:hover .appbar__mark { transform: rotate(135deg); box-shadow: 0 0 20px rgba(var(--accent-rgb), .95); }
.appbar__word {
  font-size: 14.5px; font-weight: 800; letter-spacing: .01em; color: var(--text-strong);
  white-space: nowrap;
}

.appbar__nav { display: flex; align-items: center; gap: 4px; flex: 1 1 auto; }
.navlink {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 13px; border-radius: 999px;
  color: var(--muted); font-size: 13px; font-weight: 600; letter-spacing: .01em;
  border: 1px solid transparent;
  transition: color var(--dur-1) var(--ease), background var(--dur-1) var(--ease),
              border-color var(--dur-1) var(--ease), box-shadow var(--dur-2) var(--ease);
}
.navlink .icon { color: var(--faint); transition: color var(--dur-1) var(--ease); }
.navlink:hover {
  color: var(--text-strong); background: var(--surface-2);
  border-color: var(--hairline); box-shadow: var(--glow-soft); text-decoration: none;
}
.navlink:hover .icon { color: var(--accent-bright); }
.navlink.is-active {
  color: var(--text-strong);
  background: var(--accent-bg);
  border-color: var(--accent-bd);
  box-shadow: 0 0 18px -6px rgba(var(--accent-rgb), .7);
}
.navlink.is-active .icon { color: var(--accent); }

.appbar__user { display: flex; align-items: center; gap: 10px; flex: none; }
.appbar__who {
  font-size: 12px; color: var(--muted);
  max-width: 190px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.appbar__role {
  font-size: 9px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase;
  color: var(--accent-bright); padding: 4px 8px; border-radius: 999px;
  background: var(--accent-bg); border: 1px solid var(--accent-bd);
}
.appbar__logout {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 999px; color: var(--muted); flex: none;
  border: 1px solid var(--hairline); background: var(--surface);
  transition: color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease),
              box-shadow var(--dur-2) var(--ease);
}
.appbar__logout:hover {
  color: var(--accent-bright); border-color: var(--accent-bd);
  box-shadow: var(--glow-soft); text-decoration: none;
}

.main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 32px 16px;
  background: transparent;
}
.topbar__title { font-size: 19px; font-weight: 800; color: var(--text-strong); letter-spacing: -.01em; }
.topbar__sub { font-size: 12px; color: var(--muted); margin-top: 3px; }
.topbar__actions { display: flex; align-items: center; gap: 10px; }

/* glowing accent rule under the top bar */
.goldrule {
  height: 3px;
  background: linear-gradient(90deg, transparent, var(--accent-deep) 12%, var(--accent-bright) 50%, var(--accent-deep) 88%, transparent);
  box-shadow: 0 0 18px -2px rgba(var(--accent-rgb), .60);
}

.content { padding: 26px 32px 64px; }
.content-inner { max-width: var(--content-max); margin: 0 auto; }
.content--narrow .content-inner { max-width: 880px; }

.eyebrow {
  font-size: 11px; font-weight: 700; letter-spacing: .18em;
  text-transform: uppercase; color: var(--accent);
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
}
.eyebrow .dot { width: 4px; height: 4px; border-radius: 50%; background: var(--accent);
  box-shadow: 0 0 8px rgba(var(--accent-rgb), .9); flex: none; }

/* ---- Panels / cards / sheets ------------------------------------------- */
.panel {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  box-shadow: var(--shadow-1);
}
.panel__head {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 16px 20px;
  border-bottom: 1px solid var(--hairline);
}
.panel__title {
  font-size: 12px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase;
  color: var(--text-strong);
}
.panel__actions { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.panel__body { padding: 20px; }

.card {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 10px;
  padding: 16px 18px;
  color: var(--text);
  transition: border-color var(--dur-1) var(--ease), box-shadow var(--dur-2) var(--ease);
}
.card:hover { border-color: var(--accent-bd); box-shadow: var(--glow-soft); }

/* Gate sheet: centred document panel */
.sheet {
  max-width: 860px;
  margin: 0 auto;
  background: var(--surface);
  box-shadow: var(--shadow-2);
  border: 1px solid var(--hairline);
  border-radius: 14px;
  overflow: hidden;
}
.sheet__letterhead {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 24px;
  flex-wrap: wrap;
  padding: 24px 40px 18px;
  border-top: 3px solid var(--accent);
  border-bottom: 1px solid var(--hairline);
  background: linear-gradient(180deg, var(--accent-bg) 0%, transparent 120%);
  box-shadow: 0 -1px 22px -6px rgba(var(--accent-rgb), .45) inset;
}
.sheet__letterhead .sheet__address { text-align: right; margin-bottom: 0; }
.sheet__body { padding: 30px 40px 34px; }
.sheet h1 {
  font-size: clamp(22px, 3.4vw, 30px); font-weight: 800; line-height: 1.14;
  letter-spacing: -.01em; color: var(--text-strong); margin: 10px 0 6px; text-wrap: balance;
}
.sheet__address { font-size: 13.5px; color: var(--muted); margin-bottom: 16px; }

/* section heading, accent underline */
.h-rule {
  font-size: 12px; font-weight: 800; letter-spacing: .16em; text-transform: uppercase;
  color: var(--text-strong); margin: 0 0 12px; padding-bottom: 7px;
  border-bottom: 2px solid var(--accent); display: inline-block;
}

/* ---- Ledger table (job board) ------------------------------------------ */
.ledger-wrap {
  overflow-x: auto; background: var(--surface); border: 1px solid var(--hairline);
  border-radius: 12px; box-shadow: var(--shadow-1);
}
.ledger { width: 100%; border-collapse: collapse; min-width: 760px; }
.ledger thead th {
  text-align: left;
  font-size: 10px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted);
  padding: 13px 16px;
  border-bottom: 1px solid var(--accent-bd);
  white-space: nowrap;
  background: var(--ground-2);
}
.ledger tbody td {
  padding: 13px 16px;
  border-bottom: 1px solid var(--hairline-soft);
  vertical-align: middle;
}
.ledger tbody tr {
  border-left: 3px solid transparent;
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease),
              box-shadow var(--dur-2) var(--ease), transform var(--dur-2) var(--ease);
}
.ledger tbody tr:hover {
  background: var(--surface-2);
  border-left-color: var(--accent);
  box-shadow: var(--glow-soft);
}
.ledger__dp { font-weight: 800; color: var(--text-strong); font-variant-numeric: tabular-nums; }
.ledger__prop { color: var(--text); font-weight: 600; }
.ledger__prop .sub { display: block; font-weight: 400; color: var(--muted); font-size: 12px; margin-top: 2px; }
.ledger__meta { color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.ledger__next a, .ledger__next .btn { white-space: nowrap; }
.col-num { text-align: right; font-variant-numeric: tabular-nums; }

/* ---- Command deck (KPI stat cards) ------------------------------------- */
.deck {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(158px, 1fr)); gap: 14px;
}
.stat {
  position: relative; overflow: hidden;
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  border: 1px solid var(--hairline); border-radius: 14px;
  padding: 15px 17px;
  transition: border-color var(--dur-1) var(--ease), box-shadow var(--dur-2) var(--ease),
              transform var(--dur-2) var(--ease);
}
.stat:hover { border-color: var(--accent-bd); box-shadow: var(--glow-soft); }
@media (prefers-reduced-motion: no-preference) { .stat:hover { transform: translateY(-2px); } }
.stat__label {
  display: flex; align-items: center; gap: 7px;
  font-size: 10px; font-weight: 700; letter-spacing: .13em; text-transform: uppercase;
  color: var(--muted);
}
.stat__label .icon { color: var(--faint); width: 14px; height: 14px; }
.stat__num {
  margin-top: 10px; font-size: 30px; font-weight: 800; line-height: 1;
  color: var(--text-strong); font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}
.stat__num .unit { font-size: 12px; font-weight: 600; color: var(--muted); margin-left: 4px; letter-spacing: 0; }
.stat--live { border-color: var(--accent-bd); }
.stat--live .stat__num { color: var(--accent-bright); }
.stat--live .stat__label .icon { color: var(--accent); }
.stat--live::after {
  content: ''; position: absolute; right: -30px; top: -30px; width: 90px; height: 90px;
  background: radial-gradient(circle, rgba(var(--accent-rgb), .18), transparent 70%);
  pointer-events: none;
}
.stat--flag .stat__num { color: var(--note); }
.stat--flag .stat__label .icon { color: var(--note); }

/* ---- Pipeline stage track (board rows) --------------------------------- */
.track { display: inline-flex; align-items: center; }
.track__dot {
  width: 9px; height: 9px; border-radius: 50%; flex: none;
  background: var(--surface-3); border: 1px solid var(--hairline);
  transition: background var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease);
}
.track__dot.is-done { background: var(--accent-deep); border-color: var(--accent-deep); }
.track__dot.is-now {
  background: var(--accent); border-color: var(--accent);
  box-shadow: 0 0 9px rgba(var(--accent-rgb), .95);
}
.track__seg { width: 18px; height: 2px; flex: none; background: var(--hairline); }
.track__seg.is-done { background: var(--accent-deep); }
.track__label {
  margin-top: 6px; font-size: 11px; font-weight: 600; letter-spacing: .03em; color: var(--muted);
}
.track__label.is-flag { color: var(--note); }

/* ---- Buttons ------------------------------------------------------------ */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-size: 13px; font-weight: 700; letter-spacing: .01em;
  padding: 9px 16px;
  border: 1px solid var(--hairline);
  border-radius: 8px;
  cursor: pointer;
  background: var(--surface-2);
  color: var(--text);
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease),
              border-color var(--dur-1) var(--ease), box-shadow var(--dur-2) var(--ease),
              transform var(--dur-1) var(--ease);
}
.btn:hover { text-decoration: none; border-color: var(--accent-bd); box-shadow: var(--glow-soft); }
.btn .icon { flex: none; }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .45; cursor: not-allowed; pointer-events: none; }

.btn--primary {
  background: linear-gradient(180deg, var(--accent-bright), var(--accent));
  color: var(--accent-ink); border-color: var(--accent-deep); font-weight: 800;
}
.btn--primary:hover { box-shadow: var(--glow-strong); border-color: var(--accent-bright); }

.btn--gold { background: var(--accent); color: var(--accent-ink); border-color: var(--accent-deep); font-weight: 800; }
.btn--gold:hover { background: var(--accent-bright); box-shadow: var(--glow-strong); }

.btn--ghost { background: transparent; color: var(--text); border-color: var(--hairline); }
.btn--ghost:hover { border-color: var(--accent); background: var(--accent-bg); color: var(--accent-bright); box-shadow: var(--glow-soft); }

.btn--danger { background: transparent; color: var(--block); border-color: var(--block-bd); }
.btn--danger:hover { background: var(--block); color: #1A0B08; border-color: var(--block);
  box-shadow: 0 0 0 1px rgba(232,115,95,.4), 0 10px 30px -10px rgba(232,115,95,.6); }

.btn--sm { padding: 6px 11px; font-size: 12px; }
.btn--block { width: 100%; }

/* crisp lift + press: press faster than release */
@media (prefers-reduced-motion: no-preference) {
  .btn:hover { transform: translateY(-1px); }
  .btn:active { transform: scale(0.97) translateY(1px); transition-duration: 80ms; }
}

/* ---- State badges ------------------------------------------------------- */
.badge {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 10.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  padding: 4px 9px;
  border-radius: 6px;
  border: 1px solid transparent;
  white-space: nowrap;
}
.badge .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none;
  box-shadow: 0 0 6px currentColor; }

.badge--neutral { color: var(--muted); background: var(--surface-3); border-color: var(--hairline); }
.badge--info { color: var(--info); background: var(--info-bg); border-color: var(--info-bd); }
.badge--note { color: var(--note); background: var(--note-bg); border-color: var(--note-bd); }
.badge--ok { color: var(--ok); background: var(--ok-bg); border-color: var(--ok-bd); }
.badge--block { color: var(--block); background: var(--block-bg); border-color: var(--block-bd); }
.badge--gold { color: var(--accent-bright); background: var(--accent-bg); border-color: var(--accent-bd); }
.badge--ink { color: var(--text-strong); background: var(--surface-3); border-color: var(--hairline); }

/* ---- Flags -------------------------------------------------------------- */
.flag {
  display: flex; gap: 12px;
  padding: 14px 16px;
  border: 1px solid var(--hairline);
  border-left-width: 4px;
  border-radius: 8px;
  background: var(--surface);
}
.flag + .flag { margin-top: 10px; }
.flag--block { border-left-color: var(--block); background: var(--block-bg); border-color: var(--block-bd); }
.flag--note { border-left-color: var(--note); background: var(--note-bg); border-color: var(--note-bd); }
.flag__icon { flex: none; margin-top: 1px; }
.flag--block .flag__icon { color: var(--block); }
.flag--note .flag__icon { color: var(--note); }
.flag__body { min-width: 0; }
.flag__title { font-weight: 800; color: var(--text-strong); font-size: 13.5px; }
.flag__code {
  font-size: 10px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  color: var(--muted); margin-left: 8px;
}
.flag__evidence { color: var(--text); font-size: 13px; margin-top: 5px; }
.flag__action { color: var(--muted); font-size: 12.5px; margin-top: 6px; }
.flag__action b { color: var(--accent-bright); font-weight: 700; }

/* compact inline flag pill */
.flag-pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; font-weight: 700;
  padding: 3px 9px; border-radius: 6px; border: 1px solid transparent;
}
.flag-pill--block { color: var(--block); background: var(--block-bg); border-color: var(--block-bd); }
.flag-pill--note { color: var(--note); background: var(--note-bg); border-color: var(--note-bd); }

/* ---- Forms -------------------------------------------------------------- */
.field { margin-bottom: 16px; }
.label {
  display: block;
  font-size: 11px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--text); margin-bottom: 6px;
}
.input, .textarea, .select {
  width: 100%;
  font-family: inherit; font-size: 14px; color: var(--text);
  background: var(--surface-3);
  border: 1px solid var(--hairline);
  border-radius: 8px;
  padding: 9px 12px;
  transition: border-color var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease),
              background var(--dur-1) var(--ease);
}
.input::placeholder, .textarea::placeholder { color: var(--faint); }
.input:focus, .textarea:focus, .select:focus {
  outline: none;
  border-color: var(--accent);
  background: var(--surface-2);
  box-shadow: 0 0 0 3px rgba(var(--accent-rgb), .18), 0 0 20px -6px rgba(var(--accent-rgb), .55);
}
.textarea { resize: vertical; min-height: 90px; line-height: 1.55; }
.hint { font-size: 12px; color: var(--muted); margin-top: 5px; }
.hint--inline { display: inline; margin: 0; font-weight: 600; }
/* A hint that reports a contradiction in a source document (D80): the OTP
   whose figure and words disagree. Coloured like a flag, not an error - the
   app is not broken, the document is. */
.hint--warn { color: var(--note); font-weight: 600; }
.label--sm { font-size: 12px; margin-bottom: 3px; }
.auction-panel { border: 1px solid var(--accent-bd); background: var(--accent-bg); border-radius: 10px; padding: 12px 14px; }
.auction-panel[hidden] { display: none; }
.field-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 12px; margin-top: 6px; }
.form-error { font-size: 12.5px; color: var(--block); font-weight: 600; margin-top: 6px; }
.input.is-invalid, .textarea.is-invalid { border-color: var(--block); }

.checkline { display: flex; align-items: center; gap: 9px; padding: 6px 0; }
.checkline input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--accent); }

/* ---- Drag-drop / intake ------------------------------------------------- */
.dropzone {
  border: 2px dashed var(--accent-bd);
  border-radius: 12px;
  background: var(--ground-2);
  padding: 48px 28px;
  text-align: center;
  color: var(--text);
  transition: background var(--dur-2) var(--ease), transform var(--dur-2) var(--ease),
              border-color var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease);
  cursor: pointer;
}
.dropzone:hover { border-color: var(--accent); box-shadow: var(--glow-soft); }
.dropzone .icon { color: var(--accent); }
.dropzone__title { font-size: 16px; font-weight: 800; color: var(--text-strong); margin: 12px 0 4px; }
.dropzone__hint { font-size: 13px; color: var(--muted); }
.dropzone.is-dragover {
  background: var(--accent-bg);
  border-color: var(--accent);
  box-shadow: var(--glow-strong);
}
@media (prefers-reduced-motion: no-preference) {
  .dropzone.is-dragover { transform: scale(1.01); }
  /* same playful jiggle-pause-jiggle as the empty-state hero icon, while the
     drop zone is hovered (prompt icon only, never the file-list icons) */
  .dropzone:hover .dropzone__prompt .icon { animation: empty-jiggle 1.6s var(--ease) infinite; }
}

/* Selected-file confirmation: swaps the prompt for the chosen files. */
.dropzone__files { display: none; text-align: left; }
.dropzone.is-filled {
  border-style: solid;
  border-color: var(--accent);
  background: var(--accent-bg);
  box-shadow: var(--glow-soft);
  padding: 24px;
}
.dropzone.is-filled .dropzone__prompt { display: none; }
.dropzone.is-filled .dropzone__files { display: block; }
.dropzone__files-head {
  display: flex; align-items: center; gap: 8px;
  font-size: 14px; font-weight: 800; margin-bottom: 12px;
}
.dropzone__files-head.is-ok { color: var(--accent-bright); }
.dropzone__files-head.is-note { color: var(--note); }
.dropzone__file {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; margin-top: 8px;
  background: var(--surface); border: 1px solid var(--hairline); border-radius: 8px;
}
.dropzone__file-icon { color: var(--accent); display: inline-flex; flex: 0 0 auto; }
.dropzone__file-name {
  flex: 1 1 auto; min-width: 0;
  font-size: 13px; font-weight: 600; color: var(--text-strong);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dropzone__file-size { flex: 0 0 auto; font-size: 12px; color: var(--muted); }
.dropzone__files-note { margin-top: 10px; font-size: 12px; color: var(--note); }
.btn.is-ready {
  border-color: var(--accent); color: var(--accent-bright); font-weight: 800;
  background: var(--accent-bg); box-shadow: var(--glow-soft);
}

.progress {
  height: 6px; background: var(--surface-3); overflow: hidden; border-radius: 999px;
}
.progress__bar {
  height: 100%; width: 0;
  background: linear-gradient(90deg, var(--accent-deep), var(--accent-bright));
  box-shadow: 0 0 12px rgba(var(--accent-rgb), .75);
  /* glide linearly across the 1.2s poll gap so the bar always creeps forward
     (elapsed-driven, never stuck at a fixed % then jumping to done) */
  transition: width 1.25s linear;
}

/* ---- inline button spinner (in-flight state) -------------------------- */
.spinner {
  display: none; width: 14px; height: 14px; flex: none; border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .3); border-top-color: currentColor;
  animation: spin .6s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spinner { animation-duration: 1.6s; } }
/* while a form's request is in flight: lock its submit button and swap the
   label/icon for the spinner, so it cannot be clicked twice and the user can
   see it is busy. htmx puts .htmx-request on the FORM, not the button, so the
   .btn.htmx-request rule below never catches a form-submit button. */
form.htmx-request [data-intake-submit],
form.htmx-request button[type="submit"] { pointer-events: none; opacity: .9; }
form.htmx-request [data-intake-submit] > .icon,
form.htmx-request [data-intake-submit] > span:not(.spinner),
form.htmx-request button[type="submit"] > .icon,
form.htmx-request button[type="submit"] > span:not(.spinner) { display: none; }
form.htmx-request [data-intake-submit] .spinner,
form.htmx-request button[type="submit"] .spinner { display: inline-block; }
/* generic: a button that makes its OWN request (e.g. Auto-generate headline)
   locks and swaps its label for the spinner while in flight */
.btn.htmx-request, .btn.is-submitting { pointer-events: none; opacity: .9; }
.btn.htmx-request > .icon, .btn.is-submitting > .icon,
.btn.htmx-request > span:not(.spinner), .btn.is-submitting > span:not(.spinner) { display: none; }
.btn.htmx-request .spinner, .btn.is-submitting .spinner { display: inline-block; }

/* ---- Work indicator: honest progress for a slow action ----------------- */
/* Reusable: any element carrying data-work="<what is happening>" raises this
   bar while its HTMX request is in flight (app.js drives the numbers). The real
   percentage is unknowable, so the bar creeps toward 90% on a half-life curve
   and only reaches 100% when the response lands - it never counts down a figure
   it invented. The elapsed seconds beside the label are the honest measure. */
.workbar {
  margin-top: 14px; padding: 12px 14px;
  background: var(--surface-2);
  border: 1px solid var(--accent-bd); border-radius: 10px;
  box-shadow: var(--glow-soft);
  opacity: 1;
}
.workbar__head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.workbar__spinner {
  display: inline-block;
  border-color: rgba(var(--accent-rgb), .25); border-top-color: var(--accent);
}
/* label and elapsed read as one sentence, so keep them together on the left */
.workbar__label {
  flex: 0 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 13px; font-weight: 700; color: var(--text-strong);
}
.workbar__elapsed {
  flex: none; margin-left: -2px;
  font-size: 12px; font-weight: 800;
  color: var(--accent-bright); font-variant-numeric: tabular-nums;
}
.workbar__eta { margin-top: 8px; }
.workbar .progress { position: relative; }
/* app.js ticks once a second; glide between ticks so the bar never looks stuck */
.workbar .progress__bar { transition: width 1s linear; }
/* finished: rush the bar to full, then fade the whole thing out behind it */
.workbar.is-done .progress__bar { transition: width 180ms var(--ease); }
.workbar.is-done { opacity: 0; transition: opacity var(--dur-3) var(--ease) 240ms; }

/* indeterminate sheen: this is work in progress, not a measured percentage */
@media (prefers-reduced-motion: no-preference) {
  .workbar .progress::after {
    content: ''; position: absolute; inset: 0;
    background: linear-gradient(90deg, transparent, rgba(var(--accent-bright-rgb), .30), transparent);
    transform: translateX(-100%);
    animation: work-sheen 1.6s var(--ease) infinite;
  }
  @keyframes work-sheen { to { transform: translateX(100%); } }
  .workbar.is-done .progress::after { animation: none; }
}

/* while the work runs its own triggers are locked, so it cannot be fired twice */
.is-working [data-work] { pointer-events: none; }
.is-working [data-work]:not(.is-active) { opacity: .45; }

/* a field label with an inline action on the right (Auto-generate) */
.label-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 8px; }
.label-row .label { margin-bottom: 0; }

/* --- gate-2 ad-design picker (D41) -------------------------------------- */
.adtpl-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(148px, 1fr)); gap: 14px; }
.adtpl {
  display: flex; flex-direction: column; gap: 8px; padding: 8px; cursor: pointer;
  background: var(--surface-2); border: 1.5px solid var(--hairline); border-radius: 10px;
  text-align: center; font: inherit;
  transition: border-color var(--dur-1) var(--ease), box-shadow var(--dur-2) var(--ease), transform var(--dur-1) var(--ease);
}
.adtpl:hover { border-color: var(--accent-bd); }
.adtpl:active { transform: scale(0.98); }
.adtpl.is-active { border-color: var(--accent); box-shadow: var(--glow-soft); }
.adtpl__thumb { display: block; overflow: hidden; border-radius: 6px; background: var(--surface-3); aspect-ratio: 3 / 4; }
.adtpl__thumb img { width: 100%; height: 100%; object-fit: cover; object-position: top; display: block; }
.adtpl__name { font-size: 12px; font-weight: 700; color: var(--text-strong); }
.adtpl.is-active .adtpl__name::after { content: " \00b7 selected"; color: var(--accent); font-weight: 800; }

/* ---- Sticky action bar (gate screens) ---------------------------------- */
.actionbar {
  position: sticky; bottom: 0;
  display: flex; align-items: center; justify-content: flex-end; gap: 12px;
  padding: 16px 20px;
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  border-top: 1px solid var(--accent-bd);
  box-shadow: 0 -10px 30px -12px rgba(0,0,0,.8), 0 -1px 20px -8px rgba(var(--accent-rgb), .40);
  overflow: hidden;
}
.actionbar .spacer { flex: 1 1 auto; }
.actionbar__note { font-size: 12px; color: var(--muted); }

/* accent sweep across the action bar on approval press */
.gold-sweep::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(var(--accent-bright-rgb), .38), transparent);
  transform: translateX(-100%);
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  .gold-sweep.is-sweeping::after { animation: sweep 520ms var(--ease) forwards; }
}
@keyframes sweep { to { transform: translateX(100%); } }

/* ---- Artifact gallery --------------------------------------------------- */
.gallery-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 14px;
}
.tile {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 10px;
  overflow: hidden;
  transition: border-color var(--dur-1) var(--ease), box-shadow var(--dur-2) var(--ease),
              transform var(--dur-2) var(--ease);
}
.tile:hover { border-color: var(--accent); box-shadow: var(--glow-strong); }
@media (prefers-reduced-motion: no-preference) {
  .tile:hover { transform: translateY(-3px); }
}
.tile__img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; display: block; background: var(--ground-2); }
/* Rasterised preview of an html/pdf artifact. The icon sits underneath as the
   fallback: if the thumbnail request fails the <img> removes itself and the
   icon shows through, so a tile is never a broken image. */
.tile__shot {
  position: relative; width: 100%; aspect-ratio: 1 / 1; background: var(--ground-2);
  display: flex; align-items: center; justify-content: center; overflow: hidden;
}
.tile__shot img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; object-position: center; display: block;
}
/* First lines of a text artifact (portal listing, Facebook post, email blast).
   The tail fades out rather than being cut mid-letter. */
.tile__text {
  width: 100%; aspect-ratio: 1 / 1; margin: 0; overflow: hidden;
  padding: 11px 12px; background: var(--ground-2); border-bottom: 1px solid var(--hairline);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 10px; line-height: 1.5; color: var(--text); white-space: pre-wrap; word-break: break-word;
  -webkit-mask-image: linear-gradient(180deg, #000 78%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 78%, transparent 100%);
}
/* Live scaled preview of an html artifact (the advert). The iframe is laid out
   at the design's TRUE pixel size (e.g. 1080x1350) and scaled down to the
   container by JS, so the whole design is visible and stays vector-crisp -
   rather than showing the top-left corner of a full-size page clipped to a
   short box, which is what a plain height-limited iframe does. */
/* The whole advert must be visible WITHOUT scrolling, so the box is capped by
   the viewport height and its width is derived from the design's ratio (a 4:5
   advert at 52vh tall). JS then measures the real column and sets exact pixel
   values, but these CSS values alone already show the complete design - so a
   stale cached script degrades to "slightly smaller", never to a clipped
   corner, which is what a plain height-limited iframe gives. */
.adframe {
  position: relative; overflow: hidden; background: #fff; margin-inline: auto;
  border-bottom: 1px solid var(--hairline);
  height: min(72vh, 700px);
  width: calc(min(72vh, 700px) * var(--ad-w, 1080) / var(--ad-h, 1350));
  max-width: 100%;
}
.adframe iframe {
  position: absolute; top: 0; left: 0; border: 0; display: block;
  transform-origin: top left; pointer-events: none;
  /* 560/1350 = .414 is the cap-height default; JS overrides with the measured
     fit (the smaller of width-fit and height-fit). */
  transform: scale(var(--ad-scale, 0.414));
}
/* Gate 2 reviews one advert at a time, so give it room: a single tile spans the
   panel instead of sitting in a 200px grid cell. */
.gallery-grid--review { grid-template-columns: 1fr; }

.tile__body { padding: 11px 13px; display: flex; align-items: center; justify-content: space-between; gap: 8px; }
/* A photograph being replaced (D110): dimmed, with a spinner over it, and its
   buttons locked until the new picture and the redrawn advert arrive. */
.tile__busy {
  display: none; position: absolute; inset: 0; z-index: 3;
  align-items: center; justify-content: center; gap: 8px;
  background: rgba(25, 22, 19, .62); color: #fff;
  font-size: 11px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
}
.tile__busy .spinner { display: inline-block; width: 22px; height: 22px; border-width: 3px; }
[data-photo-tile].htmx-request { cursor: progress; }
[data-photo-tile].htmx-request .tile__busy { display: flex; }
[data-photo-tile].htmx-request .tile__cap { pointer-events: none; opacity: .55; }
/* A feature line edited in place, with its Remove button (D109). */
.featline { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-width: 0; }
.featline .input { flex: 1 1 220px; min-width: 0; }
.featcard { padding: 12px; }
.iconrow > .featline { margin-bottom: 7px; }
/* While a save is in flight the boxes are read-only (app.js); say so. */
#features.is-saving .featline .input { opacity: .6; cursor: progress; }
.tile__cap {
  font-size: 10.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--text-strong);
}

/* ---- Loading (skeleton, shimmer not spinners) -------------------------- */
.skeleton {
  background: linear-gradient(90deg, var(--surface-2) 25%, var(--surface-3) 37%, var(--surface-2) 63%);
  background-size: 400% 100%;
  border-radius: 6px;
  color: transparent;
}
@media (prefers-reduced-motion: no-preference) {
  .skeleton { animation: shimmer 1.4s ease infinite; }
}
@keyframes shimmer { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }
.skeleton-row { height: 18px; margin: 14px 16px; }
.skeleton-row.w-40 { width: 40%; }
.skeleton-row.w-70 { width: 70%; }
.skeleton-row.w-90 { width: 90%; }

/* ---- Empty state -------------------------------------------------------- */
.empty {
  text-align: center;
  padding: 60px 28px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  /* centre the content both ways and fill the space below the header, so the
     empty state reads as a deliberate centred column, not a box near the top */
  min-height: 56vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
/* direct-child only, so the hero icon glows mint but the plus INSIDE the
   button keeps its dark ink (a descendant selector here painted the button's
   plus mint-on-mint, i.e. invisible) */
.empty > .icon { color: var(--accent); filter: drop-shadow(0 0 14px rgba(var(--accent-rgb), .55)); }
.empty__title { font-size: 17px; font-weight: 800; color: var(--text-strong); margin: 14px 0 6px; }
/* a tight centred column, so the description does not sprawl wider than the
   icon / title / button above and below it */
.empty__text { font-size: 13.5px; color: var(--muted); margin: 0 auto 18px; max-width: 44ch; }
.empty__cta { display: inline-flex; }
/* one-time hero-icon arrival (transform/opacity only, ease-out, <=240ms), plus
   a playful jiggle-pause-jiggle while the CTA is hovered. empty-pop stays first
   and identical in both rules so it is not restarted when the jiggle toggles. */
@media (prefers-reduced-motion: no-preference) {
  .empty > .icon { animation: empty-pop var(--dur-3) var(--ease) both; }
  .empty:has(.empty__cta:hover) > .icon {
    animation: empty-pop var(--dur-3) var(--ease) both,
               empty-jiggle 1.6s var(--ease) infinite;
  }
}
@keyframes empty-pop { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: none; } }
/* wobble hard for the first ~0.4s, then rest for ~1.2s, then repeat */
@keyframes empty-jiggle {
  0%   { transform: rotate(0); }
  3%   { transform: rotate(-11deg); }
  7%   { transform: rotate(9deg); }
  11%  { transform: rotate(-6deg); }
  15%  { transform: rotate(4deg); }
  19%  { transform: rotate(-2deg); }
  23%  { transform: rotate(0); }
  100% { transform: rotate(0); }
}

/* ---- Banners (job failures, notices) ----------------------------------- */
.banner {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 13px 16px;
  border: 1px solid var(--hairline);
  border-left-width: 4px;
  border-radius: 8px;
  background: var(--surface);
  font-size: 13.5px;
}
.banner .icon { flex: none; margin-top: 1px; }
.banner__body { min-width: 0; }
.banner__title { font-weight: 800; color: var(--text-strong); }
.banner--error { border-left-color: var(--block); background: var(--block-bg); border-color: var(--block-bd); }
.banner--error .icon { color: var(--block); }
.banner--ok { border-left-color: var(--ok); background: var(--ok-bg); border-color: var(--ok-bd); }
.banner--ok .icon { color: var(--ok); }
.banner--note { border-left-color: var(--note); background: var(--note-bg); border-color: var(--note-bd); }
.banner--note .icon { color: var(--note); }
.banner--info { border-left-color: var(--info); background: var(--info-bg); border-color: var(--info-bd); }
.banner--info .icon { color: var(--info); }

/* ---- Toasts (slide up, stack) ------------------------------------------ */
.toasts {
  position: fixed; right: 24px; bottom: 24px;
  display: flex; flex-direction: column-reverse; gap: 14px;
  z-index: 100; pointer-events: none;
}
.toast {
  pointer-events: auto;
  min-width: 240px; max-width: 360px;
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 15px;
  background: var(--surface-2);
  border: 1px solid var(--hairline);
  border-left: 4px solid var(--info);
  border-radius: 10px;
  box-shadow: var(--shadow-2);
  font-size: 13px;
}
.toast .icon { flex: none; margin-top: 1px; }
.toast--ok { border-left-color: var(--ok); }
.toast--ok .icon { color: var(--ok); }
.toast--block { border-left-color: var(--block); }
.toast--block .icon { color: var(--block); }
.toast--note { border-left-color: var(--note); }
.toast--note .icon { color: var(--note); }
.toast__title { font-weight: 800; color: var(--text-strong); }
.toast__text { color: var(--text); margin-top: 2px; }
@media (prefers-reduced-motion: no-preference) {
  .toast { animation: toast-in var(--dur-3) var(--ease); }
  @keyframes toast-in { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
}

/* ---- Layout helpers ----------------------------------------------------- */
.stack { display: flex; flex-direction: column; gap: 16px; }
.stack--sm { gap: 8px; }
.stack--lg { gap: 26px; }
.row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.row--between { justify-content: space-between; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
.spacer { flex: 1 1 auto; }
.mt-0 { margin-top: 0; } .mt-1 { margin-top: 8px; } .mt-2 { margin-top: 16px; } .mt-3 { margin-top: 24px; }

/* corroborated-facts / ledger key-value list (memo) */
.kv { width: 100%; border-collapse: collapse; }
.kv td { padding: 9px 12px; border-bottom: 1px solid var(--hairline-soft); font-size: 13.5px; vertical-align: top; }
.kv td.k { color: var(--muted); font-weight: 600; width: 40%; white-space: nowrap; }
.kv td.v { color: var(--text); font-variant-numeric: tabular-nums; }

/* raw monospace panes (memo / email markdown) */
pre.card { color: var(--text); font-size: 12.5px; line-height: 1.6; }

/* ---- Icons -------------------------------------------------------------- */
.icon { width: 18px; height: 18px; display: inline-block; vertical-align: middle; flex: none; }
.icon--sm { width: 15px; height: 15px; }
.icon--lg { width: 24px; height: 24px; }
.icon--xl { width: 40px; height: 40px; }
.icon--flip { transform: scaleX(-1); }  /* a right-arrow reused as "back" */

/* ---- HTMX swap motion --------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  .htmx-swapping { opacity: 0; transform: translateY(6px); transition: opacity var(--dur-1) var(--ease), transform var(--dur-1) var(--ease); }
  .htmx-settling { opacity: 1; transform: none; }

  .htmx-added { animation: swap-in var(--dur-3) var(--ease); }
  @keyframes swap-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

  .stagger { opacity: 0; animation: row-rise var(--dur-3) var(--ease) forwards; animation-delay: calc(var(--i, 0) * 40ms); }
  @keyframes row-rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

  /* Background polls refresh silently: suppress entrance/stagger inside them. */
  #ledger-body .stagger,
  #ledger-body .htmx-added,
  #status-board .htmx-added,
  #status-board.htmx-added { animation: none; opacity: 1; }

  /* Self-polling intake card: it re-swaps every 1.2s, so don't fade the whole
     panel out and back on each tick. The one-time entrance on settle still
     plays via the `enter` class. */
  .job-card.htmx-added { animation: none; opacity: 1; }
  .job-card.htmx-swapping { opacity: 1; transform: none; transition: none; }

  /* blur-to-sharp bridge on a freshly changed state badge */
  .polish-blur-bridge { animation: blur-bridge 360ms var(--ease); }
  @keyframes blur-bridge { from { filter: blur(4px); opacity: .4; } to { filter: none; opacity: 1; } }

  .enter { transition: opacity var(--dur-3) var(--ease), transform var(--dur-3) var(--ease); }
  @starting-style { .enter { opacity: 0; transform: translateY(6px); } }
}

.htmx-indicator { opacity: 0; }
.htmx-request .htmx-indicator, .htmx-request.htmx-indicator { opacity: 1; }

/* ---- Reduced motion: collapse to opacity-only / instant ---------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .dropzone.is-dragover, .btn:active, .btn:hover, .tile:hover { transform: none; }
}

/* ---- Responsive --------------------------------------------------------- */
@media (max-width: 860px) {
  .appbar { gap: 12px; padding: 0 14px; overflow-x: auto; }
  .appbar__word, .appbar__who { display: none; }
  .appbar__nav { flex: 0 0 auto; }
  .grid-2 { grid-template-columns: 1fr; }
  .content, .topbar { padding-left: 18px; padding-right: 18px; }
  .sheet__body { padding: 22px 20px; }
}

/* --- gate-1 physical-conflict source picker (D35) ---------------------- */
.conflict__opts { display: flex; flex-direction: column; gap: 8px; margin: 8px 0 10px; }
.conflict__opt {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border: 1px solid var(--hairline); border-radius: 8px;
  background: var(--surface-2); cursor: pointer;
  transition: border-color var(--dur-1) var(--ease), background var(--dur-1) var(--ease);
}
.conflict__opt:hover { border-color: var(--accent-bd); }
.conflict__opt:has(input:checked) { border-color: var(--accent); box-shadow: var(--glow-soft); }
.conflict__opt input { accent-color: var(--accent); flex: none; }
.conflict__src { font-weight: 700; color: var(--text-strong); min-width: 130px; }
.conflict__val { color: var(--text); flex: 1; }
.conflict__badge {
  font-size: 11px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase;
  color: var(--accent-ink); background: var(--accent); padding: 2px 8px; border-radius: 999px;
}

/* --- board row manage controls (edit, delete) -------------------------- */
.ledger__manage { text-align: center; white-space: nowrap; }
a.iconbtn { text-decoration: none; }
a.iconbtn:hover {
  color: var(--gold); border-color: var(--gold); background: rgba(172, 135, 74, .10);
}
.iconbtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 7px;
  border: 1px solid transparent; background: transparent; color: var(--faint);
  cursor: pointer; opacity: .35;
  transition: opacity var(--dur-1) var(--ease), color var(--dur-1) var(--ease),
              border-color var(--dur-1) var(--ease), background var(--dur-1) var(--ease);
}
tr:hover .iconbtn { opacity: 1; }
.iconbtn:active { transform: scale(0.94); }
.iconbtn--danger:hover {
  color: var(--block); border-color: var(--block); background: rgba(232, 115, 95, .10);
}

/* --- photo lightbox (1.2) --------------------------------------------- */
.lightbox {
  position: fixed; inset: 0; z-index: 90; display: flex; align-items: center;
  justify-content: center; padding: 4vmin; background: rgba(16, 13, 9, .86);
  cursor: zoom-out; animation: fade-in var(--dur-1) var(--ease);
}
.lightbox img {
  max-width: 100%; max-height: 100%; object-fit: contain;
  border: 1px solid var(--line); box-shadow: 0 18px 60px rgba(0, 0, 0, .5);
}

/* --- photo drag-reorder (2.4) ----------------------------------------- */
[data-photo-tile] { cursor: grab; }
[data-photo-tile].is-dragging { opacity: .45; cursor: grabbing; }
/* Drag-to-reorder has worked since D78 but nothing on screen said so, and the
   photograph itself shows a zoom-in cursor, which signals "click me" instead.
   The grab cursor and the handle are the whole discoverability fix (D91). */
[data-photo-tile] { cursor: grab; }
[data-photo-tile] .tile__grip {
  /* Bottom-left: top-left is the low-res / file-missing flag and top-right is
     the "Ad N" badge, so the grip had both to collide with. */
  position: absolute; bottom: 6px; left: 6px; z-index: 3;
  width: 26px; height: 26px; border-radius: 7px;
  background: rgba(12, 10, 8, .62); color: #fff;
  display: flex; align-items: center; justify-content: center;
  opacity: 0; transition: opacity .12s ease; pointer-events: none;
}
[data-photo-tile]:hover .tile__grip { opacity: 1; }
[data-photo-tile] .tile__grip svg { width: 15px; height: 15px; }
[data-photo-sort] { min-height: 40px; }


/* --- the advert's icon picker (D95) ---------------------------------------
   A grid of the real glyphs rather than a dropdown of words: the picture in
   the picker is the picture that prints, which a list of names cannot show. */
.iconrow { padding: 10px 0; border-top: 1px solid var(--line); }
.iconrow:first-child { border-top: 0; }
.iconrow__label { font-size: 13px; font-weight: 600; margin-bottom: 7px; color: var(--ink-2); }
.iconrow__picks { display: flex; flex-wrap: wrap; gap: 5px; }
.iconpick {
  width: 34px; height: 34px; border-radius: 8px; cursor: pointer;
  border: 1px solid var(--line); background: var(--panel-2);
  display: flex; align-items: center; justify-content: center;
  color: var(--muted); transition: border-color .12s ease, color .12s ease, background .12s ease;
}
.iconpick:hover { border-color: var(--accent-bd); color: var(--ink); }
.iconpick input { position: absolute; opacity: 0; width: 0; height: 0; }
.iconpick svg { width: 19px; height: 19px; }
.iconpick__auto { font-size: 8.5px; font-weight: 800; letter-spacing: .04em; }
.iconpick.is-on, .iconpick:has(input:checked) {
  border-color: var(--accent); color: var(--accent);
  background: var(--accent-bg); box-shadow: var(--glow);
}

.iconpick img { width: 19px; height: 19px; object-fit: contain; }
/* An uploaded glyph is a picture, not a font: it cannot take the accent colour,
   so the selected state is carried by the tile alone. */
.btn.is-active { border-color: var(--accent); color: var(--accent); background: var(--accent-bg); }


/* The gate-2 preview column, pinned while the editing column scrolls (D99).
   `align-self: start` matters: a grid item stretches to the row height by
   default, and a stretched item has nothing to stick within - the rule is
   silently ignored without it. Dropped on narrow screens, where the columns
   stack and a pinned panel would eat the viewport. */
@media (min-width: 981px) {
  .stickyish { position: sticky; top: 84px; align-self: start; max-height: calc(100vh - 104px); overflow: auto; }
  /* The scrollbar is the panel's own, so keep it off the rounded corner. */
  .stickyish::-webkit-scrollbar { width: 8px; }
  .stickyish::-webkit-scrollbar-thumb { background: var(--line); border-radius: 8px; }
}


/* Auction proposals (M9, D103). The form is long and the checks are what a
   person acts on, so the checks, files and email sit in a pinned side column
   (reusing .stickyish) and the columns stack on a narrow screen. */
.proposal-grid { display: grid; grid-template-columns: minmax(0, 3fr) minmax(320px, 2fr); gap: 24px; align-items: start; }
/* Stacks earlier than gate 2 (981px): the budget table needs the width, and
   squeezed beside the side column its cost column scrolls out of sight. */
@media (max-width: 1180px) {
  .proposal-grid { grid-template-columns: 1fr; }
  .proposal-grid .stickyish { position: static; max-height: none; }
}
.doc-slot { display: flex; flex-direction: column; gap: 8px; padding-bottom: 16px; border-bottom: 1px solid var(--hairline-soft); }
.doc-slot:last-child { padding-bottom: 0; border-bottom: 0; }
.doc-upload { display: inline-flex; }
.doc-upload .btn { cursor: pointer; }
.doc-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.doc-list li { display: flex; align-items: center; gap: 8px; font-size: 13.5px; }
.doc-list li span:first-of-type { overflow-wrap: anywhere; }
.proposal-thumbs { display: flex; flex-wrap: wrap; gap: 10px; }
.proposal-thumb { position: relative; margin: 0; width: 150px; border: 1px solid var(--hairline); border-radius: 8px; overflow: hidden; background: #fff; }
.proposal-thumb img { display: block; width: 100%; height: 170px; object-fit: contain; }
.proposal-thumb--tall img { height: 230px; }
.proposal-thumb .iconbtn { position: absolute; top: 6px; right: 6px; }
.erf-block { padding-bottom: 14px; margin-bottom: 14px; border-bottom: 1px solid var(--hairline-soft); }
/* A fixed layout shares the column out, so on a 1366px laptop the cost column
   stays in view instead of scrolling off the right (it measured 760px of table
   in a 664px column before). */
.budget-table { table-layout: fixed; width: 100%; min-width: 0; }
.budget-table th:nth-child(1) { width: 31%; }
.budget-table th:nth-child(2) { width: 29%; }
.budget-table th:nth-child(3) { width: 18%; }
.budget-table th:nth-child(4) { width: 16%; }
.budget-table th:nth-child(5) { width: 6%; }
.budget-table td { vertical-align: top; padding: 6px; }
.budget-table .textarea { min-height: 0; resize: vertical; }
.budget-table .input, .budget-table .textarea { width: 100%; min-width: 0; }
.input.is-invalid, .textarea.is-invalid { border-color: var(--block); }

/* The switch between auction proposals and OTPs (M10, D114): two segments in
   the nav pill style, first thing on both screens. On a DP's page the other
   segment is a small form (it may start that DP's record), so the form steps
   out of the layout and its button looks like the link beside it. */
.doc-switch {
  display: inline-flex; flex-wrap: wrap; gap: 4px; padding: 4px; margin-bottom: 18px; max-width: 100%;
  border: 1px solid var(--hairline); border-radius: 999px; background: var(--surface);
}
.doc-switch__form { display: contents; }
.doc-switch__opt {
  display: inline-flex; align-items: center; padding: 7px 16px; border-radius: 999px;
  border: 1px solid transparent; background: transparent; color: var(--muted);
  font: inherit; font-size: 13px; font-weight: 600; letter-spacing: .01em; cursor: pointer;
  transition: color var(--dur-1) var(--ease), background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease);
}
.doc-switch__opt:hover { color: var(--text-strong); background: var(--surface-2); text-decoration: none; }
.doc-switch__opt.is-active {
  color: var(--text-strong); background: var(--accent-bg); border-color: var(--accent-bd); cursor: default;
  box-shadow: 0 0 18px -6px rgba(var(--accent-rgb), .7);
}

/* Property reports (M11, D116): the viewing checklist's tick boxes in a grid
   that wraps to the column, and photo thumbnails small enough that 40 of them
   fit on a screen, each with a move-earlier button beside its remove button. */
.tick-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 6px 14px; margin-top: 6px; }
.tick { display: flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--text); cursor: pointer; }
.tick input { accent-color: var(--accent-deep); width: 16px; height: 16px; flex: none; }
.proposal-thumb--photo { width: 120px; background: var(--surface-2); }
.proposal-thumb--photo img { height: 90px; object-fit: cover; }
.proposal-thumb .photo-earlier { position: absolute; top: 6px; left: 6px; }
