/* ===========================================================================
   Tag Docket — visual system
   ===========================================================================

   Adapted from the Bid Desk "Hand-off" system used by the RFP product
   (docs/design-system.md in that repo). Same tokens, same scale, same rules —
   two products from one studio should look like it. Rewritten as plain custom
   properties because this app has no build step, which stays true.

   THE RULES. Everything below follows from five decisions.

   1. Paper, not white. The page is --paper; cards are white and sit on it. A
      white card on a white page has lost its background.
   2. One brand colour. --grass-600 means "primary action or current state".
      Everything else in the palette is a status.
   3. Marker yellow is a highlight, never a fill. It tints a row that needs a
      person. One per screen — three highlighted rows highlight nothing.
   4. Borders and fills carry the structure. Shadows almost never do.
   5. The type is bigger than it looks like it should be. The old sheet ran a
      15px body and 12px uppercase labels; most of what anyone actually read
      was a meta size doing body work. The floor is 14px for meta, 16px for
      content.

   WHAT CHANGED FROM THE OLD SHEET, and why:

   - Uppercase letter-spaced micro-labels are gone. That treatment reads as a
     dashboard. This is a desk — someone sits at it for an hour and ships forty
     links, and shouting every field label at them is exhausting.
   - Sections became cards. The old page separated them with a bottom border,
     which leaves a long unbroken column with no sense of where one thing ends.
   - The chrome moved to a rail. The old top bar carried the org, two context
     selects, a New button, a Settings link and an email address in one row,
     and each of them was cramped by the others.
=========================================================================== */

:root {
  /* --- Surfaces ---------------------------------------------------------- */
  --paper:      #FDFBF5;  /* the page                                        */
  --card:       #FFFFFF;  /* cards, panels, the rail                         */
  --sand:       #F3EFE3;  /* secondary panels, hover, section bands          */
  --sand-deep:  #EFE9DB;  /* inner rows, troughs, neutral badge              */

  /* --- Lines ------------------------------------------------------------- */
  --line:        #E0DACA; /* default 1px border on a card                    */
  --line-soft:   #EFE9DB; /* dividers inside a card                          */
  --line-strong: #C9C0AA; /* inputs, secondary buttons, dashed outlines      */

  /* --- Text — contrast measured on --paper ------------------------------- */
  --ink:       #23201A;   /* 14.6:1 — headings, values                       */
  --ink-soft:  #5C5749;   /*  7.0:1 — secondary body, descriptions           */
  --ink-mute:  #7A7362;   /*  4.8:1 — labels, meta, timestamps               */
  --ink-faint: #A89F8B;   /*  2.6:1 — placeholders and disabled ONLY         */

  /* --- Brand ------------------------------------------------------------- */
  --grass-50:  #E3EFE7;
  --grass-100: #CFE4D7;
  --grass-600: #2C6248;
  --grass-700: #1C4531;
  /* The focus ring: grass-600 at 16%. A token rather than a literal, because
     it is the one brand colour that was written out by hand — and a white
     label that leaves every focus ring green is visibly unfinished. */
  --brand-ring: rgba(44, 98, 72, .16);

  /* --- Marker: attention, never a fill ----------------------------------- */
  --marker:      #FFE07A;
  --marker-soft: #FFF8E2;

  /* --- Status hues. -50 is the background, -700 the text on it, -500 a dot
         or an icon only. Never -500 as text on a light background. --------- */
  --clay-50:  #FBE7E2;    /* refused, expired, destructive                   */
  --clay-500: #D2604A;
  --clay-700: #9C4030;

  --ochre-50:  #FDF4E3;   /* warning, needs attention, due soon              */
  --ochre-500: #E9B23C;
  --ochre-700: #8A6D1F;

  --tide-50:  #E5EEF1;    /* informational — active but not urgent           */
  --tide-500: #3E6B7A;
  --tide-700: #2B4C57;

  /* --- Type -------------------------------------------------------------- */
  --display: "Bricolage Grotesque", "Work Sans", ui-sans-serif, system-ui, sans-serif;
  --sans: "Work Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* --- Radii ------------------------------------------------------------- */
  --r-control: 10px;      /* buttons, inputs, chips, badges                  */
  --r-card: 14px;         /* cards, list rows, panels                        */
  --r-panel: 20px;        /* page-level containers                           */

  /* --- Elevation. One shadow, and almost nothing uses it. ---------------- */
  --shadow-soft: 0 1px 2px rgba(35, 32, 26, .04), 0 10px 28px rgba(35, 32, 26, .08);

  --rail: 15rem;
}

* { box-sizing: border-box; }

