/* PureWash funnel. Dark dashboard on the Posh read: near-black ground, quiet cards,
   one cyan for data. Data rows on the Resend read: eyebrow, headline, dotted rows.
   Depth comes from a faint top glow, gradient card faces, and a soft glow on the bars. */
:root {
  --bg: #0a0a0a;
  --card: #151515;
  --card-2: #1d1d1d;
  --card-face: linear-gradient(180deg, #1a1a1a 0%, #131313 100%);
  --card-edge: rgba(255, 255, 255, 0.07);
  --card-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.045), 0 1px 2px rgba(0, 0, 0, 0.5), 0 14px 34px -18px rgba(0, 0, 0, 0.75);
  --line: #262626;
  --line-2: #333333;
  --text: #f4f4f4;
  --text-2: #a3a3a3;
  --text-3: #707070;
  --cyan: #52b9f0;
  --warn: #e0a03a;
  --cyan-deep: #2278a8;
  --bar: linear-gradient(90deg, #3ea9e9 0%, #6cc7f7 100%);
  --bar-paid: linear-gradient(90deg, #1f6f9f 0%, #2b86b9 100%);
  --green: #40d17f;
  --red: #f0665e;
  --font: "Geist", "Inter", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  --mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --r: 14px;
  --r-sm: 10px;
  --r-pill: 999px;
}
* { box-sizing: border-box; }
html { color-scheme: dark; background: var(--bg); }
body {
  margin: 0; color: var(--text);
  background: radial-gradient(900px 420px at 50% -140px, rgba(82, 185, 240, 0.16), transparent 70%), var(--bg);
  font: 14px/1.5 var(--font); -webkit-font-smoothing: antialiased;
  font-variant-numeric: tabular-nums;
}
a { color: inherit; }
h1, h2 { margin: 0; font-weight: 600; line-height: 1.2; }
p { margin: 0; }
[hidden] { display: none !important; }
button, input, select { font: inherit; color: inherit; }
:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }

.wrap { max-width: 1120px; margin: 0 auto; padding: 0 24px 64px; }

/* top bar */
.bar { position: relative; display: flex; align-items: center; justify-content: space-between; gap: 20px; height: 60px; }
.bar::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px; background: linear-gradient(90deg, rgba(255, 255, 255, 0.14), rgba(255, 255, 255, 0.05) 55%, transparent); }
/* The lockup is type, not a picture. The logo is a consumer mark drawn for white
   paper and its wordmark is only a quarter of its own height, so at any size this
   bar can afford it renders about 15px tall in mid-grey on near-black, with the
   bubble spray cutting straight through the letterforms. Cyan on the name does the
   marking a mark would, and the two words read as one phrase. */
.brand { display: flex; align-items: baseline; gap: 14px; text-decoration: none; }
.brand .wordmark { display: flex; align-items: baseline; gap: 7px; }
.brand .pw { font-size: 16px; font-weight: 600; letter-spacing: -0.02em; color: var(--cyan); }
.brand .an { font-size: 16px; font-weight: 400; letter-spacing: -0.015em; color: var(--text); }
/* How old the numbers underneath are. On a page whose whole argument is that a
   figure is worth what its recency is worth, that is the first thing to know, so it
   sits in the masthead rather than only in the footer. Wording and colour carry the
   state rather than a dot: the row below already spends one on the month chip, and
   two dots that close together read as one system saying two things. */
.brand .fresh {
  padding-left: 14px; border-left: 1px solid rgba(255, 255, 255, 0.10);
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.01em;
  color: var(--text-3); white-space: nowrap; align-self: center;
}
.brand .fresh.stale { color: var(--warn); }
.brand .fresh:empty { display: none; }
.actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
/* White means it acts on this page — pulls the data, saves the numbers. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  border: 1px solid var(--line-2); background: linear-gradient(180deg, #1c1c1c, #141414); color: var(--text);
  border-radius: var(--r-pill); padding: 8px 14px; font-weight: 500; font-size: 13px;
  text-decoration: none; cursor: pointer; line-height: 1.2; transition: background 0.15s, border-color 0.15s;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
}
.btn:hover { background: linear-gradient(180deg, #222222, #181818); border-color: #3d3d3d; }
.btn.white { background: linear-gradient(180deg, #ffffff, #e9e9e9); color: #0a0a0a; border-color: #ffffff; box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08), 0 6px 18px -8px rgba(255, 255, 255, 0.35); }
.btn.white:hover { background: linear-gradient(180deg, #f4f4f4, #dcdcdc); }
.btn:disabled { opacity: 0.5; cursor: default; }
.btn.icon { width: 32px; height: 32px; padding: 0; border-radius: 50%; font-size: 16px; }
.btn.quiet { border-color: transparent; background: none; box-shadow: none; color: var(--text-2); padding: 8px 4px; }
.btn.quiet:hover { border-color: transparent; background: none; color: var(--text); }
/* The report switch. One control rather than two buttons that happen to sit
   together: the track is the control and the two reports live inside it, so the
   thumb moving says "same control, other side". Both labels are given the same
   width, which lets the thumb be exactly half the track and slide by exactly its
   own width — no measuring, so it is right on the first paint rather than after
   a script runs. Navigation is all this bar does now; the buttons that act on
   the data moved to the panel at the foot of the page. */
