/*
 * Seed Placement Tester — dashboard styles.
 *
 * Every colour is a token defined with light-dark(), never a bare hex in a
 * rule. The page is read in both schemes, and a hardcoded surface colour is a
 * near-white panel behind near-white text for half the people who open it.
 * A guard test enforces this; the tokens below are the only place hexes live.
 */

/* --- tokens ---------------------------------------------------------------- */

:root {
  color-scheme: light dark;

  --bg:            light-dark(#f4f5f7, #0b0d11);
  --surface:       light-dark(#ffffff, #14171d);
  --surface-2:     light-dark(#f9fafb, #1a1e25);
  --surface-3:     light-dark(#f2f4f7, #21262f);

  --border:        light-dark(#e4e7ec, #262c35);
  --border-strong: light-dark(#d0d5dd, #343b46);

  --text:          light-dark(#101828, #e7eaf0);
  --text-muted:    light-dark(#5d6b82, #98a2b3);
  --text-subtle:   light-dark(#8792a6, #6d7683);

  --accent:        light-dark(#4338ca, #6366f1);
  --accent-hover:  light-dark(#3730a3, #818cf8);
  --accent-soft:   light-dark(#eef2ff, #1e1b4b);
  --accent-fg:     light-dark(#ffffff, #ffffff);

  --danger:        light-dark(#b42318, #f97066);
  --danger-soft:   light-dark(#fef3f2, #3b1512);
  --success:       light-dark(#067647, #47cd89);
  --success-soft:  light-dark(#ecfdf3, #0d2b1d);
  --warning:       light-dark(#b54708, #f79009);
  --warning-soft:  light-dark(#fffaeb, #34240a);

  --r-sm: 4px;
  --r:    6px;
  --r-lg: 10px;

  --shadow-sm: 0 1px 2px light-dark(rgb(16 24 40 / 6%), rgb(0 0 0 / 40%));
  --shadow-md: 0 4px 12px light-dark(rgb(16 24 40 / 10%), rgb(0 0 0 / 50%));
  --shadow-lg: 0 12px 32px light-dark(rgb(16 24 40 / 14%), rgb(0 0 0 / 60%));

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Inter, system-ui, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

/*
 * The hidden attribute must actually hide.
 *
 * `hidden` works only because the UA stylesheet says `display: none`, and ANY
 * author `display` declaration outranks it — a grid or flex rule on an element
 * the script toggles silently defeats it. Global and !important on purpose:
 * the trap is not that one rule was wrong, it is that adding a display rule
 * anywhere reintroduces it on a page that still parses and still deploys.
 */
[hidden] { display: none !important; }

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 400 14px/1.55 var(--font);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { letter-spacing: -0.012em; }
h1 { font-size: 1.35rem; font-weight: 650; margin: 0 0 .25rem; }
h2 { font-size: .95rem; font-weight: 600; margin: 0; }
h3 { font-size: .95rem; font-weight: 600; margin: 0 0 .5rem; }

.eyebrow {
  font-size: .7rem; font-weight: 650; text-transform: uppercase;
  letter-spacing: .07em; color: var(--text-subtle);
}
.hint { font-size: .78rem; color: var(--text-muted); margin: .35rem 0 0; }
.measured { font-family: var(--mono); font-size: .78rem; color: var(--text-muted); }
.warn { color: var(--danger); font-size: .82rem; }

a { color: var(--accent); }

/* --- controls -------------------------------------------------------------- */

label { display: block; margin: .65rem 0; font-size: .82rem; font-weight: 500; color: var(--text-muted); }
label.inline { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
label.inline input, label.inline select { width: auto; }

input, textarea, select {
  width: 100%; margin-top: .3rem;
  padding: .5rem .65rem;
  font: 400 .875rem/1.4 var(--font);
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--r);
  transition: border-color .12s, box-shadow .12s;
}
input::placeholder, textarea::placeholder { color: var(--text-subtle); }
input:hover, textarea:hover, select:hover { border-color: var(--text-subtle); }
input:focus, textarea:focus, select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
textarea { font-family: var(--mono); font-size: .8rem; resize: vertical; }
select { appearance: none; padding-right: 1.75rem;
  background-image: linear-gradient(45deg, transparent 50%, var(--text-muted) 50%),
                    linear-gradient(135deg, var(--text-muted) 50%, transparent 50%);
  background-position: right 1rem center, right .72rem center;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
  padding: .5rem .85rem; margin: 0;
  font: 500 .8125rem/1 var(--font);
  border: 1px solid transparent; border-radius: var(--r);
  cursor: pointer; white-space: nowrap;
  transition: background-color .12s, border-color .12s, color .12s;
}
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn + .btn { margin-left: .4rem; }
.btn-sm { padding: .35rem .6rem; font-size: .75rem; }
.btn-block { width: 100%; }

.btn-primary { background: var(--accent); color: var(--accent-fg); box-shadow: var(--shadow-sm); }
.btn-primary:hover:not(:disabled) { background: var(--accent-hover); }

.btn-secondary { background: var(--surface); color: var(--text); border-color: var(--border-strong); }
.btn-secondary:hover:not(:disabled) { background: var(--surface-3); }

.btn-ghost { background: transparent; color: var(--text-muted); }
.btn-ghost:hover:not(:disabled) { background: var(--surface-3); color: var(--text); }

.btn-danger { background: var(--danger); color: light-dark(#ffffff, #1a0d0b); }
.btn-danger:hover:not(:disabled) { filter: brightness(1.08); }

.chip {
  display: inline-flex; align-items: center; gap: .3rem;
  padding: .15rem .45rem;
  font: 500 .7rem/1.4 var(--font);
  border-radius: var(--r-sm); border: 1px solid var(--border);
  background: var(--surface-2); color: var(--text-muted);
  white-space: nowrap;
}
.chip-quiet { background: transparent; border-color: transparent; color: var(--text-subtle); }

pre {
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--r);
  padding: .75rem .85rem; margin: .5rem 0 0;
  font-family: var(--mono); font-size: .75rem; line-height: 1.5;
  overflow-x: auto;
}

/* --- sign in --------------------------------------------------------------- */

#login {
  max-width: 22rem; margin: 14vh auto 0; padding: 1.75rem;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-lg);
}
#login p { color: var(--text-muted); margin: 0 0 1.25rem; }
#login .btn { margin-top: 1rem; }
#login-state:empty { display: none; }
#login-state { margin-top: .75rem; color: var(--danger); font-size: .82rem; }

/* --- three columns --------------------------------------------------------- */

/*
 * What exists, what one of them measured, and what to try next.
 *
 * The columns scroll INDEPENDENTLY under a fixed top bar, which is the point
 * of the split: reading a long report should not scroll the copy list away,
 * and writing a draft should not scroll the report away.
 *
 * The middle track is minmax(0, 1fr) rather than 1fr. A 1fr track refuses to
 * shrink below its content, so one long unbroken url in a report would push
 * the third column off the screen.
 */
#app {
  display: grid;
  grid-template-columns: minmax(13rem, 17rem) minmax(0, 1fr) minmax(23rem, 30rem);
  grid-template-rows: auto minmax(0, 1fr);
  height: 100vh;
}

#topbar {
  grid-column: 1 / -1;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 0 1rem; height: 3.25rem;
  background: var(--surface); border-bottom: 1px solid var(--border);
}
.brand { display: flex; align-items: center; gap: .5rem; }
.brand-mark { color: var(--accent); font-size: 1rem; }
.brand-name { font-weight: 650; letter-spacing: -0.012em; }
.topbar-right { display: flex; align-items: center; gap: .6rem; }

#sidebar, #results, #composer { min-height: 0; overflow-y: auto; }
#sidebar { background: var(--surface); border-right: 1px solid var(--border); padding-bottom: 2rem; }
#results { background: var(--bg); min-width: 0; padding: 0 1.5rem 3rem; }
#composer { background: var(--surface); border-left: 1px solid var(--border); padding: 0 1.25rem 3rem; }

/* One sticky header per column, so scrolling never loses the context. */
.col-head {
  position: sticky; top: 0; z-index: 1;
  display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  padding: .85rem 1rem; margin: 0 -1rem .25rem;
  background: inherit; border-bottom: 1px solid var(--border);
}
#results .col-head { margin: 0 -1.5rem .75rem; padding: .85rem 1.5rem; background: var(--bg); }
#composer .col-head { margin: 0 -1.25rem .25rem; padding: .85rem 1.25rem; }

#composer section { padding: 1rem 0; border: 0; }
#composer section + section { border-top: 1px solid var(--border); }
/* The composer is narrow; a long JSON response must not widen the column. */
#composer pre { white-space: pre-wrap; word-break: break-word; max-height: 20rem; }

/* --- the copies list ------------------------------------------------------- */

#copies { list-style: none; margin: 0; padding: .25rem .5rem; }
.copy {
  display: grid; gap: .15rem;
  padding: .55rem .65rem; border-radius: var(--r);
  cursor: pointer; border: 1px solid transparent;
  transition: background-color .1s, border-color .1s;
}
.copy + .copy { margin-top: .15rem; }
.copy:hover { background: var(--surface-2); }
.copy.selected { background: var(--accent-soft); border-color: var(--accent); }
.copy-subject { font-weight: 550; font-size: .84rem; line-height: 1.35; color: var(--text); }
.copy-meta { font-size: .72rem; color: var(--text-subtle); }
.copy-badge { font-size: .68rem; font-weight: 650; letter-spacing: .04em; margin-top: .15rem; }
.copy-badge.muted { font-weight: 500; color: var(--text-subtle); letter-spacing: 0; }

#load-more { margin: .75rem .5rem 0; width: calc(100% - 1rem); }
#copies-state:empty { display: none; }
#copies-state { padding: .5rem 1rem; color: var(--text-subtle); }

/*
 * Placement colours: three meanings only — bad, good, and a neutral for the
 * rest. A palette that distinguishes promotions from forums invites reading
 * the colour as the finding, and these observations are provisional.
 */
.placement-spam, .placement-trash { color: var(--danger); }
.placement-primary { color: var(--success); }
.placement-promotions, .placement-social,
.placement-forums, .placement-updates,
.placement-missing, .placement-archived { color: var(--warning); }

/* --- the selected copy ----------------------------------------------------- */

#detail {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-sm);
  padding: 1.25rem 1.5rem; margin-top: .25rem;
}
#detail h2 { font-size: 1.15rem; font-weight: 650; }
#detail-meta { margin: .3rem 0 1.1rem; color: var(--text-subtle); }
.detail-placement { font-size: 1.05rem; font-weight: 700; margin: 0 0 .5rem; letter-spacing: -0.01em; }
#detail-measurement .warn {
  font-weight: 400; font-size: .8rem; line-height: 1.55; color: var(--text-muted);
  background: var(--warning-soft); border: 1px solid var(--border);
  border-left: 3px solid var(--warning);
  border-radius: 0 var(--r) var(--r) 0;
  padding: .6rem .8rem; margin: .5rem 0 1rem;
}
.blockers { font-size: .8rem; color: var(--text-muted); padding-left: 1.1rem; }

#empty { margin-top: 18vh; text-align: center; color: var(--text-subtle); }
.empty-mark { display: block; font-size: 1.75rem; margin-bottom: .5rem; opacity: .5; }

/* --- the visual editor ----------------------------------------------------- */

#toolbar {
  display: flex; flex-wrap: wrap; gap: .25rem;
  padding: .3rem; margin: .5rem 0 .4rem;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r);
}
.tool {
  padding: .3rem .5rem; margin: 0;
  font: 500 .75rem/1 var(--font);
  color: var(--text-muted); background: transparent;
  border: 1px solid transparent; border-radius: var(--r-sm); cursor: pointer;
}
.tool:hover:not(:disabled) { background: var(--surface); color: var(--text); border-color: var(--border); }
.tool:disabled { opacity: .35; cursor: default; }
.tool[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent); border-color: var(--accent); }

#body {
  min-height: 13rem; padding: .75rem .9rem;
  background: var(--surface);
  border: 1px solid var(--border-strong); border-radius: var(--r);
  line-height: 1.6;
}
#body:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
#body[contenteditable="false"] { background: var(--surface-2); color: var(--text-muted); }
#body > :first-child { margin-top: 0; }
#body > :last-child { margin-bottom: 0; }

/*
 * The button preview, styled by ATTRIBUTE selector.
 *
 * Never a class: the server strips class attributes, so adding one would teach
 * the operator that what they see is what is stored.
 */
#body a[data-ist-button] {
  display: inline-block; padding: .5rem 1.15rem; margin: .5rem 0;
  background: light-dark(#1a56db, #3b82f6); color: white;
  border-radius: var(--r-sm); text-decoration: none; font-weight: 600; font-size: .85rem;
}

#body-code { min-height: 13rem; }
#code-note { margin-top: .4rem; }
#measured { margin: .6rem 0 0; }
#measured.diverged { color: var(--warning); font-weight: 500; }
#editability {
  background: var(--danger-soft); border: 1px solid var(--border);
  border-left: 3px solid var(--danger); border-radius: 0 var(--r) var(--r) 0;
  padding: .55rem .75rem; margin-top: .6rem;
}

#sent-html { margin-top: 1rem; }
#sent-html > summary {
  cursor: pointer; font-size: .78rem; font-weight: 500; color: var(--text-muted);
  padding: .3rem 0;
}
#sent-html-code { white-space: pre-wrap; word-break: break-all; max-height: 18rem; overflow-y: auto; }

/* --- send ------------------------------------------------------------------ */

#send { background: var(--danger-soft); border-radius: var(--r); padding: 1rem !important; margin-top: 1rem; }
.phrase { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.phrase code {
  background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  padding: .3rem .5rem; font-family: var(--mono); font-size: .82rem;
}

/* --- dialog ---------------------------------------------------------------- */

#link-dialog {
  border: 1px solid var(--border); border-radius: var(--r-lg);
  padding: 1.5rem; min-width: 22rem;
  background: var(--surface); color: var(--text);
  box-shadow: var(--shadow-lg);
}
#link-dialog::backdrop { background: light-dark(rgb(16 24 40 / 35%), rgb(0 0 0 / 60%)); }
#link-dialog h2 { margin-bottom: .75rem; }
.dialog-actions { display: flex; justify-content: flex-end; gap: .5rem; margin-top: 1.25rem; }
.dialog-actions .btn + .btn { margin-left: 0; }

/* --- narrower screens ------------------------------------------------------ */

/*
 * Two columns, then one. The composer folds below the results first: on a
 * narrow screen you are far likelier to be READING a result than writing a
 * draft, and a cramped editor is worse than one you scroll to.
 */
@media (max-width: 78rem) {
  #app { grid-template-columns: minmax(12rem, 16rem) minmax(0, 1fr); height: auto; }
  #sidebar { position: sticky; top: 3.25rem; height: calc(100vh - 3.25rem); }
  #results, #composer { overflow-y: visible; }
  #composer { grid-column: 2; border-left: 0; border-top: 1px solid var(--border); }
  #topbar { position: sticky; top: 0; z-index: 2; }
}

@media (max-width: 46rem) {
  #app { grid-template-columns: 1fr; }
  #sidebar { position: static; height: auto; max-height: 20rem; border-right: 0; border-bottom: 1px solid var(--border); }
  #composer { grid-column: 1; }
  #results { padding: 0 1rem 2rem; }
  #results .col-head { margin: 0 -1rem .75rem; padding: .85rem 1rem; }
}

/* ---------------------------------------------------------------------------
   Live updating

   The dashboard refreshes itself every few seconds. Two things follow from
   that: a change has to be noticeable without being loud, and the fact that
   updating is happening at all has to be visible -- a screen that silently
   stops refreshing looks exactly like a screen where nothing is happening,
   which is the failure this replaces reloading by hand to avoid.
   --------------------------------------------------------------------------- */

.live-state {
  margin-left: auto;
  font-size: 0.75rem;
  color: var(--text-muted);
  white-space: nowrap;
}

.live-state.live-error { color: var(--danger); }

/* A brief tint, not a bounce. The eye catches the change on a glance back at
   the screen; nothing moves, so nothing is harder to click. */
@keyframes just-changed {
  from { background-color: var(--accent-soft); }
  to   { background-color: transparent; }
}

.copy-badge.just-changed { animation: just-changed 2s ease-out; }

@keyframes just-arrived {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}

.copy.just-arrived { animation: just-arrived 0.4s ease-out; }

/* Respect the setting. An animation that fires on a timer, unprompted, is
   exactly the kind this preference exists to stop. */
@media (prefers-reduced-motion: reduce) {
  .copy-badge.just-changed,
  .copy.just-arrived { animation: none; }
}
