/* Typography and colour follow the ClearTrust data room, so a person moving
   between the two tools is looking at one product rather than two. Geist for
   text, Newsreader for display, and the mono kept for the one job it is better
   at: literals somebody may have to copy exactly — an operation name, a survey
   code, a token. */
@import url("https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600&family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;1,6..72,400&family=IBM+Plex+Mono:wght@400;500&display=swap");

:root {
  /* Warm paper, near-black navy ink. Taken from the data room's own values
     rather than approximated, so the two sit side by side without a shift. */
  --ground: #f6f5f1; --panel: #fcfcfb; --panel-2: #f1efe9;
  --ink: #0c1422; --ink-soft: #5a6172; --ink-faint: #7d828c;
  --rule: #e6e3da; --rule-strong: #d9d5c9;

  /* The one saturated colour, used for the action a page is actually for. */
  --brand: #1a4e8f; --brand-hover: #163f74; --on-brand: #ffffff; --brand-wash: #1a4e8f0f;

  /* The three things feedback means. Light enough on paper to read as text,
     and mapped onto the data room's own good/warn/bad rather than a second
     palette invented here. */
  --read: #17794a; --read-bg: #17794a14;
  --write: #c2483c; --write-bg: #c2483c14;
  --warn: #a06a16; --warn-bg: #a06a1614;

  --radius: 16px; --radius-sm: 10px; --radius-pill: 999px;
  --shadow: 0 1px 2px #0c14220a, 0 8px 24px -12px #0c142214;
  --shadow-lift: 0 2px 4px #0c14220f, 0 24px 48px -20px #0c14222e;

  --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --sans: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --display: "Newsreader", ui-serif, Georgia, serif;
}

/* The data room's dark surfaces, unchanged. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ground: #0b0d10; --panel: #15171b; --panel-2: #1c1f24;
    --ink: #f3f3f0; --ink-soft: #c3c2b7; --ink-faint: #8d9098;
    --rule: #2a2d33; --rule-strong: #3b3e44;
    --brand: #6ea8f5; --brand-hover: #8fbcf8; --on-brand: #0b1220; --brand-wash: #17263a;
    --read: #2fbf4a; --read-bg: #2fbf4a1f;
    --write: #f07b72; --write-bg: #f07b721f;
    --warn: #f2c46b; --warn-bg: #f2c46b1f;
    --shadow: 0 1px 2px #0000004d, 0 8px 24px -12px #00000080;
    --shadow-lift: 0 2px 6px #00000066, 0 28px 56px -24px #000000a6;
  }
}
:root[data-theme="dark"] {
  --ground: #0b0d10; --panel: #15171b; --panel-2: #1c1f24;
  --ink: #f3f3f0; --ink-soft: #c3c2b7; --ink-faint: #8d9098;
  --rule: #2a2d33; --rule-strong: #3b3e44;
  --brand: #6ea8f5; --brand-hover: #8fbcf8; --on-brand: #0b1220; --brand-wash: #17263a;
  --read: #2fbf4a; --read-bg: #2fbf4a1f;
  --write: #f07b72; --write-bg: #f07b721f;
  --warn: #f2c46b; --warn-bg: #f2c46b1f;
  --shadow: 0 1px 2px #0000004d, 0 8px 24px -12px #00000080;
  --shadow-lift: 0 2px 6px #00000066, 0 28px 56px -24px #000000a6;
}

* { box-sizing: border-box; }
/* An author `display` rule beats the user-agent's [hidden] rule, so anything
   given a display here would ignore its own hidden attribute. Say it once. */
[hidden] { display: none !important; }
body {
  margin: 0; background: var(--ground); color: var(--ink);
  font-family: var(--sans); font-size: 16px; line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
/* Display type is the serif; anything that is an interface label is not.
   A heading names a thing you are reading, which is where the serif belongs. */
h1, h2, h3, h4 { margin: 0; text-wrap: balance; font-weight: 500; letter-spacing: -0.015em; }
h1, h2 { font-family: var(--display); font-weight: 400; letter-spacing: -0.02em; }
h1 { font-size: clamp(2rem, 4.4vw, 3.1rem); line-height: 1.08; }
h2 { font-size: clamp(1.3rem, 2.4vw, 1.7rem); line-height: 1.2; }
h3, h4 { font-size: 1rem; }
p { margin: 0; }
a { color: inherit; text-underline-offset: 3px; }
code, pre { font-family: var(--mono); font-feature-settings: "zero" 1; }
:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; border-radius: 4px; }
::selection { background: var(--brand-wash); }