/* `hidden` has to beat a display rule, or every panel this app toggles — the
   QR facts, the bulk textarea, the sign-in states — shows as an empty bordered
   box. The attribute is the app's only way of hiding anything. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 16px/1.5 var(--sans);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3 {
  font-family: var(--display);
  font-optical-sizing: auto;
  letter-spacing: -.02em;
  margin: 0;
}

/* Focus is grass, never the browser default blue. */
:focus-visible { outline: 2px solid var(--grass-600); outline-offset: 2px; }
::selection { background: var(--marker); color: var(--ink); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; }
}

/* ---------------------------------------------------------------------------
   Shell
   ---------------------------------------------------------------------------
   A rail rather than a top bar. The old header carried identity, two context
   selects, a create action, navigation and an account menu on one line; at a
   laptop width the selects were about eleven characters wide, which is not
   enough to read a client name.
--------------------------------------------------------------------------- */

.app { display: flex; min-height: 100vh; }

.rail {
  width: var(--rail);
  flex: 0 0 var(--rail);
  background: var(--card);
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
}

.rail .brand {
  display: flex; align-items: center; gap: 10px;
  padding: 18px 16px;
  border-bottom: 1px solid var(--line-soft);
}
.rail .mark {
  width: 32px; height: 32px; flex: 0 0 32px;
  border-radius: 9px; background: var(--grass-600);
  display: grid; place-items: center;
  color: var(--paper); font-family: var(--display); font-weight: 800; font-size: 15px;
}
/* An agency's own logo in place of the monogram. Wordmarks are wide, so the
   slot grows sideways rather than squashing one into a square. */
.rail .mark.logo { width: auto; max-width: 112px; flex: 0 0 auto; background: none; border-radius: 0; }
.rail .mark.logo img { display: block; height: 32px; width: auto; max-width: 112px; object-fit: contain; }
.rail .brand .who { min-width: 0; }
.rail .brand .org { display: block; font-size: 16px; font-weight: 700; color: var(--ink); }
.rail .brand .email { display: block; font-size: 14px; color: var(--ink-mute); }
.rail .brand .org,
.rail .brand .email { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.rail nav { flex: 1; padding: 14px 10px; display: grid; gap: 2px; align-content: start; }
.rail nav a {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: var(--r-card);
  font-size: 16px; font-weight: 600; color: var(--ink-soft);
  text-decoration: none; cursor: pointer;
  transition: background-color .12s, color .12s;
}
.rail nav a:hover { background: var(--sand); color: var(--ink); }
.rail nav a[aria-current="page"] { background: var(--grass-50); color: var(--grass-700); }
.rail nav a svg { width: 17px; height: 17px; flex: 0 0 17px; }

.rail .foot { padding: 14px 10px; border-top: 1px solid var(--line-soft); }
.rail .foot button {
  width: 100%; display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: var(--r-card);
  background: none; border: 0; cursor: pointer;
  font: 600 16px/1.5 var(--sans); color: var(--ink-soft); text-align: left;
}
.rail .foot button:hover { background: var(--sand); color: var(--ink); }
.rail .foot button svg { width: 17px; height: 17px; flex: 0 0 17px; }

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

.topbar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
  padding: 16px 24px;
  border-bottom: 1px solid var(--line);
  background: var(--paper);
}
.topbar h1 { font-size: 28px; font-weight: 800; line-height: 1.15; }
.topbar .spacer { flex: 1; }

.context { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.context label { font-size: 14px; font-weight: 600; color: var(--ink-mute); }
.context select { width: auto; min-width: 11rem; padding: 7px 34px 7px 12px; }

main { padding: 24px; display: grid; gap: 20px; align-content: start; }
main.two-col { grid-template-columns: 1fr; }
@media (min-width: 72rem) {
  main.two-col { grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr); align-items: start; }
}
main.narrow { max-width: 52rem; }

/* Below a laptop the rail becomes a strip. Two nav items do not justify a
   drawer, and a drawer is one more tap on the device where the builder is
   already hardest to use. */
@media (max-width: 60rem) {
  .app { flex-direction: column; }
  .rail {
    width: auto; flex: none; height: auto; position: static;
    border-right: 0; border-bottom: 1px solid var(--line);
    flex-direction: row; align-items: center; gap: 8px; padding: 0 12px;
  }
  .rail .brand { border: 0; padding: 12px 4px; flex: 1; min-width: 0; }
  .rail .brand .email { display: none; }
  .rail nav { flex: 0 0 auto; display: flex; padding: 0; }
  .rail .foot { border: 0; padding: 0; }
  .rail .foot button span { display: none; }
  .topbar { padding: 14px 16px; }
  .topbar h1 { font-size: 23px; }
  /* The spacer exists to push the context right of a wide title. With the row
     wrapped it pushes the first label onto a line of its own instead. */
  .topbar .spacer { display: none; }
  .context { width: 100%; }
  .context select { flex: 1 1 8rem; min-width: 0; }
  main { padding: 16px; }
}

