/* ===========================================================================
   THE PUBLIC SURFACES — home, sign-in, sign-out, activation.

   Everything above this line is the instrument: fixed height, panes that scroll,
   13px type, thirty rows on screen. These four pages are the opposite job — one
   column, one decision, and a document that scrolls — so they opt in with
   `<body class="site">` rather than fighting `body { overflow: hidden }`.

   What they do NOT get is a second design language. Same tokens, same accent, same
   verdict colours, same hairlines, same radii. The only thing that changes is the
   type scale: a marketing page is allowed to open at 44px, and nothing else here is.
   =========================================================================== */
/* The instrument pins `html, body { height: 100% }` and `body { overflow: hidden }` so
   its panes scroll instead of the page. A document has to undo BOTH: leaving the height
   pinned makes body its own scroll container, and the viewport then renders blank
   below the fold while `window.scrollY` cheerfully reports it moved. */
html:has(body.site) { height: auto; }
body.site {
  height: auto;
  min-height: 100%;
  overflow: visible;
  font-size: 15px;
  line-height: 1.65;
  background: var(--bg);
}
body.site ::selection { background: var(--accent-bg); }

.site-wrap { max-width: 940px; margin: 0 auto; padding: 0 24px; }
.site-narrow { max-width: 460px; margin: 0 auto; padding: 0 24px; }

/* ── site chrome ─────────────────────────────────────────────────────────── */
.site-nav {
  position: sticky; top: 0; z-index: 20;
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(8px);
}
.site-nav .site-wrap { display: flex; align-items: center; gap: 10px; height: 56px; }
.wordmark { display: flex; align-items: center; gap: 8px; font-weight: 600; font-size: 15px; letter-spacing: -.015em; }
/* The slot is sized here, not by the SVG, so site.mjs filling it costs no reflow. */
/* SLATE, not the accent. /DESIGN.md: "the mark renders in --text-primary… the brand never
   adds a saturated colour of its own — colour stays reserved for the verdict", and the
   2026-08-07 decision row reverses Orbit having rendered this exact rule in `var(--accent)`
   in as many words. The argument that used to sit here — that the slate rule is about
   verdict colours and the accent is not one — is the argument that row overrules. */
.wordmark .mark { width: 20px; height: 20px; flex: none; display: block; color: var(--text); }
.wordmark .mark svg { width: 100%; height: 100%; display: block; }
.site-nav .spacer { flex: 1; }
.site-nav a.navlink { color: var(--text-2); font-size: 13.5px; font-weight: 500; padding: 6px 9px; border-radius: var(--r-md); }
.site-nav a.navlink:hover { color: var(--text); background: var(--hover); }

.site-foot {
  border-top: 1px solid var(--border); margin-top: 72px; padding: 28px 0 40px;
  color: var(--text-3); font-size: 12.5px;
}
.site-foot .site-wrap { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.site-foot a { color: var(--text-2); }
.site-foot a:hover { color: var(--text); }
.site-foot .spacer { flex: 1; }

/* ── type ────────────────────────────────────────────────────────────────── */
.hero { padding: 84px 0 56px; }
.hero h1 {
  margin: 0 0 18px; max-width: 17ch;
  font-size: clamp(34px, 5.2vw, 44px); line-height: 1.1; font-weight: 600; letter-spacing: -.03em;
}
.hero p.lede { margin: 0 0 28px; max-width: 60ch; font-size: 17px; color: var(--text-2); }
.eyebrow {
  display: inline-flex; align-items: center; gap: 7px; margin-bottom: 18px;
  height: 26px; padding: 0 10px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--panel);
  color: var(--text-2); font-size: 12px; font-weight: 500;
}
.eyebrow .ic { width: 13px; height: 13px; color: var(--text-3); }