.wrap { max-width: 74rem; margin: 0 auto; padding: 0 clamp(1.1rem, 4vw, 3rem); }
.wrap.narrow { max-width: 44rem; }
.band { border-bottom: 1px solid var(--rule-strong); }
.band.alt { background: var(--panel); }
.band > .wrap { padding-top: clamp(3rem, 7vw, 5.5rem); padding-bottom: clamp(3rem, 7vw, 5.5rem); }

/* The small letterspaced label above a heading. Sans, not mono: it is a label
   on prose rather than a literal anybody would retype. */
.eyebrow { font-size: 0.75rem; font-weight: 500; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-faint); }
.h-sec { font-family: var(--display); font-weight: 400; font-size: clamp(1.7rem, 4vw, 2.6rem); letter-spacing: -0.02em; line-height: 1.1; }
.sub { color: var(--ink-soft); font-size: clamp(1rem, 1.6vw, 1.08rem); max-width: 60ch; }
.sec-head { display: flex; flex-direction: column; gap: 0.7rem; margin-bottom: 2.2rem; }
.muted { color: var(--ink-soft); }
.hint { color: var(--ink-faint); font-size: 0.85rem; }

/* ---- site navigation ---- */
.sitenav {
  border-bottom: 1px solid var(--rule); position: sticky; top: 0; z-index: 30;
  background: color-mix(in srgb, var(--ground) 82%, transparent);
  backdrop-filter: saturate(180%) blur(12px); -webkit-backdrop-filter: saturate(180%) blur(12px);
}
/* The bar takes the width of the page under it, so the product name sits above
   the heading it belongs to rather than a centimetre to the right of it. The
   three widths are the three containers a page can be in. */
.sitenav .bar {
  display: flex; align-items: center; gap: 1.1rem; min-height: 3.5rem;
  margin: 0 auto; padding: 0 clamp(1.1rem, 4vw, 2rem);
}
/* On a page whose content is a centred column, the bar runs the full width and
   its left padding is grown to land on that column's left edge. Constraining
   the whole bar to the column instead put eight sections into 60rem, where the
   last one either wrapped onto a second row or was clipped — and a bar that
   stops short of the window looks like a panel, not a masthead. */
.sitenav .bar.app {
  max-width: none;
  padding-left: max(clamp(1.1rem, 4vw, 2rem), calc((100% - 60rem) / 2 + clamp(1.1rem, 4vw, 2rem)));
}
.sitenav .bar.full { max-width: none; }
.sitenav .bar.site {
  max-width: none; padding-right: clamp(1.1rem, 4vw, 3rem);
  padding-left: max(clamp(1.1rem, 4vw, 3rem), calc((100% - 74rem) / 2 + clamp(1.1rem, 4vw, 3rem)));
}

.sitenav .brand {
  font-weight: 600; font-size: 0.95rem; letter-spacing: -0.015em; color: var(--ink);
  text-decoration: none; display: inline-flex; align-items: center; gap: 0.5rem; flex: none;
}
/* The mark sits with the name rather than replacing it: at this size a logo
   alone is a puzzle, and the name alone is every other tool on the fleet.
   Nudged up a pixel — a square mark reads a shade low beside a lowercase
   wordmark whose first letter has no ascender. */
.sitenav .brand img { display: block; border-radius: 5px; margin-top: -1px; }
@media (max-width: 34rem) { .sitenav .brand span { display: none; } }

/* The sections, as one group, so they stay together when the bar is tight. */
/* One line, always. A nav that wraps onto a second row reads as a mistake, so
   below the width where the sections fit they scroll sideways instead — which
   is what a tool with more sections than room does. */
.sitenav .links {
  display: flex; align-items: center; gap: 0.1rem; min-width: 0;
  overflow-x: auto; scrollbar-width: none; -ms-overflow-style: none;
}
.sitenav .links::-webkit-scrollbar { display: none; }
.sitenav .nl {
  font-size: 0.875rem; font-weight: 500; color: var(--ink-soft); text-decoration: none;
  padding: 0.4rem 0.55rem; border-radius: var(--radius-pill); white-space: nowrap;
  transition: color 0.12s ease, background-color 0.12s ease;
}
.sitenav .nl:hover { color: var(--ink); background: var(--panel-2); }
/* The page you are on is filled, like the tabs and the buttons: the rest of the
   product marks a current thing by filling it, so this does too. */
.sitenav .nl[aria-current] { color: var(--ink); background: var(--panel-2); font-weight: 600; }

/* Sign out and the theme switch are not sections and do not sit among them. */
.sitenav .trailing { margin-left: auto; display: flex; align-items: center; gap: 0.9rem; flex: none; }
.sitenav .trailing button.link { font-size: 0.875rem; }

