:root{
  --paper:#F4F6F8; --surface:#FFFFFF; --surface2:#EDF0F3; --surface3:#E3E8ED;
  --line:#D9DEE5; --line2:#BFC7D1;
  --ink:#151A21; --ink2:#4B5462; --ink3:#7B8593;
  /* The brick red of the wordmark is now the identity colour: chrome, links,
     focus, selection, progress — everything that says "this is the product".
     The primary action is held out of the scheme entirely in --cta, so it is
     the one thing on any screen not wearing a colour, and is impossible to
     mistake for decoration. */
  --accent:#C1392D; --accentSoft:#FAE3E0; --accentInk:#8E2116;
  /* WhatsApp green, a step deeper than the brand's own #25D366. That colour is
     only ever behind a white ICON, and under 14px bold label text it measures
     1.98:1 — unreadable. This is the same hue family at 5.3:1, so the button
     still reads as "the WhatsApp one" and its label is actually legible. */
  --cta:#0B7C3C; --ctaHover:#096A33; --ctaText:#FFFFFF;
  --mark:var(--accent); --markHover:#9E2C22;
  /* Gradient on the "Match" half of the wordmark: brand red into violet.
     Both ends stay above 3:1 on the paper, the bar for large bold text. */
  --markFrom:#C1392D; --markTo:#6D28D9;
  --gold:#8C6210; --goldSoft:#F4E8CF;
  --good:#1C7A4B; --goodSoft:#DBEFE3;
  --warn:#9C6410; --warnSoft:#F7E9D0;
  --crit:#96143C; --critSoft:#F9DEE6;
  --info:#2B5EA0; --infoSoft:#DEE8F6;
  /* Section tints. Five soft grounds and a matching ink for each, so a section
     can carry a hue on its background AND on its small marks without the body
     text ever leaving --ink. The blush is deliberately the brand red's own
     family so the identity colour still reads as the loudest thing on the page.
     These are decoration only: --good/--warn/--crit/--info stay reserved for
     status, because a green pill that means "approved" stops meaning anything
     once green is also just a colour a section happens to be. */
  --t1:#FDE7E3; --t1i:#A32D1F;
  --t2:#DEF1E7; --t2i:#16704A;
  --t3:#FBEDD4; --t3i:#8A5B0C;
  --t4:#E5E9FB; --t4i:#3B4A9E;
  --t5:#DBEEF8; --t5i:#1F5F86;
  --shadow:0 1px 2px rgba(18,24,33,.05), 0 10px 28px -16px rgba(18,24,33,.28);
  --r:10px; --rs:6px;
  /* Field metrics live here, not in the field rule, because the desktop
     density block has to change them and cannot out-specify that rule.
     The base selector carries six :not() clauses (0,6,1); a redeclaration
     of `input,select,textarea` is (0,0,3) and loses — but it lost only for
     the inputs, since `select` matched both at (0,0,1) and took the later
     one. The result was a 42px input beside a 38px select in the same row.
     Metrics as tokens means one place decides, and every control agrees. */
  --fieldPadY:10px; --fieldPadX:12px; --fieldFS:14px;
  /* The system stack, which is what apple.com actually ships: SF Pro on Apple
     devices, and the platform's own face everywhere else. Nothing is fetched,
     so there is no render-blocking font request and no flash of fallback text
     — the first paint is already in the final typeface. */
  --f-disp:-apple-system,BlinkMacSystemFont,"SF Pro Display","Segoe UI",Roboto,
    "Helvetica Neue",Helvetica,Arial,sans-serif;
  --f-body:-apple-system,BlinkMacSystemFont,"SF Pro Text","Segoe UI",Roboto,
    "Helvetica Neue",Helvetica,Arial,sans-serif;
  /* Figures and identifiers: the same face as the body text, not a typewriter.
   *
   * This used to be SF Mono, and the giveaway was an email address in the
   * top-right chip that looked like terminal output on a page that otherwise
   * looks like a Mac app. So the monospace face is gone from the product.
   *
   * The thing mono was silently doing was keeping digits the same width, so
   * money in a table column lined up. `font-variant-numeric: tabular-nums`
   * does that job properly in a proportional font — SF Pro, Segoe UI and
   * Roboto all ship tabular figures — and it does it without dragging the
   * letters along with it. Every rule here that shows figures declares it, and
   * there is a test that fails if one stops.
   *
   * Kept as its own token rather than folded into --f-body, so that "the face
   * numbers are set in" stays one line to change. */
  --f-num:-apple-system,BlinkMacSystemFont,"SF Pro Text","Segoe UI",Roboto,
    "Helvetica Neue",Helvetica,Arial,sans-serif;
}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --paper:#0D1116; --surface:#141A21; --surface2:#1B222B; --surface3:#232C37;
    --line:#27303B; --line2:#3B4653;
    --ink:#E9EDF2; --ink2:#A6B1BE; --ink3:#6E7A89;
    --accent:#F07A6E; --accentSoft:#3B1B18; --accentInk:#FFB5AA;
    /* Dark mode can use the actual brand green: the label goes near-black on it
       rather than white, which measures 9.6:1. */
    --cta:#25D366; --ctaHover:#3BDD7B; --ctaText:#0D1116;
    --markHover:#FF9A8F;
    --markFrom:#F07A6E; --markTo:#B794FF;
    --gold:#D6A445; --goldSoft:#372C14;
    --good:#41B87B; --goodSoft:#123424;
    --warn:#D6A445; --warnSoft:#3A2D12;
    --crit:#F2749B; --critSoft:#3A1622;
    --info:#6E9BE0; --infoSoft:#182739;
    /* Same five, rebuilt for a dark ground: near-black tints that keep their hue
       at 4% lightness, with the ink lifted rather than darkened. */
    --t1:#331712; --t1i:#FFB0A4;
    --t2:#0F2A1E; --t2i:#5FCB97;
    --t3:#2E2411; --t3i:#E0B45C;
    --t4:#1A1E38; --t4i:#A3B0F0;
    --t5:#12283A; --t5i:#7FC0E6;
    --shadow:0 1px 2px rgba(0,0,0,.35), 0 12px 30px -18px rgba(0,0,0,.8);
  }
}
:root[data-theme="dark"]{
  --paper:#0D1116; --surface:#141A21; --surface2:#1B222B; --surface3:#232C37;
  --line:#27303B; --line2:#3B4653;
  --ink:#E9EDF2; --ink2:#A6B1BE; --ink3:#6E7A89;
  --accent:#F07A6E; --accentSoft:#3B1B18; --accentInk:#FFB5AA;
  --cta:#25D366; --ctaHover:#3BDD7B; --ctaText:#0D1116;
  --markFrom:#F07A6E; --markTo:#B794FF;
  --markHover:#FF9A8F;
  --gold:#D6A445; --goldSoft:#372C14;
  --good:#41B87B; --goodSoft:#123424;
  --warn:#D6A445; --warnSoft:#3A2D12;
  --crit:#F2749B; --critSoft:#3A1622;
  --info:#6E9BE0; --infoSoft:#182739;
  --t1:#331712; --t1i:#FFB0A4;
  --t2:#0F2A1E; --t2i:#5FCB97;
  --t3:#2E2411; --t3i:#E0B45C;
  --t4:#1A1E38; --t4i:#A3B0F0;
  --t5:#12283A; --t5i:#7FC0E6;
  --shadow:0 1px 2px rgba(0,0,0,.35), 0 12px 30px -18px rgba(0,0,0,.8);
}

*{box-sizing:border-box}
body{margin:0;background:var(--paper);color:var(--ink);font-family:var(--f-body);font-size:14px;
  line-height:1.5;letter-spacing:-.016em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
/* Optical tracking, the way Apple sizes it.
 *
 * The rule most type scales get backwards: tracking is not "tighter as it gets
 * bigger". It peaks negative around body size and eases back toward zero in
 * both directions — roughly -.01em at 12px, -.022em at 17px, -.016em at 32px,
 * -.003em at 48px. Small text needs the room to stay legible; a headline is
 * already large enough that tight spacing reads as cramped rather than crisp.
 * The old scale ran -.022em on a 44px h1, which is where that looked wrong. */
h1,h2,h3,h4{font-family:var(--f-disp);font-weight:600;margin:0;text-wrap:balance;line-height:1.16}
h1{font-size:27px;letter-spacing:-.018em}
h2{font-size:20px;letter-spacing:-.021em}
h3{font-size:15px;letter-spacing:-.018em;font-weight:600}
h4{letter-spacing:-.019em}
p{margin:0}
a{color:inherit}
button{font:inherit;color:inherit}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:4px}
/* Chart axes and ring centres are SVG text with their face set inline; the
   figures need lining up there too, and it cannot be done with an SVG
   presentation attribute. */
svg text{font-variant-numeric:tabular-nums}
.mono{font-family:var(--f-num);font-variant-numeric:tabular-nums;letter-spacing:-.01em}
.num{font-family:var(--f-num);font-variant-numeric:tabular-nums;letter-spacing:-.015em}

/* ---------- shell ---------- */
.app{display:grid;grid-template-columns:216px 1fr;min-height:100vh}
.rail{background:var(--surface);border-right:1px solid var(--line);display:flex;flex-direction:column;gap:2px;padding:14px 10px;position:sticky;top:0;height:100vh;overflow-y:auto}
.brand{display:flex;align-items:center;gap:9px;padding:4px 8px 14px;background:none;border:0;width:100%;text-align:left;cursor:pointer;font:inherit;color:inherit}
.brand:hover .brand-name{color:var(--markHover)}
/* The wordmark. One line now that the tagline is gone, so it carries the
   name on its own and is sized to look deliberate rather than left over.
   Per-shell sizes live here, not as inline styles in the markup. */
.brand-name{font-family:var(--f-disp);font-weight:700;font-size:19px;letter-spacing:-.018em;color:var(--ink);line-height:1.1;white-space:nowrap}
/* Second word of the wordmark in a brand gradient, so "Adtrafix Match" reads
   as one mark rather than two words of the same weight. */
.brand-accent{color:var(--mark);background:linear-gradient(90deg,var(--markFrom),var(--markTo),var(--markFrom)) 0 0/200% 100%;
  -webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;transition:background-position .6s ease}
/* On hover the gradient slides across the word instead of changing colour. */
.brand:hover .brand-accent,.amark:hover .brand-accent,.lpmark:hover .brand-accent{background-position:100% 0}
@media (prefers-reduced-motion:reduce){.brand-accent{transition:none}}
@media (forced-colors:active){.brand-accent{-webkit-text-fill-color:currentColor;background:none}}
/* Labels that name a field or a figure, in sentence case.
 *
 * These were all ~10.5px all-caps at weight 700 with wide tracking — a
 * spec-sheet register, and the thing that still looked unlike a Mac app after
 * the typeface changed. Apple's own tiles say "Steps", not "STEPS".
 *
 * The text in the markup was already sentence case; `text-transform` was doing
 * the shouting, so dropping it is enough. Sentence case needs a point more size
 * than caps to stay legible at this weight, hence 11.5-12px where it was 10.5.
 *
 * Status pills keep their caps on purpose — .stgy, .negoy, .orow .os and the
 * tag pill further down. At 10px, caps are what makes a badge read as a badge
 * rather than as a stray word. The landing page keeps its eyebrows too: a
 * marketing page has its own register, and those sections are tuned.
 */
.navgroup{font-size:11.5px;letter-spacing:0;color:var(--ink3);font-weight:600;padding:16px 9px 6px}
.navitem{display:flex;align-items:center;gap:9px;padding:7px 9px;border-radius:var(--rs);cursor:pointer;color:var(--ink2);font-weight:500;border:none;background:none;text-align:left;width:100%;font-size:13.5px}
.navitem:hover{background:var(--surface2);color:var(--ink)}
.navitem.on{background:var(--accentSoft);color:var(--accentInk);font-weight:600}
/* A fixed 19px box, because the icons are now SVG of differing visual weight and
 * a box that sizes to its contents makes every label start at a slightly
 * different x. `display:block` on the svg drops the inline-baseline gap that
 * would otherwise push each icon a pixel low. */