/* ---------------------------------------------------------------------------
   Card — the unit everything sits in
--------------------------------------------------------------------------- */

.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  padding: 20px;
}
.card > h2 {
  font-size: 21px; font-weight: 700; color: var(--ink);
  margin-bottom: 4px;
}
.card > h2 + .sub { margin-top: -2px; }
.card + .card { margin-top: 0; }

.sub { font-size: 16px; color: var(--ink-soft); margin: 0 0 16px; }
.muted { color: var(--ink-mute); }
.small { font-size: 14px; }

/* A stack of cards on the settings page. Each configurable thing is its own
   surface: the old page ran them together with hairlines, which made a long
   column where nothing had a beginning. */
.stack { display: grid; gap: 16px; align-content: start; }

/* ---------------------------------------------------------------------------
   Fields
   ---------------------------------------------------------------------------
   Labels are sentence case at 14px. The old sheet used 12px uppercase with
   letter-spacing, which is a dashboard treatment — it makes every field shout
   and it makes a long form tiring to read.
--------------------------------------------------------------------------- */

.field { display: block; margin-bottom: 16px; }
.field > span,
.field-label {
  display: block; font-size: 14px; font-weight: 600;
  color: var(--ink-soft); margin-bottom: 6px;
}
/* Same weight as a plain label, laid out as a row. Declared on `.field >` so it
   outranks the rule above, which is more specific than `.label-row` alone. */
.field > .label-row { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }

input[type=url], input[type=text], input[type=email], input[type=number], input[type=search], select, textarea {
  width: 100%;
  padding: 10px 14px;
  font: 400 16px/1.5 var(--sans);
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-control);
  transition: border-color .12s, box-shadow .12s;
}
textarea { font-family: var(--mono); font-size: 14px; resize: vertical; }
input[type=search] { appearance: none; -webkit-appearance: none; }
input::placeholder, textarea::placeholder { color: var(--ink-faint); }

input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--grass-600);
  box-shadow: 0 0 0 3px var(--brand-ring);
}

select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' stroke='%237A7362' stroke-width='1.6' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 13px center;
  padding-right: 34px;
}

.check { display: flex; gap: 10px; align-items: center; margin-bottom: 16px; font-size: 16px; }
.check input { width: auto; accent-color: var(--grass-600); }

.label-row { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }

/* ---------------------------------------------------------------------------
   Buttons
--------------------------------------------------------------------------- */

button, .btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font: 700 16px/1.5 var(--sans);
  padding: 10px 18px;
  border-radius: var(--r-control);
  border: 1px solid transparent;
  background: var(--grass-600);
  color: var(--paper);
  cursor: pointer;
  transition: background-color .12s, border-color .12s, color .12s;
}
button:hover, .btn:hover { background: var(--grass-700); }
button:active, .btn:active { transform: scale(.98); }
button:disabled { opacity: .5; cursor: not-allowed; transform: none; }

button.secondary {
  background: var(--card); color: var(--ink); border-color: var(--line-strong);
}
button.secondary:hover { background: var(--sand); }

button.ghost { background: none; color: var(--ink-mute); border-color: transparent; }
button.ghost:hover { background: var(--sand); color: var(--ink); }

button.danger { background: var(--clay-50); color: var(--clay-700); border-color: rgba(210, 96, 74, .3); }
button.danger:hover { background: var(--clay-50); border-color: var(--clay-500); }

button.sm, .btn.sm { font-size: 14px; padding: 6px 12px; }
.btn { text-decoration: none; }
.btn.secondary { background: var(--card); color: var(--ink); border-color: var(--line-strong); }
.btn.secondary:hover { background: var(--sand); }

/* A text button that lives inside a label row. Not a link — it acts. */
.linkish {
  background: none; border: 0; padding: 0;
  color: var(--grass-700); font: 600 14px/1.5 var(--sans);
  cursor: pointer;
}
.linkish:hover { background: none; text-decoration: underline; color: var(--grass-700); }

.navlink { color: var(--grass-700); font-weight: 600; text-decoration: none; cursor: pointer; }
.navlink:hover { text-decoration: underline; }