.site-sec { padding: 52px 0; border-top: 1px solid var(--border); }
.site-sec > h2 {
  margin: 0 0 10px; font-size: 26px; font-weight: 600; letter-spacing: -.022em; line-height: 1.2;
}
.site-sec > p.sub { margin: 0 0 30px; max-width: 62ch; color: var(--text-2); font-size: 15px; }
.site-sec h3 { margin: 0 0 6px; font-size: 15px; font-weight: 600; letter-spacing: -.01em; }
.site-sec p { margin: 0; color: var(--text-2); font-size: 14px; line-height: 1.6; }

.ctas { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.site .btn { height: 38px; padding: 0 16px; font-size: 14px; border-radius: var(--r-md); }
.site .btn .ic { width: 16px; height: 16px; }

/* ── blocks ──────────────────────────────────────────────────────────────── */
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 14px; }
.card {
  padding: 18px; border-radius: var(--r-lg);
  border: 1px solid var(--border); background: var(--panel);
}
.card > .ic { width: 17px; height: 17px; color: var(--text-3); margin-bottom: 11px; }

/* The loop, numbered. The number is mono because it is a step index, not decoration. */

/* ── auth / activation ───────────────────────────────────────────────────── */
.auth-page { min-height: 100vh; display: grid; place-items: center; padding: 40px 0 80px; }
.auth-card {
  width: min(420px, calc(100vw - 40px));
  padding: 28px; border-radius: var(--r-xl);
  border: 1px solid var(--border); background: var(--panel);
  box-shadow: var(--shadow-sm);
}
.auth-card .wordmark { margin-bottom: 20px; }
.auth-card h1 { margin: 0 0 6px; font-size: 21px; font-weight: 600; letter-spacing: -.02em; }
.auth-card p.sub { margin: 0 0 22px; color: var(--text-2); font-size: 13.5px; }
.auth-card .btn { width: 100%; margin-bottom: 8px; }
.auth-note {
  margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--border);
  color: var(--text-3); font-size: 12px; line-height: 1.55;
}
.auth-note a { color: var(--text-2); text-decoration: underline; text-underline-offset: 2px; }

/* The activation ladder. A step that is done says so; the one you are on is the only
   one wearing the accent; the rest are visible but plainly not yet reachable. */
.ladder { display: grid; gap: 0; }
.rung {
  display: grid; grid-template-columns: 26px minmax(0,1fr); gap: 14px;
  padding: 18px 0; border-top: 1px solid var(--border);
}
.rung:first-child { border-top: 0; }
.rung > .pip {
  width: 22px; height: 22px; border-radius: 999px; margin-top: 1px;
  display: grid; place-items: center;
  border: 1px solid var(--border-2); background: var(--panel);
  font-family: var(--mono); font-size: 10.5px; color: var(--text-3);
}
/* Deliberately NOT --v-safe. Green means one thing in this product — a verdict — and a
   completed setup step is not a judgement about anybody's code. Slate, with a check. */