.navitem .ic{width:19px;height:19px;flex:none;opacity:.78;display:grid;place-items:center}
.navitem .ic svg{display:block}
.navitem:hover .ic{opacity:1}
/* The active row already has a filled icon; full opacity is what makes the
 * difference between the two variants read as deliberate rather than as a
 * rendering artefact. */
.navitem.on .ic{opacity:1}
.navitem .cnt{margin-left:auto;font-family:var(--f-num);font-size:11px;background:var(--surface3);padding:1px 6px;border-radius:20px;color:var(--ink2);font-variant-numeric:tabular-nums}
.navitem.on .cnt{background:var(--surface);color:var(--accentInk)}

.main{min-width:0;display:flex;flex-direction:column}
.topbar{position:sticky;top:0;z-index:30;background:var(--surface);border-bottom:1px solid var(--line);display:flex;align-items:center;gap:14px;padding:10px 22px}
.seg{display:flex;background:var(--surface2);border-radius:8px;padding:2px;gap:2px}
.seg button{border:none;background:none;padding:5px 11px;border-radius:6px;font-size:12.5px;font-weight:600;cursor:pointer;color:var(--ink2);white-space:nowrap}
.seg button.on{background:var(--surface);color:var(--ink);box-shadow:0 1px 2px rgba(0,0,0,.12)}
.seg button[disabled]{cursor:not-allowed;opacity:.45}
.topbar .who{margin-left:auto;display:flex;align-items:center;gap:10px}
.iconbtn{border:1px solid var(--line);background:var(--surface);border-radius:var(--rs);width:30px;height:30px;display:grid;place-items:center;cursor:pointer;color:var(--ink2)}
.iconbtn:hover{border-color:var(--line2);color:var(--ink)}
.content{padding:22px;max-width:1320px;width:100%}
.pagehead{display:flex;align-items:flex-start;gap:16px;margin-bottom:18px;flex-wrap:wrap}
.pagehead .eyebrow{font-size:12px;letter-spacing:0;color:var(--ink3);font-weight:600;margin-bottom:4px}
.pagehead .sub{color:var(--ink2);font-size:13.5px;margin-top:5px;max-width:62ch}
.pagehead .acts{margin-left:auto;display:flex;gap:8px;flex-wrap:wrap}

/* ---------- primitives ---------- */
.card{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--shadow)}
.card-p{padding:16px}
.card-h{padding:13px 16px;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:10px}
.card-h h3{font-size:14px}
.card-h .r{margin-left:auto;color:var(--ink3);font-size:12px}
.grid{display:grid;gap:14px}
.row{display:flex;gap:14px;flex-wrap:wrap}
.grid>*,.split>*,.split3>*,.tiles>*,.row>*,.card,.main,.msgs,.ccard{min-width:0}
.card-h .r{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Fully-rounded, like the reference. The primary keeps --cta rather than taking
   a hue: it is the one control on any screen not wearing a colour, which is
   what makes it unmistakable for decoration now that the rest of the page is
   colourful. Horizontal padding goes up with the radius — a capsule needs room
   at the ends or the label sits in the curve. */
.btn{border:1px solid var(--line2);background:var(--surface);padding:8px 18px;border-radius:999px;font-weight:600;font-size:13px;cursor:pointer;display:inline-flex;align-items:center;gap:7px;white-space:nowrap}
.btn:hover{background:var(--surface2)}
/* The primary action is the one element deliberately kept out of the colour
   scheme. A second hue next to the brand red just gives the eye two things to
   argue about — green worst of all, being red's opposite. Ink competes on
   contrast instead (14:1 on paper), which leaves the red as the only colour on
   the page and still makes the button the loudest thing on it. Inverts to
   near-white on dark, where ink would disappear into the background. */
.btn.pri{background:var(--cta);border-color:var(--cta);color:var(--ctaText)}
.btn.pri:hover{background:var(--ctaHover);border-color:var(--ctaHover)}
.btn.sm{padding:5px 13px;font-size:12px}
.btn:disabled{opacity:.45;cursor:not-allowed}
.pill{display:inline-flex;align-items:center;gap:5px;font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px;letter-spacing:.01em;white-space:nowrap}
.pill.ok{background:var(--goodSoft);color:var(--good)}
.pill.warn{background:var(--warnSoft);color:var(--warn)}
.pill.crit{background:var(--critSoft);color:var(--crit)}
.pill.info{background:var(--infoSoft);color:var(--info)}
.pill.neu{background:var(--surface3);color:var(--ink2)}
.pill.acc{background:var(--accentSoft);color:var(--accentInk)}
.pill.gold{background:var(--goldSoft);color:var(--gold)}
.tag{display:inline-block;font-size:11px;padding:2px 7px;border-radius:4px;background:var(--surface2);border:1px solid var(--line);color:var(--ink2);font-weight:500}
.muted{color:var(--ink3)}
.lbl{font-size:12px;letter-spacing:0;color:var(--ink3);font-weight:600}
.hr{height:1px;background:var(--line);border:0;margin:0}

/* stat tiles */
.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(168px,1fr));gap:12px}
.tile{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);padding:13px 14px;position:relative;overflow:hidden}
.tile .k{font-size:11.5px;letter-spacing:0;color:var(--ink3);font-weight:600}
.tile .v{font-family:var(--f-num);font-size:23px;font-weight:500;letter-spacing:-.02em;margin-top:6px;line-height:1;font-variant-numeric:tabular-nums}
.tile .d{font-size:12px;margin-top:6px;color:var(--ink2);display:flex;align-items:center;gap:5px;padding-right:66px;min-height:18px}
.tile .up{color:var(--good);font-weight:700}
.tile .dn{color:var(--crit);font-weight:700}
.tile .spark{position:absolute;right:10px;bottom:8px;opacity:.5}

/* tables */
table.t{width:100%;border-collapse:collapse;font-size:13px}
table.t th{text-align:left;font-size:11.5px;letter-spacing:0;color:var(--ink3);font-weight:600;padding:9px 12px;border-bottom:1px solid var(--line);white-space:nowrap;background:var(--surface2)}
table.t td{padding:10px 12px;border-bottom:1px solid var(--line);vertical-align:middle}
table.t tr:last-child td{border-bottom:0}
table.t tbody tr:hover{background:var(--surface2)}
.tscroll{overflow-x:auto}
.tnum{font-family:var(--f-num);font-variant-numeric:tabular-nums;text-align:right}
/* A numeric column's HEADER has to be right-aligned too, or it sits at the left
 * of the column while its figures sit at the right — and a reader pairs each
 * number with the nearest heading above it, which is the next column's. "47"
 * under "Followers" when it is the Match score.
 *
 * `table.t th` is (0,1,2) and already sets text-align:left, which beats `.tnum`
 * at (0,1,0) — so the header was dragged back to the left however the cells
 * were aligned. This needs the class and both elements to outrank it. Fourth
 * time in this file that a compound selector has quietly beaten a single class;
 * if a `.tnum` ever stops taking effect, check what else is selecting it. */
table.t th.tnum{text-align:right}

/* avatar */
/* The initials are painted first and the photo sits on top, so a picture that
 * fails to load (Instagram's CDN URLs are signed and expire) reveals the
 * initials rather than an empty circle. `overflow:hidden` is what crops a
 * square photo to the disc. */