/* ---- buttons and forms ---- */
/* Pills, as in the data room: the shape carries the affordance, so the label
   does not have to be shouted in monospace to look pressable. */
button, .btn {
  font-family: var(--sans); font-size: 0.9rem; font-weight: 500; letter-spacing: 0; cursor: pointer;
  border: 1px solid var(--rule-strong); background: var(--panel); color: var(--ink);
  padding: 0.55rem 1.1rem; border-radius: var(--radius-pill); text-decoration: none;
  transition: background-color 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
button:hover, .btn:hover { border-color: var(--ink-faint); background: var(--panel-2); }
/* One filled colour per view, on the thing the view is for. */
button.primary, .btn.primary { background: var(--brand); color: var(--on-brand); border-color: var(--brand); }
button.primary:hover { background: var(--brand-hover); border-color: var(--brand-hover); }
button.quiet { background: transparent; }
button.quiet:hover { background: var(--panel-2); }
button.link {
  border: 0; background: none; color: var(--ink-soft); padding: 0.2rem 0.3rem;
  border-radius: var(--radius-sm); font-size: 0.85rem; text-decoration: none;
}
button.link:hover { color: var(--brand); background: transparent; text-decoration: underline; }
button.danger { color: var(--write); border-color: color-mix(in srgb, var(--write) 40%, transparent); background: transparent; }
button.danger:hover { background: var(--write-bg); border-color: var(--write); }
button[disabled] { opacity: 0.45; cursor: not-allowed; }

/* An icon sits inside the button rather than beside it, so the label and the
   mark move as one thing and a row of them lines up on the text baseline
   whatever the labels are. */
button svg, .btn svg { width: 0.95em; height: 0.95em; vertical-align: -0.12em; margin-right: 0.45em; flex: none; }
button, .btn { display: inline-flex; align-items: center; white-space: nowrap; }

/* The row of things you can do to a survey.
   Eight buttons in one flat row wrapped wherever they happened to run out of
   width, which put "Close" — the only irreversible one — next to whatever
   landed beside it. They are grouped by what they do instead: reading, asking,
   sharing, and ending. The groups wrap; the buttons inside one never do. */
.toolbar { display: flex; flex-wrap: wrap; gap: 0.5rem 1.1rem; align-items: center; margin-top: 1.1rem; }
.toolbar .group { display: flex; gap: 0.4rem; align-items: center; }
/* A hairline between groups, so the grouping is visible without a label. */
.toolbar .group + .group { padding-left: 1.1rem; border-left: 1px solid var(--rule); }
/* Ending a survey is not one of the everyday actions and does not sit among
   them: it goes to the far end, past the space. */
.toolbar .end { margin-left: auto; }
@media (max-width: 52rem) {
  .toolbar .group + .group { padding-left: 0; border-left: 0; }
  .toolbar .end { margin-left: 0; }
}

label { display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.9rem; }
label.check { flex-direction: row; align-items: center; gap: 0.4rem; }
/* The field label and the small caption above a figure are the same thing in
   two places, and neither is a literal — so both are sans, like the eyebrow. */
.cap { font-size: 0.7rem; font-weight: 500; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-faint); }
input, select, textarea {
  font-family: var(--sans); font-size: 0.94rem; color: var(--ink);
  background: var(--panel); border: 1px solid var(--rule-strong); border-radius: var(--radius-sm);
  padding: 0.55rem 0.7rem; width: 100%;
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-wash);
}
input[type="checkbox"] { width: auto; }
textarea { min-height: 6rem; resize: vertical; }

.msg { border: 1px solid var(--rule-strong); border-radius: var(--radius-sm); padding: 0.8rem 1rem; font-size: 0.9rem; margin: 0.8rem 0; }
.msg.err { border-color: var(--write); background: var(--write-bg); color: var(--write); }
.msg.ok { border-color: var(--read); background: var(--read-bg); color: var(--read); }
.msg.warn { border-color: var(--warn); background: var(--warn-bg); color: var(--warn); }

/* ---- cards ---- */
/* Cards sit apart on the page rather than sharing hairlines in a slab: the
   data room separates them, and a separated card can carry its own rounding. */