.viewtoggle {
  display: inline-flex; align-items: center; position: relative; flex: none;
  border: 1px solid var(--line-2); border-radius: var(--r-pill); padding: 3px;
  background: linear-gradient(180deg, #171717, #121212);
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.4);
}
.viewtoggle .thumb {
  position: absolute; top: 3px; bottom: 3px; left: 3px; width: 68px;
  border-radius: var(--r-pill); background: linear-gradient(180deg, #ffffff, #e9e9e9);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08), 0 6px 18px -8px rgba(255, 255, 255, 0.35);
  transition: transform 0.22s cubic-bezier(0.4, 0.1, 0.2, 1);
}
.viewtoggle[data-on="ads"] .thumb { transform: translateX(68px); }
.viewtoggle a {
  position: relative; z-index: 1; width: 68px; text-align: center; text-decoration: none;
  border-radius: var(--r-pill); padding: 7px 0; font-size: 13px; font-weight: 500;
  color: var(--text-2); transition: color 0.18s ease;
}
.viewtoggle a:hover { color: var(--text); }
.viewtoggle a[aria-current="page"] { color: #0a0a0a; }

/* The panel at the foot of the page: everything that changes the numbers rather
   than reads them. Each action sits with the stamp saying when it last ran,
   because apart they answer nothing — a button cannot tell you whether it needs
   pressing, and a timestamp in a footer has nothing to offer. */
.ops {
  margin-top: 44px; border: 1px solid var(--card-edge); border-radius: var(--r);
  background: var(--card-face); box-shadow: var(--card-shadow); padding: 20px 22px 8px;
}
.ops-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; padding-bottom: 14px; }
.ops-head .eyebrow { padding-right: 0; }
.ops-key { display: flex; align-items: center; gap: 9px; }
.ops-key label { font-size: 12.5px; color: var(--text-3); }
.ops-key .input { width: 132px; }
.ops-row { display: grid; grid-template-columns: 1fr auto auto; gap: 18px; align-items: center; padding: 15px 0; border-top: 1px solid rgba(255, 255, 255, 0.06); }
.ops-row .what { min-width: 0; }
.ops-row .what b { display: block; font-size: 13.5px; font-weight: 500; }
.ops-row .what span { display: block; margin-top: 3px; font-size: 12.5px; color: var(--text-3); }
/* The stamp is the row's real content, so it takes the mono face the figures use. */
.ops-row .when { font-family: var(--mono); font-size: 12px; color: var(--text-2); white-space: nowrap; }
.ops-row .when.never { color: var(--text-3); }
.ops-row .when.stale { color: var(--warn); }
.ops-row .btn { white-space: nowrap; }
.ops .notice { margin: 0 0 14px; }
.ops-foot {
  display: flex; flex-wrap: wrap; gap: 6px 18px; justify-content: space-between;
  padding: 13px 0 12px; border-top: 1px solid rgba(255, 255, 255, 0.06);
  font-size: 12.5px; color: var(--text-3);
}
.ops-foot a { color: var(--text-2); }

@media (max-width: 620px) {
  .ops-row { grid-template-columns: 1fr auto; }
  .ops-row .when { grid-column: 1 / -1; order: 3; }
}
@media (prefers-reduced-motion: reduce) {
  .viewtoggle .thumb, .viewtoggle a { transition: none; }
}
.input { border: 1px solid var(--line-2); background: linear-gradient(180deg, #171717, #121212); border-radius: var(--r-pill); padding: 8px 12px; font-size: 13px; min-width: 0; box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.4); }
.input::placeholder { color: var(--text-3); }
select.input {
  appearance: none; padding-right: 28px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path d='M1 1l4 4 4-4' fill='none' stroke='%23a3a3a3' stroke-width='1.5'/></svg>"), linear-gradient(180deg, #171717, #121212);
  background-repeat: no-repeat; background-position: right 11px center, 0 0;
}

/* title row */
.title { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px 24px; padding: 28px 0 18px; }
/* One gap on both axes, not just across. The month-state pill is a flex item in the
   headline, and every phone from 360px up wraps it onto its own row — where a column-
   only gap left it sitting flush against the headline. Matching the two means the pill
   keeps the same distance from the title whether it lands beside it or beneath it, and
   the row gap costs nothing at any width wide enough not to wrap. */
.title h1 { font-size: 26px; letter-spacing: -0.02em; display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }
.title h1 span { font-weight: 300; }
.status { display: inline-flex; align-items: center; gap: 7px; padding: 3px 10px 3px 8px; border-radius: var(--r-pill); font-size: 12px; font-weight: 500; font-style: normal; letter-spacing: 0; background: rgba(255, 255, 255, 0.06); color: var(--text-2); border: 1px solid rgba(255, 255, 255, 0.06); }
.status::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--cyan); box-shadow: 0 0 8px rgba(82, 185, 240, 0.7); }
.status.done { color: var(--green); background: rgba(64, 209, 127, 0.1); border-color: rgba(64, 209, 127, 0.18); }
.status.done::before { background: var(--green); box-shadow: 0 0 8px rgba(64, 209, 127, 0.6); }
.period { display: flex; align-items: center; gap: 8px; }
.period .range { color: var(--text-2); font-size: 13px; margin-left: 6px; }

/* notices, Resend's info strip */
.notice { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border: 1px solid var(--card-edge); background: var(--card-face); box-shadow: var(--card-shadow); border-radius: var(--r-sm); color: var(--text-2); font-size: 13px; margin-bottom: 10px; }
.notice svg { flex: none; color: var(--cyan); }
.notice a { color: var(--text); text-decoration: underline; text-decoration-style: dashed; text-underline-offset: 3px; cursor: pointer; }
.notice.ok { color: var(--green); }
.notice.ok svg { color: var(--green); }
.notice.err { color: var(--red); }
.notice.err svg { color: var(--red); }

/* cards */
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 12px; margin-top: 8px; }
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 12px; margin-top: 12px; }
.grid.two-up { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }
.card, .panel {
  position: relative; background: var(--card-face); border: 1px solid var(--card-edge); border-radius: var(--r);
  padding: 18px 20px; min-width: 0; box-shadow: var(--card-shadow);
}
.eyebrow { font-size: 11px; font-weight: 500; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-2); padding-right: 24px; }
/* Where a number comes from, at the eyebrow's weight so it never competes with the figure. */
.card-badge {
  position: absolute; top: 18px; right: 20px; display: inline-flex; align-items: center; gap: 5px;
  font-size: 10.5px; font-weight: 500; letter-spacing: 0.07em; line-height: 1.5; color: var(--text-3);
}
.card-badge svg { width: 13px; height: 13px; fill: currentColor; opacity: 0.8; }
.big { display: block; margin-top: 8px; font-size: 30px; font-weight: 600; letter-spacing: -0.02em; line-height: 1.1; }
.cards .big { background: linear-gradient(180deg, #ffffff 0%, #c9c9c9 100%); -webkit-background-clip: text; background-clip: text; color: transparent; }
.big.dim, .cards .big.dim { background: none; -webkit-background-clip: initial; background-clip: initial; color: var(--text-3); }
.foot { margin-top: 6px; font-size: 12.5px; color: var(--text-2); }

/* sparklines in the summary cards. One weight, one meaning: every day drawn is a day
   whose number is finished. Unsettled days never reach the page. */
.spark-wrap { position: relative; margin-top: 14px; height: 44px; }
.spark { display: block; width: 100%; height: 44px; overflow: visible; }
.spark-line {
  fill: none; stroke: var(--cyan); stroke-width: 1.5px;
  stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke;
}
/* Always filled: the line only ever ends on a finished day. Same footprint
   either way, so the mark never appears to change size as a month settles. */
.spark-end { position: absolute; right: -6px; margin-top: -6px; overflow: visible; filter: drop-shadow(0 0 4px rgba(82, 185, 240, 0.45)); }
.spark-empty { margin-top: 14px; height: 44px; border-top: 1px dashed rgba(255, 255, 255, 0.08); display: flex; align-items: flex-end; font-size: 11.5px; color: var(--text-3); }
.spark-axis {
  display: flex; justify-content: space-between; gap: 8px; margin-top: 7px; min-height: 13px;
  font-size: 10.5px; line-height: 1.2; letter-spacing: 0.02em; color: var(--text-3); opacity: 0.75;
}
.spark-note { margin-top: 6px; min-height: 16px; font-size: 11.5px; line-height: 1.35; color: var(--text-3); }
.spark-note b { font-weight: 500; color: var(--text-2); }

/* panels */
.panel { margin-top: 12px; }
.panel-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.panel h2 { font-size: 17px; letter-spacing: -0.01em; }
.legend { display: flex; gap: 14px; font-size: 12px; color: var(--text-2); }
.legend i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 6px; vertical-align: -1px; background: var(--bar); }
.legend .paid i { background: var(--bar-paid); }

/* the funnel bars */
.funnel { display: grid; gap: 14px; margin-top: 18px; }
.frow { display: grid; grid-template-columns: minmax(150px, 230px) 1fr 64px 150px; gap: 14px; align-items: center; }
.frow .name { font-size: 13.5px; font-weight: 500; }
.frow .name small { display: block; font-weight: 400; color: var(--text-3); font-size: 12px; }
.track {
  position: relative; height: 26px; border-radius: 4px; overflow: hidden;
  background-color: rgba(255, 255, 255, 0.035);
  background-image: repeating-linear-gradient(90deg, transparent 0, transparent calc(25% - 1px), rgba(255, 255, 255, 0.06) calc(25% - 1px), rgba(255, 255, 255, 0.06) 25%);
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.45);
}
.fill {
  position: absolute; top: 0; bottom: 0; left: 0; width: 0; background: var(--bar);
  border-radius: 0 4px 4px 0; box-shadow: 0 0 16px rgba(82, 185, 240, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.25);
  transition: width 0.5s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.fill.paid { background: var(--bar-paid); box-shadow: 2px 0 0 #141414, inset 0 1px 0 rgba(255, 255, 255, 0.12); }
.frow .val { text-align: right; font-size: 15px; font-weight: 600; }
.frow.empty .val { color: var(--text-3); }
.frow .rate { font-size: 12.5px; color: var(--text-2); }
.funnel-note { margin-top: 16px; font-size: 12.5px; color: var(--text-3); }

/* dotted rows, Resend */
.rows { list-style: none; margin: 14px 0 0; padding: 0; }
.rows li { display: grid; grid-template-columns: 1fr auto auto; gap: 14px; align-items: center; padding: 9px 0; border-top: 1px solid rgba(255, 255, 255, 0.06); font-size: 13.5px; }
.rows li:first-child { border-top: 0; padding-top: 2px; }
.lab { display: flex; align-items: center; gap: 8px; min-width: 0; }
.lab span { min-width: 0; }
.lab.trunc span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lab .is-paid { color: var(--cyan); font-weight: 500; }
.rows .n.is-paid, .rows .p.is-paid { color: var(--cyan); }
.dot { width: 6px; height: 6px; border-radius: 50%; background: var(--text-3); flex: none; }
.dot.all { background: var(--cyan); box-shadow: 0 0 6px rgba(82, 185, 240, 0.6); }
.dot.paid { background: var(--cyan-deep); box-shadow: 0 0 6px rgba(34, 120, 168, 0.6); }
.rows .n { color: var(--text-2); text-align: right; }
.rows .p { text-align: right; min-width: 5ch; font-weight: 500; }
.rows .p.none { color: var(--text-3); font-weight: 400; }
.pill { display: inline-block; padding: 1px 7px; border-radius: var(--r-pill); font-size: 11px; font-weight: 500; background: rgba(82, 185, 240, 0.14); color: var(--cyan); font-style: normal; border: 1px solid rgba(82, 185, 240, 0.18); }
.note { margin-top: 12px; font-size: 12.5px; color: var(--text-3); }
.meta { margin-top: 20px; font-size: 12.5px; color: var(--text-3); display: flex; flex-wrap: wrap; gap: 6px 18px; }
.meta a { color: var(--text-2); }

/* entry page */
.form { display: grid; gap: 18px; }
.two { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.field { display: grid; gap: 6px; }
.field label { font-size: 13px; font-weight: 500; }
.field .input { border-radius: var(--r-sm); font-size: 16px; padding: 10px 12px; width: 100%; }
.hint { font-size: 12px; color: var(--text-3); }
.steps { margin: 10px 0 0; padding-left: 18px; color: var(--text-2); font-size: 13.5px; }
.steps li { margin: 6px 0; }
code { color: var(--text); background: rgba(255, 255, 255, 0.07); padding: 1px 6px; border-radius: 5px; font-family: var(--mono); font-size: 12.5px; }
table { width: 100%; border-collapse: collapse; margin-top: 12px; font-size: 13.5px; }
th, td { text-align: left; padding: 9px 8px; border-top: 1px solid rgba(255, 255, 255, 0.06); white-space: nowrap; }
th { border-top: 0; font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-2); font-weight: 500; }
.num { text-align: right; }
.scroll { overflow-x: auto; }

@media (max-width: 720px) {
  .wrap { padding: 0 16px 48px; }
  /* The lockup takes its own row and the controls sit under it, rather than the
     brand and a half-wrapped button sharing a line. */
  .bar { height: auto; padding: 12px 0; flex-wrap: wrap; gap: 12px; }
  .bar .brand, .bar .actions { flex: 1 0 100%; }
  .brand .fresh { margin-left: auto; }
  .frow { grid-template-columns: 1fr auto; row-gap: 6px; }
  .frow .track { grid-column: 1 / -1; }
  .frow .rate { grid-column: 1 / -1; }
  .two { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
  .fill, .btn { transition: none; }
}

/* ads page: one measure per row, the ad group as a bar and everyone else as a tick on
   the same scale. Each row scales to its own pair, so what you read is the gap, not the
   length — the four measures are in different units and share no axis. */
.key { display: flex; align-items: center; gap: 7px; font-size: 12px; color: var(--text-2); }
.key i { display: inline-block; flex: none; }
.key .k-fill { width: 14px; height: 8px; border-radius: 2px; background: var(--bar); }
.key .k-mark { width: 2px; height: 12px; border-radius: 1px; background: var(--text-2); margin-left: 8px; }
.ctable { display: grid; gap: 14px; margin-top: 18px; }
.crow { display: grid; grid-template-columns: minmax(160px, 250px) 1fr 76px 168px; gap: 14px; align-items: center; }
.crow .cname { font-size: 13.5px; font-weight: 500; }
.crow .cname small { display: block; font-weight: 400; color: var(--text-3); font-size: 12px; line-height: 1.35; }
.ctrack {
  position: relative; height: 24px; border-radius: 4px;
  background-color: rgba(255, 255, 255, 0.035);
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.45);
}
.cfill {
  position: absolute; top: 0; bottom: 0; left: 0; background: var(--bar);
  border-radius: 0 4px 4px 0; box-shadow: 0 0 16px rgba(82, 185, 240, 0.28), inset 0 1px 0 rgba(255, 255, 255, 0.25);
  transition: width 0.5s cubic-bezier(0.2, 0.7, 0.2, 1);
}
/* Everyone else, as a reference tick. Two surface-coloured edges keep it legible where
   it crosses the fill, the same trick the sparkline end-dot uses. */
.cmark {
  position: absolute; top: -3px; bottom: -3px; width: 2px; margin-left: -1px;
  background: var(--text); box-shadow: 0 0 0 2px #141414;
}
.crow .cval { text-align: right; font-size: 15px; font-weight: 600; }
.crow .crest { font-size: 12.5px; color: var(--text-2); }
.gap { display: inline-block; margin-left: 6px; font-weight: 500; }
.gap.worse { color: var(--red); }
.gap.better { color: var(--green); }
.gap.level { color: var(--text-3); }
@media (max-width: 860px) {
  .crow { grid-template-columns: 1fr 70px; grid-template-areas: "name val" "track track" "rest rest"; row-gap: 8px; }
  .crow .cname { grid-area: name; }
  .crow .ctrack { grid-area: track; }
  .crow .cval { grid-area: val; }
  .crow .crest { grid-area: rest; }
}

/* ads page: the reach strip. Figures on one line rather than three cards, so the top of
   the page does not read as the top of a funnel. */
.strip { display: flex; flex-wrap: wrap; gap: 14px 40px; margin-top: 16px; }
.strip .fig { min-width: 0; }
.strip .big { margin-top: 0; font-size: 26px; }
.strip small { display: block; margin-top: 4px; font-size: 12.5px; color: var(--text-2); }
.panel .notice { margin-top: 16px; margin-bottom: 0; align-items: flex-start; line-height: 1.5; }
.panel .notice svg { margin-top: 3px; }
.panel .notice b { font-weight: 500; color: var(--text); }

/* a breakdown of the row above it, indented and quieter so it reads as a child rather
   than as another item in the list */
.rows li.sub { padding-left: 22px; border-top-color: rgba(255, 255, 255, 0.03); font-size: 13px; color: var(--text-2); }
.rows li.sub .dot { width: 4px; height: 4px; background: var(--line-2); }
.rows li.sub .p { font-weight: 400; color: var(--text-2); }
.rows .is-good { color: var(--cyan); }
.rows .lab span.is-good { font-weight: 500; }