.actions { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.hint { color: var(--ink-mute); font-size: 14px; }
kbd {
  font: 600 13px/1 var(--sans);
  border: 1px solid var(--line-strong); border-bottom-width: 2px; border-radius: 5px;
  padding: 3px 5px; background: var(--sand); color: var(--ink-soft);
}

/* ---------------------------------------------------------------------------
   Badges — sentence case, never uppercase
--------------------------------------------------------------------------- */

.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 10px; border-radius: 999px;
  font-size: 14px; font-weight: 600; border: 1px solid;
  background: var(--sand-deep); color: var(--ink-mute); border-color: var(--line);
}
.badge.brand { background: var(--grass-50); color: var(--grass-700); border-color: var(--grass-100); }
.badge.go    { background: var(--grass-50); color: var(--grass-700); border-color: var(--grass-100); }
.badge.wait  { background: var(--ochre-50); color: var(--ochre-700); border-color: rgba(233, 178, 60, .35); }
.badge.stop  { background: var(--clay-50); color: var(--clay-700); border-color: rgba(210, 96, 74, .35); }
.badge.info  { background: var(--tide-50); color: var(--tide-700); border-color: rgba(62, 107, 122, .3); }

/* ---------------------------------------------------------------------------
   Channel chips
--------------------------------------------------------------------------- */

.channels { border: 0; padding: 0; margin: 0 0 18px; }
.channels legend { padding: 0; font-size: 14px; font-weight: 600; color: var(--ink-soft); margin-bottom: 8px; }
.channel-group { margin-bottom: 12px; }
.channel-group:last-child { margin-bottom: 0; }
.channel-group h3 {
  font-family: var(--sans); letter-spacing: 0;
  font-size: 14px; font-weight: 600; color: var(--ink-mute); margin: 0 0 6px;
}
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  border: 1px solid var(--line-strong); background: var(--card);
  border-radius: 999px; padding: 6px 14px;
  font: 600 14px/1.4 var(--sans); color: var(--ink-soft); cursor: pointer;
}
.chip:hover { background: var(--sand); border-color: var(--line-strong); color: var(--ink); }
.chip[aria-pressed="true"] {
  background: var(--grass-600); border-color: var(--grass-600); color: var(--paper);
}
.chip[aria-pressed="true"]:hover { background: var(--grass-700); border-color: var(--grass-700); }

.dimensions {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  margin-bottom: 18px;
}
.dimensions .field { margin-bottom: 0; }

/* ---------------------------------------------------------------------------
   Preview — the composed link
   ---------------------------------------------------------------------------
   Sand rather than white, because it is output rather than input: the one
   block on the page nobody types into.
--------------------------------------------------------------------------- */

.preview {
  background: var(--sand);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  padding: 14px 16px;
  font-family: var(--mono); font-size: 14px; line-height: 1.6;
  color: var(--ink);
  word-break: break-all;
  min-height: 3.4rem;
  margin-bottom: 16px;
}
.preview .guidance {
  display: block; margin-top: 8px;
  font-family: var(--sans); font-size: 14px; color: var(--ink-soft);
}

/* ---------------------------------------------------------------------------
   Findings
   ---------------------------------------------------------------------------
   Three severities, three hues, and only one of them stops a mint. A warning
   that looked like a refusal would send a buyer back to the spreadsheet.
--------------------------------------------------------------------------- */

.findings { display: grid; gap: 8px; margin-bottom: 18px; }
.finding {
  border-radius: var(--r-control);
  padding: 11px 14px;
  font-size: 16px;
  border: 1px solid;
}
.finding b { display: block; font-weight: 700; margin-bottom: 2px; }
.finding .fix { font-size: 14px; }

.finding.block { background: var(--clay-50); border-color: rgba(210, 96, 74, .35); color: var(--clay-700); }
.finding.block .fix { color: var(--clay-700); opacity: .85; }
.finding.warn  { background: var(--ochre-50); border-color: rgba(233, 178, 60, .4); color: var(--ochre-700); }
.finding.warn .fix { color: var(--ochre-700); opacity: .85; }
.finding.info  { background: var(--tide-50); border-color: rgba(62, 107, 122, .3); color: var(--tide-700); }
.finding.info .fix { color: var(--tide-700); opacity: .85; }

/* A one-line status note under a control. Lighter than a .finding, which is a
   block someone has to read before acting; these report a condition that is
   already true. */
.note { font-size: 14px; margin: 10px 0 0; }
.note.stop { color: var(--clay-700); }
.note.warn { color: var(--ochre-700); }

/* ---------------------------------------------------------------------------
   QR panel — the numbers are the point, not the picture
--------------------------------------------------------------------------- */

.qr {
  display: flex; gap: 18px; align-items: flex-start;
  background: var(--card);
  border: 1px solid var(--line); border-radius: var(--r-card);
  padding: 16px; margin-bottom: 18px;
}
.qr svg { width: 128px; height: 128px; flex: 0 0 128px; }
.qr .facts { font-size: 16px; min-width: 0; }
.qr .facts dl { display: grid; grid-template-columns: auto 1fr; gap: 4px 14px; margin: 0 0 10px; }
.qr .facts dt { color: var(--ink-mute); font-size: 14px; }
.qr .facts dd { margin: 0; font-variant-numeric: tabular-nums; font-weight: 600; }
.qr .note {
  font-size: 14px; color: var(--ochre-700);
  background: var(--ochre-50); border: 1px solid rgba(233, 178, 60, .4);
  border-radius: var(--r-control); padding: 8px 11px; margin-top: 6px;
}