.grid { display: grid; gap: 1rem; background: none; border: 0; }
.g2 { grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr)); }
.g3 { grid-template-columns: 1fr; }
@media (min-width: 40rem) {
  .g3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* A grid that ends on a dead cell reads as a mistake. When the last card
     would sit alone on its row, let it take the width instead. */
  .g3 > .card:last-child:nth-child(odd) { grid-column: span 2; }
}
@media (min-width: 62rem) {
  .g3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .g3 > .card:last-child:nth-child(3n + 1) { grid-column: span 3; }
  .g3 > .card:last-child:nth-child(3n + 2) { grid-column: span 2; }
}
.card {
  background: var(--panel); padding: 1.5rem 1.6rem; display: flex; flex-direction: column; gap: 0.55rem;
  border: 1px solid var(--rule); border-radius: var(--radius); box-shadow: var(--shadow);
}
.band.alt .card { background: var(--panel); }
.card h3 { font-family: var(--sans); font-weight: 600; font-size: 1rem; letter-spacing: -0.01em; }
.card p { color: var(--ink-soft); font-size: 0.9rem; }
.card ul { margin: 0.1rem 0 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 0.3rem; }
.card li { position: relative; padding-left: 0.95rem; font-size: 0.87rem; color: var(--ink-soft); }
.card li::before {
  content: ""; position: absolute; left: 0.1rem; top: 0.62em;
  width: 0.34rem; height: 0.34rem; border-radius: 50%; background: var(--brand); opacity: 0.55;
}
.card li strong, .card p strong { color: var(--ink); font-weight: 600; }
code.inline, .card code, li code, p code, td code {
  font-size: 0.84em; background: var(--panel-2); border: 1px solid var(--rule);
  padding: 0.06em 0.34em; border-radius: 5px;
}
.band.alt .card code { background: var(--panel); }

/* ---- code blocks ---- */
pre.block {
  background: var(--panel-2); border: 1px solid var(--rule-strong); padding: 0.8rem 0.9rem;
  font-size: 0.78rem; line-height: 1.55; overflow-x: auto; margin: 0;
}
pre.block .k { color: var(--read); }
pre.block .s { color: var(--write); }
pre.block .c { color: var(--ink-faint); }

/* ---- an endpoint you can copy ---- */
.ep { display: flex; align-items: stretch; border: 1px solid var(--rule-strong); background: var(--panel); }
.ep code { flex: 1; min-width: 0; overflow-x: auto; white-space: nowrap; padding: 0.5rem 0.6rem; font-size: 0.8rem; }
.ep button { border: 0; border-left: 1px solid var(--rule-strong); background: var(--ink); color: var(--ground); padding: 0 0.8rem; }

/* ---- signed-in pages ---- */
.authwrap { max-width: 60rem; margin: 0 auto; padding: clamp(1.4rem, 4vw, 2.6rem) clamp(1.1rem, 4vw, 2rem) 4rem; }
.authwrap.full { max-width: none; }
.authwrap h1 { font-family: var(--display); font-weight: 400; font-size: clamp(1.7rem, 3.4vw, 2.3rem); letter-spacing: -0.02em; }
/* Every panel on a signed-in page is one of the data room's cards. */
.panel {
  border: 1px solid var(--rule); border-radius: var(--radius); background: var(--panel);
  padding: 1.5rem 1.6rem; margin: 1.2rem 0; box-shadow: var(--shadow);
}
/* A panel heading is an interface label, so it stays in the sans — the serif
   is for the things a page is about, not for the boxes they sit in. */
.panel h2 { font-family: var(--sans); font-size: 1.02rem; font-weight: 600; letter-spacing: -0.01em; margin-bottom: 0.5rem; }
.row { display: flex; gap: 0.8rem; flex-wrap: wrap; align-items: flex-end; }
.row > * { flex: 1 1 12rem; }
.row > .tight { flex: 0 0 auto; }

/* ---- sign-in card ---- */
.centre { min-height: 100vh; display: grid; place-items: center; padding: 2rem 1.1rem; }
.signin {
  width: 100%; max-width: 25rem; border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--panel); padding: 2rem 1.9rem; box-shadow: var(--shadow-lift);
}
.signin h1 { font-family: var(--display); font-weight: 400; font-size: 1.6rem; letter-spacing: -0.02em; margin-bottom: 0.3rem; }
.signin form { display: flex; flex-direction: column; gap: 0.85rem; margin-top: 1.2rem; }
.signin .foot { margin-top: 1rem; display: flex; justify-content: space-between; font-size: 0.8rem; color: var(--ink-faint); }

/* ---- tables ---- */
/* A wide table scrolls inside its own box rather than pushing the page sideways
   or, worse, quietly clipping the controls at the right-hand end. */
