/* SECTION - Error Page
   Rebuilt 2026-10-21 against Figma frame 6633:5604 ("layout 404"), replacing
   the two-column text-beside-artwork layout this file used to describe.

   The frame is 1440x390 and everything in it is centred in one column, so the
   whole page is three nested flex columns whose only job is to carry the three
   gaps the frame draws. Those gaps are the reason the --space- tokens below
   look arbitrary: the fluid scale tops out at exactly the frame's numbers at
   its own 1440px width (--space-3xs = 6px, --space-xs = 18px, --space-s =
   24px), so taking tokens here is both faithful at 1440 and fluid below it.

   Colours are all Codex semantic roles with dark counterparts already in
   css-brand-tokens.css, so this page needs no dark-specific rule. **Joy
   verified dark mode on 2026-10-21 and signed it off, hover included** -- so
   this file having no [data-theme='dark'] block in it is the finished state,
   not an omission.

   Worth recording what carries the button's hover in dark, because an earlier
   note here got it wrong. In dark the lift does very little: --shadow-hover is
   #10171e66, the page's own near-black at 40%, falling on a wash that is
   #172029 at the top and transparent below it. But the button never relied on
   the shadow -- it steps --neutral-bg-component (#2e3e4e) to
   --neutral-bg-component-hover (#3f5467), which is a far wider step than the
   light pair's #deebec -> #d4e2e4, and it keeps its border. That surface step
   *is* Codex's dark hover for a neutral component; the shadow is a light-mode
   affordance. Joy's words: "applying our codex styles."

   This is NOT the home-page card situation (c0eb7ca), and the two should not be
   conflated. Those cards sat directly on --page-bg-middle, so #10171e at 40%
   over #10171e was literally invisible -- and their per-colour rules overrode
   the shared hover border, which left the shadow as the only cue they had. This
   button overrides nothing and has both a border and a fill step. The card fix
   landed on the same conclusion from the other direction: it gave them a border
   step because that is "exactly what the neutral cards 1-3 do in dark
   (#2e3e4e -> #3f5467)" -- the same pair this button already had. */

/* SECTION - Page layout
   Added 2026-10-21 (Joy: "the footer needs to be at the bottom of the page
   with the 404 message centre aligned").

   This is the one template short enough for the page to be shorter than the
   window, so it is the one template that needs a sticky footer. Without this
   the footer ends wherever the content ends -- around 500px down a 1080px
   window -- with a band of empty page background below it, and the 404 message
   sits at the top rather than in the middle of the space it has.

   Scoped to `html.error-page` and NOT applied sitewide, which is the whole
   point: <body> and <main> are shared by every template, and the last time
   something was declared on <body> for one page's benefit
   (`place-items: center`) it took the footer band off the window edges above
   ~2279px and cost two wrong diagnoses to find. The exact same scoped
   sticky-footer pattern already exists for the custom product pages at
   css-page-custom.css:23 -- for a different reason (their content is all
   position:fixed, so <main> collapses to 0) but with the same shape, so this
   is a second instance of an established idiom rather than a new one.

   Three things were checked before touching <body>, since all three would
   have been silent regressions:

   - **The header does not move.** <header> carries `block-flow--sm`, i.e.
     `margin-block-start: min(2rem, 4vh)` (css-utilities.css:618), and turning
     a parent into a flex container stops its children's margins collapsing
     out of it. That margin is already inside <body> though: `overflow-x:
     hidden` (style.css) makes overflow-y compute to `auto`, which establishes
     a block formatting context, which already prevents the collapse. So the
     ~32px above the header is there today and is unchanged.
   - **No sibling margins un-collapse.** <header>, <main> and .footer-wrapper
     are the three in-flow children; main and the footer wrapper declare no
     block margins at all (the footer's old `margin-block-end` was deleted on
     2026-10-19), so there is no adjacent pair to collapse in the first place.
   - **Nothing shrink-wraps.** `align-items` is left at its default `stretch`
     rather than being set to `center` the way css-page-custom.css:34 does.
     All three children declare `width: 100%` so the two resolve identically
     today, but `stretch` is the one that stays correct if a future child
     doesn't -- which is precisely how the `place-items` bug worked. */
html.error-page body {
  display: flex;
  flex-direction: column;
  /* css-reset.css:125 puts `padding-bottom: 3rem` on every page. With
     `min-height: 100svh` and border-box that is 48px of page background below
     the footer, i.e. the gap this task is about -- the footer would stop short
     of the window bottom even once it is pushed down. Zeroed here only.
     Note it was never protecting against the Forethought launcher either:
     that is position:fixed and floats over the footer regardless. */
  padding-bottom: 0;
}

/* `1 0 auto`, matching css-page-custom.css:38: grow to absorb the leftover
   window height, but never shrink -- if the content is ever taller than the
   window (a long translation, a narrow phone) main keeps its natural height
   and the page scrolls, rather than being squashed to fit. */
