/* KB4 Home Page
   Forethought widget + sitewide side-panel docking now live in
   css-page-forethought.css instead (moved out since most of that panel
   behavior applies on every page, not just this one, and it's easier to
   iterate on together in its own file). Header-search-on-the-home-page
   overrides now live in css-page-header.css instead, alongside the rest
   of the header's own styles.

   Below: Brand Refresh Phase 2's `.kb-*` component styles (see
   docs/brand-refresh/plan.md), followed by an older, pre-refresh
   home-page section (search/hero/wave/callout-banner) that hasn't been
   reconciled with the new styles yet -- flagging that some of it may
   duplicate/conflict with style.css rather than silently touching it. */

/* =====================================================================
   Brand Refresh Phase 2 -- Homepage rebuild (isolated)
   New `.kb-*` classes built on the Codex token tier in css-brand-tokens.css
   (assets/css-brand-tokens.css). Deliberately NOT sharing .card/
   .card-grid (assets/css-components.css) -- those also back
   category_page.hbs and section_page.hbs, and this phase must stay
   isolated from the rest of the theme per docs/brand-refresh/plan.md.
   Spacing reuses the theme's existing fluid --space-* scale
   (css-root.css) rather than introducing fixed px values from the
   Figma export. Interactive elements below keep the sitewide
   `*:focus-visible` rule in css-reset.css rather than declaring their own
   outline; since that rule's default colour became --form-focus-ring
   sitewide (2026-10-02) the cards no longer override it at all, and only
   pin --outline-offset through the custom-property hooks it reads.
   ===================================================================== */

/* ---- Hero ---- */
/* Overrides style.css's shared `.hero` (padding/place-items/text-align
   center) for the homepage only -- the new left-aligned hero layout is
   specific to this page; other pages using `.hero` keep the original
   centered treatment. */

/* THE HOME PAGE'S CORNER GRADIENTS ARE GONE FROM HERE, and the page is not
   losing them -- they are sitewide now, on <main>, in css-reset.css. Joy,
   2026-10-25: "this is something that should be placed as a global setting,
   rather than page by page." This page and the search results page were the only
   two that had them, and both local copies came out in the same commit so
   nothing double-paints.

   WHAT WAS HERE: `body .home-page`, carrying the same two radial glows the
   global rule now has verbatim -- 52.44% x 56.77% at 100% 100% and
   52.44% x 56.76% at 0% 0%, --page-bg-corner to --page-bg-corner-transparent, as
   background-image longhands over the flat --page-bg-middle base on <html>.

   THE BOX MOVED from the hero wrapper <div> to <main>, its parent, and that is
   the only substantive change: on desktop the two are the same height, because
   the <div> wraps the hero and #page-container (home_page.hbs:13) and the only
   thing <main> adds is .back-to-top-wrapper, which is position: absolute here.
   Below 45em that wrapper is in flow and pulls itself up into #page-container's
   bottom margin, so it adds close to nothing there either. The glows are sized
   as a percentage of their positioning area, which is why the box is worth
   naming at all.

   THREE FINDINGS FROM THIS RULE'S HISTORY ARE STILL LIVE and the global rule
   depends on all three, so they are kept here rather than lost with the code:

     1. NOT THE ROOT. It looks tidier and it is wrong. On <html> the background
        box is either the whole document, which scales the glows with page length
        and hides the lower one behind the opaque footer band, or -- with
        background-attachment: fixed -- the viewport, which holds their size but
        concentrates them enough that the upper one reads through as a tint under
        the header and makes the flat #faffff header band look like it fails to
        match. Both were tried on 2026-10-19 and rejected.
     2. ONE BOX ONLY. `home-page` is on two elements: <html> (home_page.hbs:9,
        for the html.home-page rules in this file, css-page-forethought.css and
        css-page-header.css) and the wrapper <div>. Before 2026-10-19 this
        background sat in the bare `.home-page` block below, matched both and
        painted twice -- two copies measured against different boxes, meeting as
        a hard vertical seam 26rem from the right edge when the Forethought panel
        docked and narrowed one of them. The global rule names <main> directly,
        so it cannot repeat this, but a second wash added anywhere can.
     3. LONGHANDS, NOT THE `background` SHORTHAND, and a token rather than the
        `transparent` keyword for the outer stop. The shorthand resets
        background-color, which would force the rule to restate the flat base
        <html> already owns. And fading to `transparent` is fading to
        rgba(0,0,0,0), so the ramp dips through grey on the way out, where
        --page-bg-corner-transparent is the same colour at zero alpha. The stops
        were tokenised on 2026-10-20 for dark mode: the dark homepage frame
        (6501:3224) binds the same two Figma variables, resolving to #1e2a35 and
        #1e2a3500, so the old literals had kept a pale mint wash in the corners
        of a slate page.

   The `.home-page` block below is untouched and stays unscoped: its ~40 nested
   selectors resolve at their current specificity and several are in live
   specificity fights across files (see css-page-header.css:643), so qualifying
   that block would raise every one of them by an element. */