.scroll-x { overflow-x: auto; }
.scroll-x > table { min-width: max-content; }
table { border-collapse: collapse; width: 100%; font-size: 0.88rem; }
td select, td input { min-width: 7.5rem; }
td .actions { display: flex; gap: 0.3rem; white-space: nowrap; }
th, td { text-align: left; padding: 0.45rem 0.6rem; border-bottom: 1px solid var(--rule); vertical-align: top; }
th { font-size: 0.7rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-faint); font-weight: 500; white-space: nowrap; }
tbody tr:hover { background: var(--panel-2); }
/* A chip, not a boxed literal: these are states, not things to retype. */
.tag {
  display: inline-block; font-size: 0.72rem; font-weight: 500; letter-spacing: 0.01em;
  border: 1px solid var(--rule-strong); border-radius: var(--radius-pill);
  padding: 0.1rem 0.55rem; color: var(--ink-soft); margin-right: 0.25rem;
}
.tag.on { border-color: var(--read); color: var(--read); background: var(--read-bg); }
.tag.off { border-color: var(--write); color: var(--write); background: var(--write-bg); }
.tag.mid { border-color: var(--warn); color: var(--warn); background: var(--warn-bg); }

/* ---- theme switch ---- */
.themeswitch { display: inline-flex; border: 1px solid var(--rule-strong); border-radius: var(--radius-pill); overflow: hidden; }
.themeswitch button { border: 0; border-left: 1px solid var(--rule-strong); background: transparent; padding: 0.2rem 0.45rem; font-size: 0.66rem; color: var(--ink-faint); }
.themeswitch button:first-child { border-left: 0; }
.themeswitch button[aria-pressed="true"] { background: var(--ink); color: var(--ground); }

/* ---- feedback-specific: segments, scores, the response page ---------------
   A segment is the one thing a reader looks for on every row, so it is a chip
   with its own colour rather than a word among words. The three states are
   deliberately not red/amber/green: colour alone must not carry the meaning,
   so the word is always there too. */
.seg {
  display: inline-block; font-size: 0.72rem; font-weight: 500; letter-spacing: 0.01em;
  border: 1px solid var(--rule-strong); border-radius: var(--radius-pill);
  padding: 0.1rem 0.6rem; white-space: nowrap;
}
.seg.promoter, .seg.satisfied, .seg.effortless { border-color: var(--read); color: var(--read); background: var(--read-bg); }
.seg.detractor, .seg.dissatisfied, .seg.strained { border-color: var(--write); color: var(--write); background: var(--write-bg); }
.seg.passive, .seg.neutral { border-color: var(--warn); color: var(--warn); background: var(--warn-bg); }

/* A headline number, big enough to be the answer to the question. Set in the
   display serif at this size: it is the figure somebody came to read, not a
   value to be copied, and the serif is what the data room puts its numbers in. */
.score { font-family: var(--display); font-variant-numeric: tabular-nums; font-weight: 400; }
.score.big { font-size: clamp(2.4rem, 6vw, 3.6rem); letter-spacing: -0.03em; line-height: 1; }
.score.up::after { content: " ▲"; color: var(--read); font-size: 0.5em; vertical-align: middle; }
.score.down::after { content: " ▼"; color: var(--write); font-size: 0.5em; vertical-align: middle; }
.metric { display: flex; flex-direction: column; gap: 0.3rem; }
.metric .cap { order: -1; }
.metric .sub { font-size: 0.78rem; color: var(--ink-faint); }

/* The distribution bar under a score: promoters, passives, detractors to
   scale. Reading "NPS 32" without it tells you nothing about the shape. */
.dist { display: flex; height: 0.5rem; border-radius: var(--radius-pill); overflow: hidden; background: var(--panel-2); }
.dist span { display: block; }
.dist .good { background: var(--read); }
.dist .mid { background: var(--warn); }
.dist .bad { background: var(--write); }

/* ---- the public response page ----
   The one page a customer ever sees. It has to work in one tap, on a phone,
   from an email client's in-app browser, with the score already chosen. */
.answer { min-height: 100vh; display: grid; place-items: center; padding: 2rem 1rem; }
.answer .card-lg {
  width: 100%; max-width: 34rem; border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--panel); padding: clamp(1.5rem, 4vw, 2.4rem); box-shadow: var(--shadow-lift);
}
.answer h1 { font-family: var(--display); font-weight: 400; font-size: clamp(1.3rem, 3.6vw, 1.75rem); letter-spacing: -0.02em; line-height: 1.25; }
.scale { display: flex; flex-wrap: wrap; gap: 0.35rem; margin: 1.4rem 0 0.5rem; }
/* Eleven of these have to sit on one line on a phone, so they take the pill
   shape's rounding but not its padding — a 0-10 scale that wraps its last
   number onto a row of its own, full width, reads as a different control. */
