:root{
  --ink:#151A21; --page:#F5F7F8; --card:#FFFFFF; --border:#DEE3E7;
  --muted:#697683; --faint:#9AA6B0;
  --accent:#0F7B6C; --accent-soft:#E3F3F0;
  --danger:#A8321F; --danger-soft:#FBECE9;
  --warn:#8A6100; --warn-soft:#FDF3DC;
  --hair:#EEF1F2;
  --ui:system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
}
*,*::before,*::after{box-sizing:border-box}
html,body{margin:0;padding:0}
body{background:var(--page);color:var(--ink);font:13px/1.45 var(--ui);-webkit-font-smoothing:antialiased}

/* Every figure that's meant to line up in a column gets this. */
.num{font-family:var(--mono);font-variant-numeric:tabular-nums}

:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:2px}
.sidebar :focus-visible{outline-color:#7FD6C6}

/* ---------- app shell ---------- */
.app{display:flex;align-items:stretch;min-height:100vh}
.sidebar{flex:0 0 216px;width:216px;background:var(--ink);color:#fff;position:sticky;top:0;height:100vh;overflow:auto;display:flex;flex-direction:column}
.brand{padding:18px 16px 14px;border-bottom:1px solid rgba(255,255,255,.10)}
.brand b{display:block;font-size:13px;letter-spacing:-.01em}
.brand span{display:block;font-size:10px;text-transform:uppercase;letter-spacing:.09em;color:#8B95A3;margin-top:3px}

nav{padding:10px 8px;display:flex;flex-direction:column;gap:1px;flex:1}
nav a{display:block;font-size:12.5px;color:#C7CED8;text-decoration:none;border-radius:4px;padding:7px 9px}
nav a:hover{background:rgba(255,255,255,.07);color:#fff}
nav a[aria-current="page"]{background:#fff;color:var(--ink);font-weight:600}

/* Section groups use native <details> — expand/collapse with zero JS.
   Group headers deliberately look exactly like regular links (same size,
   color, hover) so the menu only has two text treatments — normal and
   selected. What marks a header as expandable is the chevron on the
   right, which points down while the group is open; sub-items are
   indented under it. */
nav details{margin-bottom:1px}
nav summary{list-style:none;cursor:pointer;display:flex;align-items:center;font-size:12.5px;color:#C7CED8;border-radius:4px;padding:7px 9px;user-select:none}
nav summary::-webkit-details-marker{display:none}
nav summary:hover{background:rgba(255,255,255,.07);color:#fff}
nav summary::after{content:"";margin-left:auto;width:6px;height:6px;border-right:1.5px solid #8B95A3;border-bottom:1.5px solid #8B95A3;transform:rotate(-45deg);transition:transform .15s}
nav summary:hover::after{border-color:#fff}
nav details[open]>summary::after{transform:rotate(45deg)}
nav details .grp{display:flex;flex-direction:column;gap:1px;padding-bottom:6px}
nav details .grp a{padding-left:21px}
nav .flat{margin-top:4px;padding-top:8px;border-top:1px solid rgba(255,255,255,.10);display:flex;flex-direction:column;gap:1px}

.sidefoot{margin-top:auto;padding:12px 16px 16px;border-top:1px solid rgba(255,255,255,.10);display:flex;align-items:center;justify-content:space-between;gap:8px}
.sidefoot .who{font-size:11px;color:#8B95A3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sidefoot button{font:inherit;font-size:11px;color:#C7CED8;background:none;border:1px solid rgba(255,255,255,.18);border-radius:4px;padding:4px 8px;cursor:pointer}
.sidefoot button:hover{color:#fff;border-color:rgba(255,255,255,.35)}

.content{flex:1;min-width:0;padding:22px 26px 72px;max-width:1400px}
.view-head{border-bottom:2px solid var(--ink);padding-bottom:9px;margin-bottom:18px;display:flex;justify-content:space-between;align-items:flex-end;gap:16px;flex-wrap:wrap}
h1{font-size:18px;margin:0;letter-spacing:-.015em}
.sub{margin:5px 0 0;font-size:12px;color:var(--muted);max-width:80ch}

.card{background:var(--card);border:1px solid var(--border);border-radius:6px;padding:15px}
.placeholder{color:var(--muted);font-size:13px;padding:28px 15px;text-align:center;border-style:dashed}

/* ---------- data tables ---------- */
.table-wrap{overflow-x:auto;background:var(--card);border:1px solid var(--border);border-radius:6px}
table{width:100%;border-collapse:collapse;white-space:nowrap}
th,td{padding:8px 10px;border-bottom:1px solid var(--hair);text-align:left;font-size:12.5px}
th{background:var(--page);font-size:10.5px;text-transform:uppercase;letter-spacing:.06em;color:var(--faint);font-weight:600;position:sticky;top:0}
tbody tr:last-child td{border-bottom:0}
tbody tr:nth-child(odd){background:var(--hair)}
tbody tr:hover{background:var(--page)}
td.num,th.num{text-align:right}

/* Source/subid identifier columns default to whatever width their widest
   value needs, which leaves a lot of dead space next to narrower
   numeric/date columns. Capped explicitly, with wrapping allowed instead
   of forcing the column wider for one long outlier. Used on any table with
   a SourceCode/SubNodeID-shaped column, including dynamic-column tables
   that match by field name at render time rather than fixed position.

   min-width matches width/max-width deliberately: table auto-layout treats
   a word-break:break-word cell as shrinkable to near-nothing, and on a
   table with many other nowrap columns (Reputation Calculation Log has
   30+), the browser crushes these down to make room for the rigid ones
   unless min-width gives it a floor it isn't allowed to cross. */
td.col-source,th.col-source{width:35ch;min-width:35ch;max-width:35ch;white-space:normal;word-break:break-word}
td.col-subid,th.col-subid{width:25ch;min-width:25ch;max-width:25ch;white-space:normal;word-break:break-word}
td.col-wide,th.col-wide{width:40ch;min-width:40ch;max-width:40ch;white-space:normal;word-break:break-word}

/* .table-fixed opts a table OUT of the default auto-layout every other
   table on this site still uses (.col-source/.col-subid/.col-wide above are
   all tuned for auto-layout specifically — leave that alone). Auto-layout
   sizes each column from THAT table instance's own content, so the exact
   same .col-compact/.col-grow markup can render at different pixel widths
   on two otherwise-identical tables just because their rows differ (e.g.
   the Offers dashboard's four tabs, confirmed rendering inconsistently
   before this). Fixed-layout makes column widths purely a function of the
   CSS below — identical every time, on any tab, with any data. */
table.table-fixed{table-layout:fixed}

/* A column whose per-row content is always short and roughly uniform (an
   ID, a YYYY-MM-DD date, a capped number, a status tag) has no reason to
   grow just because the table has leftover room. An explicit width on
   every OTHER column is what actually funnels that leftover space into
   .col-grow below — a column with no width of its own is exactly what
   both auto- and fixed-layout give the remaining space to.
   th.col-compact allows wrapping (unlike the td) since a couple of these
   headers — "Revenue Per Lead" — don't fit 100px on one line and
   fixed-layout, unlike auto, won't just quietly widen the column to fit;
   it clips instead. Data cells never need this — their values are always
   short. */
td.col-compact,th.col-compact{width:100px}
th.col-compact{white-space:normal}

/* The one column that should actually absorb whatever room the compact
   columns above don't use — no max-width (unlike .col-wide, which several
   other tables rely on staying capped), just a floor so it never gets
   crushed and wrapping instead of forcing horizontal scroll for one long
   value. */
td.col-grow,th.col-grow{width:auto;min-width:220px;white-space:normal;word-break:break-word}

/* Pins an actions column to the right edge of .table-wrap's own horizontal
   scroll — for a table with enough columns that the action buttons would
   otherwise only be reachable by scrolling all the way right (confirmed
   this was actually happening on All Offers at a normal laptop width, not
   just in theory). td needs an explicit opaque background (not "inherit")
   because it sits OVER whatever scrolls underneath it, and the zebra
   stripe means that background differs by row — inherit pulls the correct
   one from each row's own <tr>. th uses the header's own solid background
   directly since every header cell already shares that same color. */
td.col-actions,th.col-actions{position:sticky;right:0;background:inherit;box-shadow:-6px 0 8px -6px rgba(0,0,0,.2)}
th.col-actions{background:var(--page)}

/* Status pill — Sent/Failed/Pending, reusing the *-soft tokens already
   reserved for exactly this in :root but unused until Batch Delivery's
   Run History needed one. */
.tag{display:inline-flex;align-items:center;padding:2px 9px;border-radius:20px;font-size:11px;font-weight:600;letter-spacing:.02em;white-space:nowrap}
.tag-sent{background:var(--accent-soft);color:var(--accent)}
.tag-failed{background:var(--danger-soft);color:var(--danger)}
.tag-pending{background:var(--warn-soft);color:var(--warn)}
.tag-neutral{background:var(--hair);color:var(--muted)}

/* Per-row action list: a couple of inline links plus a "more actions"
   overflow menu, for tables with too many possible actions per row to
   show as individual buttons/links (11, for All Offers). */
.row-actions{display:flex;gap:10px;align-items:center;white-space:nowrap}
.overflow-menu{position:relative;display:inline-block}
.overflow-btn{background:none;border:1px solid var(--border);border-radius:5px;width:26px;height:26px;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;color:var(--muted);font-size:15px;line-height:1;padding:0}
.overflow-btn:hover{background:var(--page);color:var(--ink)}
/* position:fixed (not absolute) so the dropdown is positioned relative to
   the viewport, not to .table-wrap — that container's overflow-x:auto
   forces its overflow-y to auto too (per the CSS overflow spec, one axis
   can't stay 'visible' once the other isn't), which clips any
   in-flow-clipped descendant that extends past the table's own
   tightly-fitted box. That only became visible once a filter (e.g. Status =
   Capped) left just a couple of rows, so every row's dropdown had nowhere
   to overflow into. Fixed positioning escapes that clipping entirely; the
   JS that opens it sets top/left from the button's real screen position. */
.overflow-dropdown{display:none;position:fixed;background:var(--card);border:1px solid var(--border);border-radius:6px;box-shadow:0 8px 24px rgba(20,24,31,.18);min-width:180px;z-index:50;padding:4px}
.overflow-dropdown.open{display:block}
.overflow-dropdown a{display:block;padding:7px 10px;font-size:12.5px;color:var(--ink);text-decoration:none;border-radius:4px;white-space:nowrap}
.overflow-dropdown a:hover{background:var(--page)}
/* position:fixed only escapes clipping (the .table-wrap issue above) — it
   does NOT escape the stacking-context tree, which still follows DOM
   ancestry regardless of the descendant's own position value. The dropdown
   is a descendant of its row's td.col-actions, which — being position:sticky
   — always forms its own stacking context (auto z-index, ordered by DOM
   position). So an open dropdown still paints underneath any *later* row's
   sticky .col-actions cell (its Edit/Status links) once it visually extends
   over that row. Promoting the open row itself to an explicit z-index lifts
   its entire stacking context (dropdown included) above every other row's,
   which all stay at the implicit auto/0 level. The JS that toggles
   .overflow-dropdown.open adds/removes this on the same <tr> at the same
   time. */
tbody tr.row-elevated{position:relative;z-index:10}

.filter-bar{display:flex;flex-wrap:wrap;align-items:flex-end;gap:10px;margin-bottom:14px}
.filter-bar .field{margin-bottom:0;min-width:180px}
.btn-row{display:flex;gap:10px;align-items:center}
.link-clear{font-size:12.5px;color:var(--muted);text-decoration:none}
.link-clear:hover{color:var(--ink);text-decoration:underline}

/* Two-way editor mode switch (Offer Creative's Form/Code toggle) — same
   visual language as .btn.secondary, just grouped and with an active state. */
.mode-toggle{display:flex;gap:6px;margin-bottom:16px}
.mode-btn{font:inherit;font-size:13px;font-weight:600;color:var(--ink);background:var(--card);border:1px solid var(--border);border-radius:5px;padding:8px 14px;cursor:pointer}
.mode-btn:hover{background:var(--page)}
.mode-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}
.link-action{color:var(--accent);text-decoration:underline;cursor:pointer;background:none;border:0;font:inherit;padding:0}
.link-action:hover{color:var(--ink)}

.meta-row{margin-top:10px;font-size:11.5px;color:var(--faint)}
.state-msg{padding:24px 15px;text-align:center;color:var(--muted);font-size:13px}

/* Instant, client-side row search (SA.wireLiveSearch in shared.js) —
   deliberately styled apart from .filter-bar's inputs so it doesn't look
   like it needs the Filter button pressed; it acts immediately on
   whatever rows are already on screen. */
.search-input{font:inherit;font-size:13px;padding:8px 10px;border:1px solid var(--border);border-radius:5px;background:#fff;color:var(--ink);width:100%;max-width:280px;margin-bottom:14px}
.search-input:focus-visible{outline:2px solid var(--accent);outline-offset:1px}

/* ---------- login gate (used by login.html) ---------- */
.gate-wrap{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:24px;background:var(--page)}
.gate-card{background:var(--card);border:1px solid var(--border);border-radius:8px;padding:26px 24px;width:100%;max-width:340px;box-shadow:0 12px 32px rgba(20,24,31,.10)}
.gate-brand{margin-bottom:18px;padding-bottom:14px;border-bottom:1px solid var(--hair)}
.gate-brand b{display:block;font-size:14px;letter-spacing:-.01em}
.gate-brand span{display:block;font-size:11px;color:var(--muted);margin-top:2px}
.field{margin-bottom:12px;display:flex;flex-direction:column;gap:4px}
.field label{font-size:11px;color:var(--muted)}
.field input,.field select{font:inherit;font-size:13px;padding:8px 9px;border:1px solid var(--border);border-radius:5px;background:#fff;color:var(--ink)}
.field input:focus-visible,.field select:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.hint{font-size:11px;color:var(--faint)}
/* Global: any readonly field reads as "shown for context, not editable"
   rather than looking identical to an active input. Higher specificity
   than the dark-mode input override below, so this wins in both themes
   automatically via the --hair token. */
.field input[readonly]{background:var(--hair);color:var(--muted);cursor:default}

/* Scrollable checkbox list — used for the Funnel Groups / EW Brands
   multi-selects on the threshold Add forms. A native <select multiple>
   makes it hard to see everything that's checked at a glance; this doesn't. */
.checklist{max-height:160px;overflow-y:auto;border:1px solid var(--border);border-radius:5px;padding:6px 8px;background:#fff}
.checklist label{display:flex;align-items:center;gap:6px;padding:3px 2px;font-size:12.5px;cursor:pointer}
.checklist label:hover{background:var(--page)}
.btn{font:inherit;font-size:13px;font-weight:600;color:#fff;background:var(--accent);border:0;border-radius:5px;padding:9px 14px;cursor:pointer;display:inline-flex;align-items:center;gap:6px}
.btn:hover{filter:brightness(1.06)}
.btn:disabled{opacity:.6;cursor:default}
.btn.block{width:100%;justify-content:center}
.btn.secondary{background:var(--card);color:var(--ink);border:1px solid var(--border)}
.btn.secondary:hover{background:var(--page);filter:none}
.gate-msg{margin-top:12px;font-size:11.5px;line-height:1.5;color:var(--danger);min-height:1em}
.gate-msg:empty{margin-top:0}

/* ---------- confirmation modal ---------- */
.modal-overlay{display:none;position:fixed;inset:0;background:rgba(15,18,23,.45);align-items:center;justify-content:center;z-index:1000;padding:20px}
.modal-overlay.active{display:flex}
.modal-box{background:var(--card);border:1px solid var(--border);border-radius:8px;padding:22px;max-width:380px;width:100%;max-height:90vh;overflow-y:auto;box-shadow:0 12px 32px rgba(20,24,31,.25)}
.modal-box.wide{max-width:520px}
.modal-box h2{font-size:15px;margin:0 0 14px}
.modal-box p{margin:0 0 16px;font-size:13px;color:var(--ink);white-space:pre-line;line-height:1.5}
.modal-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:4px}
.modal-msg{font-size:12.5px;color:var(--danger);min-height:1em;margin:-6px 0 12px}
.modal-msg:empty{margin:0}
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.form-grid .field.span2{grid-column:1 / -1}

@media (prefers-color-scheme: dark){
  :root{
    --ink:#EDEFF2; --page:#12151A; --card:#1A1E24; --border:#2B313A;
    --muted:#9AA4B0; --faint:#6E7783;
    --accent-soft:#122824; --danger-soft:#2C1714; --warn-soft:#2A2110; --hair:#232830;
  }
  .field input,.field select,.checklist,.search-input{background:#12151A;color:var(--ink)}
  .gate-card{box-shadow:0 12px 32px rgba(0,0,0,.5)}
  .modal-box{box-shadow:0 12px 32px rgba(0,0,0,.5)}
}
