/* ═══════════════════════════════════════════════════════════════════════════
   gw-system.css — THE PRIMITIVES. Loaded LAST, after sentinel.css and
   gw-editorial.css, because its whole job is to end arguments those two sheets
   have been having with each other.

   WS1 · 2026-08-11.

   gw-tokens.css declares the scale. This file is what SPENDS it. Until now the
   token layer resolved on every route and almost nothing painted from it, so
   the system was real in the diff and invisible on the page.

   Measured in Chromium against the rendered routes before this file existed:

     22 distinct filled-button treatments across 16 public routes — six fills,
        five radii, four weights, heights from 33px to 100px. The same label,
        "Run a free scan", shipped in three polarities: light-on-dark on `/`
        and `/oneshot`, a different light-on-dark on `/how-it-works`, and the
        INVERSE on `/register` and `/login`.
     4  distinct <h1> treatments.
     13 border radii on five pages against a four-token scale.

   ── WHY THE PRIMARY BUTTON READS ITS OWN COLOURS FROM THE WRAPPER ──────────

   DESIGN.md §7.1 specifies one primary object, byte-identical everywhere:
   `background:#F7F6F4; color:#111316` — 17.0:1, the strongest pair in §3.2.
   Taken literally that is a light button, and it is invisible on this site's
   editorial pages, whose ground is #F7F6F4 paper.

   The site runs two themes side by side in one document (DESIGN_AMENDMENTS.md
   A-1), so the primary needs both polarities and they must never be chosen by
   hand — that is precisely how 22 treatments happened. Both halves come from
   the wrapper's own theme instead:

       background: var(--gw-sys-color-text-high)
       color:      var(--gw-sys-color-on-high)

   which resolves to #111316 on #F7F6F4 ink on the paper estate and #F7F6F4 on
   #08090A on the near-black estate. Both are 17.0:1. It is ONE object with one
   rule; the polarity is a property of the surface it is standing on, and no
   call site gets a vote.

   ── HOVER IS NOT AN OPACITY FADE ─────────────────────────────────────────

   The sitewide `:hover{opacity:.88}` dropped the primary CTA from 17.98:1 to
   13.87:1 — a 23% loss of separation — and fading a control on hover is the
   visual grammar of DISABLING it (F-086). Per-role instead, and the fill moves
   further from the ground rather than closer: `--gw-sys-color-cta-hi` is
   #000000 on paper and #FFFFFF on near-black, declared per theme in
   gw-tokens.css beside the pair it belongs to.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── 1 · BUTTONS ─────────────────────────────────────────────────────────────
   The selector list is long on purpose. It is the census: every filled control
   that measured as a primary CTA on a public route, named, so that the count
   is 2 and the list is the evidence. A new CTA class that is not in here is a
   twenty-third treatment, and test_button_primitive_is_one_object.py says so.
   ─────────────────────────────────────────────────────────────────────────── */
/* On the self-chained selectors (`.vs-btn.vs-btn`): several of these classes
   are styled from a per-page <style> block that the head emits AFTER this
   file, so equal specificity loses on source order alone. Repeating the class
   raises specificity without reaching for !important — which in a primitives
   sheet would make every legitimate per-instance override impossible too. */
.gw-btn.gw-btn,
.gwe .btn,
.gwe .btn.lg,
.sx .btn,
.sx .btn.lg,
.masthead .mcta,
.enb-btn.enb-btn,
.vs-btn.vs-btn,
.gwsb-btn.gwsb-btn,
.supcta.supcta,
.xs-buy.xs-buy,
.sx a.go.go,
.gwe a.go.go {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  box-sizing: border-box;
  min-height: var(--gw-sys-tap-min, 44px);
  /* The vertical padding is REAL, not zero, and min-height is the floor under
     it rather than the only thing holding the button open. `padding: 0 24px`
     with `line-height: 1` gives a 15px label a 15px content box and lets
     min-height do all the work — which is fine for exactly as long as every
     label fits on one line. The moment one wraps (a longer locale, a narrow
     card, a 320px phone) the content box is 30px, min-height stops binding,
     and the two lines sit flush against the top and bottom edges of the fill.
     8px top and bottom costs NOTHING at rest: 15px label + 16px padding + 2px
     border = 33px, still under the 44px floor, so every button on the site is
     the same height it was, to the pixel. It only starts paying when the label
     wraps, which is the case it is here for. */
  padding: var(--gw-sys-space-8, 8px) var(--gw-sys-space-24, 24px);
  border: 1px solid transparent;
  border-radius: var(--gw-sys-radius-md, 6px);
  font-family: var(--gw-sys-type-font-sans);
  font-size: var(--gw-sys-type-body-s-size, .9375rem);
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  box-shadow: none;
  background-image: none;
  transition:
    background-color var(--gw-sys-dur-micro, 140ms) var(--gw-sys-ease-out, cubic-bezier(.2,0,0,1)),
    color            var(--gw-sys-dur-micro, 140ms) var(--gw-sys-ease-out, cubic-bezier(.2,0,0,1)),
    border-color     var(--gw-sys-dur-micro, 140ms) var(--gw-sys-ease-out, cubic-bezier(.2,0,0,1)),
    box-shadow       var(--gw-sys-dur-micro, 140ms) var(--gw-sys-ease-out, cubic-bezier(.2,0,0,1));
}