.scale button {
  flex: 1 1 0; min-width: 2.1rem; max-width: 4.5rem;
  padding: 0.7rem 0.15rem; font-size: 1rem; font-weight: 500;
  font-variant-numeric: tabular-nums; background: var(--panel);
  border-radius: var(--radius-sm); justify-content: center;
}
.scale button:hover { border-color: var(--brand); background: var(--brand-wash); }
.scale button[aria-pressed="true"] { background: var(--brand); color: var(--on-brand); border-color: var(--brand); }
.scale-ends { display: flex; justify-content: space-between; font-size: 0.72rem; color: var(--ink-faint); }
.answer .done { text-align: center; padding: 1.5rem 0; }
.answer .done .big { font-family: var(--display); font-size: 1.5rem; font-weight: 400; margin-bottom: 0.4rem; }

/* ---- the records browser ---- */
/* The filter bar over the records browser.
   Every control is one cell of a fixed width, so the bar fills left to right
   and stops where it stops. Before this the seven dropdowns were nested inside
   a flex child of their own, which wrapped as a block and left a hole the width
   of the search box beside them; display:contents dissolves that wrapper so its
   dropdowns are cells of the bar like everything else. */
.filterbar {
  display: flex; flex-wrap: wrap; align-items: end; gap: 0.7rem 0.65rem;
  padding: 1rem 1.15rem; margin: 0 0 1rem;
  border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--panel); box-shadow: var(--shadow);
}
/* 7rem holds the longest value any of these dropdowns carries. At 7.6rem the
   whole bar came to one pixel wider than the space it had on a large screen,
   and wrapped — a margin that thin is not a layout, it is a coincidence. */
.filterbar > label, .filterbar .facets > label { flex: 0 0 7rem; gap: 0.3rem; }
/* Search earns the leftover width; it is the one people type into. */
.filterbar > label.grow { flex: 1 1 12rem; min-width: 10rem; }
.filterbar > label.narrow { flex: 0 0 5.2rem; }
.filterbar > label.date { flex: 0 0 8.6rem; }
.filterbar .facets { display: contents; }
/* The two buttons keep together at the end of the bar. */
.filterbar .actions { flex: 0 0 auto; margin-left: auto; display: flex; gap: 0.5rem; align-items: end; }
.filterbar input, .filterbar select { height: 2.4rem; }
.filterbar input[type="date"] { min-width: 0; }
@media (max-width: 60rem) { .filterbar .actions { margin-left: 0; } }