html.error-page main {
  display: flex;
  flex-direction: column;
  flex: 1 0 auto;
}

/* The chain that carries main's new height down to the band, so the wash can
   fill it and the message can centre in it. main is a flex column, so this
   grows; #page-container is .grid-content, i.e. a grid whose single implicit
   row is `auto`, and `align-content` on a grid defaults to `normal` which
   behaves as `stretch` -- so that row absorbs the extra height and .error
   stretches with it. Nothing in .grid-content sets align-content; if anything
   ever does, this is the link that breaks.

   margin-block-end is style.css:69's sitewide 5rem. Harmless when the content
   sits at the top of the page, but with the band centred it is 80px of
   asymmetry -- it would push the message up off centre by half of it and
   leave a gap the wash fades out before reaching. (1,1,0) here against
   (1,0,0) there, so this wins on specificity and does not depend on style.css
   being injected after every <link>, which it is.) */
html.error-page #page-container {
  flex: 1 0 auto;
  margin-block-end: 0;
}
/* !SECTION - Page layout */

/* THIS PAGE IS THE ONE EXCLUSION FROM THE SITEWIDE CORNER GLOWS. css-reset.css
   paints Codex's two --page-bg-corner radials on `html:not(.error-page) main`,
   and the `:not()` is there for the wash below: this page has its own
   deliberate, differently-shaped treatment, built to its own Figma frame and
   signed off on 2026-10-21. Corner glows under it would show through at the
   bottom of the band, where this wash has already faded out. If that exclusion
   is ever lifted, it is this rule that has to be reconciled with it. */