/* PRIMARY — one object. 17.0:1 in both polarities, by construction. */
.gw-btn-primary.gw-btn-primary,
.gwe .btn,
.gwe .btn.lg,
.sx .btn,
.sx .btn.lg,
.masthead .mcta,
.enb-btn.enb-btn-primary,
.vs-btn.vs-btn.primary,
.gwsb-btn.gwsb-btn,
.supcta.supcta,
.xs-buy.xs-buy,
.sx a.go.go,
.gwe a.go.go {
  background-color: var(--gw-sys-color-text-high, #F7F6F4);
  color: var(--gw-sys-color-on-high, #111316);
  border-color: var(--gw-sys-color-text-high, #F7F6F4);
}

/* SECONDARY — the only other treatment there is. */
.gw-btn-secondary.gw-btn-secondary,
.gwe .btn.ghost,
.gwe .btn.bare,
.sx .btn.ghost,
.enb-btn.enb-btn-secondary,
.vs-btn.vs-btn.secondary {
  background-color: transparent;
  background-image: none;
  color: var(--gw-sys-color-text-high, #F7F6F4);
  border: 1px solid var(--gw-sys-color-line-strong, #5D6773);
  box-shadow: none;
}

.gw-btn-primary.gw-btn-primary:hover,
.gwe .btn:hover,
.sx .btn:hover,
.masthead .mcta:hover,
.enb-btn.enb-btn-primary:hover,
.vs-btn.vs-btn.primary:hover,
.gwsb-btn.gwsb-btn:hover,
.supcta.supcta:hover,
.xs-buy.xs-buy:hover,
.sx a.go.go:hover,
.gwe a.go.go:hover {
  /* NOT opacity. The fill moves AWAY from the ground and gains one shadow. */
  opacity: 1;
  background-color: var(--gw-sys-color-cta-hi, #FFFFFF);
  border-color: var(--gw-sys-color-cta-hi, #FFFFFF);
  box-shadow: var(--gw-sys-shadow-1, 0 1px 2px rgba(0,0,0,.28));
  text-decoration: none;
}

.gw-btn-secondary.gw-btn-secondary:hover,
.gwe .btn.ghost:hover,
.gwe .btn.bare:hover,
.sx .btn.ghost:hover,
.enb-btn.enb-btn-secondary:hover,
.vs-btn.vs-btn.secondary:hover {
  opacity: 1;
  background-color: transparent;
  border-color: var(--gw-sys-color-signal, #AF5125);
}

/* The secondary must win over the primary block above where a control carries
   both classes; the ghost/bare modifiers are more specific than `.gwe .btn`
   only by one class, so state it after and let source order settle it. */
.gwe .btn.ghost,
.gwe .btn.bare,
.sx .btn.ghost {
  background-color: transparent;
  color: var(--gw-sys-color-text-high, #F7F6F4);
  border-color: var(--gw-sys-color-line-strong, #5D6773);
}

.gw-btn[disabled],
.gwe .btn[disabled],
.sx .btn[disabled] {
  opacity: .65;
  cursor: default;
  box-shadow: none;
}

/* `.lg` was a fifth height (50px) and a sixth radius. A larger button is a
   layout decision — more horizontal padding — not a different treatment. */
.gwe .btn.lg, .sx .btn.lg {
  min-height: var(--gw-sys-tap-min, 44px);
  /* Same vertical padding as the base rule, for the same wrapped-label
     reason — this rule re-states `padding` in full, so omitting it here
     would put the zero back on every .lg button. */
  padding: var(--gw-sys-space-8, 8px) var(--gw-sys-space-32, 32px);
}

/* Width is a layout decision, not a treatment: `.block` keeps its job and
   changes nothing else. */
.gw-btn.block,
.gwe .btn.block,
.sx .btn.block {
  display: flex;
  width: 100%;
}

/* ── 2 · ONE H1 TREATMENT ────────────────────────────────────────────────────
   Four measured: 76/300 display, 42/700 Rajdhani on /security, 32/800 and
   32/700 system-font on the shell-less pages. A page's H1 is the one element a
   reader uses to work out what site they are on, so four of them is four
   sites. The homepage hero keeps its own d0/d1 size — it is the one place a
   larger step is earned and it is being rebuilt in a parallel workstream — and
   everything else lands here.
   ─────────────────────────────────────────────────────────────────────────── */
h1,
.sx h1,
.sx-app h1,
.gwe h1 {
  font-family: var(--gw-sys-type-font-display);
  font-size: var(--gw-sys-type-h1-size, clamp(1.75rem, 1.4rem + 1.5vw, 2.625rem));
  font-weight: var(--gw-sys-type-h1-weight, 350);
  line-height: var(--gw-sys-type-h1-leading, 1.15);
  letter-spacing: var(--gw-sys-type-h1-tracking, -0.02em);
  max-width: var(--gw-sys-measure-display, 14ch);
  text-wrap: balance;
  overflow-wrap: break-word;
}

/* Six pages beat the rule above on specificity from their own <style> block
   and were measured doing it: /how-it-works 32px/800, /register 38.4px/800,
   /login 42px/800, /blog/ 38.4px/350, /for-founders 58px/700,
   /enterprise 72px/300. The weights are the real offence — DESIGN.md §2.1 and
   IDENTITY_SYSTEM.md §4.2 both say weight FALLS as size rises, and an 800 at
   38px is the inversion. Named, so the list is the evidence and a seventh
   shows up as a seventh. */
.hiw h1,
.sx .authcard h1,
h1.regh,
.bi-hero-tight h1,
.enb h1 {
  font-size: var(--gw-sys-type-h1-size, clamp(1.75rem, 1.4rem + 1.5vw, 2.625rem));
  font-weight: var(--gw-sys-type-h1-weight, 350);
  line-height: var(--gw-sys-type-h1-leading, 1.15);
  letter-spacing: var(--gw-sys-type-h1-tracking, -0.02em);
}

/* The hero H1 is the ONE exception, and it is a different STEP of the same
   scale rather than a different treatment: same face, same weight, same
   leading discipline. `.hero`/`.herodark` are the two hero wrappers that
   ship. */
.sx h1.hero,
.gwe .herodark h1,
.gwe .hero h1,
.vl-hero h1 {
  font-size: var(--gw-sys-type-d1-size, clamp(2.5rem, 1.6rem + 4.2vw, 4.75rem));
  font-weight: var(--gw-sys-type-d1-weight, 300);
  line-height: var(--gw-sys-type-d1-leading, 1.02);
  letter-spacing: var(--gw-sys-type-d1-tracking, -0.03em);
  max-width: none;
}

/* ── 3 · RADII — four values, and nothing between them ───────────────────────
   13 painted on five pages: 5 6 7 8 9 10 12 14 18 999. Values one pixel apart
   are not decisions. The card grids were the worst of it: /oneshot rendered 27
   cards in nine padding+radius combinations, several ASYMMETRIC (18/18/16/18)
   because two rem values rounded to different pixels on opposite edges of one
   box. Cards in the same grid were visibly not the same card.
   ─────────────────────────────────────────────────────────────────────────── */
.gwe .btn, .sx .btn, .sx .btn.lg, .masthead .mcta, .gw-btn.gw-btn,
.enb-btn.enb-btn, .vs-btn.vs-btn, .gwsb-btn.gwsb-btn, .supcta.supcta {
  border-radius: var(--gw-sys-radius-md, 6px);
}
/* A pill is a CHIP. `.xs-buy` and `.go` were pill-shaped buttons, which is a
   third button shape wearing a chip's costume — both are radius-md now. */
.xs-buy.xs-buy, .sx a.go.go, .gwe a.go.go {
  border-radius: var(--gw-sys-radius-md, 6px);
}
.badge, .chip, .pill, .gwe .badge, .sx .tag, .sx-app .tag, .sx .chip {
  border-radius: var(--gw-sys-radius-pill, 999px);
}
.gwe .ocard, .gwe .pcell, .gwe .outcome, .gwe .rev, .gwe .tl .tstep,
.sx .card, .sx .blogcard, .sx .authcard, .sx-app .card, .gwe-card {
  border-radius: var(--gw-sys-radius-lg, 12px);
}
.gwe input, .gwe select, .gwe textarea,
.sx input, .sx select, .sx textarea,
.sx .fld, .sx-app .fld {
  border-radius: var(--gw-sys-radius-sm, 4px);
}

/* ── 4 · THE CARD PRIMITIVE ──────────────────────────────────────────────────
   DESIGN.md §7.2. One padding tuple, one radius, one surface, one hairline —
   available to anything that wants to stop inventing a card. */
.gwe-card {
  box-sizing: border-box;
  padding: var(--gw-sys-space-16, 16px);
  border-radius: var(--gw-sys-radius-lg, 12px);
  background: var(--gw-sys-color-raised, #14171C);
  border: 1px solid var(--gw-sys-color-line, #2E3338);
}
.gwe-card:hover {
  border-color: var(--gw-sys-color-line-strong, #5D6773);
}

/* ── 5 · MOTION — the four durations, and no `transition: all` ───────────── */
@media (prefers-reduced-motion: reduce) {
  .gw-btn, .gwe .btn, .sx .btn, .masthead .mcta, .gwe-card {
    transition-duration: .01ms !important;
  }
}