/* The tag bar under it is a plain wrapping row. */
.facets { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.facets label { flex: 1 1 8rem; }
.toolbar { display: flex; gap: 0.7rem; flex-wrap: wrap; align-items: flex-end; margin: 1rem 0 0.7rem; }
/* Pills in a row, as in the data room: the one you are on is filled, the rest
   are quiet. A folder-tab with a notched border says "there is more behind
   this"; these are siblings, and only one can be current. */
.tabs { display: flex; gap: 0.4rem; flex-wrap: wrap; margin: 0.8rem 0 1.2rem; }
.tabs button {
  border: 1px solid transparent; background: transparent; color: var(--ink-soft);
  padding: 0.45rem 0.95rem; border-radius: var(--radius-pill); font-size: 0.88rem;
}
.tabs button:hover { background: var(--panel-2); border-color: transparent; color: var(--ink); }
.tabs button[aria-selected="true"] {
  background: var(--ink); border-color: var(--ink); color: var(--ground); font-weight: 500;
}
.tabs button[aria-selected="true"]:hover { background: var(--ink); color: var(--ground); }
.cols { margin: 0.4rem 0; font-size: 0.85rem; }
.cols summary { cursor: pointer; color: var(--ink-soft); font-size: 0.85rem; font-weight: 500; }
.colpick { display: flex; flex-wrap: wrap; gap: 0.5rem 1rem; padding: 0.7rem 0 0.2rem; }
.colpick label { flex-direction: row; align-items: center; gap: 0.35rem; font-size: 0.82rem; }
.grid-wrap { overflow-x: auto; border: 1px solid var(--rule); border-radius: var(--radius); background: var(--panel); box-shadow: var(--shadow); }
.datagrid { min-width: max-content; }
.datagrid th { position: sticky; top: 0; background: var(--panel-2); z-index: 2; cursor: pointer; }
.datagrid th[aria-sort="ascending"]::after { content: " ↑"; }
.datagrid th[aria-sort="descending"]::after { content: " ↓"; }
.datagrid td { max-width: 26rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.datagrid tbody tr { cursor: pointer; }
.showing { font-size: 0.8rem; color: var(--ink-faint); margin: 0.5rem 0; }
.pager { display: flex; gap: 0.5rem; align-items: center; margin-top: 0.8rem; }

/* The row detail, as a drawer rather than another page: the list you were
   reading is still there behind it. */
.drawer {
  position: fixed; inset: 0 0 0 auto; width: min(34rem, 100%); background: var(--panel);
  border-left: 1px solid var(--rule-strong); overflow-y: auto; z-index: 50;
  padding: 1.2rem 1.3rem 3rem; box-shadow: -18px 0 44px #0000001f;
}
.drawer h2 { font-size: 1.05rem; margin-bottom: 0.2rem; }
.drawer dl { display: grid; grid-template-columns: minmax(7rem, auto) 1fr; gap: 0.35rem 0.9rem; margin: 1rem 0 0; font-size: 0.86rem; }
.drawer dt { font-size: 0.7rem; font-weight: 500; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-faint); padding-top: 0.25em; }
.drawer dd { margin: 0; overflow-wrap: anywhere; }
.scrim { position: fixed; inset: 0; background: #0006; z-index: 40; }

/* A modal rather than the drawer, for the things that are a table. The drawer
   is 34rem of right-hand column, which is right for one record's fields and
   wrong for forty rows of six columns — those want the width. */
.modal {
  position: fixed; inset: 0; z-index: 50; display: flex; align-items: center; justify-content: center;
  padding: 2rem 1rem; pointer-events: none;
}
.modal > .sheet {
  pointer-events: auto; background: var(--panel); border: 1px solid var(--rule);
  width: min(64rem, 100%); max-height: min(85vh, 52rem); display: flex; flex-direction: column;
  border-radius: var(--radius); box-shadow: var(--shadow-lift); overflow: hidden;
}
.modal .sheet > header {
  padding: 1.4rem 1.5rem 1.1rem; border-bottom: 1px solid var(--rule); background: var(--panel);
  display: flex; align-items: flex-start; gap: 1rem; flex-wrap: wrap;
}
.modal .sheet > header h2 { font-size: 1.05rem; margin: 0 0 0.2rem; }
.modal .sheet > header .grow { flex: 1 1 16rem; min-width: 0; }
.modal .sheet > .controls {
  padding: 0.75rem 1.5rem; border-bottom: 1px solid var(--rule);
  display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center;
}
/* A sheet with no tabs and no filter should not show the strip that would have
   held them. */
.modal .sheet > .controls:empty { display: none; }
.modal .sheet > .controls input[type="search"] { flex: 1 1 12rem; min-width: 8rem; }
/* The table scrolls, the frame does not: the header and the counts stay put
   however far down the list somebody reads. */
.modal .sheet > .body { overflow: auto; flex: 1 1 auto; }
.modal .sheet > .body table { width: 100%; }
.modal .sheet > .body th {
  position: sticky; top: 0; z-index: 1; background: var(--panel-2);
  box-shadow: inset 0 -1px 0 var(--rule);
}
.modal .sheet > footer {
  padding: 0.9rem 1.5rem; border-top: 1px solid var(--rule); font-size: 0.8rem; color: var(--ink-faint);
  display: flex; gap: 0.8rem; align-items: center; flex-wrap: wrap;
}
@media (max-width: 40rem) {
  .modal { padding: 0; }
  .modal > .sheet { max-height: 100vh; height: 100vh; width: 100%; }
}

/* ---- the marketing page ---- */
/* Vertical only. Writing it as shorthand set the horizontal padding to zero,
   which cancelled the gutter .wrap had just put there — so the hero sat flush
   against the column edge, and against the window edge on a narrow screen. */
.hero { padding-block: clamp(3.4rem, 9vw, 6.5rem) clamp(2.6rem, 6vw, 4rem); }
.hero h1 {
  font-family: var(--display); font-weight: 400; letter-spacing: -0.03em; line-height: 1.04;
  font-size: clamp(2.4rem, 7.5vw, 4.6rem); max-width: 20ch;
}
.hero .lede { font-size: clamp(1.02rem, 2vw, 1.2rem); color: var(--ink-soft); max-width: 56ch; margin-top: 1.2rem; }
.cta { display: flex; gap: 0.7rem; flex-wrap: wrap; margin-top: 1.9rem; align-items: center; }
.tagline { font-size: 0.75rem; font-weight: 500; letter-spacing: 0.08em; text-transform: uppercase; color: var(--brand); }
.split { display: grid; gap: clamp(1.6rem, 4vw, 3rem); align-items: start; }
@media (min-width: 56rem) { .split { grid-template-columns: 1fr 1fr; } }
.numbers { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: 1px; background: var(--rule); border: 1px solid var(--rule); }
.numbers > div { background: var(--panel); padding: 0.9rem 1rem; }
.foot { border-top: 1px solid var(--rule-strong); padding: 2rem 0 3rem; font-size: 0.82rem; color: var(--ink-faint); }
.foot a { color: var(--ink-soft); }

/* The score row on the response page is radio buttons, so it works with no
   scripting at all. The input itself is taken out of the flow rather than
   hidden with display:none, which would take it out of the tab order too. */
/* Eleven of these have to sit on one line, including on a phone. A basis of
   zero with a small minimum lets them share the width evenly; a fixed basis
   left the eleventh just over the edge, where it wrapped onto a row of its own
   and stretched the full width, which reads as a different control entirely. */
.scale label {
  flex: 1 1 0; min-width: 2.05rem; max-width: 4.5rem; position: relative; cursor: pointer;
  border: 1px solid var(--rule-strong); background: var(--panel);
  font-variant-numeric: tabular-nums; font-weight: 500; font-size: 1rem;
  border-radius: var(--radius-sm);
  display: grid; place-items: center; padding: 0.75rem 0.15rem;
  transition: border-color 0.12s ease, background-color 0.12s ease;
}
.scale label:hover { border-color: var(--brand); background: var(--brand-wash); }
.scale input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.scale label:has(input:checked), .scale label[aria-pressed="true"] { background: var(--brand); color: var(--on-brand); border-color: var(--brand); }
.scale label:has(input:focus-visible) { outline: 2px solid var(--brand); outline-offset: 2px; }

/* ---- the log view ----
   A terminal, in a page. Monospaced and dense, because the value is in
   scanning it — and the upstream lines are the ones the eye should land on. */
.logview {
  border: 1px solid var(--rule-strong); background: var(--panel);
  font-family: var(--mono); font-size: 0.76rem; line-height: 1.6;
  height: min(68vh, 44rem); overflow-y: auto; overflow-x: hidden; padding: 0.4rem 0;
}
.logline {
  display: grid; grid-template-columns: 5.4rem 4.4rem 1fr auto; gap: 0.7rem;
  padding: 0.1rem 0.8rem; cursor: pointer; border-left: 2px solid transparent;
}
.logline:hover { background: var(--panel-2); }
.logline .lt { color: var(--ink-faint); }
.logline .lx { color: var(--ink-faint); opacity: 0.65; }
.logline .lb { overflow-wrap: anywhere; }
.logline .lm { color: var(--ink-faint); white-space: nowrap; }
.logline .why { color: var(--write); }

/* A call leaving this server. Marked on the left, coloured, and the only kind
   that gets a background — so a page of log resolves to "where did we go". */
.logline.upstream { background: var(--read-bg); border-left-color: var(--read); }
.logline.upstream:hover { background: var(--panel-2); }
.logline.upstream .arrow { color: var(--read); font-weight: 700; margin-right: 0.3rem; }
.logline.upstream .target { color: var(--read); font-weight: 700; }
.logline .outcome.ok { color: var(--read); }
.logline .outcome.bad { color: var(--write); font-weight: 700; }
.logline.upstream.failed { background: var(--write-bg); border-left-color: var(--write); }
.logline.upstream.failed .arrow, .logline.upstream.failed .target { color: var(--write); }

.logline.access { border-left-color: var(--warn); }
.logline.error, .logline.failed:not(.upstream) { color: var(--write); border-left-color: var(--write); }
.logline.server { color: var(--ink-soft); border-left-color: var(--rule-strong); }
.logline.request { color: var(--ink-faint); }
.logjson { margin: 0.2rem 0.8rem 0.5rem 3rem; font-size: 0.72rem; max-height: 22rem; overflow: auto; }


/* ---- help ----
   Explanations sit next to the thing they explain, always visible. A tooltip
   is help you have to already suspect exists, and a help page is help nobody
   reads at the moment they need it. */
.help {
  border-left: 2px solid var(--rule-strong); padding: 0.1rem 0 0.1rem 0.8rem;
  margin: 0.8rem 0; color: var(--ink-soft); font-size: 0.86rem;
}
.help strong { color: var(--ink); font-weight: 600; }
.help code { font-size: 0.82em; }
.help + .help { margin-top: -0.2rem; }
details.help-more { margin: 0.8rem 0; font-size: 0.86rem; }
details.help-more summary {
  cursor: pointer; color: var(--brand); font-size: 0.85rem; font-weight: 500;
}
details.help-more[open] summary { margin-bottom: 0.5rem; }
details.help-more > div { color: var(--ink-soft); border-left: 2px solid var(--rule); padding-left: 0.8rem; }
details.help-more p { margin: 0 0 0.5rem; }
details.help-more p:last-child { margin-bottom: 0; }