.rung.done > .pip { background: var(--text-2); border-color: transparent; color: var(--knockout); }
.rung.now  > .pip { background: var(--accent); border-color: transparent; color: var(--accent-fg); }
.rung.done > .pip svg { width: 12px; height: 12px; }
.rung h3 { margin: 0 0 3px; font-size: 14.5px; font-weight: 600; }
.rung p { font-size: 13.5px; }
.rung.todo h3, .rung.todo p { color: var(--text-3); }
.rung .rung-do { margin-top: 12px; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.field { display: grid; gap: 5px; margin-top: 12px; max-width: 380px; }
.field label { font-size: 12px; color: var(--text-2); font-weight: 500; }
.field input, .field select {
  height: 32px; padding: 0 10px; border-radius: var(--r-md);
  border: 1px solid var(--border); background: var(--panel-2);
  color: var(--text); font-size: 13px; outline: none;
}
.field input:focus, .field select:focus { border-color: var(--accent); }
.field .help { font-size: 11.5px; color: var(--text-3); }

@media (max-width: 720px) {
  .hero { padding: 56px 0 40px; }
  .site-sec { padding: 40px 0; }
}

/* ── the Archive's bulk bar ──────────────────────────────────────────────────
   The only select-all in the product, and the only permanently destructive action.
   It gets its own strip rather than living in the filter bar, because a destructive
   control that shares a row with "Grouped by Team" is a control somebody clicks by
   accident. Disabled with nothing selected — never hidden. */
.bulkbar {
  flex: none; display: flex; align-items: center; gap: 8px;
  padding: 7px 12px;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
}
.bulkbar .spacer { flex: 1; }
.bulk-check { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; color: var(--text-2); font-size: 12px; }
.bulk-check input { accent-color: var(--accent); width: 14px; height: 14px; }
.rowcheck { display: grid; place-items: center; }
.rowcheck input { accent-color: var(--accent); width: 14px; height: 14px; cursor: pointer; }

/* ===========================================================================
   THE HOME PAGE.

   Two earlier attempts bracketed this one. The first showed the whole product —
   a board list, a check on a pull request, a diff, comparison tables — and read
   like a PDF. The second cut so hard it stopped saying anything: five sections,
   330 words, and no reason to keep scrolling.

   This is the middle, and the shape is borrowed from how review tools actually
   market themselves: MANY short sections rather than few long ones. An icon, a
   headline, one or two sentences, next. You can skim the whole page in fifteen
   seconds and still come away knowing six things — which is not true of an essay
   and not true of a page with nothing on it.

   What carries the interest between claims is MOTION and the MASCOT, not more
   prose. Everything reveals on scroll, the hero cycles through the three verdicts
   on its own, and the dog reacts. All of it is off under prefers-reduced-motion.
   =========================================================================== */

/* ── motion ──────────────────────────────────────────────────────────────── */
/* One reveal for the whole page, driven by an IntersectionObserver in home.html.
   Elements start displaced and un-inked; `.in` is added once, and never removed —
   a reveal that re-runs on scroll-up is a fidget, not an entrance. */
/* The hidden state is ARMED by the blocking head script, never by the stylesheet.
   A page whose content is invisible until JavaScript decides otherwise is one broken
   observer away from a blank page — so if that script does not run, `data-reveal` is
   never set, this rule never matches, and everything is simply visible. Arming it in
   the head rather than in the module also means there is no flash of the un-animated
   page first. */
[data-reveal="on"] .rise { opacity: 0; transform: translateY(14px); }
[data-reveal="on"] .rise.in {
  opacity: 1; transform: none;
  transition: opacity 620ms var(--ease), transform 620ms var(--ease);
}
[data-reveal="on"] .rise.d1.in { transition-delay: 70ms; }
[data-reveal="on"] .rise.d2.in { transition-delay: 140ms; }
[data-reveal="on"] .rise.d3.in { transition-delay: 210ms; }
[data-reveal="on"] .rise.d4.in { transition-delay: 280ms; }

@media (prefers-reduced-motion: reduce) {
  [data-reveal="on"] .rise, [data-reveal="on"] .rise.in { opacity: 1; transform: none; transition: none; }
  .hero-orb, .pulse { animation: none !important; }
  .verdict-swap { transition: none !important; }
}

/* ── hero ────────────────────────────────────────────────────────────────── */
.hero-grid {
  display: grid; grid-template-columns: minmax(0,1.05fr) minmax(0,.95fr);
  gap: 56px; align-items: center;
}
@media (max-width: 900px) { .hero-grid { grid-template-columns: minmax(0,1fr); gap: 40px; } }

/* The install indicator: the promise, stated where the button is. */
.install-line { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 18px; color: var(--text-3); font-size: 12.5px; }
.install-line .ic { width: 14px; height: 14px; }
.install-line .pip {
  display: inline-grid; place-items: center; width: 17px; height: 17px; border-radius: 999px;
  background: var(--elev-2); border: 1px solid var(--border);
  font-family: var(--mono); font-size: 9.5px; color: var(--text-2);
}

/* The hero stage: one run, getting judged. */
.stage { position: relative; display: grid; justify-items: center; gap: 18px; }
.hero-orb {
  position: absolute; inset: -8% -6% auto 50%; translate: -50% 0;
  width: 300px; height: 300px; border-radius: 999px;
  background: var(--accent); opacity: .07; filter: blur(58px);
  animation: breathe 9s ease-in-out infinite; pointer-events: none;
}
@keyframes breathe { 0%, 100% { transform: scale(1); opacity: .07; } 50% { transform: scale(1.12); opacity: .11; } }

.verdict-swap { position: relative; z-index: 1; width: min(400px, 100%); }
.vcard {
  border-radius: var(--r-lg); border: 1px solid var(--border);
  background: var(--panel); box-shadow: var(--shadow-sm); overflow: hidden;
}
.vcard-top {
  display: flex; align-items: center; gap: 8px; padding: 10px 14px;
  border-bottom: 1px solid var(--border); color: var(--text-3); font-size: 11px;
}
.vcard-top .spacer { flex: 1; }
.vcard-body { padding: 14px; }
.vcard-title { font-size: 13.5px; font-weight: 600; margin-bottom: 11px; letter-spacing: -.01em; }
.vcard-v { display: flex; align-items: center; gap: 8px; font-size: 13.5px; font-weight: 600; transition: color 420ms var(--ease); }
.vcard-v svg { width: 16px; height: 16px; }
.vcard.v-safe   .vcard-v { color: var(--v-safe); }
.vcard.v-review .vcard-v { color: var(--v-review); }
.vcard.v-block  .vcard-v { color: var(--v-block); }
.vcard-why { margin-top: 7px; font-size: 12.5px; color: var(--text-2); line-height: 1.55; min-height: 40px; }
.vcard-foot {
  display: flex; align-items: center; gap: 8px; padding: 10px 14px;
  border-top: 1px solid var(--border); background: var(--panel-2);
  font-family: var(--mono); font-size: 10.5px; color: var(--text-3);
}
.vcard-foot .spacer { flex: 1; }
/* The dots say the card is a rotation, not a screenshot that happens to be red. */
.swap-dots { display: flex; gap: 6px; justify-content: center; }
.swap-dots i { width: 5px; height: 5px; border-radius: 999px; background: var(--border-2); transition: background 300ms var(--ease); }
.swap-dots i.on { background: var(--text-3); }

/* ── the six-up grid: the density model, minus the essays ────────────────── */
.grid6 { display: grid; grid-template-columns: repeat(auto-fit, minmax(258px, 1fr)); gap: 1px; margin-top: 38px; background: var(--border); border: 1px solid var(--border); border-radius: var(--r-lg); overflow: hidden; }
.cell { padding: 22px; background: var(--panel); }
.cell > .ic { width: 17px; height: 17px; color: var(--text-3); margin-bottom: 12px; }
.cell b { display: block; font-size: 14.5px; font-weight: 600; letter-spacing: -.012em; margin-bottom: 6px; }
.cell p { font-size: 13px; color: var(--text-2); line-height: 1.55; }

/* ── the loop ────────────────────────────────────────────────────────────── */
/* Four beats, and they must sit on ONE row on a desktop: the row IS the argument
   (this happens, then this, then this). auto-fit was breaking it 3 + 1, which reads
   as a grid of features rather than a sequence. */
.beats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 26px; margin-top: 38px; }
@media (max-width: 1000px) { .beats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 28px; } }
@media (max-width: 560px)  { .beats { grid-template-columns: minmax(0, 1fr); } }
.beat > .ic { width: 18px; height: 18px; color: var(--text-3); margin-bottom: 12px; }
.beat .who {
  display: inline-block; margin-bottom: 8px; padding: 2px 8px; border-radius: 999px;
  border: 1px solid var(--border); font-size: 10.5px; color: var(--text-3); font-weight: 500;
}
.beat.you .who { border-color: var(--accent); color: var(--accent); }
.beat b { display: block; font-size: 15px; font-weight: 600; letter-spacing: -.012em; margin-bottom: 6px; }
.beat p { font-size: 13.5px; color: var(--text-2); line-height: 1.55; }