.error-page {
  /* The frame fills this band with a wash that runs edge to edge, which is why
     the <section> is a `full-width` grid item rather than sitting in the
     content column. 33.42%/99.28% and the colour are the frame's own; the
     179.77deg it draws is 180deg, i.e. the CSS default, so the angle is
     omitted.

     The frame's second stop is #faffff at zero alpha -- the page background,
     not this wash -- but gradient interpolation is premultiplied, so fading
     --neutral-bg-soft to `transparent` is the same ramp without needing a
     paired -transparent token that Codex doesn't define. (--page-bg-corner-
     transparent, which the sitewide corner glows use, is a real Codex token;
     there is no neutral/bg-soft-transparent to match it.)

     The band is as tall as whatever the sticky-footer chain above leaves it,
     not the frame's 390px, so the wash now starts under the header's bottom
     edge and fades out around four-fifths of the way down the gap to the
     footer. At 1440x900 that is close to the frame; on a tall window it is a
     longer fade, which is the right way for a one-stop vertical wash to
     stretch.

     align-items centres the column in that height -- this is the "404 message
     centre aligned" half of the task, and it only has anything to centre
     because of the chain above. justify-content was already doing the
     horizontal half.

     padding-block is --space-3xl, which resolves to 96px at 1440 against the
     frame's 103. It is no longer what positions the content, since centring
     does that; it is now a floor, so that on a window too short to centre in
     (or once the content is taller than the band) the message still keeps its
     breathing room instead of butting against the header and footer. Chasing
     the last 7px would mean hardcoding a value off the scale on the one axis
     where this page should stay fluid -- same call as the header's 75-vs-72.
     padding-inline is --gap-sm because that is grid-content's own gutter, so
     the column lands where every other band's content does. */
  .error {
    display: flex;
    justify-content: center;
    align-items: center;
    padding-block: var(--space-3xl);
    padding-inline: var(--gap-sm);
    background-image: linear-gradient(
      var(--neutral-bg-soft) 33.42%,
      transparent 99.28%
    );
  }

  /* Frame 6638:6540 -- the content block and the button, 24px apart. */
  .kb-error-inner {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-s);
    max-width: 30rem;
    text-align: center;
  }

  /* Frame 6633:5605 -- the graphic chip above the two lines of text, 18px. */
  .kb-error-content {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-xs);
  }

  /* Frame 6633:6499 -- heading over body copy, 6px.
     No `text-box: trim-both` here, unlike the home page's brand headings: the
     6px is measured between full line boxes in the frame, so trimming the
     half-leading away would close the gap tighter than drawn. */
  .kb-error-text {
    display: flex;
    flex-direction: column;
    gap: var(--space-3xs);
  }

  /* Codex `heading/sm`: Sora SemiBold at font/size/xl (20px, which --step-3
     resolves to) with no tracking -- the old h1 carried a -0.075rem
     letter-spacing that the frame does not draw.

     --leading-body-0 is 1.4, which is the leading heading/sm itself specifies.
     The name says body because that is where 1.4 lives on this theme's scale;
     the heading scale's nearest step is --leading-heading-3 at 1.3. Taking the
     frame's value rather than the better-named token because the 6px gap above
     is measured against this line box. */
  .kb-error-title {
    font-family: var(--ff-logo);
    font-size: var(--step-3);
    font-weight: var(--font-bold);
    line-height: var(--leading-body-0);
    color: var(--neutral-text);
  }

  /* Codex `body/regular/base`, same three declarations as
     .kb-topic-card-desc on the home page, in --neutral-text-soft rather than
     --neutral-text. `balance` so that once the line is too long for the 30rem
     column it breaks into two even lines instead of one long and one short. */
  .kb-error-desc {
    font-family: var(--brand-font-family-sans);
    font-size: var(--step-0);
    line-height: var(--leading-body-0);
    color: var(--neutral-text-soft);
    text-wrap: balance;
  }

  /* Codex `graphic`, size sm / severity neutral / emphasis regular -- the
     48px neutral counterpart to the home page's 60px branded chip. Fixed rem
     rather than the fluid scales for the same reason that one gives: the size
     is the mockup's and a circle has to stay a circle, so it does not scale
     with type. aspect-ratio is belt-and-braces, for if the explicit height
     ever comes off.

     Note the border is --neutral-border-alpha where the home chip takes
     -alpha-strong; that is the frame's own distinction between the two
     emphases, not drift. */
  .kb-icon-graphic {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 3rem;
    height: 3rem;
    aspect-ratio: 1 / 1;
    border: var(--border-width-regular) solid var(--neutral-border-alpha);
    border-radius: var(--radius-round);
    background-color: var(--neutral-bg-component);
    color: var(--neutral-icon);
  }

  /* svg, not i -- the Font Awesome kit JS replaces the <i> with an <svg>, so
     an `i` selector matches nothing once the page has rendered. */
  .kb-icon-graphic svg {
    font-size: 1.5rem;
  }

  /* Codex `button-md`, emphasis regular, with a leading arrow-left.
     Deliberately NOT .btn: that is the brand coral primary, and overriding its
     --bg/--fg/--border-* to reach a neutral pill would leave this fighting
     .btn:hover and .btn:active for the fills (css-buttons.css:15 warns about
     exactly that). As of 2026-10-24 .btn also carries Codex's brand gradient as
     a `background-image`, which paints above whatever background-color a
     neutral override sets -- so the gap between the two treatments is wider
     now, not narrower, and `--bg-image: none` would be a third thing to
     restate.

     This is the third copy of Codex's regular-button treatment in the theme --
     .back-to-top-link (css-components.css) and the header's locale chip
     (css-page-header.css) are the other two. All three are page- or
     component-scoped on purpose; .btn is Codex's *strong* button and these are
     its regular one, so extracting one shared .kb-button-regular is still the
     button migration's job (docs/brand-refresh/plan.md), not this file's.

     No width: the frame's 178px is 16 + 14 + 8 + label + 16, i.e. entirely
     content-driven, so pinning it would clip a longer translation. */
  .kb-error-home {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    block-size: 2.5rem;
    padding-inline: 1rem;
    border: var(--border-width-regular) solid var(--neutral-border-alpha-strong);
    border-radius: var(--radius-round);
    background-color: var(--neutral-bg-component);
    box-shadow: 0 var(--shadow-y-offset) var(--shadow-blur) 0
      var(--shadow-regular);
    color: var(--neutral-text);
    font-family: var(--ff-logo);
    font-size: var(--step-0);
    font-weight: var(--font-bold);
    line-height: var(--leading-control);
    text-decoration: none;
    transition:
      background-color 200ms ease-in-out,
      box-shadow 200ms ease-in-out;
  }

  /* The glyph is --neutral-icon-strong in the frame while the label is
     --neutral-text. Those are the same hex in both themes, but they are
     separate roles, so each is stated where it belongs. */
  .kb-error-home svg {
    font-size: 0.875rem;
    color: var(--neutral-icon-strong);
  }

  /* Hover and press are Codex's own, the same pair .back-to-top-link took:
     a background step plus a taller, softer shadow for the lift, and a press
     that drops the shadow outright so it reads as the exact inverse. */
  .kb-error-home:hover {
    background-color: var(--neutral-bg-component-hover);
    box-shadow: 0 var(--shadow-y-offset-hover) var(--shadow-blur-hover) 0
      var(--shadow-hover);
  }

  .kb-error-home:active {
    background-color: var(--neutral-bg-component-active);
    box-shadow: none;
  }

  /* Colour is left to css-reset.css's sitewide --form-focus-ring; the frame's
     own focus effect is the legacy salmon #f69581, which the 2026-10-02 ring
     recolour deliberately replaced. Only the offset needs pinning, and the
     shadow has to drop so a focused button is not also lifted.
     Ordered after :hover/:active because all three are (0,2,0) -- source order
     is what keeps the ring on a button that is hovered and focused at once. */
  .kb-error-home:focus-visible {
    --outline-offset: 2px;
    box-shadow: none;
    transition: none;
  }
}
/* !SECTION - Error Page */