.av{border-radius:50%;display:grid;place-items:center;font-family:var(--f-disp);font-weight:500;color:#fff;flex:none;letter-spacing:0;position:relative;overflow:hidden}
.av .avimg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.who-line{display:flex;align-items:center;gap:9px;min-width:0}
.who-line .nm{font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.who-line .hd{font-family:var(--f-num);font-size:11.5px;color:var(--ink3)}

/* verified check */
.vbadge{display:inline-flex;align-items:center;gap:4px;font-size:10.5px;font-weight:500;color:var(--accentInk);background:var(--accentSoft);padding:1.5px 7px;border-radius:20px;white-space:nowrap;flex:none}

/* creator cards */
.ccards{display:grid;grid-template-columns:repeat(auto-fill,minmax(268px,1fr));gap:14px}
.ccard{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);overflow:hidden;display:flex;flex-direction:column;transition:border-color .15s, transform .15s}
.ccard:hover{border-color:var(--line2);transform:translateY(-1px)}
.ccard-top{padding:14px;display:flex;gap:11px;align-items:flex-start;min-height:104px}
.ccard-stats{display:grid;grid-template-columns:repeat(3,1fr);border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.ccard-stats div{padding:9px 10px;border-right:1px solid var(--line);min-width:0}
.ccard-stats div:last-child{border-right:0}
.ccard-stats .k{font-size:11px;letter-spacing:0;color:var(--ink3);font-weight:600;white-space:nowrap}
.ccard-stats .v{font-family:var(--f-num);font-size:14px;font-weight:500;margin-top:3px;font-variant-numeric:tabular-nums}
.ccard-foot{padding:10px 14px;display:flex;align-items:center;gap:8px;margin-top:auto}

/* match ring */
.ring{position:relative;display:grid;place-items:center;flex:none}
.ring .rv{position:absolute;font-family:var(--f-num);font-weight:500;letter-spacing:-.025em;font-variant-numeric:tabular-nums}

/* filters */
.filters{display:flex;flex-direction:column;gap:14px}
.fgroup .fh{display:flex;align-items:center;gap:6px;margin-bottom:7px}
.chiprow{display:flex;flex-wrap:wrap;gap:5px}
.chip{border:1px solid var(--line);background:var(--surface);padding:3.5px 9px;border-radius:20px;font-size:12px;cursor:pointer;font-weight:500;color:var(--ink2)}
.chip:hover{border-color:var(--line2)}
.chip.on{background:var(--accentSoft);border-color:var(--accent);color:var(--accentInk);font-weight:600}
input[type=range]{width:100%;accent-color:var(--accent)}
/*
   Listed by EXCLUSION, not by enumeration.
   
   This rule used to name every type it wanted — text, email, password, tel…
   Twice that has gone wrong. First `email`, `password` and `tel` were missing,
   so those boxes fell back to the browser's default ~20-character width while
   their neighbours filled the row. Then a batch of fields written without any
   `type` attribute at all did the same thing: `input[type=text]` does not match
   a bare `<input>`, however it behaves.
   
   An allow-list of types has to be updated by whoever adds a field, and nobody
   ever does. A deny-list of the four that genuinely need native rendering
   cannot be forgotten. */
input:not([type=range]):not([type=checkbox]):not([type=radio]):not([type=file]):not([type=submit]):not([type=button]),
select, textarea {
  width:100%;
  /* Roomier than before. These are the boxes somebody types a product URL into
     on a phone, and 7px of padding made a 28px-tall target. */
  padding:var(--fieldPadY) var(--fieldPadX);
  /* Colour goes through a variable for the same reason the corner does, and
     for a sharper one: this selector is (0,6,1), while `input:focus` is
     (0,1,1). A focus rule that set `border-color` directly would LOSE to it,
     and focus indication would be dead on every field in the app. Setting a
     custom property sidesteps that — the cascade for `--fieldBorder` is its
     own contest, which the six :not() clauses never enter. */
  border:1px solid var(--fieldBorder, var(--line2));
  /* Read through a variable so a field that needs a different corner —
     the one glued to a /shop/ or @ prefix — can change it without having
     to out-specify the six :not() clauses above. */
  border-radius:var(--fieldR, 8px);
  background:var(--surface);
  color:var(--ink);
  font:inherit;
  font-size:var(--fieldFS);
  /* Declared in px rather than a ratio so a select, whose own line box the
     browser computes differently, ends up exactly as tall as the input
     next to it. */
  line-height:20px;
  transition:border-color .12s, box-shadow .12s;
}
input:not([type=range]):not([type=checkbox]):not([type=radio]):hover,
select:hover, textarea:hover { --fieldBorder:var(--ink3) }
/* After :hover on purpose — equal specificity, so source order decides, and a
   focused field that the pointer happens to be over must still read as
   focused. */
input:focus,select:focus,textarea:focus{
  outline:none;
  --fieldBorder:var(--accent);
  /* The ring does the work, so the border does not have to thicken and shift
     the text by a pixel on focus. */
  box-shadow:0 0 0 3px var(--accentSoft);
}
input::placeholder,textarea::placeholder{color:var(--ink3)}
input:disabled,select:disabled,textarea:disabled{background:var(--surface2);color:var(--ink3);cursor:not-allowed}

/* A native select renders differently on every platform and sat a pixel or two
   off from the inputs beside it. Its own arrow is replaced with one drawn here
   so a row of controls lines up. */
select{
  appearance:none;-webkit-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' fill='none' stroke='%237B8593' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1.6 6 6.4 11 1.6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-position:right 12px center;
  padding-right:34px;
}
label.fl{display:block;font-size:12.5px;font-weight:600;letter-spacing:0;color:var(--ink2);margin-bottom:6px}
.field{margin-bottom:15px}

/* A field with a fixed prefix glued to it: /shop/<name>, @<handle>. The two
   halves share a border and a focus ring, so they read as one control rather
   than a box next to a box. Was three copies of the same inline style, each
   carrying the old padding and corner radius. */
.pfxrow{display:flex;align-items:stretch}
.pfxrow .pfx{display:flex;align-items:center;padding:0 12px;white-space:nowrap;
  border:1px solid var(--line2);border-right:0;border-radius:8px 0 0 8px;
  background:var(--surface2);color:var(--ink3);font-family:var(--f-num);font-size:14px}
.pfxrow input{--fieldR:0 8px 8px 0}
/* The prefix has to light up with the input or the control looks half-focused. */
.pfxrow:focus-within .pfx{border-color:var(--accent)}

/* bars */
.bar{height:6px;background:var(--surface3);border-radius:20px;overflow:hidden}
.bar>i{display:block;height:100%;background:var(--accent);border-radius:20px}
.hb{display:grid;grid-template-columns:96px 1fr 46px;gap:10px;align-items:center;font-size:12.5px;padding:3px 0}
.hb .hbn{color:var(--ink2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hb .hbv{font-family:var(--f-num);text-align:right;font-size:12px;color:var(--ink2);font-variant-numeric:tabular-nums}

/* pipeline */
.pipe{display:flex;flex-direction:column;gap:0}
.pstep{display:grid;grid-template-columns:22px 1fr;gap:12px;align-items:start;position:relative;padding-bottom:14px}
.pstep:last-child{padding-bottom:0}
.pstep .dot{width:22px;height:22px;border-radius:50%;border:2px solid var(--line2);background:var(--surface);display:grid;place-items:center;font-size:10px;font-family:var(--f-num);color:var(--ink3);z-index:1;font-variant-numeric:tabular-nums}
.pstep.done .dot{background:var(--accent);border-color:var(--accent);color:#fff}
:root[data-theme="dark"] .pstep.done .dot{color:#330A05}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]) .pstep.done .dot{color:#330A05}}
.pstep.now .dot{border-color:var(--accent);box-shadow:0 0 0 4px var(--accentSoft);color:var(--accentInk);font-weight:700}
.pstep:not(:last-child)::before{content:"";position:absolute;left:10px;top:22px;bottom:0;width:2px;background:var(--line)}
.pstep.done:not(:last-child)::before{background:var(--accent)}
.pstep .ptitle{font-weight:600;font-size:13px}
.pstep.pending .ptitle{color:var(--ink3);font-weight:500}
.pstep .pmeta{font-size:12px;color:var(--ink3);margin-top:1px}

/* wizard */
.steps{display:flex;gap:0;border:1px solid var(--line);border-radius:var(--r);overflow:hidden;background:var(--surface)}
.steps div{flex:1;padding:9px 12px;font-size:12px;font-weight:600;color:var(--ink3);border-right:1px solid var(--line);display:flex;align-items:center;gap:7px;white-space:nowrap;overflow:hidden}
.steps div:last-child{border-right:0}
.steps div.on{background:var(--accentSoft);color:var(--accentInk)}
.steps div.past{color:var(--ink2)}
.steps .sn{font-family:var(--f-num);font-size:11px;width:17px;height:17px;border-radius:50%;background:var(--surface3);display:grid;place-items:center;flex:none;font-variant-numeric:tabular-nums}
.steps div.on .sn{background:var(--accent);color:#fff}
:root[data-theme="dark"] .steps div.on .sn{color:#330A05}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]) .steps div.on .sn{color:#330A05}}

/* chat */
.chat{display:grid;grid-template-columns:250px 1fr;height:560px;overflow:hidden}
.threads{border-right:1px solid var(--line);overflow-y:auto}
.thread{padding:11px 13px;border-bottom:1px solid var(--line);cursor:pointer;display:flex;gap:9px}
.thread:hover{background:var(--surface2)}
.thread.on{background:var(--accentSoft)}
.msgs{display:flex;flex-direction:column;min-width:0}
.msgbody{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:10px;background:var(--surface2)}
.msg{max-width:74%;padding:9px 12px;border-radius:12px;font-size:13px;background:var(--surface);border:1px solid var(--line)}
.msg.me{align-self:flex-end;background:var(--accentSoft);border-color:transparent;color:var(--accentInk)}
.msg .mt{font-size:10.5px;color:var(--ink3);margin-top:4px;font-family:var(--f-num);font-variant-numeric:tabular-nums}
.msg.me .mt{color:var(--accentInk);opacity:.7}
.msgin{display:flex;gap:8px;padding:11px;border-top:1px solid var(--line);background:var(--surface)}

/* misc */
.split{display:grid;grid-template-columns:280px 1fr;gap:16px;align-items:start}
.split3{display:grid;grid-template-columns:1fr 320px;gap:16px;align-items:start}

/* Campaign form: the brief on the left, who it reaches on the right. The panel
   sticks so the consequence of a filter stays in view while the filter is set. */
.nsplit{display:grid;grid-template-columns:minmax(0,1fr) 320px;gap:16px;align-items:start;max-width:1180px}
.ncov{position:sticky;top:16px}
.covrow{display:flex;align-items:baseline;justify-content:space-between;gap:10px;padding:6px 0;font-size:13px;border-bottom:1px solid var(--line)}
.covrow:last-of-type{border-bottom:0}
.covrow span{color:var(--ink2)}
.covrow.warn span,.covrow.warn strong{color:var(--gold)}
.reqlist{margin-top:14px;padding-top:12px;border-top:1px solid var(--line)}
.reqitem{font-size:12.5px;color:var(--ink2);padding:4px 0 4px 14px;position:relative;line-height:1.45}
.reqitem::before{content:'○';position:absolute;left:0;color:var(--gold)}
/* A bare mark, not a badge: an outlined pill next to every required label read
   as a row of buttons. The star sits on the baseline of the label it belongs
   to; the tick that replaces it is set at the same width so nothing shifts. */
.reqtag{display:inline-block;min-width:10px;font-size:14px;line-height:1;font-weight:700;color:var(--gold);margin-left:4px;vertical-align:baseline;cursor:help}
.reqtag.done{font-size:11px;color:var(--accent)}
.reqnote{font-size:12px;color:var(--ink2);margin-top:6px;line-height:1.45}
/* Rendered always so it can be filled in place; it must take no room when the
   requirement is met. */
.reqnote:empty{display:none}

/* Picking the campaign post from the creator's own synced media. Each tile is
   a button so the choice is keyboard-reachable and obviously a choice. */
.mediapick{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:9px}
.mpick{text-align:left;background:var(--surface);border:1px solid var(--line);border-radius:9px;
  padding:9px 10px;cursor:pointer;display:flex;flex-direction:column;gap:5px;font:inherit;color:inherit}
.mpick:hover{border-color:var(--ink3)}
.mpick.on{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent) inset}
.mp-top{display:flex;align-items:center;justify-content:space-between;gap:8px}
.mp-cap{font-size:12.5px;line-height:1.4;color:var(--ink)}
.mp-stats{font-size:11.5px;color:var(--ink3)}
.mp-used{font-size:11px;color:var(--gold)}

/* A figure the creator gave us rather than one we measured. It has to read
   differently at a glance, or a report mixes claims and measurements. */
.sr{color:var(--gold);border-bottom:1px dotted var(--gold)}

/* Onboarding: the signup wizard's four stages, continued inside the app. */
.onbl{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px}
.onbi{display:flex;align-items:flex-start;gap:11px;padding:9px 2px}
.onbi+.onbi{border-top:1px solid var(--line)}
.onbn{flex:none;width:21px;height:21px;border-radius:50%;display:grid;place-items:center;
  font-size:11px;font-weight:700;border:1px solid var(--line2);color:var(--ink3);margin-top:1px}
.onbi.done .onbn{background:var(--accent);border-color:var(--accent);color:#fff}
.onbi.now .onbn{border-color:var(--accent);color:var(--accent)}
.onbt{flex:1;min-width:0;font-size:13px;line-height:1.45}
.onbi.done .onbt strong{color:var(--ink3);font-weight:500}
.onbw{display:block;color:var(--ink3);font-size:12px}
.onbi.todo .onbt{opacity:.72}
:root[data-theme="dark"] .onbi.done .onbn{color:#330A05}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]) .onbi.done .onbn{color:#330A05}}

/* The outcome of a row action, in the table, under the row it is about. */
tr.rownote td{padding:10px 14px;font-size:12.5px;line-height:1.5}
tr.rownote.bad td{background:var(--goldSoft);color:var(--ink);border-left:3px solid var(--gold)}
tr.rownote.ok td{background:var(--accentSoft);color:var(--ink);border-left:3px solid var(--accent)}
tr.rownote .rn{display:flex;align-items:flex-start;gap:9px}
tr.rownote .rn-ic{font-weight:700;line-height:1.5;flex:none}
tr.rownote.bad .rn-ic{color:var(--gold)}
tr.rownote.ok .rn-ic{color:var(--accent)}
tr.rownote .rn-t{flex:1;min-width:0}
tr.rownote .btn{flex:none}
.kv{display:grid;grid-template-columns:130px 1fr;gap:6px 14px;font-size:13px}
.kv .k{color:var(--ink3);font-weight:500}
.empty{padding:38px 20px;text-align:center;color:var(--ink3)}
.banner{display:flex;gap:11px;align-items:flex-start;padding:12px 14px;border-radius:var(--r);border:1px solid var(--line);background:var(--surface2);font-size:13px}
.banner.acc{background:var(--accentSoft);border-color:transparent;color:var(--accentInk)}
.banner.warn{background:var(--warnSoft);border-color:transparent;color:var(--warn)}
.banner.crit{background:var(--critSoft);border-color:transparent;color:var(--crit)}
.banner.info{background:var(--infoSoft);border-color:transparent;color:var(--info)}
.scrim{position:fixed;inset:0;background:rgba(10,14,20,.5);z-index:60;display:flex;align-items:flex-start;justify-content:center;padding:36px 18px;overflow-y:auto;backdrop-filter:blur(2px)}
.modal{background:var(--surface);border:1px solid var(--line);border-radius:14px;max-width:940px;width:100%;box-shadow:0 30px 80px -20px rgba(0,0,0,.5)}
.toast{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);background:var(--ink);color:var(--paper);padding:10px 18px;border-radius:20px;font-size:13px;font-weight:600;z-index:90;box-shadow:var(--shadow)}
.why{display:flex;gap:7px;align-items:flex-start;font-size:12.5px;padding:3px 0}
.why .ck{color:var(--accent);font-weight:800;flex:none;font-family:var(--f-num)}
.why .xk{color:var(--ink3);font-weight:800;flex:none;font-family:var(--f-num)}

/* The dark-panel auth shell and the old three-card landing used to live here.
   Every auth screen now uses the light split layout further down, and the
   landing page is its own section — these rules matched nothing, and an unused
   second auth system is how a screen ends up half-converted. Removed rather
   than left to be rediscovered. */
.oauthcard{border:1px solid var(--line2);border-radius:12px;overflow:hidden;background:var(--surface)}
.oauthhead{padding:14px 16px;background:var(--surface2);border-bottom:1px solid var(--line);display:flex;align-items:center;gap:10px}
.scoperow{display:flex;gap:11px;padding:11px 16px;border-bottom:1px solid var(--line);align-items:flex-start}
.scoperow code{font-family:var(--f-num);font-size:11.5px;color:var(--accentInk);background:var(--accentSoft);padding:2px 7px;border-radius:4px;white-space:nowrap;flex:none}

/* The permission list, collapsed. Inside a <details> the rows are body copy
   rather than their own card, so they lose the card's horizontal padding and
   the last one loses its rule. Specificity carries these over .scoperow above
   whatever the source order, but they are written after it anyway. */
.discl{margin-top:11px;border-top:1px solid var(--line);padding-top:9px}
.discl>summary{font-size:12px;font-weight:600;color:var(--ink2);cursor:pointer;list-style:none;display:flex;align-items:center;gap:6px}
.discl>summary::-webkit-details-marker{display:none}
.discl>summary::before{content:"\203A";font-size:15px;line-height:1;color:var(--ink3);transition:transform .15s}
.discl[open]>summary::before{transform:rotate(90deg)}
.discl>summary:hover{color:var(--ink)}
/* Stacked, not side by side: `instagram_manage_insights` and its description
   cannot share 320px of sidebar without both of them wrapping to four lines. */
.discl .scoperow{flex-direction:column;align-items:flex-start;padding:9px 0;font-size:12.5px;gap:4px}
.discl .scoperow code{font-size:11px;padding:2px 6px;white-space:normal;overflow-wrap:anywhere}
.discl .scoperow:last-of-type{border-bottom:0}

/* An official platform mark on a connect button. Deliberately smaller than the
   label: Meta's brand rules say their mark must not be the dominant element,
   and it is there to identify the destination, not to badge our button. */
.pmark{width:15px;height:15px;flex:none;display:block}
.btn.sm .pmark{width:13px;height:13px}
.synclist{display:grid;gap:0}
.syncrow{display:flex;gap:11px;align-items:center;padding:10px 0;border-bottom:1px solid var(--line);font-size:13px}
.syncrow .sic{width:20px;height:20px;border-radius:50%;display:grid;place-items:center;font-size:11px;flex:none;background:var(--surface3);color:var(--ink3);font-family:var(--f-num)}
.syncrow.done .sic{background:var(--accent);color:#fff}
:root[data-theme="dark"] .syncrow.done .sic{color:#330A05}
.syncrow.doing .sic{border:2px solid var(--accent);background:transparent;color:var(--accent);animation:spin 1s linear infinite}
.syncrow.pending{color:var(--ink3)}
@keyframes spin{to{transform:rotate(360deg)}}
.authfoot{display:flex;gap:9px;margin-top:22px;align-items:center;flex-wrap:wrap}

.tabbar{display:flex;gap:2px;border-bottom:1px solid var(--line);margin-bottom:16px;overflow-x:auto}
.tabbar button{border:none;background:none;padding:8px 13px;font-size:13px;font-weight:600;color:var(--ink3);cursor:pointer;border-bottom:2px solid transparent;white-space:nowrap}
.tabbar button:hover{color:var(--ink)}
.tabbar button.on{color:var(--accentInk);border-bottom-color:var(--accent)}

.prose{max-width:70ch;font-size:14px;color:var(--ink2)}
.prose h3{color:var(--ink);margin:20px 0 7px}
.prose ul{margin:7px 0;padding-left:19px}
.prose li{margin:3px 0}
.prose code{font-family:var(--f-num);font-size:12.5px;background:var(--surface2);padding:1px 5px;border-radius:4px;color:var(--ink)}

.erd{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:10px}
.ent{border:1px solid var(--line);border-radius:8px;background:var(--surface);overflow:hidden}
.ent .eh{padding:7px 10px;background:var(--surface2);font-family:var(--f-num);font-size:12px;font-weight:600;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:6px}
.ent .eb{padding:8px 10px;font-size:11.5px;color:var(--ink2);font-family:var(--f-num);line-height:1.7}
.ent .eb b{color:var(--ink);font-weight:600}

@media (max-width:960px){
  .app{grid-template-columns:1fr}
  .rail{position:fixed;left:0;top:0;bottom:0;width:216px;z-index:70;transform:translateX(-100%);transition:transform .2s;height:100vh}
  .rail.open{transform:none;box-shadow:0 0 60px rgba(0,0,0,.4)}
  .split,.split3,.nsplit{grid-template-columns:1fr}
  /* Stacked, a sticky panel would sit over the form it describes. */
  .ncov{position:static}
  .chat{grid-template-columns:1fr;height:auto}
  .threads{max-height:190px;border-right:0;border-bottom:1px solid var(--line)}
  .msgbody{height:340px}
  .content{padding:16px}
  .steps{overflow-x:auto}
}
@media (max-width:760px){
  .grid{grid-template-columns:1fr!important}
  .kv{grid-template-columns:1fr!important;gap:1px 0}
  .kv .k{margin-top:7px}
  .erd{grid-template-columns:1fr 1fr}
  .hb{grid-template-columns:76px 1fr 42px}
  .pagehead .acts{margin-left:0}
  h1{font-size:22px}
}
@media (max-width:640px){
  .topbar{gap:8px;padding:8px 12px}
  .seg{overflow-x:auto;min-width:0}
  .seg button{padding:5px 8px;font-size:12px}
  .who-line>div:nth-child(2){display:none}
  .topbar .who{gap:6px}
}
@media (min-width:961px){ .menubtn{display:none} }
@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}


/* ===========================================================================
   Density pass
   ---------------------------------------------------------------------------
   Adtrafix Match is an operations tool: an advertiser comparing twenty creators and a
   creator checking six campaigns both want to see more at once and scroll
   less. The original spacing is presentation-comfortable rather than
   work-comfortable — generous headings, tall cards, six creators per screen.
   This tightens type, padding and row heights the way ad consoles do.

   Deliberately NOT copied from Google or Meta: their chrome, palette and
   iconography. Borrowing the density is sensible; dressing Adtrafix Match up as
   somebody else's product is not, and it is their trade dress.

   Kept intact on purpose:
   - touch targets stay ≥30px high, so this is still usable on a laptop trackpad
   - scoped to ≥961px. The mobile rules live in a max-width block ABOVE this one,
     so anything unscoped here would win at every width and quietly undo the
     single-column phone layout — same specificity, later in the file
   - contrast tokens are unchanged; nothing here makes text harder to read
   ========================================================================== */
@media (min-width:961px){
body{font-size:13px}
h1{font-size:21px}
h2{font-size:17px}
h3{font-size:14px}

/* Shell: a narrower rail and a slimmer top bar give the working area back. */
.app{grid-template-columns:196px 1fr}
.rail{padding:10px 8px;gap:1px}
.brand{padding:2px 6px 10px}
.navgroup{margin-top:10px}
.navitem{padding:5px 8px;font-size:13px;gap:8px}
.topbar{padding:7px 16px;gap:12px}
.content{padding:16px 18px;max-width:1440px}

/* Headings stop taking a fifth of the screen before any data appears. */
.pagehead{margin-bottom:13px;gap:12px}
.pagehead .sub{font-size:12.5px;margin-top:3px;max-width:78ch}
.pagehead .eyebrow{font-size:10px;margin-bottom:3px}

/* Cards and tables: the main win, since almost everything sits in one. */
.card-p{padding:12px}
.card-h{padding:9px 12px}
.card-h h3{font-size:13px}
.grid{gap:11px}
.tiles{grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:9px}
.tile{padding:10px 11px}
.tile .v{font-size:19px;margin-top:4px}
.tile .d{font-size:11.5px;margin-top:4px;min-height:16px}
table.t{font-size:12.5px}
table.t th{padding:6px 10px}
table.t td{padding:7px 10px}

/* More creators per row, and shorter cards so a second row is visible. */
.ccards{grid-template-columns:repeat(auto-fill,minmax(238px,1fr));gap:11px}

/* Controls: still comfortably clickable, no longer oversized. */
.btn{padding:6px 15px;font-size:12.5px;gap:6px}
.btn.sm{padding:4px 11px;font-size:11.5px}
.chip{padding:3px 8px;font-size:11.5px}
.field{margin-bottom:12px}
.fl{font-size:11.5px}
/* Tighter than the base, still a comfortable target. Set as tokens, not as a
   redeclaration of the field rule: that rule is (0,6,1) and an override here
   would lose to it — silently, and only for the inputs, leaving selects the
   one control that shrank. */
:root{--fieldPadY:8px; --fieldPadX:11px; --fieldFS:13.5px}
select{padding-right:32px}
.split3{grid-template-columns:1fr 296px;gap:13px}
.banner{padding:9px 11px;font-size:12.5px}

/* Brand lockup: at the narrower rail "CREATOR MARKETPLACE" wrapped to two
   lines and pushed the nav down. Shrink the tracking rather than the rail. */

/* Creator cards carry most of the discovery screen, so they carry most of the
   saving. The 104px min-height on the top block was reserving room for a third
   tag row that most creators do not have. */
/* Enough for two tag rows, which is what most creators have. Dropping the
   floor to zero saved a few pixels and cost the alignment of the stats strip
   across a row of cards, which is the thing the eye actually scans. */
.ccard-top{padding:10px;gap:9px;min-height:113px}
.ccard-stats div{padding:6px 8px}
.ccard-stats .v{font-size:13px;margin-top:2px}
.ccard-foot{padding:7px 10px;gap:6px}

/* The filter rail was sized for the old type scale. */
.split3{grid-template-columns:1fr 272px}
}

/* ===========================================================================
   Consumer auth layout
   ---------------------------------------------------------------------------
   The split every consumer sign-in uses: the case on the left, the form on the
   right, on a light ground rather than the dark panel the onboarding wizards
   use. A creator arriving from an Instagram DM lands here, and the wizard
   chrome read as enterprise software.

   The artwork is drawn in SVG in this codebase. Photographs of people would
   need licensing we do not have, and stock faces on a marketplace that trades
   on real creator identity invites exactly the wrong assumption about who is
   already here.
   ========================================================================== */
/* Two columns that stay together.
 *
 * The grid still spans the viewport so the surface colour and the footer rule
 * run edge to edge, but each column pins its content toward the middle — the
 * copy right-aligned in its half, the card left-aligned in its. Without that,
 * a 1920px screen pushed them into opposite corners with a third of the window
 * empty between them. The pair now reads as one block at any width. */
.asplit{min-height:100vh;display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  background:var(--surface);align-items:center;column-gap:56px}
.ahero{padding:44px 0;display:flex;flex-direction:column;justify-content:center;gap:10px;
  width:100%;max-width:490px;margin-left:auto;padding-left:40px}
.amark{display:flex;align-items:center;gap:10px;margin-bottom:18px;background:none;border:0;padding:0;text-align:left;cursor:pointer;font:inherit;color:inherit}
.amark:hover .brand-name{color:var(--markHover)}
.amark .brand-name{font-size:21px}
.ahero h1{font-size:44px;line-height:1.08;letter-spacing:-.03em;max-width:12ch;font-weight:600}
.ahero h1 em{font-style:normal;color:var(--accent)}
.ahero p{color:var(--ink2);font-size:15px;line-height:1.6;max-width:44ch;margin-top:14px}
.aform{padding:40px 40px 40px 0;display:flex;justify-content:flex-start;align-items:center;
  width:100%;max-width:490px;margin-right:auto}
.acard{width:100%;max-width:420px;background:var(--surface);border:1px solid var(--line);
  border-radius:14px;box-shadow:0 2px 6px rgba(18,24,33,.06),0 16px 44px -22px rgba(18,24,33,.34);padding:22px}
.acard h2{font-size:18px;margin-bottom:3px}
.acard .anote{color:var(--ink2);font-size:12.5px;line-height:1.55;margin-bottom:16px}
.acard .field{margin-bottom:12px}
.acard input{padding:11px 12px;font-size:15px;border-radius:8px}
.acard .btn.pri{width:100%;justify-content:center;padding:12px;font-size:14px;border-radius:999px}
.acard .aalt{border-top:1px solid var(--line);margin-top:16px;padding-top:14px;text-align:center}
.acard .aalt .btn{width:100%;justify-content:center;padding:10px;border-radius:999px}
/* A text link that happens to be a button. Was scoped to .acard, so the same
   class on the landing page rendered as a bordered box — unscoped now, because
   the style is about what the control is, not where it sits. */
.alink{background:none;border:none;color:var(--accent);font-size:12.5px;font-weight:600;cursor:pointer;padding:6px;text-decoration:none}
.alink:hover{text-decoration:underline}
.ahero figure{margin:26px 0 0;margin-left:-14px}
.ahero figure svg{width:100%;max-width:520px;display:block}
.afoot{grid-column:1 / -1;border-top:1px solid var(--line);padding:14px 40px;color:var(--ink3);font-size:11.5px;
  display:flex;gap:14px;flex-wrap:wrap;align-items:center}
.afoot a{color:var(--ink3)}
@media (max-width:900px){
  /* One column here, so the grid's spare height would otherwise be shared out
     between the copy and the card and push them apart. Pack them at the top and
     let the footer row take the slack, so the pair reads as one block and the
     rule still lands on the bottom edge. */
  .asplit{grid-template-columns:1fr;grid-template-rows:auto auto 1fr;align-items:start;column-gap:0}
  .ahero{padding:30px 22px 6px;text-align:left;max-width:none;margin-left:0}
  .ahero h1{font-size:29px;max-width:100%}
  .ahero p{font-size:14px}
  .ahero figure{margin-top:14px}
  .ahero figure svg{max-width:300px}
  .aform{padding:18px 20px 40px;max-width:none;margin-right:0;justify-content:center}
  .afoot{padding:14px 22px;align-self:end}
}

/* Entry pages share the sign-in split. The dark gradient slab read as a
   marketing page; this is a door, and a door should be quiet. */
.ahero .ebrow{font-size:12px;letter-spacing:0;color:var(--ink3);font-weight:600;margin-bottom:4px}
.ahero .proof{display:flex;flex-direction:column;gap:9px;margin-top:24px;max-width:52ch}
.ahero .proof>div{display:flex;gap:9px;align-items:flex-start;font-size:13px;line-height:1.55;color:var(--ink2)}
.ahero .proof b{color:var(--ink);font-weight:600}
.ahero .tick{color:var(--accent);flex:none}
.acard .eacts{display:flex;flex-direction:column;gap:8px}
.acard .eacts .btn{width:100%;justify-content:center;padding:11px;border-radius:999px}


/* Signup wizard, on the same light split as the rest of auth. The dark panel
   with the tall stepper was the last screen still wearing the old chrome. */
.wsteps{list-style:none;margin:26px 0 0;padding:0;display:flex;flex-direction:column;gap:2px;max-width:40ch}
.wstep{display:flex;gap:11px;align-items:flex-start;padding:7px 0}
.wstep .wnum{width:22px;height:22px;border-radius:50%;flex:none;display:grid;place-items:center;
  font-size:11.5px;font-weight:700;border:1.5px solid var(--line2);color:var(--ink3);background:var(--surface)}
.wstep.done .wnum{background:var(--accent);border-color:var(--accent);color:#fff}
.wstep.now .wnum{border-color:var(--accent);color:var(--accent);box-shadow:0 0 0 3px var(--accentSoft)}
.wstep .wt{font-size:13px;font-weight:600;line-height:1.35}
.wstep.pending .wt{color:var(--ink3);font-weight:500}
.wstep .wm{font-size:11.5px;color:var(--ink3);margin-top:1px}
.acard .wbar{height:3px;border-radius:20px;background:var(--surface3);overflow:hidden;margin-bottom:16px}
.acard .wbar>i{display:block;height:100%;background:var(--accent);border-radius:20px;transition:width .25s}
/* "Step 2 of 4" on the sign-in card. Same family as .ahero .ebrow beside it,
   so it changes with it — one screen shouting and one not is worse than both. */
.acard .wsc{font-size:12px;letter-spacing:0;color:var(--ink3);font-weight:600;margin-bottom:5px}
.acard .wfoot{display:flex;gap:9px;align-items:center;flex-wrap:wrap;margin-top:16px}
.acard .wfoot .btn.pri{width:auto;flex:1;min-width:150px}
@media (max-width:900px){ .wsteps{display:none} }

/* The wizard card carries more fields than a sign-in, so it gets more room.
   Scoped to the wizard so the two-field sign-in stays compact. */
@media (min-width:901px){
  .asplit:has(.wsteps) .acard{max-width:460px}
}

/* ===========================================================================
   Landing page
   ---------------------------------------------------------------------------
   The one page strangers see. It splits the two audiences in the nav, in the
   hero and again at the bottom, because a creator and a brand want opposite
   things and a single generic call to action serves neither.

   Everything here is the app's own type scale and palette — the page and the
   product should not look like two different companies.
   ========================================================================= */
.lp{background:var(--paper);min-height:100vh}
.lp section,.lpnav,.lpfoot{max-width:1120px;margin:0 auto;padding-left:24px;padding-right:24px}

.lpnav{display:flex;align-items:center;gap:22px;padding-top:18px;padding-bottom:18px;flex-wrap:wrap}
.lpmark{background:none;border:0;cursor:pointer;text-align:left;display:flex;align-items:center;padding:0}
.lpmark:hover .brand-name{color:var(--markHover)}
.lpnav .lpmark .brand-name{font-size:22px}
.lpfoot .lpmark .brand-name{font-size:18px}
.lplinks{display:flex;gap:4px;flex-wrap:wrap}
.lplink{background:none;border:0;cursor:pointer;color:var(--ink2);font-size:14px;font-weight:500;letter-spacing:-.016em;
  padding:7px 11px;border-radius:var(--rs)}
.lplink:hover{background:var(--surface2);color:var(--ink)}
.lpacts{margin-left:auto;display:flex;gap:8px;align-items:center}

/* The burger. Hidden until the links stop fitting beside the logo — see the
   700px block below, which is where it and the panel are switched on together.
   Drawn from three spans rather than an ☰ glyph so the bars keep their weight
   next to the sign-in button instead of inheriting a font's idea of one. */
.lpburger{display:none;width:38px;height:38px;flex:none;background:var(--surface);
  border:1px solid var(--line);border-radius:var(--rs);cursor:pointer;
  flex-direction:column;justify-content:center;align-items:center;gap:4px;padding:0}
.lpburger span{display:block;width:16px;height:1.6px;border-radius:2px;background:var(--ink2);
  transition:transform .18s,opacity .12s}
.lpburger:hover{background:var(--surface2)}
.lpburger:hover span{background:var(--ink)}
.lpburger.on{background:var(--ink);border-color:var(--ink)}
.lpburger.on span{background:var(--paper)}
/* Open, the bars fold into a cross. The dark fill already says something is
   showing; the cross says what tapping it again will do. */
.lpburger.on span:nth-child(1){transform:translateY(5.6px) rotate(45deg)}
.lpburger.on span:nth-child(2){opacity:0}
.lpburger.on span:nth-child(3){transform:translateY(-5.6px) rotate(-45deg)}

/* Sign-in chooser. Adtrafix Match has one sign-in; this menu picks the framing of the
   page you land on, so it reads as a short list with an explanation attached
   rather than as three separate front doors. */
.lpmenu{position:relative}
.lpmenu .caret{margin-left:7px;font-size:10px;color:var(--ink3)}
.lpmenupop{position:absolute;right:0;top:calc(100% + 7px);z-index:40;width:min(300px,calc(100vw - 32px));
  background:var(--surface);border:1px solid var(--line);border-radius:12px;padding:6px;
  box-shadow:0 2px 6px rgba(18,24,33,.07),0 18px 46px -22px rgba(18,24,33,.4)}
.lpmenuitem{display:block;width:100%;text-align:left;background:none;border:0;cursor:pointer;
  padding:9px 11px;border-radius:var(--rs);font:inherit;color:inherit}
.lpmenuitem:hover{background:var(--surface2)}
.lpmenuitem.on{background:var(--accentSoft)}
.lpmenuitem strong{display:block;font-size:14px;font-weight:600;letter-spacing:-.016em}
.lpmenuitem.on strong{color:var(--accentInk)}
.lpmenuitem span{display:block;font-size:12px;color:var(--ink3);margin-top:3px;line-height:1.4;letter-spacing:-.01em}
.lpmenunote{margin:4px 5px 2px;padding-top:8px;border-top:1px solid var(--line);
  font-size:11px;line-height:1.5;color:var(--ink3)}
.btn.lg{padding:12px 26px;font-size:14.5px}

.lphero{display:grid;grid-template-columns:minmax(0,1.08fr) minmax(0,1fr);gap:44px;align-items:center;
  padding-top:34px;padding-bottom:44px}
/* Marketing type follows Apple's scale rather than the product's. The tables
   inside the app live at 13px because they have eight columns to fit; a
   landing page has no such excuse, so this runs on Apple's own sizes — 17px
   body, a 12px floor for labels — with their tracking at each size. */
.lphero h1{font-size:44px;line-height:1.07;letter-spacing:-.005em;margin-bottom:16px}
/* `.lphero p` would also match .lpwelcome, which is a <p> in the same block —
   and at 0,1,1 it outranks the 0,1,0 class rule, so the remembered-side note
   was being rendered at 17px in a 46ch box and wrapping onto two lines. Scoped
   to the lede, which is the only paragraph this was ever meant to size.
   No max-width: the column is already a 59ch measure, and capping it shorter
   just left a stripe of dead space inside the column. */
.lphead > p:not(.lpwelcome){color:var(--ink2);font-size:17px;line-height:1.47;letter-spacing:-.022em}
.lphacts{display:flex;gap:10px;margin-top:24px;flex-wrap:wrap}
.lphead .ebrow{font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink3);
  font-weight:700;margin-bottom:10px}
/* Hero media. The aspect ratio is declared so the column holds its height
   before a single byte of video arrives — without it the page reflows under
   the reader the moment the poster decodes. */
.herovid{margin:0;border-radius:16px;overflow:hidden;background:var(--surface3);
  aspect-ratio:1000/562;box-shadow:var(--shadow);position:relative}
.herovid video,.herovid img{width:100%;height:100%;object-fit:cover;display:block}
/* The embed fills the same frame the file did. object-fit does nothing to an
   iframe — YouTube letterboxes inside it — so the box has to be the video's own
   ratio, which is what aspect-ratio above already gives it. */
/* pointer-events:none is what removes the hover chrome — the title, the channel
   name, the share and watch-later buttons and the wordmark that YouTube paints
   over the film when a cursor enters it. There is no player parameter that
   turns those off: `showinfo` was removed in 2018 and `modestbranding` in 2023,
   so the only way to stop the overlay is to stop the pointer reaching the
   player at all. The side effect is that the film cannot be clicked, which is
   right for scenery and wrong for a player — see the note in heroMedia(). It
   also lets a scroll gesture over the hero scroll the page instead of being
   swallowed by the iframe. */
.herovid iframe{width:100%;height:100%;display:block;border:0;pointer-events:none}
/* Cropping the player's furniture out of frame.
   -------------------------------------------------------------------------
   pointer-events stops the overlay YouTube paints on hover. It does nothing
   about the one it paints while the player is loading and again at each loop
   restart — the title, the channel avatar and name, the AI and link buttons and
   the wordmark, which is what you see for a beat every time the film wraps.
   There is no parameter for that either.

   So the iframe is made three times taller than the frame and centred in it.
   YouTube letterboxes the video inside whatever box it is given, so the film
   still renders full-width at 16:9 and looks identical — but the chrome is
   anchored to the iframe's own edges, which are now a full frame-height above
   and below the visible area. The overflow:hidden on .herovid does the rest.

   What this does NOT hide is the large play/pause control, which YouTube
   centres on the video rather than on the player. Removing that needs either
   the IFrame Player API (more third-party script, and another CSP entry) or the
   video file itself. */
.herovid-yt{position:relative}
.herovid-yt iframe{position:absolute;top:50%;left:0;height:300%;transform:translateY(-50%)}
/* The still sits behind the frame. If YouTube is slow, blocked by a network,
   or the video ever stops being embeddable, the hero degrades to the poster
   instead of to a grey rectangle — which is what a failed iframe looks like,
   and it looks like a broken site. */
.herovid-yt{background-image:url('/hero.jpg');background-size:cover;background-position:center}
/* Shown only on the reduced-motion still: the film is not playing, so there has
   to be a way to reach it. */
.heroplay{position:absolute;left:14px;bottom:14px;background:var(--surface);
  color:var(--ink);border:1px solid var(--line);border-radius:999px;
  padding:8px 16px;font-size:13px;font-weight:600;text-decoration:none;
  box-shadow:var(--shadow)}
.heroplay:hover{background:var(--surface2)}

/* Proof: real counts, or what the product does. Never a borrowed badge. */
.lpproof{padding-top:34px;padding-bottom:34px;
  --secInk:var(--t5i);background:var(--t5);border-radius:28px}
.lp .lpproof{margin-bottom:14px}
.lpproof .lpstat strong{color:var(--t5i)}
/* Used by the campaign-steps section, beside its four steps. */
.lppic{line-height:0;border-radius:14px;overflow:hidden;box-shadow:var(--shadow)}
.lppic img{width:100%;height:auto;display:block}
/* Hugs its contents: two real numbers stretched across a 1120px card read as
   a band that failed to load the other four. */
.lpstats{display:inline-flex;gap:44px;flex-wrap:wrap;padding:20px 30px;background:var(--surface);
  border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--shadow);max-width:100%}
.lpstat{display:flex;flex-direction:column;gap:2px}
.lpstat strong{font-size:29px;letter-spacing:-.017em;color:var(--ink)}
.lpstat span{font-size:12px;letter-spacing:-.01em;color:var(--ink3)}
.lpfine{margin-top:9px;font-size:12px;line-height:1.45;letter-spacing:-.01em;color:var(--ink3)}

/* Colour, by the band.
   -------------------------------------------------------------------------
   Each landing section is a rounded tinted block rather than a full-bleed
   stripe. Two reasons: a full-bleed band needs `width:100vw` on a
   max-width container, and 100vw includes the scrollbar — that is the classic
   way a page acquires a few pixels of sideways scroll on Windows. And the
   inset block matches the rounded-panel language the CTAs and FAQ rows already
   use. `--secBg` is the ground and `--secInk` the hue its small marks take, so
   one pair of variables per section drives both. */
.lpsec{padding-top:54px;padding-bottom:54px;
  --secBg:transparent; --secInk:var(--accent);
  background:var(--secBg);border-radius:28px}
/* The gap between bands, and why it is written `.lp .lpsec` rather than
   `.lpsec`. Further up, `.lp section` sets `margin:0 auto` to centre the
   column — and at 0,1,1 that beats a bare `.lpsec` at 0,1,0, so a margin
   declared there silently resolves to 0 and the bands touch. The apparent gap
   was only the corner radius letting the paper show through. Two classes wins;
   changing `.lp section` to a shorthand-free `margin-inline:auto` would work
   too, but that rule is shared with the nav and the footer. */
.lp .lpsec{margin-bottom:14px}

#lp-how   { --secBg:var(--t1); --secInk:var(--t1i) }
#lp-run   { --secBg:var(--t2); --secInk:var(--t2i) }
#lp-cats  { --secBg:var(--t3); --secInk:var(--t3i) }
#lp-faq   { --secBg:var(--t4); --secInk:var(--t4i) }
#lp-results{ --secBg:var(--t5); --secInk:var(--t5i) }

/* Marks take the band's hue; body copy never does. The step icon, the section
   keyline and the category glyph are decoration beside text that already says
   what they say, so they can carry colour without carrying meaning. */
.lpsec .lpstepi{background:color-mix(in srgb, var(--secInk) 12%, transparent);color:var(--secInk)}
.lpsec .lpk{color:var(--secInk)}
.lpsec .lpcati{color:var(--secInk)}
.lpsec .lptab[aria-selected="true"]{border-color:var(--secInk)}
.lpsec .hmscore b{color:var(--secInk)}
.lpsec .hmbar>i{background:var(--secInk)}
.lpsec .hmtier.on .hmk{color:var(--secInk)}
/* Cards inside a tinted band keep a white ground so the text contrast the rest
   of the page relies on does not change from section to section. */
.lpsec .lpcat,.lpsec .lpq,.lpsec .rpcard,.lpsec .hmcard{background:var(--surface)}
/* The tabs' own track was --surface2, which disappears against a tint. */
#lp-how .lptabs{background:color-mix(in srgb, var(--t1i) 8%, var(--surface))}
#lp-how .lphowm{background:color-mix(in srgb, var(--t1i) 14%, var(--surface))}
.lpsec h2{font-size:28px;letter-spacing:-.018em;margin-bottom:8px}
.lpsub{color:var(--ink2);font-size:17px;line-height:1.47;letter-spacing:-.022em;max-width:62ch;margin-bottom:26px}
/* Steps. One shape for both How-it-works columns and the campaign flow: an
   icon, a heading, a sentence. The icon is decoration beside a heading that
   already names the step, so it is drawn in the ink colour rather than the
   accent — four red discs down a column read as four alerts. */
.lpsteps{list-style:none;margin:0 0 20px;padding:0;display:flex;flex-direction:column;gap:18px}
.lpstep{display:flex;gap:13px;align-items:flex-start}
.lpstepi{flex:none;width:34px;height:34px;border-radius:9px;background:var(--surface2);
  color:var(--ink2);display:grid;place-items:center}
.ic24{width:18px;height:18px;display:block}
.lpstept{min-width:0}
.lpstept strong{display:block;font-size:17px;color:var(--ink);margin-bottom:4px;letter-spacing:-.022em}
.lpstept span{display:block;font-size:14px;line-height:1.6;letter-spacing:-.016em;color:var(--ink2)}

/* How it works: a switcher, then one side at a time.
   ------------------------------------------------------------------------- */
/* The pill group. Left-aligned rather than centred, because every other
   heading and sub-line on this page starts at the same left edge and a centred
   control under a left-aligned h2 reads as a mistake. */
.lptabs{display:inline-flex;gap:3px;padding:4px;background:var(--surface2);
  border:1px solid var(--line);border-radius:999px;margin-bottom:28px;max-width:100%;
  overflow-x:auto;scrollbar-width:none}
.lptabs::-webkit-scrollbar{display:none}
.lptab{flex:none;background:none;border:1px solid transparent;border-radius:999px;cursor:pointer;
  padding:9px 20px;font:inherit;font-size:14.5px;font-weight:500;letter-spacing:-.016em;
  color:var(--ink2);white-space:nowrap}
.lptab:hover{color:var(--ink)}
.lptab[aria-selected="true"]{background:var(--surface);border-color:var(--accent);
  color:var(--ink);font-weight:600;box-shadow:0 1px 2px rgba(18,24,33,.06)}

.lphow{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:48px;align-items:center}
.lphowc{min-width:0}
.lphowl{font-size:19px;line-height:1.45;letter-spacing:-.022em;color:var(--ink);
  max-width:34ch;margin-bottom:26px}
.lphowc .lpsteps{margin-bottom:24px}

/* The illustrative card. A tinted slab behind a white card, which is the shape
   the reference uses; the tint is the brand's own soft accent rather than a
   borrowed blue. */
.lphowm{margin:0;background:var(--accentSoft);border-radius:var(--r);padding:26px;
  display:flex;flex-direction:column;gap:12px}
.hmcap{font-family:var(--f-num);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--accentInk);font-weight:700;opacity:.8}
.hmcard{background:var(--surface);border:1px solid var(--line);border-radius:12px;padding:18px;
  box-shadow:0 1px 3px rgba(18,24,33,.06),0 14px 34px -22px rgba(18,24,33,.4)}
.hmhead{display:flex;justify-content:space-between;align-items:flex-start;gap:14px;margin-bottom:16px}
.hmhead strong{display:block;font-size:15px;letter-spacing:-.018em}
.hmhead>div>span{display:block;font-size:12px;color:var(--ink3);margin-top:2px}
.hmscore{text-align:right;flex:none}
.hmscore b{display:block;font-size:26px;line-height:1;letter-spacing:-.02em;color:var(--accent)}
.hmscore span{font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--ink3)}

.hmbars{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:11px}
.hmrow{display:grid;grid-template-columns:1fr;gap:4px}
.hmlab{font-size:12.5px;color:var(--ink2);letter-spacing:-.01em}
.hmbar{height:5px;border-radius:20px;background:var(--surface3);display:block;overflow:hidden}
.hmbar>i{display:block;height:100%;background:var(--accent);border-radius:20px}
/* An unmeasured component is drawn as an empty track, not a short bar. A short
   bar is a low score; this is the absence of one, and the two must not look
   alike. */
.hmbar[data-none]{background:repeating-linear-gradient(90deg,var(--surface3) 0 4px,transparent 4px 8px)}
.hmnote{font-size:11px;color:var(--ink3);letter-spacing:-.005em}
.hmnote.off{color:var(--ink3);font-style:italic}

.hmtier{border-top:1px solid var(--line);padding-top:12px;margin-top:12px}
.hmtier:first-of-type{border-top:0;padding-top:0;margin-top:0}
.hmk{font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--ink3);
  font-weight:700;margin-bottom:5px}
.hmtier.on .hmk{color:var(--accentInk)}
.hmtier p{font-size:12.5px;line-height:1.55;color:var(--ink2);letter-spacing:-.01em}
.hmfoot{margin-top:14px;padding-top:12px;border-top:1px solid var(--line);
  font-size:11.5px;line-height:1.5;color:var(--ink3);letter-spacing:-.005em}

/* Real results: the carousel, and the honest stand-in for it.
   ------------------------------------------------------------------------- */
/* The provenance tag. Three sources, and the third is styled differently on
   purpose — a number the brand reported is not a number Adtrafix Match measured, and a
   reader skimming should be able to see which is which without reading the
   label. Muted rather than alarming: brand-reported is legitimate, just not
   ours to vouch for. */
/* align-self so the pill hugs its text: as a flex item in the card column an
   inline-block stretches to full width and reads as a bar, not a tag. */
.rsrc{display:inline-block;align-self:flex-start;margin-top:auto;font-family:var(--f-num);font-size:10px;
  letter-spacing:.07em;text-transform:uppercase;font-weight:700;padding:5px 9px;border-radius:20px}
.rsrc-collab_measured{background:var(--accentSoft);color:var(--accentInk)}
.rsrc-creator_account{background:var(--surface2);color:var(--ink2)}
.rsrc-brand_reported{background:transparent;color:var(--ink3);border:1px dashed var(--line2);
  text-transform:none;letter-spacing:.01em;font-family:inherit;font-size:11px;font-weight:600}

.rprove{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:18px;margin-top:4px}
.rpcard{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  padding:22px;display:flex;flex-direction:column;gap:10px;box-shadow:var(--shadow)}
.rpcard h3{font-size:17px;letter-spacing:-.022em}
.rpcard p{font-size:14px;line-height:1.6;letter-spacing:-.016em;color:var(--ink2);margin-bottom:6px}
.rcta{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-top:26px}
.rcta span{font-size:13.5px;color:var(--ink3);letter-spacing:-.01em}

/* The carousel. Wide card on the left, a strip of the other stories on the
   right — the reference's shape, and it works because the peek cards tell you
   more stories exist without spending a row on dots. */
.rcar{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:30px;align-items:start;margin-top:4px}
.rshot{margin:0 0 20px;border-radius:var(--r);overflow:hidden;background:var(--surface2)}
.rshot img{width:100%;height:auto;display:block}
.rshot-none{display:grid;place-items:center;min-height:240px;padding:30px;
  background:var(--accentSoft);border-radius:var(--r)}
.rshot-none p{font-size:22px;line-height:1.3;letter-spacing:-.022em;color:var(--accentInk);
  text-align:center;max-width:26ch;font-weight:600}
/* margin:0 because a bare blockquote carries a browser indent, which pushed
   the quote out of line with everything else in the column. */
.rquote{font-size:23px;line-height:1.35;letter-spacing:-.024em;color:var(--ink);
  max-width:34ch;margin:0 0 10px;font-weight:600}
.rwho{font-size:13.5px;color:var(--ink3);letter-spacing:-.01em;margin-bottom:14px}
.rmetric{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin-bottom:18px}
.rmetric b{font-size:26px;letter-spacing:-.02em;color:var(--accent)}
.rmetric>span{font-size:13.5px;color:var(--ink2);letter-spacing:-.01em}
.rmetric .rsrc{margin-top:0}

.rside{display:flex;flex-direction:column;gap:16px;align-items:flex-end}
.rpeek{list-style:none;margin:0;padding:0;display:flex;gap:12px}
.rpk{width:88px;height:186px;padding:0;border:1px solid var(--line);border-radius:999px;
  overflow:hidden;cursor:pointer;background:var(--surface2);display:grid;place-items:center;
  opacity:.72;transition:opacity .18s}
.rpk:hover,.rpk.on{opacity:1}
.rpk.on{border-color:var(--accent)}
.rpk img{width:100%;height:100%;object-fit:cover;display:block}
.rpk>span{font-size:17px;font-weight:700;color:var(--ink3);letter-spacing:-.01em}
.rnav{display:flex;gap:10px}
.rarrow{width:40px;height:40px;border-radius:50%;border:1px solid var(--line);
  background:var(--surface);cursor:pointer;font-size:19px;line-height:1;color:var(--ink2)}
.rarrow:hover{background:var(--surface2);color:var(--ink)}

/* Campaign stage: where it really is, and who it is waiting on.
   -------------------------------------------------------------------------
   Toned by who must act rather than by how far along the campaign is. A card
   sitting at zero applications is not a problem and should not look like one;
   a campaign holding drafts that need approving is the one worth a colour. */
.stg{border:1px solid var(--line);border-left-width:3px;border-radius:var(--rs);
  padding:9px 11px;margin:10px 0 0;background:var(--surface2)}
.stg-c{margin:10px 0 2px}
.stgl{display:flex;align-items:center;gap:8px}
.stgl strong{font-size:13.5px;letter-spacing:-.016em;color:var(--ink)}
.stg p{margin:4px 0 0;font-size:12px;line-height:1.5;color:var(--ink2);letter-spacing:-.005em}
.stgd{width:7px;height:7px;border-radius:50%;flex:none;background:var(--ink3)}
/* The one label that is a call to action rather than a description. */
.stgy{margin-left:auto;font-size:10px;letter-spacing:.07em;text-transform:uppercase;
  font-weight:700;color:var(--warn);background:var(--warnSoft);padding:3px 7px;border-radius:20px}
.stg-warn{border-left-color:var(--warn);background:var(--warnSoft)}
.stg-warn .stgd{background:var(--warn)}
.stg-info{border-left-color:var(--info)}
.stg-info .stgd{background:var(--info)}
.stg-neu{border-left-color:var(--line2)}

.lpchoose{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:20px;margin-top:24px}
.lpcard{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  padding:26px;box-shadow:var(--shadow);display:flex;flex-direction:column;gap:9px}
.lpic{width:38px;height:38px;border-radius:10px;background:var(--accentSoft);color:var(--accentInk);
  display:grid;place-items:center;font-size:17px;margin-bottom:4px}
.lpcard h3{font-size:19px}
.lpcard p{font-size:13.5px;color:var(--ink2);line-height:1.6}
.lpca{display:flex;gap:8px;margin-top:8px;flex-wrap:wrap}

.lpfoot{display:flex;align-items:center;gap:20px;flex-wrap:wrap;padding-top:26px;padding-bottom:40px;
  border-top:1px solid var(--line);margin-top:20px}
.lpfl{margin-left:auto;display:flex;gap:6px;align-items:center;flex-wrap:wrap}
.lpfl a{color:var(--ink3);font-size:12.5px;text-decoration:none;padding:7px 10px}
.lpfl a:hover{color:var(--ink)}
.lpfl .lplink{font-size:12.5px;font-weight:500;color:var(--ink3)}


@media (max-width:900px){
  .lpcats{grid-template-columns:repeat(3,minmax(0,1fr))}
  .lphero{grid-template-columns:1fr;gap:26px;padding-top:20px}
  .lphero h1{font-size:33px}
  .herovid{order:-1}
  .lpsec h2{font-size:23px}
  .lpstats{gap:26px}
  .lpstat strong{font-size:23px}
  /* Steps first, example second. The card is there to show the shape of a
     score; stacked above the words it explains, it is just a tall graphic
     between the heading and the point. */
  .lphow{grid-template-columns:1fr;gap:26px}
  .lphowl{font-size:16.5px;max-width:none;margin-bottom:20px}
  .lptabs{margin-bottom:22px}
  .lphowm{padding:18px}
  /* The peek strip goes under the story rather than beside it, and scrolls
     sideways instead of shrinking each capsule into a sliver. */
  .rcar{grid-template-columns:1fr;gap:22px}
  .rside{align-items:stretch;flex-direction:column-reverse;gap:14px}
  .rpeek{overflow-x:auto;scrollbar-width:none;padding-bottom:2px}
  .rpeek::-webkit-scrollbar{display:none}
  .rpk{width:66px;height:140px;flex:none}
  .rnav{justify-content:flex-end}
  .rquote{font-size:19px;max-width:none}
}
/* Below this the four links no longer fit beside the logo. They used to wrap
   onto a second line of their own, which read as a stray row of text under the
   masthead rather than as navigation. Same buttons, folded into a panel behind
   the burger: the header stays one line, and the links get proper tap targets
   instead of the 7px padding that suits a desktop hover. */
@media (max-width:700px){
  .lpburger{display:flex}
  /* No side padding on the panel, so the dividers run its full width instead of
     stopping two hairs short of a rounded corner. The rows square off to match,
     and overflow:hidden keeps a hover on the first or last one inside the
     curve. */
  .lplinks{display:none;order:3;width:100%;flex-direction:column;gap:0;
    margin:10px 0 4px;padding:0;overflow:hidden;background:var(--surface);
    border:1px solid var(--line);border-radius:12px}
  .lplinks.open{display:flex}
  /* Scoped to the panel: `.lplink` on its own would also catch the footer's
     small print, which is the same class doing a different job. */
  .lplinks .lplink{text-align:left;padding:12px 16px;font-size:15px;color:var(--ink);border-radius:0}
  .lplinks .lplink + .lplink{border-top:1px solid var(--line)}
}
@media (max-width:640px){
  .lpnav{gap:12px}
  .lpacts{margin-left:auto}
  .lphero h1{font-size:28px}
  .btn.lg{padding:9px 16px}
  /* Two pills fit at this width; the group scrolls sideways rather than
     wrapping if a third side is ever added. */
  .lptab{padding:8px 15px;font-size:13.5px}
  .lphowm{padding:14px}
  .hmcard{padding:15px}
}

/* Categories: the eight a brief can actually ask for. Display tiles, not
   buttons — no hover lift, no pointer, because clicking one does nothing and a
   card that looks pressable and is not is a small lie. */
/* Four across, so eight categories land as two full rows rather than six and
   a stranded pair. */
/* Campaign steps: numbered list on the left, the roster a brand browses on the
   right. Real markup for the steps — a picture of four steps cannot be
   selected, translated, resized or read aloud. */
/* Four steps read as two rows of two, never three-and-a-stray. The phone
   override sits immediately below rather than up in the shared breakpoint
   block: an override written earlier in the file than its base rule loses at
   every width, which is exactly how this grid stayed two-up on a phone. */
.lpflow{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:26px 34px;margin-top:26px}
@media (max-width:760px){ .lpflow{grid-template-columns:1fr} }

.lpcats{list-style:none;margin:26px 0 0;padding:0;display:grid;
  grid-template-columns:repeat(4,minmax(0,1fr));gap:12px}
.lpcat{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  padding:13px 15px 13px 13px;display:flex;align-items:center;gap:13px;
  font-size:15px;font-weight:600;letter-spacing:-.019em;color:var(--ink)}
/* A face rather than a glyph, at a size the source can actually carry. Blown
   up to fill the card these frames go soft, and a soft photograph on a page
   arguing for measured data is the wrong impression to leave. */
.lpcatpic{display:block;line-height:0;flex:none}
.lpcatpic img{width:76px;height:76px;object-fit:cover;display:block;border-radius:10px}
/* Still used by any category the server adds that has no photograph. */
.lpcati{color:var(--accent);display:block;line-height:0;flex:none;width:76px;text-align:center}

/* FAQ: native details/summary, so each row is keyboard reachable and is read
   by a screen reader as the disclosure it is, with no script of our own in the
   way. Expand-all is the one part that needs JavaScript — which is why it is a
   convenience above the list rather than the mechanism inside it. */
/* The expand-all control, right-aligned above the list. */
.lpfaqbar{display:flex;justify-content:flex-end;margin-top:-8px;margin-bottom:14px}
.lpexpand{display:inline-flex;align-items:center;gap:7px;background:none;border:0;cursor:pointer;
  font:inherit;font-size:13.5px;font-weight:600;letter-spacing:-.016em;color:var(--accent);
  padding:6px 2px;border-radius:var(--rs)}
.lpexpand:hover{text-decoration:underline}
.lpexi{width:13px;height:13px;flex:none;display:block}

.lpfaq{display:flex;flex-direction:column;gap:10px}
/* A large radius rather than a true pill. At 999px a closed row is a perfect
   stadium, but the same rule makes an open one — 200px tall with an answer in
   it — bulge at the sides. 26px reads as a pill while the row is one line and
   still as a rounded card once it is not. */
.lpq{background:var(--surface);border:1px solid var(--line);border-radius:26px;overflow:hidden}
.lpq[open]{border-color:var(--line2)}
.lpq summary{display:flex;align-items:center;gap:16px;padding:19px 26px;cursor:pointer;
  list-style:none;font-size:17px;font-weight:600;letter-spacing:-.022em;color:var(--ink)}
.lpq summary::-webkit-details-marker{display:none}
.lpq summary:hover{background:var(--surface2)}
/* Whose question this is. Plain small caps, not a chip: a pill inside a pill
   was two competing shapes in one row, and this label is a note, not a badge.
   It stays in the muted ink — eight accent labels down the section read as
   eight warnings. */
.lpqw{flex:none;font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;font-weight:700;
  color:var(--ink3);min-width:60px}
.lpqt{flex:1;min-width:0}
/* A plus that becomes a minus. Two bars, one rotated away on open — closer to
   the reference than a chevron, and it reads as add/remove rather than as a
   direction. */
.lpqi{flex:none;width:15px;height:15px;position:relative}
.lpqi::before,.lpqi::after{content:"";position:absolute;inset:50% 0 auto 0;height:1.8px;
  border-radius:2px;background:var(--ink2);transform:translateY(-50%);transition:transform .18s ease}
.lpqi::after{transform:translateY(-50%) rotate(90deg)}
.lpq[open] .lpqi::after{transform:translateY(-50%) rotate(0deg)}
.lpqa{padding:0 26px 22px 76px;font-size:14px;line-height:1.6;letter-spacing:-.016em;
  color:var(--ink2);max-width:76ch}

@media (max-width:640px){
  /* The label wraps above the question on a phone, so the row is question-first
     and the plus stays pinned to the right of it. */
  .lpq{border-radius:20px}
  .lpq summary{flex-wrap:wrap;gap:6px 12px;padding:15px 18px;font-size:15.5px}
  .lpqw{min-width:0;flex-basis:100%;order:1;font-size:10px}
  .lpqt{flex:1;order:2}
  .lpqi{order:3}
  .lpqa{padding:0 18px 18px}
  .lpfaqbar{margin-bottom:12px}
  .lpcats{grid-template-columns:repeat(2,minmax(0,1fr));gap:9px}
  .lpcat{padding:10px 12px 10px 10px;font-size:13px;gap:11px}
  .lpcatpic img{width:62px;height:62px}

  /* Phone rhythm. The desktop spacing was set for a 1120px column; carried
     down unchanged it leaves a page that is mostly gaps, and the reader has
     to scroll past air between every idea. */
  .lp section,.lpnav,.lpfoot{padding-left:18px;padding-right:18px}
  .lpsec{padding-top:34px;padding-bottom:6px}
  .lpsec h2{font-size:21px}
  .lpsub{font-size:13.5px}
  .lpsteps{gap:15px}
  .lpstepi{width:30px;height:30px;border-radius:8px}
  .ic24{width:16px;height:16px}
  .lpstept strong{font-size:14px}
  .lpstept span{font-size:13px}
  .lpflow{margin-top:20px;gap:17px}
}


/* The closing band: one last offer of the same choice the hero made, not a
   second pair of cards restating it. */
.lpend{text-align:center;padding-bottom:64px}
/* Two cards, one face each — restrained on purpose. The earlier version led
   with a 96px portrait above the heading, which made the last thing on the
   page the loudest; the face is a 48px mark beside the heading now, and the
   button is the only thing asking for attention. */
.lpsides{display:grid;grid-template-columns:repeat(auto-fit,minmax(272px,1fr));gap:14px;
  margin:26px auto 0;max-width:680px;text-align:left}
.lpside{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  padding:20px;display:flex;flex-direction:column;gap:8px;align-items:flex-start}
.lpsidehd{display:flex;align-items:center;gap:12px}
.lpsideimg{width:48px;height:48px;border-radius:50%;object-fit:cover;display:block;flex:none}
.lpside h3{font-size:17px;font-weight:600;letter-spacing:-.022em}
.lpside p{color:var(--ink2);font-size:14px;line-height:1.6;letter-spacing:-.016em;flex:1;margin:0}
.lpside .btn{margin-top:6px}
/* Kept next to the rules it overrides. Written up in the shared phone block it
   would sit earlier in the file than these and quietly do nothing. */
@media (max-width:640px){
  .lpsides{gap:11px;margin-top:20px}
  .lpside{padding:16px}
  .lpsideimg{width:42px;height:42px}
  .lpend{padding-bottom:44px}
}
.lpend .lpsub{margin-left:auto;margin-right:auto;max-width:52ch}
.lpend .lphacts{justify-content:center;margin-top:24px}
.lpend .lpfine{margin-top:16px}
/* Says why the page is ordered as it is, and offers the way back. */
/* One line: the sentence and the way out of it belong together. */
.lpwelcome{margin-top:14px;font-size:12.5px;letter-spacing:-.01em;color:var(--ink3);line-height:1.45;
  display:flex;align-items:center;gap:4px;flex-wrap:wrap}
.lpwelcome .alink{font-size:12.5px;padding:2px 4px}
.lpend .lpwelcome{margin-left:auto;margin-right:auto}

/* Price negotiation: the round trip made visible.
   -------------------------------------------------------------------------
   A creator used to read her own fee off a table she could not act on. These
   are the controls that let her answer, and they are toned the same way the
   campaign stage is: colour means someone owes a move, not that things are
   going well. */
.qrow{margin-top:13px}
.qrow .fl{display:block;margin-bottom:5px}
.qin{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--line2);
  border-radius:999px;padding:3px 3px 3px 12px;background:var(--surface)}
.qin>span{font-size:13px;color:var(--ink3)}
.qin input{width:92px;border:0;background:none;padding:6px 0;font:inherit;font-size:13.5px;
  color:var(--ink);outline:none}
.qhint{margin-top:7px;font-size:11.5px;line-height:1.5;color:var(--ink3)}

.nego{border:1px solid var(--line);border-left-width:3px;border-radius:var(--rs);
  padding:11px 13px;margin-top:10px;background:var(--surface2)}
.nego p{margin:5px 0 0;font-size:12.5px;line-height:1.55;color:var(--ink2)}
.negoh{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.negoh strong{font-size:14px;letter-spacing:-.016em}
.negow{font-size:11px;color:var(--ink3)}
/* The one state that is a task. */
.negoy{margin-left:auto;font-size:10px;letter-spacing:.07em;text-transform:uppercase;
  font-weight:700;color:var(--warn);background:var(--warnSoft);padding:3px 7px;border-radius:20px}
.nego-you{border-left-color:var(--warn);background:var(--warnSoft)}
.nego-done{border-left-color:var(--good);background:var(--goodSoft)}
.negonote{font-style:italic}
.negoacts{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-top:11px}

.othread{margin-top:9px}
.othread summary{font-size:11.5px;color:var(--ink3);cursor:pointer}
.orow{display:flex;gap:9px;align-items:baseline;font-size:12px;padding:6px 0;
  border-bottom:1px solid var(--line)}
.orow .ow{min-width:74px;color:var(--ink2)}
.orow .os{margin-left:auto;font-size:10.5px;text-transform:uppercase;letter-spacing:.06em;color:var(--ink3)}
.orow p{flex-basis:100%;margin:2px 0 0;font-size:11.5px;color:var(--ink3);font-style:italic}
tr.onote td{font-size:12px;color:var(--ink3);font-style:italic;padding-top:0}

/* Profile gaps: what is not measured, and where to go about it.
   -------------------------------------------------------------------------
   Toned by consequence, not by severity of feeling. `blocks` is red because
   nothing works until it is done; `measurement` is amber because she is being
   judged on part of herself; `field` is informational because it is a few
   points either way. Nothing here is styled as a scold. */
.gaps{border:1px solid var(--line);border-radius:var(--r);background:var(--surface);
  padding:16px 18px;margin-bottom:18px;box-shadow:var(--shadow)}
.gapsh strong{display:block;font-size:15px;letter-spacing:-.018em}
.gapsh span{display:block;font-size:12.5px;color:var(--ink2);margin-top:3px}
.gapl{list-style:none;margin:14px 0 0;padding:0;display:grid;gap:10px;
  grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}
.gap{border:1px solid var(--line);border-left-width:3px;border-radius:var(--rs);padding:11px 13px}
.gapt{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
.gapt strong{font-size:13px;letter-spacing:-.016em}
.gapw{font-size:11.5px;letter-spacing:0;color:var(--ink3);font-weight:600}
.gap p{margin:5px 0 9px;font-size:12px;line-height:1.55;color:var(--ink2)}
.gap-crit{border-left-color:var(--crit);background:var(--critSoft)}
.gap-warn{border-left-color:var(--warn);background:var(--warnSoft)}
.gap-info{border-left-color:var(--info)}

/* Her score on a brief, before she applies rather than after. */
.mline{display:flex;align-items:center;gap:11px;margin-top:12px;padding-top:11px;
  border-top:1px solid var(--line)}
.mnum{font-size:23px;font-weight:600;letter-spacing:-.02em;color:var(--ink)}
.mline strong{display:block;font-size:12px;letter-spacing:0;color:var(--ink3);font-weight:600}
.mline>div>span{display:block;font-size:12px;color:var(--ink2);margin-top:1px}
/* A partial score is not a worse score, it is a less complete one. */
.mline-p .mnum{color:var(--ink2)}
.mwhy{margin-top:7px;font-size:11.5px;line-height:1.5;color:var(--ink3)}

/* Creative approval: options side by side.
 *
 * Fixed-height previews on purpose. A brand comparing three versions is
 * comparing them, and a portrait reel next to a landscape image next to a square
 * makes three cards of three different heights that cannot be scanned as a set. */
.dgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(272px,1fr));gap:14px;align-items:start}
.dopt{border:1px solid var(--line);border-radius:var(--r);padding:12px;background:var(--surface)}
.card.dopt{padding:0}
.dopt-ok{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent) inset}
.dpv{width:100%;height:280px;object-fit:contain;display:block;border-radius:var(--rs);background:var(--surface3)}
/* A deleted file is a state, not a failure, so it gets a panel that says so
   rather than a broken player. */
.dpv-gone{height:auto;min-height:88px;display:grid;place-items:center;text-align:center;
  padding:16px;font-size:12.5px;color:var(--ink3);border:1px dashed var(--line2)}
.dopt textarea{width:100%;font:inherit;font-size:13px;padding:8px 10px;border:1px solid var(--line);
  border-radius:var(--rs);background:var(--surface);color:var(--ink);resize:vertical}
@media (max-width:640px){ .dpv{height:220px} }
/* One choice between three things, so the three buttons line up however much
   caption or warning sits above them. */
.dgrid{align-items:stretch}
.card.dopt{display:flex;flex-direction:column}
.card.dopt>.card-p{display:flex;flex-direction:column;flex:1}
.dopt .dact{margin-top:auto;padding-top:12px;display:flex;gap:8px}

/* ------------------------------------------------- the public storefront --
   The only screen whose visitor has never heard of Adtrafix Match, arriving from a
   link in a bio on a phone. Sized for that first: one column, big taps, and
   nothing between the tap and the product. */
.shopwrap{max-width:720px;margin:0 auto;padding:28px 16px 48px}
.shophead{text-align:center;display:grid;justify-items:center;gap:8px;margin-bottom:24px}
.shophead h1{font-size:23px;font-weight:700;letter-spacing:-.01em;margin:4px 0 0}
.shopby{font-size:13px;color:var(--ink3)}
.shopintro{font-size:14px;color:var(--ink2);line-height:1.6;max-width:44ch;margin:4px 0 0}
.shopgrid{display:grid;grid-template-columns:repeat(2,1fr);gap:12px}
.shopitem{display:flex;flex-direction:column;border:1px solid var(--line);border-radius:12px;
  overflow:hidden;background:var(--surface);text-decoration:none;color:inherit}
.shopitem:hover{border-color:var(--line2)}
.shopimg{aspect-ratio:1;background:var(--surface2);display:grid;place-items:center;overflow:hidden}
.shopimg img{width:100%;height:100%;object-fit:cover;display:block}
/* No stock photo stand-in. An invented product image on a page recommending a
   real product is the one thing here that would actually mislead a shopper. */
.shopinit{font-size:30px;font-weight:700;color:var(--ink3)}
.shopmeta{padding:11px 12px 13px;display:grid;gap:3px}
.shoptitle{font-size:13.5px;font-weight:600;line-height:1.35}
.shopshop{font-size:11.5px;color:var(--ink3)}
.shopprice{font-size:12.5px;font-family:var(--f-num);font-variant-numeric:tabular-nums;margin-top:2px}
.shopprice span{font-size:11px;color:var(--ink3);font-family:inherit;font-variant-numeric:normal}
.shopempty{text-align:center;padding:48px 8px;color:var(--ink2)}
.shopempty h1{font-size:19px;margin-bottom:8px;color:var(--ink)}
.shopfoot{margin-top:30px;padding-top:16px;border-top:1px solid var(--line);text-align:center}
.shopdisc{font-size:11.5px;color:var(--ink3);line-height:1.6;max-width:46ch;margin:0 auto}
.shopmark{font-size:11px;color:var(--ink3);margin-top:12px}
.shopmark a{color:var(--ink3)}
@media (max-width:420px){
  .shopgrid{grid-template-columns:1fr}
  .shopwrap{padding:22px 14px 40px}
}

/* A product with no picture is a compact row, not a square of empty grey.
   There is no image upload yet, so this is every card today — reserving a
   1:1 box for a picture that does not exist turned two products into a page
   you had to scroll twice. It is also the honest shape: we are not holding
   space for something we are about to invent. */
.shopgrid:has(.shopitem.noimg){grid-template-columns:1fr}
.shopitem.noimg{flex-direction:row;align-items:center}
.shopitem.noimg .shopimg{aspect-ratio:auto;width:60px;height:60px;flex:none;border-radius:10px;margin:10px 0 10px 10px}
.shopitem.noimg .shopinit{font-size:21px}
.shopitem.noimg .shopmeta{padding:10px 14px}