/* ---------------------------------------------------------------------------
   Bulk result
--------------------------------------------------------------------------- */

.batch { border: 1px solid var(--line); border-radius: var(--r-card); overflow: hidden; }
.batch .head {
  background: var(--sand); padding: 11px 16px;
  font-size: 14px; font-weight: 700; color: var(--ink);
  border-bottom: 1px solid var(--line);
}
.batch .row {
  display: flex; gap: 10px; padding: 9px 16px;
  font-size: 14px; border-bottom: 1px solid var(--line-soft);
}
.batch .row:last-child { border-bottom: 0; }
.batch .row .mark { flex: 0 0 1.1rem; font-weight: 700; }
.batch .row.ok .mark { color: var(--grass-600); }
.batch .row.bad { background: var(--clay-50); }
.batch .row.bad .mark { color: var(--clay-700); }
.batch .row .detail { font-family: var(--mono); color: var(--ink-soft); word-break: break-all; min-width: 0; }

/* ---------------------------------------------------------------------------
   Recent links
--------------------------------------------------------------------------- */

.log .entry { padding: 12px 0; border-bottom: 1px solid var(--line-soft); }
.log .entry:first-child { padding-top: 0; }
.log .entry:last-child { border-bottom: 0; padding-bottom: 0; }
.log .campaign { font-size: 16px; font-weight: 700; color: var(--ink); }
.log .url {
  display: block; margin-top: 3px;
  font-family: var(--mono); font-size: 13px; color: var(--ink-mute);
  word-break: break-all;
}
/* Rule 3: marker tints the row that needs a person to look at it. A link
   somebody already minted is the one thing in this list worth stopping on. */
.log .entry.dupe-row {
  background: var(--marker-soft);
  margin: 0 -20px; padding-left: 20px; padding-right: 20px;
  border-bottom-color: transparent;
}
.log .dupe { font-size: 14px; font-weight: 700; color: var(--ochre-700); }

/* ---------------------------------------------------------------------------
   Rows — the settings list primitive
--------------------------------------------------------------------------- */

.rows { border: 1px solid var(--line); border-radius: var(--r-card); overflow: hidden; }
.rows .r {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 14px; font-size: 16px;
  border-bottom: 1px solid var(--line-soft);
  background: var(--card);
}
.rows .r:last-child { border-bottom: 0; }
.rows .r .grow { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.rows .r .tag {
  font-size: 14px; font-weight: 600; color: var(--ink-mute);
  background: var(--sand-deep); border: 1px solid var(--line);
  border-radius: 999px; padding: 2px 9px; white-space: nowrap;
}
.rows .r .tag.go   { background: var(--grass-50); color: var(--grass-700); border-color: var(--grass-100); }
.rows .r .tag.wait { background: var(--ochre-50); color: var(--ochre-700); border-color: rgba(233, 178, 60, .35); }
.rows .r .tag.stop { background: var(--clay-50); color: var(--clay-700); border-color: rgba(210, 96, 74, .35); }
.rows .r code { font-family: var(--mono); font-size: 14px; color: var(--ink-soft); }
 /* Rule 2: one brand colour, and it means "the primary action". A row action
    is never that — a taxonomy list has twelve of them, and twelve green
    buttons make a wall in which the real action cannot be found. */
.rows .r button, .copyable button {
  padding: 5px 11px; font-size: 14px;
  background: var(--card); color: var(--ink); border-color: var(--line-strong);
}
.rows .r button:hover, .copyable button:hover { background: var(--sand); }
.rows .r.muted-row { background: var(--sand); }
.rows .r.muted-row .grow { color: var(--ink-mute); }

form.inline { display: flex; gap: 8px; margin-top: 14px; flex-wrap: wrap; }
form.inline input, form.inline select { width: auto; flex: 1 1 12rem; }
form.inline button { flex: 0 0 auto; }
/* A message about the form belongs under it, not squeezed in beside the
   button as another flex item. */
form.inline .note { flex-basis: 100%; margin: 0; }

/* ---------------------------------------------------------------------------
   Plan meter
--------------------------------------------------------------------------- */

.meter { height: 8px; background: var(--sand-deep); border-radius: 999px; overflow: hidden; margin: 10px 0 8px; }
.meter span { display: block; height: 100%; background: var(--grass-600); border-radius: 999px; }
.meter.over span { background: var(--clay-500); }

.big { font-family: var(--display); font-size: 35px; font-weight: 800; line-height: 1.1; letter-spacing: -.02em; }

/* ---------------------------------------------------------------------------
   Numbered steps — the GA4 connection instructions
--------------------------------------------------------------------------- */

.steps { counter-reset: s; margin: 12px 0 0; padding: 0; list-style: none; }
.steps li { padding: 8px 0 8px 32px; position: relative; font-size: 16px; }
.steps li::before {
  counter-increment: s; content: counter(s);
  position: absolute; left: 0; top: 8px;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--grass-50); color: var(--grass-700);
  border: 1px solid var(--grass-100);
  font: 700 13px/1 var(--sans);
  display: grid; place-items: center;
}
.copyable { display: flex; gap: 6px; margin-top: 7px; }
.copyable code {
  flex: 1; min-width: 0; padding: 8px 11px;
  font-family: var(--mono); font-size: 14px;
  background: var(--sand); border: 1px solid var(--line);
  border-radius: var(--r-control); word-break: break-all;
}
.copyable button { flex: 0 0 auto; padding: 6px 12px; font-size: 14px; }