/* ── the three answers ───────────────────────────────────────────────────── */
.answers { display: grid; gap: 1px; margin-top: 34px; background: var(--border); border: 1px solid var(--border); border-radius: var(--r-lg); overflow: hidden; }
.answer { display: flex; align-items: center; gap: 12px; padding: 16px 18px; background: var(--panel); }
.answer svg, .answer .parked-glyph { width: 17px; height: 17px; flex: none; }
.answer b { font-size: 14px; font-weight: 600; min-width: 148px; }
.answer.safe svg, .answer.safe b { color: var(--v-safe); }
.answer.review svg, .answer.review b { color: var(--v-review); }
.answer.block svg, .answer.block b { color: var(--v-block); }
.answer span { font-size: 13.5px; color: var(--text-2); }
@media (max-width: 620px) { .answer { align-items: flex-start; flex-wrap: wrap; } .answer b { min-width: 0; } }

/* ── the gate, as its own band ───────────────────────────────────────────── */
.band { background: var(--panel-2); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
.band .site-sec { border-top: 0; }
.reviews-grid { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); gap: 44px; align-items: center; margin-top: 34px; }
@media (max-width: 860px) { .reviews-grid { grid-template-columns: minmax(0,1fr); gap: 28px; } }
.chk-mini { border-radius: var(--r-lg); border: 1px solid var(--border); background: var(--panel); overflow: hidden; }
/* `chk-row`, not `row`: the app's issue list already owns `.row` and pins it to
   `height: var(--row-h)`. A marketing card reusing that name inherits a 40px cage and
   its second line lands on top of the next one. */
