/* ============================================================
   components.css — Digital Crochet
   Loaded after tokens.css and base.css. No raw values.

   Border, fill, radius and shadow are spent by role rather than
   stamped on every block, so the hierarchy stays readable.
   ============================================================ */

@layer components {

  /* ---------- site header ---------------------------------- */
  .site-header {
    position: sticky;
    top: 0;
    z-index: 50;
    /* OPAQUE, not 88% + blur (owner, 17 Sep 2026). A sticky header over a
       translucent background composites whatever is passing under it into the
       logo's effective colour -- mid-scroll the hero's white input field read
       as a blob behind the mark, and the contrast of the brand text was a
       different number at every scroll position. --c-bg is the band the header
       sits on at rest in both themes, so at rest nothing changes; what changes
       is that the logo now has ONE measurable background. The blur went with
       it: it cannot show through an opaque surface and only cost a layer. */
    background: var(--c-bg);
    border-bottom: 1px solid var(--c-line);
  }
  .site-header .wrap {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding-block: var(--sp-2);
  }
  .site-header .btn,
  .brand span { white-space: nowrap; }
  /* Logo and CTA on one line need ~350px at the normal gap. Below 390px
     tighten the gap; below 360px there is no room for both, and a wrapped
     brand name looks broken, so the CTA goes (owner, 17 Sep 2026). The
     page body still carries CTAs. */
  @media (max-width: 389px) { .site-header .wrap { gap: var(--sp-1); } }
  @media (max-width: 359px) { .site-header .btn { display: none; } }
  .brand {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: var(--text-0);
    letter-spacing: -0.03em;
    color: var(--c-ink);
    text-decoration: none;
    margin-right: auto;
  }
  .brand {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
  }
  .brand__mark {
    width: 1.55rem;
    height: auto;
    color: var(--c-brand);
    flex: none;
  }
  .brand em { color: var(--c-brand); font-style: normal; }
  .band--dark .brand__mark { color: var(--c-brand-on-dark); }
  /* The footer sits on --c-surface-2, which is light: the plain
     brand token, not the on-dark one. */
  .site-footer .brand__mark { color: var(--c-brand); }

  .site-nav { display: flex; gap: var(--sp-3); font-size: var(--text--1); }
  .site-nav a { color: var(--c-muted); text-decoration: none; }
  .site-nav a:hover,
  .site-nav a[aria-current="page"] { color: var(--c-ink); }

  .nav-toggle { display: none; }

  @media (max-width: 880px) {
    .site-nav { display: none; }
    .site-nav[data-open="true"] {
      display: grid;
      gap: var(--sp-2);
      flex-basis: 100%;
      padding-block: var(--sp-2);
      border-top: 1px solid var(--c-line);
      font-size: var(--text-0);
    }
    .nav-toggle {
      display: inline-flex;
      align-items: center;
      background: transparent;
      color: var(--c-ink);
      border: 1px solid var(--c-line);
      border-radius: var(--radius-sm);
      padding: 0.5rem 0.75rem;
      font: inherit;
      font-size: var(--text--1);
      cursor: pointer;
    }
  }

  /* ---------- buttons -------------------------------------- */
  .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-1);
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--text-0);
    line-height: 1.2;
    padding: 0.8rem 1.3rem;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    text-decoration: none;
    cursor: pointer;
    transition: background-color var(--dur) var(--ease),
                border-color var(--dur) var(--ease);
  }
  .btn--primary { background: var(--c-brand); color: var(--c-on-brand); }
  .btn--primary:hover {
    background: color-mix(in oklab, var(--c-brand) 88%, black);
    color: var(--c-on-brand);
  }
  .btn--secondary {
    background: var(--c-surface);
    color: var(--c-ink);
    border-color: var(--c-line);
  }
  .btn--secondary:hover { background: var(--c-surface-2); color: var(--c-ink); }

  .band--dark .btn--secondary {
    background: transparent;
    color: var(--c-dark-ink);
    border-color: var(--c-dark-line);
  }
  .band--dark .btn--secondary:hover { background: var(--c-dark-panel); }

  .btn[disabled], .btn[aria-disabled="true"] { opacity: 0.45; cursor: not-allowed; }
  .btn--sm { padding: 0.5rem 0.85rem; font-size: var(--text--1); }

  /* ---------- "not shipped yet" badge -----------------------
     Every unreleased feature carries this. It is the difference
     between a roadmap and a false claim. */
  .soon {
    display: inline-block;
    font-family: var(--font-mono);
    font-size: 0.66rem;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    padding: 0.2rem 0.45rem;
    border-radius: 999px;
    background: var(--c-soon-bg);
    color: var(--c-soon);
    vertical-align: middle;
  }

  /* ---------- cards ---------------------------------------- */
  /* ONE SET OF BOX RULES (17 Sep 2026). .card, .price and .feature each
     declared their own padding, radius, border and gap, so three things that
     read as the same object were not. They share the block below now. The only
     differences left are the ones that carry meaning: the indigo rule down the
     left of .feature, and the brand border and shadow on .price--featured.

     height:100% is what makes a row of cards end level. It needs the grid to
     stretch its items, which is why `align-items: start` was removed from
     every card grid -- it was the reason bottoms were ragged, and it was
     inline on 20 of them. */
  .card, .price, .feature {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    height: 100%;
    background: var(--c-surface);
    border: 1px solid var(--c-line);
    border-radius: var(--radius-md);
    padding: var(--sp-3);
  }
  .card { container-type: inline-size; }

  /* A whole card that is a link. Without this the browser underlines every
     line of it, heading and body, which is what made the services grid read
     as a wall of underlined text.

     EVERY CARD HEADING IS THE SAME INK AT REST (owner, 17 Sep 2026). The
     heading used to carry --c-brand to mark the card as a link, which worked
     while every card was one. The services families broke it: four of the nine
     have no page yet and are plain divs, so an indigo heading sat beside a
     black one in the same row and read as "this card is broken" rather than
     "this one has no page yet". A colour that means "link" only reads that way
     when the reader can see something to compare it against, and here the
     comparison said the wrong thing.

     So the affordance moves to hover and the cursor, which are the states that
     actually distinguish a link from a card, and are available on the element
     the reader is pointing at rather than on all nine at once. Keyboard users
     get the sitewide focus treatment from base.css. */
  a.card { text-decoration: none; color: inherit; }
  a.card:hover { border-color: var(--c-brand); }
  a.card:hover h3 { color: var(--c-brand); }
  .band--dark a.card:hover { border-color: var(--c-brand-on-dark); }
  .band--dark a.card:hover h3 { color: var(--c-brand-on-dark); }

  /* The action sits on the same baseline whatever the copy above it does.
     Scoped to actions on purpose: pushing a trailing <p> down would tear body
     copy away from its heading. */
  .card    > :last-child:is(a, .btn, .row),
  .price   > :last-child:is(a, .btn, .row),
  .feature > :last-child:is(a, .btn, .row) { margin-top: auto; }
  .card--tint { background: var(--c-surface-2); border-color: transparent; }

  /* A shipped feature. Indigo rule = available today. */
  /* .feature takes the shared box above. These two carry meaning and stay: the
     indigo rule marks a working feature, and the radius opens toward it. */
  .feature {
    border-left: 3px solid var(--c-brand-bright);
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
  }
  /* The rule bleeds into the card as a wash that fades out by 42%. */
  .feature { position: relative; }
  .feature::before {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(to right,
      color-mix(in oklab, var(--c-brand-bright) 7%, transparent), transparent 42%);
  }
  .feature > * { position: relative; }
  /* A roadmap item. Muted rule, so the two never blur together. */
  .feature--soon { border-left-color: var(--c-soon); }
  .feature--soon::before {
    background: linear-gradient(to right,
      color-mix(in oklab, var(--c-soon) 8%, transparent), transparent 42%);
  }
  .feature h3 { font-size: var(--text-0); }
  .feature p { font-size: var(--text--1); color: var(--c-muted); }
  /* --c-muted is the LIGHT-band muted value. On a dark band it measured
     2.46:1 against --c-dark-panel -- a real AA failure, found by reading the
     computed colour of every text node on every dark band rather than assuming
     the on-dark tokens were in use. Any muted text that lands on a dark card
     takes the on-dark value. */
  .band--dark .feature p,
  .band--dark .card p,
  .band--dark .price p { color: var(--c-dark-muted); }

  /* ---------- the savings calculator -----------------------
     The product's biggest number, so it gets the strongest
     treatment on the page and nothing else competes with it. */
  .calc {
    background: var(--c-dark);
    color: var(--c-dark-ink);
    border-radius: var(--radius-lg);
    padding: var(--sp-4);
  }
  .calc label {
    display: block;
    font-size: var(--text--1);
    color: var(--c-dark-muted);
    margin-bottom: var(--sp-1);
  }
  .calc input[type="range"] { width: 100%; accent-color: var(--c-brand-bright); }
  .calc input[type="number"] {
    font: inherit;
    font-family: var(--font-mono);
    width: 100%;
    padding: 0.7rem 0.8rem;
    color: var(--c-dark-ink);
    background: var(--c-dark-panel);
    border: 1px solid var(--c-dark-line);
    border-radius: var(--radius-sm);
  }
  .calc__out {
    margin-top: var(--sp-3);
    padding-top: var(--sp-3);
    border-top: 1px solid var(--c-dark-line);
    display: grid;
    gap: var(--sp-2);
  }
  .calc__line {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--sp-2);
    font-size: var(--text--1);
  }
  .calc__line .n { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
  .calc__line--cost .n { color: var(--c-cost-on-dark); }
  .calc__total {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--sp-2);
    padding-top: var(--sp-2);
    border-top: 1px solid var(--c-dark-line);
  }
  .calc__total .label { font-size: var(--text--1); color: var(--c-dark-muted); }
  .calc__total .n {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: var(--text-3);
    color: var(--c-save-on-dark);
    font-variant-numeric: tabular-nums;
  }
  /* When we cost more, the figure is not a saving and is not green. */
  .calc__total--more .n { color: var(--c-dark-muted); }
  .calc__note { margin-top: var(--sp-2); font-size: 0.72rem; color: var(--c-dark-muted); }

  /* Two bars on one scale: the larger figure is 100%. Widths set by site.js. */
  .calc__bars { margin-top: var(--sp-3); display: grid; gap: var(--sp-1); }
  .calc__bar { display: grid; gap: 0.25rem; font-size: var(--text--1); color: var(--c-dark-muted); }
  .calc__bar-track { display: block; height: 0.6rem; border-radius: 999px; background: var(--c-dark-panel); overflow: hidden; }
  .calc__bar-fill { display: block; height: 100%; width: 0; border-radius: 999px; }
  .calc__bar-fill--them { background: var(--c-bar-them); }
  .calc__bar-fill--us { background: var(--c-bar-us); }

  /* ---------- depth on the dark surfaces --------------------
     A glow and a masked grid behind the content. The glow percentage
     is capped by contrast: every text colour on these surfaces must
     pass 4.5:1 against the LIGHTEST point of the glow, not --c-dark.
     Measured 17 Sep 2026 from rendered pixels: the owner's 55% put
     --c-dark-muted at 3.81:1, 40% at 4.49:1, 35% at 4.73:1 (the worst of
     four pages and the calculator, at 360 and 1280 wide). Raise it and
     re-measure. */
  .band--dark, .calc { position: relative; isolation: isolate; overflow: hidden; }
  .band--dark::before, .calc::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -2;
    pointer-events: none;
    background: radial-gradient(60% 70% at 82% 12%,
      color-mix(in oklab, var(--c-glow) 35%, transparent) 0%, transparent 68%);
  }
  .band--dark::after, .calc::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    /* The fade used to be a mask-image, which forces a composited layer -- and
       above the fold on the dark hero that was the expensive part of the band.
       Same picture, no mask: a vignette painted in the band's OWN colour sits
       on top of the lattice and closes it toward the edges. First layer wins in
       `background`, so the vignette is listed first. Both surfaces that use
       this (.band--dark and .calc) are --c-dark, so it blends exactly. */
    background:
      radial-gradient(90% 80% at 50% 30%, transparent 20%, var(--c-dark) 78%),
      linear-gradient(to right, color-mix(in oklab, var(--c-grid) 4%, transparent) 1px, transparent 1px),
      linear-gradient(to bottom, color-mix(in oklab, var(--c-grid) 4%, transparent) 1px, transparent 1px);
    background-size: 100% 100%, 44px 44px, 44px 44px;
  }
  /* "prefers-contrast: reduce" is not a value the query accepts, so it would
     never match. "more" is the setting a reader who needs contrast turns on. */
  @media (prefers-contrast: more) {
    .band--dark::before, .band--dark::after,
    .calc::before, .calc::after,
    .feature::before { display: none; }
  }

  /* ---------- the report: what the free report looks like ----
     The ONE place an invented business appears, and only because it is
     labelled Example (owner, 17 Sep 2026). Never reuse without the label. */
  .report {
    background: var(--c-dark);
    color: var(--c-dark-ink);
    border: 1px solid var(--c-dark-line);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-2);
    overflow: hidden;
  }
  .report__head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-3);
    background: var(--c-dark-panel);
    border-bottom: 1px solid var(--c-dark-line);
    font-family: var(--font-display);
    font-weight: 600;
  }
  /* On a light band the report IS the dark object. On a dark band it was
     --c-dark on --c-dark and dissolved, hairline and all -- so it takes the
     panel value, and its head takes a tint DERIVED from that panel so the
     two still separate. */
  /* A card on a dark band takes the panel value, or it is a white slab on a
     dark ground. Same three boxes, same on-dark tokens, no new colours. */
  .band--dark .card,
  .band--dark .price,
  .band--dark .feature {
    background: var(--c-dark-panel);
    border-color: var(--c-dark-line);
  }
  .band--dark .feature { border-left-color: var(--c-brand-on-dark); }
  .band--dark .card--tint { background: color-mix(in oklab, var(--c-dark-panel) 70%, var(--c-dark) 30%); }

  .band--dark .report { background: var(--c-dark-panel); }
  .band--dark .report__head {
    background: color-mix(in oklab, var(--c-dark-panel) 86%, var(--c-dark-ink) 14%);
  }
  .report__rows { list-style: none; margin: 0; padding: 0; }
  .report__row {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 0.15rem var(--sp-2);
    padding: 0.75rem var(--sp-3);
    border-bottom: 1px solid var(--c-dark-line);
  }
  .report__check { font-size: var(--text--1); font-weight: 600; }
  .report__finding { grid-column: 1; font-size: var(--text--1); color: var(--c-dark-muted); }
  .report__row .pill { grid-column: 2; grid-row: 1 / span 2; align-self: center; }
  .report__foot { padding: var(--sp-3); display: grid; gap: var(--sp-1); }
  .report__math { font-family: var(--font-mono); font-size: 0.72rem; color: var(--c-dark-muted); }
  .report__figure {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: var(--text-3);
    line-height: var(--lh-tight);
    color: var(--c-brand-on-dark);
    font-variant-numeric: tabular-nums;
  }
  .pill {
    display: inline-block;
    font-family: var(--font-mono);
    font-size: 0.66rem;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    white-space: nowrap;
    padding: 0.2rem 0.5rem;
    border-radius: 999px;
    border: 1px solid currentColor;
    color: var(--c-dark-muted);
  }
  .pill--leak  { color: var(--c-leak); }
  .pill--watch { color: var(--c-watch); }
  .pill--ok    { color: var(--c-ok); }
  .pill--example { color: var(--c-brand-on-dark); }

  /* ---------- the hero report runs a scan ------------------
     On load the rows resolve top to bottom, 180ms apart, and the leak figure
     lands last. The visitor watches a business being audited and understands
     what we sell before reading a word. ~1.2s end to end.

     NO OPACITY ANYWHERE IN HERE, and that is not a style preference: ancestor
     opacity multiplies into the effective text colour, axe measures the
     effective colour, and a 0.35 resting opacity put --c-ink at 2.22:1 and
     cost 4 a11y points the last time it was tried. frontend-craft, Motion.
     Every row is fully visible and readable at every moment of this. The
     motion is a 6px slide, plus each chip settling from --c-dark-muted -- the
     neutral the .pill base class ALREADY defaults to, not an invented colour
     -- into the one its modifier gives it.

     THE FINISHED REPORT IS THE BASE STYLE. These animations only deviate from
     it, and `backwards` holds the from-state through the delay. So if the
     animation never runs -- reduced motion, an old browser, a screenshot, the
     social preview -- the reader gets the completed report, not a half-drawn
     one. Nothing here is the resting state of anything.

     Time-based, iteration count 1: it runs ONCE on load. Deliberately NOT
     `animation-timeline: view()`, which is what the rest of this file uses --
     that re-triggers every time the hero scrolls back into view, and a
     permanently moving hero is a thing people scroll away from. */
  @media (prefers-reduced-motion: no-preference) {
    .report__row,
    .report__foot  { animation: report-settle var(--dur) var(--ease) backwards; }
    .report__row .pill { animation: report-chip var(--dur) var(--ease) backwards; }
    .report__row:nth-child(1),
    .report__row:nth-child(1) .pill { animation-delay: 180ms; }
    .report__row:nth-child(2),
    .report__row:nth-child(2) .pill { animation-delay: 360ms; }
    .report__row:nth-child(3),
    .report__row:nth-child(3) .pill { animation-delay: 540ms; }
    .report__row:nth-child(4),
    .report__row:nth-child(4) .pill { animation-delay: 720ms; }
    .report__row:nth-child(5),
    .report__row:nth-child(5) .pill { animation-delay: 900ms; }
    .report__foot { animation-delay: 1080ms; }
  }
  @keyframes report-settle { from { transform: translateY(6px); } }
  @keyframes report-chip   { from { color: var(--c-dark-muted); } }

  /* ---------- comparison table ----------------------------- */
  .compare { border-collapse: collapse; width: 100%; min-width: 36rem; }
  .compare caption {
    text-align: left;
    color: var(--c-muted);
    font-size: var(--text--1);
    padding-bottom: var(--sp-2);
  }
  .compare th, .compare td {
    text-align: left;
    padding: 0.8rem 1rem;
    border-bottom: 1px solid var(--c-line);
  }
  .compare thead th {
    font-family: var(--font-mono);
    font-size: 0.68rem;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--c-muted);
  }
  .compare tbody th { font-family: var(--font-body); font-weight: 500; font-size: var(--text--1); }
  .compare td { font-size: var(--text--1); font-variant-numeric: tabular-nums; }
  .compare .us { background: var(--c-brand-soft); font-weight: 600; color: var(--c-ink); }
  .compare .them { color: var(--c-cost); }
  .compare tbody tr:last-child th,
  .compare tbody tr:last-child td { border-bottom: 0; }

  /* ---------- pricing -------------------------------------- */
  /* .price takes the shared box above; only what differs lives here. */
  /* Only the recommended tier lifts. Lifting all three would
     flatten the hierarchy and recommend nothing. */
  /* The card title takes whichever heading level the page's outline needs
     -- h2 on /pricing/, where the h1 above it is the section heading, and h3
     elsewhere under a section h2. It renders identically either way, so the
     level is a document-structure decision and not a visual one. Added
     17 Sep 2026: /pricing/ was the one page of 22 still failing
     heading-order after the footer fix, on an h1 -> h3 skip. */
  .price h2, .price h3 { font-size: var(--text-1); }
  .price--featured { border-color: var(--c-brand); box-shadow: var(--shadow-2); }
  .price__amount {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: var(--text-3);
    font-variant-numeric: tabular-nums;
  }
  .price__amount small { font-size: var(--text--1); font-weight: 500; color: var(--c-muted); }
  .price ul { list-style: none; padding: 0; display: grid; gap: 0.4rem; }
  .price li { font-size: var(--text--1); padding-left: 1.4rem; position: relative; }
  .price li::before {
    content: "";
    position: absolute;
    left: 0; top: 0.55em;
    width: 0.5rem; height: 0.28rem;
    border-left: 2px solid var(--c-save);
    border-bottom: 2px solid var(--c-save);
    transform: rotate(-45deg);
  }

  /* ---------- forms ---------------------------------------- */
  .field { display: grid; gap: 0.35rem; }
  .field > label { font-size: var(--text--1); font-weight: 500; }
  .field > .hint { font-size: 0.78rem; color: var(--c-muted); }
  .field input, .field select, .field textarea {
    font: inherit;
    font-size: var(--text--1);
    padding: 0.7rem 0.8rem;
    color: var(--c-ink);
    background: var(--c-surface);
    border: 1px solid var(--c-line);
    border-radius: var(--radius-sm);
  }
  .field textarea { min-height: 5.5rem; resize: vertical; }

  /* ---------- on a dark band --------------------------------
     Added 17 Sep 2026 when the homepage hero became .band--dark. A white
     input and a --c-dark card both stopped working the moment the ground
     under them changed. Every value below is an existing on-dark token, or
     a mix derived from one -- no new colours. */
  .band--dark .field > .hint { color: var(--c-dark-muted); }
  .band--dark .field input,
  .band--dark .field select,
  .band--dark .field textarea {
    color: var(--c-dark-ink);
    background: var(--c-dark-panel);
    border-color: var(--c-dark-line);
  }
  .band--dark .field input::placeholder,
  .band--dark .field textarea::placeholder { color: var(--c-dark-muted); }
  .field [aria-invalid="true"] { border-color: var(--c-cost); }
  .field .error { font-size: 0.78rem; color: var(--c-cost); }

  /* Consent. Not a dark pattern: unticked by default, and the
     label says exactly what it permits. */
  .consent {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--sp-2);
    align-items: start;
    background: var(--c-surface-2);
    border-radius: var(--radius-sm);
    padding: var(--sp-2);
  }
  .consent input { margin-top: 0.25rem; accent-color: var(--c-brand); }
  .consent label { font-size: 0.82rem; color: var(--c-muted); }

  /* Honeypot. Never displayed, never announced. */
  .hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

  .form-status { font-size: var(--text--1); min-height: 1.5em; }
  .form-status[data-state="error"] { color: var(--c-cost); }
  .form-status[data-state="ok"] { color: var(--c-save); }

  /* ---------- app screenshot frame ------------------------- */
  .shot {
    border: 1px solid var(--c-line);
    border-radius: var(--radius-lg);
    overflow: hidden;
    background: var(--c-surface-2);
    box-shadow: var(--shadow-2);
  }
  .shot__bar {
    display: flex;
    gap: 0.35rem;
    padding: 0.6rem 0.8rem;
    border-bottom: 1px solid var(--c-line);
    background: var(--c-surface);
  }
  .shot__bar span {
    width: 0.55rem; height: 0.55rem;
    border-radius: 999px;
    background: var(--c-line);
  }

  /* .placeholder was removed 17 Sep 2026 with the last [[PLACEHOLDER]].
     The class rendered a dashed "fact we do not have" box, which is the right
     idea in a draft and was wrong on a live site for weeks. If you need one
     again while drafting, add it back locally -- do not ship it. */

  /* ---------- accordion — <details>, no JS ----------------- */
  .faq { display: grid; gap: var(--sp-1); }
  .faq details {
    background: var(--c-surface);
    border: 1px solid var(--c-line);
    border-radius: var(--radius-sm);
    padding: 0.8rem 1rem;
  }
  .faq summary {
    cursor: pointer;
    font-weight: 500;
    font-size: var(--text-0);
    list-style: none;
    display: flex;
    justify-content: space-between;
    gap: var(--sp-2);
  }
  .faq summary::-webkit-details-marker { display: none; }
  .faq summary::after { content: "+"; font-family: var(--font-mono); color: var(--c-brand); }
  .faq details[open] summary::after { content: "\2212"; }
  .faq details > p {
    margin-top: var(--sp-2);
    font-size: var(--text--1);
    color: var(--c-muted);
    max-width: var(--measure);
  }

  /* ---------- footer --------------------------------------- */
  .site-footer {
    background: var(--c-surface-2);
    border-top: 1px solid var(--c-line);
    color: var(--c-muted);
    padding-block: var(--sp-6) var(--sp-4);
    font-size: var(--text--1);
  }
  .site-footer a { color: var(--c-muted); text-decoration: none; }
  .site-footer a:hover { color: var(--c-ink); }
  /* h2, not h4: these are top-level groupings inside the footer
     landmark, and an h4 with no h3 above it failed Lighthouse's
     heading-order on all 22 pages. The explicit size and weight
     below keep the rendering identical to the h4 it replaced. */
  .site-footer h2 {
    color: var(--c-ink);
    margin-top: 0;
    font-family: var(--font-mono);
    font-size: 0.68rem;
    font-weight: 500;
    letter-spacing: var(--track-label);
    text-transform: uppercase;
    margin-bottom: var(--sp-2);
  }
  .site-footer ul { list-style: none; padding: 0; display: grid; gap: 0.4rem; }
  .nap { color: var(--c-ink); font-style: normal; line-height: 1.8; }
  .site-footer__legal {
    margin-top: var(--sp-5);
    padding-top: var(--sp-3);
    border-top: 1px solid var(--c-line);
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2) var(--sp-3);
    justify-content: space-between;
  }
}