/* ---------------------------------------------------------------------------
   Sign in — a doorway, not a page
--------------------------------------------------------------------------- */

.signin-page {
  min-height: 100vh; display: grid; place-items: center;
  padding: 24px; background: var(--sand);
}
.signin {
  width: 100%; max-width: 25rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-panel);
  padding: 36px 32px;
}
.signin .mark {
  width: 44px; height: 44px; border-radius: var(--r-card);
  background: var(--grass-600); color: var(--paper);
  display: grid; place-items: center; margin: 0 auto 18px;
  font-family: var(--display); font-weight: 800; font-size: 20px;
}
.signin h1 { font-size: 28px; font-weight: 800; text-align: center; margin-bottom: 6px; }
.signin .sub { text-align: center; font-size: 16px; color: var(--ink-mute); margin-bottom: 24px; }
.signin .field { margin-bottom: 14px; }
.signin button[type=submit] { width: 100%; padding: 12px 18px; }
.signin .finding { margin-top: 18px; }
.signin .hint { display: block; margin-top: 16px; text-align: center; }

/* ---------------------------------------------------------------------------
   History
   ---------------------------------------------------------------------------
   A filtered list and nothing else. Every control is visible at once because
   the question this page answers — what did we ship for X — is asked on almost
   every visit, and hiding the controls that answer it makes each one longer.
--------------------------------------------------------------------------- */

.filters { padding: 18px 20px; }
.filter-row { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end; }
.filters .dimensions { margin: 14px 0 0; gap: 12px; }
.filter-foot { display: flex; align-items: center; gap: 14px; margin-top: 14px; flex-wrap: wrap; }
.filter-foot .spacer { flex: 1; }

.link-row { align-items: flex-start; gap: 12px; }
.link-row .line { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 3px; }
.link-row .line strong { font-size: 16px; font-weight: 700; }
.link-row .url {
  display: block; font-family: var(--mono); font-size: 13px;
  color: var(--ink-mute); word-break: break-all;
}
.link-row .meta { font-size: 14px; color: var(--ink-mute); margin-top: 4px; }
.link-row button { flex: 0 0 auto; }

/* The opened row. Sand, so it reads as belonging to the row above rather than
   as another entry in the list. */
.rows .r.expand { background: var(--sand); display: block; padding: 16px 14px; }
.trail { border-top: 1px solid var(--line); padding-top: 10px; }
.trail .ev { font-size: 14px; padding: 3px 0; display: flex; gap: 8px; }
.trail .verb { font-weight: 700; min-width: 7rem; }

/* ---------------------------------------------------------------------------
   The minted link
   ---------------------------------------------------------------------------
   The preview box used to clear on a successful mint, so the one string the
   page exists to produce disappeared at the moment it existed. It now stays,
   marked as done, with the only control that matters next to it.
--------------------------------------------------------------------------- */

.preview { position: relative; }
.preview .preview-url { display: block; padding-right: 4.5rem; }
.preview .copy-preview { position: absolute; top: 10px; right: 10px; }

.preview.minted { background: var(--grass-50); border-color: var(--grass-100); }
.preview .minted-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.preview .minted-head .spacer { flex: 1; }
.preview .minted-url { display: block; color: var(--ink); }

.log .entry-head { display: flex; align-items: baseline; gap: 6px; }
.log .entry-head .spacer { flex: 1; }
.log .entry-head button { padding: 2px 8px; font-size: 13px; }

.qr-actions { display: flex; gap: 8px; margin-bottom: 8px; }
.qr-actions button { padding: 5px 11px; font-size: 14px;
  background: var(--card); color: var(--ink); border-color: var(--line-strong); }