.chk-row { display: grid; grid-template-columns: 18px minmax(0,1fr) auto; gap: 11px; padding: 13px 14px; align-items: start; }
.chk-row + .chk-row { border-top: 1px solid var(--border); }
.chk-mini svg { width: 17px; height: 17px; display: block; }
.chk-mini .nm { font-size: 13px; }
.chk-mini .nm b { font-weight: 600; }
.chk-mini .v-block { color: var(--v-block); }
.chk-mini .sub2 { margin-top: 3px; font-size: 12px; color: var(--text-2); line-height: 1.5; }
.chk-mini .det { color: var(--accent); font-size: 12px; font-weight: 500; }
.chk-row.muted svg { color: var(--text-3); }
.chk-row.muted .nm { color: var(--text-2); }
.pointlist { display: grid; gap: 14px; margin-top: 18px; }
.pointlist li { display: grid; grid-template-columns: 15px minmax(0,1fr); gap: 11px; font-size: 13.5px; color: var(--text-2); line-height: 1.55; list-style: none; }
.pointlist li .ic { width: 15px; height: 15px; color: var(--text-3); margin-top: 3px; }
.pointlist { padding: 0; margin-left: 0; }
.pointlist b { color: var(--text); font-weight: 600; }

/* ── closer ──────────────────────────────────────────────────────────────── */
.closer { padding: 84px 0 30px; text-align: center; }
.closer h2 { font-size: clamp(27px, 3.6vw, 36px); letter-spacing: -.028em; margin: 0 0 12px; font-weight: 600; }
.closer p { max-width: 48ch; margin: 0 auto 26px; color: var(--text-2); font-size: 15px; }
.closer .ctas { justify-content: center; }
.fineprint, .site-sec p.fineprint {
  margin-top: 18px; max-width: 64ch;
  color: var(--text-3); font-size: 12.5px; line-height: 1.6;
}
.closer .fineprint { margin-left: auto; margin-right: auto; }