.home-page {
  text-align: start;

  .hero {
    padding: var(--space-2xl-3xl) 0;
    place-items: center;
    text-align: start;
    display: flex;
  }

  .hero-inner {
    /* Was `min(60ch, 100vw - 2rem)`. This is the width .hero has to state by
       hand because `display: flex` above dropped the grid placement that would
       otherwise have centred it in the content column (css-components.css:2543).
       Pinned to rem on 2026-10-25: `ch` is typeface-dependent, so the Inter swap
       stretched this text column from 549px to 605px and it is the widening Joy
       saw on the home-page banner. 34.3rem is the Open Sans value.
       css-utilities.css:750 has the full account. */
    width: min(34.3rem, 100vw - 2rem);
    display: inline-flex;
    flex-direction: column;
  }

  .home-search .hero {
    padding: 0;
    place-items: normal;
  }

  .kb-hero-heading {
    display: flex;
    align-items: center;
    gap: var(--space-2xs);
  }

  .kb-hero-heading .fa-hand-wave {
    color: var(--brand-icon);
  }

  .kb-hero-heading p {
    font-family: var(--ff-logo);
    font-weight: var(--font-bold);
    color: var(--neutral-text);
  }

  .kb-hero-title {
    font-family: var(--ff-logo);
    font-weight: var(--font-bold);
    color: var(--neutral-text);
    line-height: var(--leading-heading-9);
    font-size: var(--step-9);
    margin-block: var(--space-s);
  }

  /* ---- Info banner ---- */
  /* This is Codex's Message at severity=info, and its colour layer was already
     right. The shadow was the one value that wasn't: `--shadow-dropdown` is a
     legacy `css-root.css` literal (`0 4px 6px rgba(0,0,0,.1)`) with no dark
     tier, so dark mode got a flat black smudge. Codex's Message carries
     `shadow/regular`, measured on the Components frame as a 2px-offset 6px
     blur below the bottom border -- which is what our own primitives already
     assemble to, dark tier included. Two other files still reference
     `--shadow-dropdown`; they go with the `css-root.css` consolidation. */
  .kb-banner {
    display: flex;
    align-items: flex-start;
    gap: var(--space-s);
    width: 100%;
    padding: var(--space-s);
    background-color: var(--info-bg);
    border: 1px solid var(--info-border);
    border-radius: var(--radius-sm);
    box-shadow: 0 var(--shadow-y-offset) var(--shadow-blur) 0
      var(--shadow-regular);
    color: var(--info-text);

    /* THERE IS NO DARK RULE HERE ANY MORE, and the absence is the whole
       treatment: every colour above is an `--info-*` role reference and each of
       those has a dark tier, so dark mode is already correct with nothing
       stated.

       WHAT WAS HERE until 2026-10-29 was Codex's STRONG emphasis -- three
       declarations, `--info-bg-strong`, `--info-border-strong` and
       `--fixed-white` -- matching what the `callout-*` classes did in dark. Joy
       reversed both in the same breath: her team asked for regular emphasis
       sitewide, and when told this banner is not a `callout-*` class and so had
       not followed the callouts, "No you need to change the home page as well."
       The Callouts section of css-components.css carries the full measurement
       set; this banner is info, so it reads the note/support row.

       THIS BANNER IS WHERE THAT WHOLE THREAD STARTED. Joy flagged its dark
       version on accessibility, strong emphasis was the designed answer, and the
       numbers say the reversal does not undo that fix: the ink goes from
       --fixed-white at 7.88:1 to --info-text at 7.57:1, AAA either way, on a
       panel whose own severity is still carried by an icon at 5.49:1.

       WHAT DOES CHANGE IS HOW LOUD THE PANEL IS. Against the dark page wash
       (--page-bg-middle #10171e) the regular fill sits at 1.34:1 where the
       strong fill sat at 2.29:1, and the border drops from 4.97:1 to 2.29:1.
       Neither is a 1.4.11 failure -- the icon and the text convey the message
       and both pass -- but this banner is the most prominent thing on the page
       and it will read considerably quieter. That is regular emphasis, and it is
       Codex's own; it is not a regression to be fixed by bending a role token,
       which is the mistake the --info-text note in css-brand-tokens.css records
       being made here once already. */
  }

  .kb-banner-icon {
    color: var(--info-icon);
    font-size: var(--step-5);
    flex-shrink: 0;

    /* NO DARK RULE HERE EITHER, for the same reason as `.kb-banner` above:
       --info-icon has a dark tier (#44b1d9), which is 5.49:1 on the regular
       fill and clears the 3:1 non-text threshold comfortably. It replaced a
       `--fixed-white` override that existed only to serve the strong panel.

       The icon stays a bare glyph rather than Codex's round chip, and that is
       still a live decision rather than a leftover -- the chip belongs to strong
       emphasis, regular has none, and it was independently rejected on
       2026-10-25 because a chip is 2em where a glyph is 1em and it threw the
       alignment of anything with a resized icon. The Callouts section of
       css-components.css keeps that record. */
  }

  .kb-banner-content {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: var(--space-3xs);
  }

  .kb-banner-title {
    font-weight: var(--font-bold);
    font-size: var(--step-1);
    line-height: var(--leading-body-1);
  }

  .kb-banner-text {
    font-size: var(--step-0);
    line-height: var(--leading-body-0);
  }

  /* ---- Section headings (shared by the sections below) ---- */
  .kb-section-title {
    font-family: var(--ff-logo);
    font-weight: var(--font-bold);
    color: var(--neutral-text);
    font-size: var(--step-4);
    line-height: var(--leading-heading-4);
    margin-block-end: var(--space-m);
  }

  /* Trims the half-leading above/below every brand heading so the surrounding
     `gap`/margin is the only thing setting its spacing. Progressive enhancement;
     block containers only, which is why .kb-badge (inline-flex) isn't here. */
  @supports (text-box: trim-both cap alphabetic) {
    .kb-hero-title,
    .kb-section-title,
    .kb-topic-card-title,
    .kb-update-card-title,
    .kb-help-card-title {
      text-box: trim-both cap alphabetic;
    }
  }

  /* ---- Browse by topic ---- */
  .kb-topic-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
    gap: var(--space-s);
  }

  .kb-topic-card,
  .kb-update-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    padding: var(--space-s);
    color: var(--neutral-text);
    border: var(--border-width-regular) solid var(--neutral-border-soft);
    border-radius: var(--radius-md);
    background-color: var(--neutral-bg);
    box-shadow: 0 var(--shadow-y-offset) var(--shadow-blur) 0
      var(--shadow-regular);
    text-decoration: none;
    text-align: start;
    align-items: flex-start;
  }

  /* Interactive/hover treatment applies to both -- .kb-topic-card and
   .kb-update-card are each a single whole-card <a> (both in home_page.hbs --
   .kb-update-card comes from the tmpl-recent-articles micro-template, which
   moved there from footer.hbs on 2026-10-19), so a pointer cursor and hover
   lift are accurate for both. */
  .kb-topic-card,
  .kb-update-card {
    transition: all 200ms ease-in-out;
    will-change: transform;
    backface-visibility: hidden;
    cursor: pointer;
  }

  /* .kb-topic-card is the direct grid item, so the grid's default
   align-items: stretch already gives it a full-row height for free.
   .kb-update-card is nested one level inside its grid item (the <li> in
   kb-updates-grid), so it needs an explicit height to pick up that same
   stretched height -- otherwise it only sizes to its own content and cards
   in the same row end up different heights. */
  .kb-update-card {
    height: 100%;
  }

  .kb-topic-card:hover,
  .kb-update-card:hover {
    border-color: var(--neutral-border);
    box-shadow: 0 var(--shadow-y-offset-hover) var(--shadow-blur-hover) 0
      var(--shadow-hover);
  }

  /* Shadow goes to none, not back to the resting 2px/6px -- that's Codex's
     active spec (.kb-button-regular:active), and it makes press the inverse of
     the hover lift instead of just an undo of it. The border darkening is ours;
     Codex has no border change here, but on a card the shadow alone is a weak
     cue at this size. */
  .kb-topic-card:active,
  .kb-update-card:active {
    border-color: var(--neutral-border-strong);
    box-shadow: none;
  }

  /* Codex's focus-visible treatment, read out of the inspector. Despite the
     token's name, --form-focus-ring is Codex's universal focus color, not a
     form-only one -- their rule's selector list covers a, button, input,
     select, textarea and the [role=] equivalents alongside bare
     :focus-visible.

     Note what focus deliberately does NOT do: it drops the shadow rather than
     lifting it the way :hover does. Focus is a "you are here" marker, not a
     hover stand-in, so the two states stay visually distinguishable when a
     card is both hovered and focused. `transition: none` is Codex's too -- the
     ring appears instantly instead of easing in over the card's 200ms.

     Colour is no longer set here. It used to be, back when css-reset.css's
     sitewide --outline-color was still salmon; that default became
     --form-focus-ring on 2026-10-02, so pinning it again here would just be a
     second copy of the same token to keep in sync. --outline-width is already
     2px there too. --outline-offset is the one that still needs overriding,
     because the reset falls back to max(2px, 0.15em), which lands just over
     2px at the card's font size where Codex uses a flat 2px.
     Note the reset's companion `border` never reaches these cards -- they
     declare their own border above at higher specificity, so there's no
     second line to cancel the way the skip link has to.

     Ordered after :hover/:active on purpose. All three are (0,3,0), so source
     order is what makes the focus ring win on a card that's both hovered and
     focused -- that's why Codex needs `box-shadow: none !important` here and
     we don't. */
  .kb-topic-card:focus-visible,
  .kb-update-card:focus-visible {
    --outline-offset: 2px;
    box-shadow: none;
    transition: none;
  }

  /* Color cycles by rendered position, not by category identity -- categories
   are a moving target (see docs/brand-refresh/plan.md), so this uses
   :nth-child on the actual DOM order instead of a Handlebars index/modulo
   (the theme's templating layer has no arithmetic helper for that). Cards
   1-3 in each group of 6 stay the default neutral styling above; 4-6 cycle
   through deep-teal(info)/indigo/aubergine, then the pattern repeats for any
   further categories. Exact bg/border pairs per Joy's Figma spec: category 4
   reuses the semantic --info-* role tokens; 5 and 6 reference --color-* /
   --chart-sequential-* directly since there's no semantic role for those
   hues. Border-width/radius/shadow are shared with the base rule above (same
   for every category, only bg/border color varies here). */
  /* Dark mode, added 2026-10-20 against the dark home frame (6501:3224).
     Category 4 needs nothing: --info-bg/--info-border are semantic roles and
     already flip to #023249/#08577c, which is exactly what the frame renders
     (sampled off the frame's own pixels, and the same four info values the
     Dark.tokens.json port produced independently).

     5 and 6 are the case plan.md:263 warned about. They reference primitives,
     and a primitive is one colour in both themes by definition -- so the pale
     --color-indigo-0-5 / --color-aubergine-0-5 fills stayed pale on a slate
     page. The dark pairs have to be stated, and they are stated *here*, nested
     against each light rule, rather than as new --topic-card-* semantic tokens
     in css-brand-tokens.css. Two reasons: there is still no semantic role for
     these hues (the note above says as much, and inventing one would add names
     the Codex export does not have), and a hue that is only decided in one
     place reads better as one block than as two files that must agree.

     `:root[data-theme='dark'] &` and not a plain nested selector -- :root has to
     stay at the front, and these rules are already inside `.home-page`, so a
     non-& form would compile to `.home-page :root[...]` and match nothing.

     The border values were measured, not guessed. Figma's variable dump lists
     the hues bound in the frame but not which property each lands on, and the
     candidates were adjacent palette steps. So the pixels were solved instead:
     both card borders render as a 1px line anti-aliased across two pixels
     between the page (#10171e) and the card fill, and un-blending that pair
     gives #8d78d7 and #d77795 -- within 1-2 per channel of --color-indigo-6
     (#8c77d5) and --color-aubergine-6 (#d97797), and ~13 off the next step
     either side, so the step is unambiguous.

     Which makes the aubergine border identical in both themes, and it is
     deliberately not restated below: --color-aubergine-6 is already the light
     value, and a restated no-op is just somewhere for the two to drift apart.
     Indigo does change, because its light border is
     --chart-sequential-indigo-6 -- and that token has a dark tier of its own
     (#523f8e), so leaving it would not have been a no-op but a wrong value.

     Hover, added 2026-10-21. Joy: the coloured cards had no hover response in
     dark mode. Two things stack up to produce that, and both matter:

     First, the shared `:hover` rule above sets border-color: --neutral-border,
     but it never reaches cards 4-6. Every rule in this block sets
     border-color too, at the same (0,2,0) and *later* in the file -- and the
     dark nested blocks are higher still, since [data-theme] adds a component.
     So a coloured card keeps its resting border when hovered, in both themes.
     Do not "fix" that by moving these rules above :hover: the hover border
     would then win and a coloured card would go grey-bordered on hover.

     Second, that leaves the box-shadow as the coloured cards' only hover cue,
     and in dark the shadow does nothing. --shadow-hover is #10171e66 there,
     near-black at 40% over a #10171e page. In light it is #10171e1a on white
     and reads fine, which is why only dark looked dead.

     So each coloured card gets its own dark hover border, one palette step
     brighter than its resting one. Border-only on purpose: that is exactly
     what the neutral cards 1-3 do in dark (--neutral-border-soft #2e3e4e ->
     --neutral-border #3f5467), so the coloured cards now respond in the same
     kind and roughly the same magnitude rather than growing a fill change the
     neutrals don't have. Card 4 reaches for --color-deep-teal-10 rather than
     staying semantic with --info-border-strong (#2390bc): that token is two
     steps up and would make card 4 jump noticeably harder than 5 and 6.

     Light mode is deliberately untouched -- the shadow carries hover there and
     Joy signed that off. If the coloured cards ever want a light hover border
     too, it belongs here as a non-nested declaration, not as a change to the
     shared rule above. */
  .kb-topic-card:nth-child(6n + 4) {
    background-color: var(--info-bg);
    border-color: var(--info-border);

    :root[data-theme='dark'] &:hover {
      border-color: var(--color-deep-teal-10);
    }
  }

  .kb-topic-card:nth-child(6n + 5) {
    background-color: var(--color-indigo-0-5);
    border-color: var(--chart-sequential-indigo-6);

    :root[data-theme='dark'] & {
      background-color: var(--color-indigo-13-brand);
      border-color: var(--color-indigo-6);
    }

    :root[data-theme='dark'] &:hover {
      border-color: var(--color-indigo-5);
    }
  }

  .kb-topic-card:nth-child(6n) {
    background-color: var(--color-aubergine-0-5);
    border-color: var(--color-aubergine-6);

    :root[data-theme='dark'] & {
      background-color: var(--color-aubergine-13-5-brand);
    }

    :root[data-theme='dark'] &:hover {
      border-color: var(--color-aubergine-5);
    }
  }

  .kb-topic-card-title {
    font-family: var(--ff-logo);
    font-weight: var(--font-bold);
    font-size: var(--step-2);
    line-height: var(--leading-heading-2);
    color: var(--neutral-text);
  }

  .kb-topic-card-desc {
    font-family: var(--brand-font-family-sans);
    font-size: var(--step-0);
    line-height: var(--leading-body-0);
    color: var(--neutral-text);
    flex: 1;
  }

  /* Shared with .kb-update-card-link in the Recent updates section below.
     Both are the same thing -- a bold label plus a chevron, as the whole
     card's "this navigates" affordance -- and the update card took this
     wording and treatment on 2026-10-21 when its date row was removed (Joy:
     "just have it say View Article with the right chevron, similar to the
     category card"). One rule rather than two near-copies, so they can't
     drift. The update card's one genuine difference, margin-top: auto, is
     stated on its own down there. */
  .kb-topic-card-link,
  .kb-update-card-link {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    font-family: var(--brand-font-family-sans);
    font-weight: var(--font-bold);
    font-size: var(--step-0);
    line-height: var(--leading-control);
    color: var(--neutral-text);
  }

  /* Shared with :focus-visible, not only :hover. The card's focus ring says
     "you are here"; the underline says "this navigates" -- two different
     messages, and a keyboard user needs the second one as much as a mouse user
     does. Only the content-level cues are shared this way: the container's
     shadow lift stays hover-only, because it's redundant with the ring for
     "you are here" and muddies it visually (see the :focus-visible rule above,
     which drops the shadow for exactly that reason).

     :is() takes the specificity of its highest argument, and :hover and
     :focus-visible are both (0,1,0), so this selector stays (0,3,0) -- the
     source-order relationships the card's own state rules depend on are
     unchanged. */
  .kb-topic-card:is(:hover, :focus-visible) .kb-topic-card-link,
  .kb-update-card:is(:hover, :focus-visible) .kb-update-card-link {
    text-decoration: underline;
  }

  /* ---- Recent updates ---- */
  /* The home page's own copy of this grid. The .kb-updates-grid rule in
     css-components.css is nested in html.category-page, html.section-page,
     html.requests-page, html.new-request-page and html.article-page -- the
     home page is not one of them, so Recent updates is styled here on this
     page and there on the other two that render it.

     `gap` was --space-m until 2026-10-29, pairing a wider gap with
     .kb-topic-grid's --space-s above. Joy ended that: "on the recent updates
     cards on every page we are using the wrong gap on the grid -- it should be
     the same as for the topic cards." Both copies moved in the same change.

     THE TRACKS NOW MATCH TOO, as of 2026-10-29. Joy: "We need to change the
     recent updates to be the same as the category and section cards." This was
     a plain `auto-fit, minmax(17rem, 1fr)`, so a wide monitor got four or five
     cards to a row on the home page while the other two pages held exactly
     three, and a short row here was shared out between whatever cards there
     were instead of sitting in thirds. It is now a copy of the
     css-components.css rule, auto-fill and all.

     THESE TWO RULES ARE NOW LINE-FOR-LINE IDENTICAL AND MUST STAY THAT WAY.
     They cannot share one declaration: the css-components.css copy is nested
     inside those five html.*-page selectors, and widening that list to include
     the home page would drag the whole block's ~18 selectors onto this page at
     (0,2,1) -- above everything in this file -- which would silently kill the
     home page's .kb-badge--0 .. --3 colour cycle, among other things. So the
     duplication is deliberate and the cross-reference is the safeguard: change
     one, change the other.

     The reasoning behind the track math -- why auto-fill rather than auto-fit,
     why the minimum is a third of the row rather than a flat 17rem, and why
     the `- 1px` is not a fudge -- is written once, on the .kb-updates-grid
     rule in css-components.css. Read it there before touching any of these
     three values. */
  .kb-updates-grid {
    --kb-updates-col-min: max(
      17rem,
      calc((100% - 2 * var(--space-s)) / 3 - 1px)
    );
    display: grid;
    grid-template-columns: repeat(
      auto-fill,
      minmax(var(--kb-updates-col-min), 1fr)
    );
    gap: var(--space-s);
  }

  /* Padding and line-height are the Codex Badge measured 1:1 -- 4px/6px and
     line-height 1. That is the same pair [class*='badge-'] in
     css-components.css already carries, next to the measurement note that
     recorded it; our badge happens to match that attribute selector (the
     modifier class contains the substring `badge-`) and was overriding it with
     different numbers.

     Both are FLAT on purpose. The inline padding used to be var(--space-2xs),
     which is a fluid clamp, so it grew to 12px at desktop against 2px of block
     padding and read as lopsided -- and a component's insides stay off the
     --space-* scale regardless, only page flow rides it.

     line-height 1 on --step--1 gives a ~12.6px text box, which with the 1px
     border that .kb-badge--0 .. --3 add comes to ~22.6px against the 22px Codex
     ships -- the half pixel is our fluid type step, not a different spec.

     .kb-badge in css-components.css has these same two declarations. Keep the
     two in step.

     white-space is declared here only to stop an accident. [class*='badge-']
     sets nowrap, and this badge matches that selector because the modifier class
     contains the substring `badge-` -- but the category page's plain .kb-badge
     does not match it, so the two pages disagreed on wrapping by coincidence of
     naming rather than by decision. They both wrap now rather than both
     nowrapping: the narrowest this card ever gets is the 3-up crossover, where
     its inner width is about 224px, and a badge measured on this page already
     ran to 218px. nowrap there is six pixels from pushing the text out of the
     card, and a category name longer than the one measured would do it. */
  .kb-badge {
    display: inline-flex;
    align-items: center;
    align-self: flex-start;
    padding: 0.25rem 0.375rem;
    border-radius: var(--radius-sm);
    font-size: var(--step--1);
    font-weight: var(--font-bold);
    text-decoration: none;
    line-height: 1;
    white-space: normal;
  }

  .kb-update-card-title {
    font-family: var(--ff-logo);
    font-weight: var(--font-bold);
    font-size: var(--step-1);
    line-height: var(--leading-heading-1);
    color: var(--neutral-text);
  }

  /* Everything else this link needs is up with .kb-topic-card-link, including
     the hover/focus underline. Two things are its own:

     margin-top: auto -- the update cards are stretched to a common row height
     (see .kb-update-card's height: 100% above), so this pushes the link to the
     bottom edge and keeps the links level across a row however many lines the
     titles above them wrap to. The topic cards need no equivalent, their
     description fills the slack instead.

     font-size -- Joy's call, 2026-10-21: keep the --step--1 the date row used
     rather than inheriting the topic card's --step-0. The update cards carry a
     category badge and a title above this, so the link is the third thing in
     the stack and reads better staying quieter than the topic card's, where it
     is the only bold line under the description. Weight stays bold, shared. */
  .kb-update-card-link {
    margin-top: auto;
    font-size: var(--step--1);
  }

  /* Badge color is keyed to the article's category, not to where its card
   lands in the grid -- so a given category keeps the same tag color no
   matter which 3 recent articles happen to be showing or in what order.
   Specifically: the tmpl-recent-articles template in home_page.hbs reads
   category.position (Zendesk's own admin-configured category order -- the
   same ordering "Browse by topic" renders in) and sets kb-badge--n:
   position 0-2 (categories 1-3) -> --0 (neutral), position 3-5
   (categories 4-6) -> --1/--2/--3 (deep-teal/indigo/aubergine). We initially
   tried deriving this from the category's index in the `categories` array
   instead of reading .position directly, but the array this JS template
   receives is a different fetch than the one Handlebars uses for "Browse by
   topic" -- more categories, different order -- so array index didn't
   correspond to the same "position" at all (confirmed via a live debug
   render). .position is intrinsic to the category object itself, so it's
   reliable regardless of which array/order it arrived in; it also required
   adding "position" to the data-properties allow-list on the mount div in
   home_page.hbs, since it wasn't being fetched before. Any category past the
   6th (or with no position) falls back to --0/neutral rather than recycling
   into a color, since Joy confirmed this mapping is meant to be fixed per
   category identity, not a repeating pattern (KB4 is converging on exactly 6
   categories; the >6 case is just a safety net until then).

   Exact border/bg/text per Joy's Figma spec, one per category -- deliberately
   punchier than the matching topic card (darker bg + fixed-white text rather
   than the card's pale bg + role text color) so the tag reads clearly at
   badge size. --0 is the exception: it mirrors its card exactly (border/bg/
   text all identical to the neutral card treatment) since "no color" doesn't
   have a punchier variant to reach for. */
  .kb-badge--0 {
    border: var(--border-width-regular) solid var(--neutral-border-soft);
    background-color: var(--neutral-bg);
    color: var(--neutral-text);
  }

  .kb-badge--1 {
    border: var(--border-width-regular) solid var(--color-deep-teal-13-5-brand);
    background-color: var(--color-deep-teal-9);
    color: var(--fixed-white);
  }

  .kb-badge--2 {
    border: var(--border-width-regular) solid var(--color-indigo-13-brand);
    background-color: var(--color-indigo-9);
    color: var(--fixed-white);
  }

  .kb-badge--3 {
    border: var(--border-width-regular) solid var(--color-aubergine-13-5-brand);
    background-color: var(--color-aubergine-9);
    color: var(--fixed-white);
  }

  /* ---- Need more help? ---- */
  .kb-help-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
    gap: var(--space-s);
  }

  .kb-help-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    padding: var(--space-s);
    color: var(--neutral-text);
    border: var(--border-width-regular) solid var(--neutral-border-soft);
    border-radius: var(--radius-md);
    background-color: var(--neutral-bg);
    box-shadow: 0 var(--shadow-y-offset) var(--shadow-blur) 0
      var(--shadow-regular);
    text-decoration: none;
    transition: all 200ms ease-in-out;
    will-change: transform;
    backface-visibility: hidden;
    cursor: pointer;
    align-items: start;
  }

  .kb-help-card:hover {
    border-color: var(--neutral-border);
    box-shadow: 0 var(--shadow-y-offset-hover) var(--shadow-blur-hover) 0
      var(--shadow-hover);
  }

  /* Same inverse-of-hover press as .kb-topic-card/.kb-update-card above. */
  .kb-help-card:active {
    border-color: var(--neutral-border-strong);
    box-shadow: none;
  }

  /* Same focus treatment as .kb-topic-card/.kb-update-card above -- see the
     longer note there for why the colour is left to css-reset.css's sitewide
     default, why the offset still needs pinning, and why focus drops the shadow
     rather than lifting it. */
  .kb-help-card:focus-visible {
    --outline-offset: 2px;
    box-shadow: none;
    transition: none;
  }

  /* Fixed rem rather than the fluid --space- / --step- scales: this is a
     decorative chip whose size is the mockup's, and the circle has to stay a
     circle, so it doesn't scale the way type and spacing do. aspect-ratio is
     belt-and-braces -- it only matters if the explicit height ever comes off. */
  .kb-icon-graphic {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    /* Both chip and arrow opt out of shrinking now that a flexible title shares
       their row -- a narrow card would otherwise squash the circle into an oval
       and clip the arrow's 1em window before the title wrapped. */
    flex-shrink: 0;
    width: 3.75rem;
    height: 3.75rem;
    aspect-ratio: 1 / 1;
    border: var(--border-width-regular) solid var(--neutral-border-alpha-strong);
    border-radius: var(--radius-round);
    background-color: var(--brand-bg);
    color: var(--fixed-white);
  }

  /* 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.875rem;
  }

  /* Icon chip, title and external-link arrow all share the top row as of
     2026-10-21 -- the title used to sit below this row, and the layout Joy asked
     for puts it inline between the other two.
     The explicit width is required: .kb-help-card sets align-items: start, so
     without it this row shrinks to its own content and the arrow has nothing to
     be pushed away from. The title carries `flex: 1` (below) rather than this
     row carrying `justify-content: space-between`, which is what held the
     two-item version apart: with three items, space-between would distribute
     free space *between* them and leave the title floating mid-row instead of
     sitting against the chip.
     `center`, not `flex-start`: the chip is 3.75rem and a one-line title is
     nowhere near that tall, so top-aligning them reads as the title having
     fallen to the top of the card. Centring is also what the reference layout
     shows against its own two-line heading block. */
  .kb-help-card-top {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    width: 100%;
  }

  /* Two stacked copies of the arrow in a 1em box clipped by overflow: hidden.
     On hover or keyboard focus the resting copy exits top-right while the second
     arrives from bottom-left, so the arrow reads as being replaced rather than
     drifting away.
     Both copies travel the same delta -- the incoming one just starts offset by
     it. That's a direct read of the Figma export, where `translate` is relative
     to each layer's own position, which is why both of its keyframes ran
     0 -> (30px, -30px).

     Rebuilt as a transition rather than the exported `animation`: a one-shot
     keyframe plays once and snaps back when the pointer leaves, where a
     transition reverses cleanly.

     The hover color is the export's own (#10171E = --neutral-icon-strong). The
     resting color is --neutral-icon-soft rather than the export's #384649
     (= --neutral-icon), so the arrow starts lighter and the hover shift is a
     bigger jump than Figma showed -- Joy's call after seeing it in preview. */
  .kb-help-card-arrow {
    --kb-arrow-travel: 30px;
    display: grid;
    place-items: center;
    overflow: hidden;
    flex-shrink: 0;
    width: 1em;
    height: 1em;
    font-size: var(--step-4);
    color: var(--neutral-icon-soft);
    transition: color 200ms linear;
  }

  .kb-help-card-arrow svg {
    grid-area: 1 / 1;
  }

  .kb-help-card-arrow .kb-arrow-in {
    translate: calc(var(--kb-arrow-travel) * -1) var(--kb-arrow-travel);
  }

  /* Paired with :focus-visible like the two underline cues above -- on this card
     the arrow is the affordance, so a keyboard user shouldn't be the only one
     who never sees it move. */
  .kb-help-card:is(:hover, :focus-visible) .kb-help-card-arrow {
    color: var(--neutral-icon-strong);
  }

  /* Motion is opt-in, matching css-reset.css/css-search.css. With it off the
     incoming copy simply stays parked outside the clip and only the color
     changes -- no extra rules needed to hide it. */
  @media (prefers-reduced-motion: no-preference) {
    .kb-help-card-arrow svg {
      transition: translate 200ms linear;
    }

    .kb-help-card:is(:hover, :focus-visible) .kb-arrow-out {
      translate: var(--kb-arrow-travel) calc(var(--kb-arrow-travel) * -1);
    }

    .kb-help-card:is(:hover, :focus-visible) .kb-arrow-in {
      translate: 0 0;
    }
  }

  /* `flex: 1` is what keeps the arrow at the far end of the row: the title takes
     all the free space, so there is none left to distribute. It also means a long
     title wraps inside its own box instead of pushing the arrow out of the card.
     Still a block container, not flex, even though it is now a flex *item* --
     being an item doesn't change its inner display, and block is what the
     text-box trim above needs (the same reason .kb-badge can't be trimmed). */
  .kb-help-card-title {
    flex: 1;
    font-family: var(--ff-logo);
    font-weight: var(--font-bold);
    font-size: var(--step-2);
    line-height: var(--leading-heading-2);
    color: var(--neutral-text);
  }

  .kb-help-card-desc {
    font-family: var(--brand-font-family-sans);
    font-size: var(--step-0);
    line-height: var(--leading-body-0);
    color: var(--neutral-text-soft);
  }

  /* SECTION Home Page */
  /* The pre-refresh search treatment, and the block home_page.hbs:5 calls
     "unreconciled". Its geometry is almost entirely overridden now -- the hero
     placeholder by `html.home-page #ft-search-spacer .search-wrapper input`
     (css-page-forethought.css:197, which carries an id and so wins outright) and
     the mobile header row by `.mobile-navbar .home-search input`
     (css-page-header.css:449, which is (0,3,1) against this block's (0,2,1)).
     What was *not* overridden was the colour, because the rules above it only
     set the properties they mean to change. So this block was still handing out
     the old salmon on a page where nothing else is salmon any more, and three of
     its four colours were literals that no theme could move.

     Recoloured 2026-10-20, geometry deliberately untouched -- the 2px border,
     0.25rem radius and 1rem/3rem padding are all dead under the overrides above,
     and re-deriving them from the frame is the hero-search geometry question,
     not this one.

     The states now match the decisions already documented at
     css-page-header.css:489 and :501 for the same field one breakpoint up,
     rather than being decided again here: hover moves the fill only (Codex's
     .kb-input-text:hover does not touch the border), and the border darkens to
     --form-border-active on focus alone, so the two states stay distinct.

     `outline: none` is gone, and that is a fix rather than a tidy-up. At (0,3,1)
     it beat the sitewide `*:focus-visible` ring (0,1,0) outright, so the mobile
     header search field had no focus ring at all -- but only on the home page,
     since this block needs a .home-page ancestor. css-page-header.css:509 sets
     `--outline-offset: 2px` for that very field, i.e. the rule one file over was
     already written expecting a ring this was suppressing. The salmon
     box-shadow that stood in for it goes with it; the ring is the cue.

     `.search-field` has no consumer anywhere in templates/ -- kept and tokenised
     rather than deleted only so that a dead selector cannot come back carrying a
     light-mode-only literal. */
  .home-page {
    .search-field {
      background-color: var(--form-bg);
      display: block !important;
    }
    .search-wrapper {
      position: relative;
      display: block !important;
    }

    .home-search {
      position: relative;
      width: 100%;
      z-index: 2;
      margin-block-start: 0.5rem;
    }

    .home-search input {
      border: 2px solid var(--form-border);
      border-radius: 0.25rem;
      padding: 1rem 3rem;
      width: 100%;
      transition:
        border-color 300ms,
        background-color 300ms;

      &:hover {
        background-color: var(--form-bg-hover);
      }

      &:focus {
        border-color: var(--form-border-active);
        background-color: var(--form-bg-active);
      }
    }
  }

  .hero-heading {
    .fa-flip-horizontal {
      margin-right: 1rem;
      svg {
        height: 1.5rem;
      }
    }
    h1 {
      display: inline;
    }
  }
  .hero-heading {
    display: inline;
  }

  @media screen and (max-width: 44.9em) {
    .hero-inner {
      padding-left: 1rem;
      padding-right: 1rem;
    }

    .hero-heading {
      gap: 0.5rem;
      svg {
        height: 1.25rem;
      }
    }
  }

  .wave {
    animation-name: wave-animation; /* Refers to the name of your @keyframes element below */
    animation-duration: 2s; /* Change to speed up or slow down */
    animation-iteration-count: infinite; /* Never stop waving :) */
    transform-origin: bottom-left; /* Pivot around the bottom-left palm */
    animation-delay: 250ms;
    display: inline-block;
  }

  @keyframes wave-animation {
    0% {
      transform: rotate(20deg);
    }
    10% {
      transform: rotate(4deg);
    } /* The following five values can be played with to make the waving more or less extreme */
    20% {
      transform: rotate(26deg);
    }
    30% {
      transform: rotate(4deg);
    }
    40% {
      transform: rotate(24deg);
    }
    50% {
      transform: rotate(4deg);
    }
    60% {
      transform: rotate(16deg);
    } /* Reset for the last half to pause */
    100% {
      transform: rotate(16deg);
    }
  }

  /* !Section - Home Hero */

  /* SECTION - Home Main */
  /* `.callout-banner.home` was deleted here on 2026-10-25. No markup on this
     page -- or anywhere in templates/ -- carried both classes; `.kb-banner`
     above replaced it, and the rule was still overriding --fg/--bg/--accent
     back to legacy plum primitives plus a --hover that no longer exists
     anywhere. Nothing on the page changed by removing it. */
  /* !Section - Home Main */
}