.qr-actions button:hover { background: var(--sand); }

/* Asking for a taxonomy value, inline in the field that needs it. */
.request-box { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 8px; }
.request-box input { flex: 1 1 10rem; padding: 7px 11px; font-size: 14px; }
.request-box button { flex: 0 0 auto; padding: 6px 12px; font-size: 14px; }
.request-box .hint { flex-basis: 100%; }
.request-box .note { flex-basis: 100%; margin: 0; }

/* Set mode: several values per dimension, one destination. */
.dimensions select[multiple] { padding: 6px 8px; }
.dimensions select[multiple] option { padding: 3px 4px; }
.preview .set-count {
  font-family: var(--display); font-size: 35px; font-weight: 800;
  letter-spacing: -.02em; margin-right: 8px;
}

/* A field narrowed by another selection says so, or a missing option reads as
   a taxonomy that never had it. */
.hint.narrowed { display: block; margin-top: 5px; color: var(--ochre-700); }

/* "Ask for one" sits on every dimension, so six of them shout in chorus — the
   same noise the uppercase micro-labels made, arriving by a different route.
   Quiet until the field is being worked in, then present. Dimmed rather than
   hidden: a control that only exists on hover does not exist on a phone, and
   the person most likely to need a missing value is the one already typing. */
.linkish[data-request] { color: var(--ink-faint); font-weight: 500; }
.field:hover .linkish[data-request],
.field:focus-within .linkish[data-request],
.linkish[data-request]:focus-visible { color: var(--grass-700); font-weight: 600; }

/* An empty dimension explains itself. It used to render as a bare "—", or in
   set mode as a collapsed box reading "0 selected", neither of which says what
   is wrong or what to do. */
.hint.empty-dim { display: block; margin-top: 5px; }
select:disabled { background: var(--sand); color: var(--ink-faint); cursor: not-allowed; }

/* Two findings on one import row ran together into "...in this row.That
   campaign name..." — .note carries a top margin, which does nothing when the
   spans sit inline beside each other. */
.rows .r .note { display: inline; margin: 0 0 0 .5em; }
.rows .r .note:first-of-type { margin-left: .35em; }

/* A multiple select holds its height whatever is in it. Without this, one
   whose options are all filtered out collapses to an empty sliver beside its
   own label, which reads as broken rather than as waiting for an earlier
   choice. */
/* A chevron belongs on a control that drops down. A multiple select does not,
   and the arrow was being drawn over its scrollbar. */
select[multiple] { min-height: 5.5rem; background-image: none; padding-right: 12px; }

/* ---------------------------------------------------------------------------
   Tooltips
   ---------------------------------------------------------------------------
   One bubble on the body, fixed-positioned against its trigger. Placed inline
   it would be clipped by every `.rows` list, which is overflow: hidden for its
   rounded corners — clipping happens before stacking, so no z-index helps.

   Ink on paper rather than the card colours, so it reads as a note laid over
   the page rather than another panel in it. The one sanctioned shadow.
--------------------------------------------------------------------------- */

#tip-bubble {
  position: fixed; z-index: 50;
  max-width: 19rem;
  padding: 8px 11px;
  background: var(--ink); color: var(--paper);
  border-radius: var(--r-control);
  font: 500 14px/1.45 var(--sans);
  box-shadow: var(--shadow-soft);
  pointer-events: none;
}

/* The standalone explainer: a small "?" beside a term. Quiet, like the
   "Ask for one" links — a page of loud help dots is its own kind of noise. */
button.tip {
  display: inline-grid; place-items: center;
  width: 18px; height: 18px; padding: 0; margin-left: 6px;
  border-radius: 999px; border: 1px solid var(--line-strong);
  background: var(--card); color: var(--ink-mute);
  font: 700 11px/1 var(--sans); vertical-align: 2px; cursor: help;
}
button.tip:hover, button.tip:focus-visible { background: var(--grass-50); color: var(--grass-700); border-color: var(--grass-100); }
button.tip:active { transform: none; }
h2 button.tip { vertical-align: 4px; }

/* Something that explains itself on hover gets the dotted underline readers
   already know means "there's more here". */
dt[data-tip], span[data-tip] { cursor: help; text-decoration: underline dotted var(--line-strong); text-underline-offset: 3px; }

/* ---------------------------------------------------------------------------
   Guide
--------------------------------------------------------------------------- */

.guide .card p { margin: 0 0 12px; }
.guide .card p:last-child { margin-bottom: 0; }
.guide h3 { font-size: 17px; font-weight: 700; margin: 18px 0 6px; letter-spacing: -.01em; }
.guide .card > h2 { margin-bottom: 12px; }
.guide ul { margin: 0 0 12px; padding-left: 20px; }
.guide li { margin-bottom: 7px; }
.guide a[data-nav] { color: var(--grass-700); font-weight: 600; }
.guide .aside {
  background: var(--sand); border-radius: var(--r-control);
  padding: 10px 13px; font-size: 15px; color: var(--ink-soft); margin-top: 14px;
}
.guide .steps li { padding-bottom: 10px; }
.guide code { font-family: var(--mono); font-size: 14px; background: var(--sand); padding: 1px 5px; border-radius: 5px; }

.guide .contents {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: 4px 16px; margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line-soft);
}
.guide .contents a { color: var(--grass-700); font-weight: 600; text-decoration: none; padding: 3px 0; }
.guide .contents a:hover { text-decoration: underline; }
/* Anchors land below the top edge, not flush against it. */
.guide section[id] { scroll-margin-top: 16px; }

.guide table.roles { width: 100%; border-collapse: collapse; margin: 16px 0 4px; font-size: 15px; }
.guide .roles th { text-align: left; font-size: 14px; color: var(--ink-mute); font-weight: 600; padding: 0 0 6px; }
.guide .roles td { padding: 9px 12px 9px 0; border-top: 1px solid var(--line-soft); vertical-align: top; }
.guide .roles td:first-child { width: 7rem; }

.guide .glossary { display: grid; grid-template-columns: 9rem 1fr; gap: 10px 16px; margin: 0; }
.guide .glossary dt { font-weight: 700; }
.guide .glossary dd { margin: 0; color: var(--ink-soft); }
@media (max-width: 40rem) {
  .guide .glossary { grid-template-columns: 1fr; gap: 2px; }
  .guide .glossary dd { margin-bottom: 10px; }
}

/* ---------------------------------------------------------------------------
   Onboarding
   ---------------------------------------------------------------------------
   The next-step strip: one sentence, one action, dismissable. Brand-tinted
   rather than tide, because it is an invitation, not a status report.
--------------------------------------------------------------------------- */

.nextstep {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 16px 10px 24px;
  background: var(--grass-50); border-bottom: 1px solid var(--grass-100);
  color: var(--grass-700);
}
.nextstep p { margin: 0; flex: 1; font-size: 15px; font-weight: 500; }
.nextstep .dismiss { padding: 2px 10px; font-size: 20px; line-height: 1; color: var(--grass-700); }
@media (max-width: 60rem) {
  .nextstep { flex-wrap: wrap; padding: 10px 12px 10px 16px; }
  .nextstep p { flex-basis: calc(100% - 44px); }
  .nextstep .dismiss { margin-left: auto; }
}

.welcome { margin: 24px 24px 0; border-color: var(--grass-100); }
.welcome ol { margin: 8px 0 16px; padding-left: 20px; }
.welcome li { margin-bottom: 8px; color: var(--ink-soft); }
.welcome li strong { color: var(--ink); }
.welcome .actions { display: flex; flex-wrap: wrap; gap: 8px; }
@media (max-width: 60rem) { .welcome { margin: 16px 16px 0; } }

/* ---------------------------------------------------------------------------
   Look and feel
--------------------------------------------------------------------------- */

.brand-edit { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 18px; }
@media (max-width: 40rem) { .brand-edit { grid-template-columns: 1fr; } }
.brand-field .label { display: block; font-size: 14px; font-weight: 600; color: var(--ink-soft); margin-bottom: 8px; }

.swatches { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }
.swatches:empty { display: none; }
.swatch {
  width: 40px; height: 40px; padding: 0; border-radius: 10px;
  border: 2px solid var(--card); box-shadow: 0 0 0 1px var(--line-strong);
}
.swatch:hover { transform: none; }
.swatch[aria-checked="true"] { box-shadow: 0 0 0 2px var(--ink); }

.picker { display: inline-flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 600; color: var(--ink-soft); cursor: pointer; }
.picker input[type=color] { width: 40px; height: 40px; padding: 2px; border: 1px solid var(--line-strong); border-radius: 10px; background: var(--card); cursor: pointer; }

.logo-slot {
  display: grid; place-items: center; height: 72px; margin-bottom: 10px;
  border: 1px dashed var(--line-strong); border-radius: var(--r-control); background: var(--paper);
}
.logo-slot img { max-height: 52px; max-width: 80%; object-fit: contain; }
.logo-actions { display: flex; gap: 8px; align-items: center; }
.upload { position: relative; overflow: hidden; }
.upload input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.upload:focus-within { outline: 2px solid var(--grass-600); outline-offset: 2px; }

.brand-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--line-soft); }
.brand-actions .spacer { flex: 1; }

/* Signing in without an org, as someone in several agencies. */
.org-choice { display: grid; gap: 8px; }
.org-choice .btn { width: 100%; }
