/* SECTION - General Styles */
body {
  /* THE DOCUMENT'S BASE SIZE, and until 2026-10-25 nothing set one. No
     `font-size` existed on <html> or <body> anywhere in the theme, so the base
     was the browser's default 16px -- a value from outside our type scale that
     every unconverted run of text was quietly sitting on. Converted pages pin
     --step-0 (14.00-14.22px) themselves, so the two coexisted 11% apart and Joy
     reported it off the request list and the single-request page: "I noticed the
     font shrank a little." Nothing had shrunk; those pages had joined the scale
     and the rest of the document never had.

     --step-1, not --step-0. This is deliberately almost a no-op on screen --
     --step-1 is 15.751px at a 320px viewport and 15.997px at 1440, so against
     the old flat 16px the shift is -0.249px at its largest (the NARROW end, not
     the wide one) and -0.003px on a desktop. The point is
     structural: the base now comes from our scale instead of from the UA, which
     is what lets `article_page` inherit a defined prose size rather than pinning
     one. --step-0 was the other candidate and is wrong here: it would have
     shrunk every unpinned run by 11%, which is the direction Joy had already
     called too small.

     THE CONVENTION THIS SETS: <body> is the PROSE base, and UI chrome opts
     *down* to --step-0 explicitly. That is already how the theme behaves -- the
     converted chrome all pins --step-0 -- so this names the existing split
     rather than changing it. Article prose and anything else that pins nothing
     lands on --step-1 for free. --step--1 stays the floor (css-root.css:128);
     don't size text below it.

     Does not touch the layout widths restored in 3e798e4. Every --step-* is a
     `clamp()` of rem + vi, and `rem` resolves against <html>, not <body>, so a
     size here cannot feed back into them -- which is the whole reason those
     widths went to rem rather than em.

     Does reach form controls, though it changes nothing for them today:
     css-reset.css:380 already gives input, button, textarea and select
     `font-size: inherit`, so they were following <body> rather than the UA's
     ~13.3px before this and simply keep doing so. The part that matters for
     `new_request_page` is that whatever is set here is what its fields render
     at -- they have no size of their own to fall back on.

     Accessibility, since this is the question that prompted it: WCAG specifies
     NO minimum font size -- there is no such success criterion. What applies is
     1.4.4 Resize Text and 1.4.12 Text Spacing, and both still pass, because this
     is a rem-based clamp rather than a px pin and so continues to scale with the
     reader's own base-size setting. (`text-size-adjust: none` at
     css-reset.css:115 only suppresses mobile auto-inflation; it does not block
     user zoom or user font settings.) */
  font-size: var(--step-1);
  line-height: 1.5;
  /* THE DOCUMENT'S FAMILY, and it was still Open Sans until 2026-10-25. Joy
     found it on the single-request page: "The request_page is still using Open
     Sans as the font instead of Inter. I think it's still referring to our :root
     file." It was, exactly -- this read `var(--ff-primary)`, which css-root.css
     defines as `'Open Sans', system-ui, sans-serif`.

     THIS IS THE SIBLING OF THE BUG ALREADY FIXED ON THE NEXT LINE, and that is
     the useful part. On 2026-10-20 the `color` here was migrated off
     --clr-neutral-160 for precisely this reason -- anything that does not name
     its own value inherits from this rule, so one stale declaration here
     mis-paints most of the page. The family was left behind in that same pass.
     Both declarations had the same defect and only one got fixed, which is why
     the symptom came back five days later wearing a different hat.

     Why it hid for so long: twenty-three refreshed components pin
     --brand-font-family-sans themselves, so every part of the theme that had
     been through a round was already Inter and looked right. The pages that
     still read Open Sans are the ones whose CSS pins no family at all --
     css-page-request.css has ZERO `font-family` declarations in it, which is why
     the single-request page is where Joy saw it.

     --brand-font-family-sans, not --font-family-secondary. Both are Inter;
     Codex's own token carries no fallbacks, where this one is
     `'Inter', Verdana, sans-serif`. It is also the token the other 23 sites
     already use, so this makes the inherited family the same object as the
     pinned one rather than a second spelling of it.

     Codex backs Inter for body copy: in the Semantic Scales file every
     `body/*` type style binds `font/family/secondary` (Inter) and only
     `heading/*` binds `font/family/primary` (Sora).

     NOTHING SURVIVES THIS -- --ff-primary now has no live reference in the
     theme. Two sites pinned it explicitly and so would not have inherited the
     new family: the search field and the paginator digits, both on the search
     results page. Both pins were deleted in the same commit. Neither was a real
     exception; they only looked deliberate because the document's family was
     --ff-primary too, so the pin and the inherited value were the same face and
     the pin changed nothing. Left standing they would have become the only Open
     Sans on the site -- an Inter page with one Open Sans input in it. The note
     at css-page-search-results.css:1784 has the full history, including the
     reasoning that wrongly called the digits deliberate.

     AND THE LAST TWO TRACES ARE GONE TOO, 2026-10-28. This note used to end by
     saying css-root.css:82 still defined --ff-primary and document_head.hbs
     still downloaded Open Sans from Google Fonts, that the definition would go
     with the css-root.css consolidation, and that the download was held back on
     purpose because Zendesk article authors can specify a family inline in
     content this theme cannot see. Joy overruled both: "let's get rid of Open
     Sans everywhere--including Google Fonts request."

     So --ff-primary no longer exists (css-root.css:81 has its epitaph) and the
     face is not requested. The author risk the old paragraph described is still
     real but it is now a content problem, not a stylesheet one: an article body
     whose inline style says `font-family: 'Open Sans'` falls through to the next
     name it lists. If that ever turns up, the fix is an @font-face block
     aliasing the name onto Inter, not restoring a 100KB download for every
     visitor on every page -- document_head.hbs has that note next to the
     request. */
  font-family: var(--brand-font-family-sans);
  /* The document's ink, and the only place it is set -- migrated off
     --clr-neutral-160 (#333333) on 2026-10-20 so it follows [data-theme].
     This one declaration was why the dark theme looked half-finished. Anything
     that doesn't name its own colour inherits from here, which is most of the
     page: the hero <h1>, every article body (.article-content sets no colour of
     its own), card copy, list text. All of it stayed #333333 in dark mode --
     dark grey on a dark background. The hero heading is simply the biggest and
     so the one that got reported.
     Note for anyone who looks for this on <html> instead: it cannot live there.
     A declaration on <body> wins over an inherited value, so whatever <html>
     says is overridden the moment this rule exists (css-reset.css:81 has a note
     to the same effect).
     Light mode is not unaffected -- this is #10171e rather than #333333 now,
     the brand's ink, slightly darker and slightly higher contrast sitewide.
     That is the intended value, not a side effect, but it is a visible change
     outside dark mode and worth knowing when diffing screenshots.
     Surfaces that stay light in dark mode have to opt out of this, since they
     would otherwise get white ink on a white fill. The ones that still exist
     are listed and pinned at the end of css-utilities.css. */
  color: var(--neutral-text);
  min-height: 100svh;
  /* No `place-items: center` here. It was removed 2026-10-21; do not restore it.
     It was written for a <body> that was expected to be a grid container and
     never became one, so it read as inert -- but Chrome implements Box Alignment
     for block-level boxes, and the `justify-items: center` half of it therefore
     made every in-flow child of <body> that does not declare a width shrink to
     fit its own max-content and centre in what was left. <main> and the header
     were already immune by declaring `width: 100%` for unrelated reasons; the
     footer band was not, so above ~2279px viewport it detached from the window
     edges and its background and border-top stopped short with an even gutter
     either side (reported 2026-10-21 at 2545px; the band measured 2278.75px at
     left 133). The declaration had no upside left: `align-items` does not apply
     to a block container at all, and the only boxes it was still centring were
     three empty zero-width divs. Every Forethought box at this level is
     `absolute` or `fixed`, so none of them were ever subject to it.
     The one place it was NOT inert is the custom product pages, where
     css-page-custom.css:23 makes <body> a flex column -- there it was doing real
     cross-axis centring, so that file now declares `align-items: center`
     itself rather than inheriting it from here. Those pages would have been
     unaffected either way, because both of their in-flow children declare
     `width: 100%` and so resolve identically under `align-items: stretch`.
     Check them explicitly after any future change here; plan.md:167 explains
     why they are the template most likely to diverge.
     `overflow-x: hidden` stays, and is now the only thing containing the
     Forethought widget's own ~32px of horizontal overflow. */
  overflow-x: hidden;

  /* ---- Sticky footer, sitewide ----
     Joy, 2026-10-23: "the footer needs to be situated to the bottom of the page
     even when the content doesn't fill it out." Reported against a section page
     holding two articles, where the footer ended two-thirds of the way down the
     window with page background below it.

     THIS IS THE THIRD COPY OF THIS PATTERN AND THE FIRST GLOBAL ONE.
     css-page-custom.css:23 and css-page-error.css:76 already scope exactly
     these declarations to `html.product-page` and `html.error-page`, for the
     same reason in a more extreme form -- on those pages <main> collapses to
     0 height, so the footer rode up under the header. Every other template has
     the milder version of the same bug whenever its content is shorter than the
     window: the category and section pages, search results with two hits, an
     empty requests list. So this belongs on <body>, not on a fourth scope.
     The two page-scoped copies are left alone rather than deleted -- they are
     now redundant, but the custom pages also set `align-items: center` and
     `min-height: 100vh` in the same rule, and untangling that is its own
     change. Deleting them is a cleanup, not part of this fix.

     `align-items` IS LEFT AT ITS DEFAULT `stretch`, deliberately, and this is
     the one line to be careful about in this rule. <header>, <main> and
     .footer-wrapper all declare `width: 100%`, so stretch and center resolve
     identically today -- but the `place-items: center` bug described above is
     precisely what happens when a child that does *not* declare a width meets
     a centring alignment on this element. Stretch stays correct for a future
     child; center silently shrink-wraps it. Do not "tidy" this by adding an
     alignment here.

     Nothing un-collapses that was collapsing. Making <body> a flex container
     stops its children's margins collapsing out of it, but `overflow-x: hidden`
     above already made overflow-y compute to `auto`, which establishes a block
     formatting context, which already prevented that -- so the ~32px above the
     header from `block-flow--sm` is there today and is unchanged. And of the
     three in-flow children, main and .footer-wrapper declare no block margins
     at all, so there is no adjacent pair to collapse either.

     The Forethought boxes at this level are all `absolute` or `fixed` (see the
     place-items note above), so none of them become flex items taking a share
     of the column. */
  display: flex;
  flex-direction: column;

  /* css-reset.css:99 puts `padding-bottom: 3rem` on every page. With
     `min-height: 100svh` and border-box, that is 48px of body background
     *below* the footer -- which is the gap in Joy's screenshot, and it would
     survive the flex column above: the footer gets pushed to the bottom of the
     content box, and the padding sits under it. So it has to go for the footer
     to reach the window edge.
     Zeroed here rather than deleted at source because that declaration is in
     the reset, which also covers the two templates that already zero it
     themselves; one override beside the rule that needs it is easier to follow
     than an edit to css-reset.css plus two now-pointless overrides. It was
     never protecting against the Forethought launcher, which is position:fixed
     and floats over the footer regardless. */
  padding-bottom: 0;
}

main {
  position: relative;

  /* `1 0 auto`, matching css-page-custom.css:38 and css-page-error.css:87:
     grow to absorb whatever window height the header and footer leave over, so
     the footer lands on the window's bottom edge on a short page -- but never
     shrink, so a page taller than the window keeps main's natural height and
     scrolls rather than being squashed into it.

     THIS ALSO FIXES WHERE THE BACK-TO-TOP BUTTON SITS, and the two changes are
     load-bearing for each other. That button is absolutely positioned inside
     <main> and clamped to it (css-components.css's Back-to-Top section). Before
     this, a short page gave it a track only as tall as the content, so it had
     nowhere to go; with main filling the window, the track does too, and the
     button rests just above the footer on a page that cannot scroll and at
     `calc(100vh - 5rem)` on one that can. */
  flex: 1 0 auto;
  /* 100%, not 100vw: vw counts the classic scrollbar gutter, so 100vw made
     every page ~15px wider than its container, and `place-items: center` on
     <body> then centred the excess, putting half of it off the left edge where
     `overflow-x: hidden` makes it unrecoverable. That centring is gone as of
     2026-10-21 (see the <body> rule above), so the overflow would now all land
     on one side rather than being split -- still wrong, just differently, so
     this declaration stays. 100% resolves against <body>, which also keeps it
     correct if <body> ever narrows for the docked Forethought panel again (see
     css-page-forethought.css). */
  width: 100%;
}

#page-container {
  width: 100%;
  margin-block-end: 5rem;
}

/* THE 5rem ABOVE IS THE PAGE'S WHOLE BOTTOM GAP, at every width, and it is
   deliberately NOT changed at the mobile breakpoint -- read this before adding
   a media query here, because one was added on 2026-10-24 and reverted the
   same day.

   Joy: "why is there more margin/padding on the bottom of the pages in mobile
   vs in desktop? I prefer the spacing on desktop and would like to keep it
   uniform." She was measuring a real 2x, and the cause is that the back-to-top
   button changes positioning scheme at 45em (css-components.css, Back to Top).
   On desktop it is `position: absolute`, out of flow, contributing no height,
   so this 5rem is the entire gap. Below 45em it is in flow as the last block in
   <main>, and its own top margin COLLAPSES with this one rather than replacing
   it -- so the gap became this 5rem plus the 48px circle plus its bottom
   margin: 161px at 390px wide against 80px on desktop.

   The first attempt zeroed this margin at the breakpoint and had the wrapper
   carry the full 5rem itself. It made six templates uniform and BROKE THE TWO
   THAT PAINTED A BACKGROUND, which is why it is gone:

     - The wash on the home page and the search results page was painted on a
       box that ENCLOSED this margin (`.home-page` was an outer <div> wrapping
       #page-container, home_page.hbs:13; `.search-page-wrapper` is
       #page-container itself and restates this margin as padding,
       css-page-search-results.css). Either way the 5rem was inside the painted
       box and the gradient covered it.
     - The back-to-top wrapper is a sibling OUTSIDE that box on both. So
       whatever bottom gap the wrapper supplied out of its own margins was
       unpainted, and the flat --page-bg-middle showed through as a pale band
       above the footer -- the bug Joy reported on 2026-10-22, reported again on
       2026-10-24 against the search results page.
     - Zeroing this margin therefore moved 80px of gap from inside the painted
       box to outside it, which was the wrong direction on exactly those two
       pages.

   PAST TENSE ON PURPOSE, because the wash moved on 2026-10-25: it is sitewide
   now, on <main>, in css-reset.css. That changes this trap in two ways worth
   knowing before anyone reads the paragraph above as still-current fact.

   It no longer applies to two pages; it applies to all of them but the error
   page. And the specific failure it describes can no longer happen, because
   <main> encloses BOTH this margin and the back-to-top wrapper -- the wrapper is
   inside the painted box now, so a gap it supplies is painted like any other.
   What remains true is the measurement that drove the revert: zeroing this at
   the breakpoint moves the gap rather than fixing it, and the arrangement below
   already lands all seven templates on the same 80px. So the conclusion stands
   and the margin stays; the reason is now uniformity alone, not an unpainted
   band.

   WHAT REPLACED IT: this 5rem stays, and the wrapper pulls the button UP into
   it with a negative top margin instead of adding to it. One rule in
   css-components.css, no page-specific cases, and it comes out at 16px / 48px
   circle / 16px on all seven templates -- 80px total, matching desktop, with
   the circle inside the painted area everywhere. The
   arithmetic and the two different ways it resolves are written up there; the
   short version is that sibling margins collapse to
   `max(positives) + min(negatives)`, so 5rem against -4rem is 1rem.

   The practical consequence for this rule: THIS VALUE IS NOW LOAD-BEARING FOR
   THE BUTTON'S POSITION, not just the footer gap. css-components.css restates
   the 5rem to derive its negative margin from it, so the two have to change
   together. Its comment says the same thing back. */

/*!SECTION - General Styles */

/* SECTION - Hero */

/*!SECTION - Hero */
/* SECTION - Call to Action */
.cta {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: var(--space-l);
  gap: var(--gap-sm);
  position: relative;
  & a {
    padding: 0.75rem 2rem;
  }
}
/*!SECTION - Call to Action */

/*SECTION - Breadcrumbs

   Rebuilt 2026-10-22 against Codex's live `.kb-breadcrumb-link` rule read out of
   DevTools. The Figma frame (node 6819:7684 in Knowledge-Base-Prototype-v2.0)
   was the first reference and got two things wrong that only the live CSS
   showed: the crumb links are underlined at rest, and the hover is a colour
   change to brand rather than a change of decoration.

   Codex's own declarations, and what each maps to here:

     Codex .kb-breadcrumb-link             ->  this block
     ------------------------------------      ---------------------------------
     color: --neutral-text-soft                same token, both tiers exist
     font-family: --font-family-secondary      --brand-font-family-sans (Inter)
     font-size: --font-size-xs (12px)          --step--1 (12.44px), see below
     font-weight: --font-weight-regular        same token
     line-height: 1.3                          --leading-body--1
     text-decoration: underline                same
     text-decoration-skip-ink: none            same
     text-underline-offset: 2px                left to css-reset.css, see below
     border-radius: --radius-sm                same token
     transition: color .2s                     --motion-duration-control (0.2s)
     :hover { color: --brand-text }            same token, both tiers exist
     :focus-visible { }                        nothing -- see the focus note

   Every colour is a semantic role with a dark-tier counterpart, so this block
   has no dark-mode rule and still lands the right way round in both themes.
   That is the point of the rebuild: what it replaced was built on
   --clr-secondary-140, --clr-secondary-5 and --clr-neutral-160, and the legacy
   --clr-* ramp has no dark tier at all, so breadcrumbs rendered light-mode ink
   on a dark background on all seven templates that show them (article,
   category, section, search_results, request, requests, new_request).

   STRUCTURE. {{breadcrumbs}} is Zendesk's and cannot be changed. It emits the
   *whole* landmark, not just the list:

     <nav aria-label='Breadcrumb'>
       <ol class='breadcrumbs'><li><a>...</li></ol>
     </nav>

   so the wrapper this block hangs off is a plain <div>, with no role and no
   label of its own:

     <div class='kb-breadcrumbs'>
       {{breadcrumbs}}
     </div>

   It was a second <nav aria-label='Breadcrumb'> for about an hour on
   2026-10-22, which nested one landmark inside another and advertised two
   identical "Breadcrumb" navigations to a screen reader. Do not put the
   element or the label back -- the helper already supplies both.

   THE WRAPPER STAYS even though it now holds nothing but the helper's output,
   and it is not a candidate for "simplifying" away. Every anchor rule in this
   block is scoped through it to win the specificity ties described below; delete
   it and the crumb links go back to being default links. Its other job is the
   margins, which have to sit on something that is not the <ol> the helper owns.

   NO HOME ICON. There was a house to the left of the trail until 2026-10-22,
   when Joy's team asked for it to be removed as confusing -- so it is gone from
   all seven templates, not hidden in CSS. Both the frame and Codex's live
   component do draw one (Codex as a decorative aria-hidden <svg>, a sibling of
   the crumb row rather than one of the crumbs), so this is a deliberate
   departure from the design and not an oversight: the first crumb already says
   "KnowBe4 Knowledge Base", and a house in front of it was a second, wordless
   way of saying the same thing. If it ever comes back it goes back as a real
   <i> inside this wrapper, which the kit converts to an <svg> -- never as a
   ::before codepoint on the first crumb. That version existed too, and it needed
   a clipping box, `color: transparent`, a first-child/last-child specificity
   guard, it put the icon's accessible name behind a trick, and it rendered a
   tofu box anyway (see the ICONS note).

   ICONS. The Font Awesome kit is loaded as JS only (document_head.hbs:267,
   kit dd3a01f44e, FA 7.3.1 Pro) with no Font Awesome webfont CSS anywhere in
   the theme. That matters twice over:

   - `--fa-font-regular` and its siblings are *never defined* -- they come from
     FA's webfont CSS, which we do not load. `font: var(--fa-font-regular)` is
     therefore an invalid declaration, the content renders in the inherited
     family, and the codepoint shows as tofu. That is not a typo in one place:
     26 rules in css-icons.css and more in css-links.css, css-components.css,
     css-page-article.css, css-page-search-results.css, css-page-new-request.css
     and css-page-requests.css all depend on it, and every one of them is dead.
     Worth fixing centrally, but not as a side effect of breadcrumbs -- it would
     make icons appear across the theme in one go.
   - Naming the family outright instead does not rescue it either. `font-family:
     var(--fa-family-classic, 'Font Awesome 7 Pro')` was tried here on the
     separator and rendered tofu in preview on 2026-10-22: there is no webfont
     for that family to resolve to, and the kit's `data-search-pseudo-elements`
     did not swap an <svg> in. So a codepoint in `content:` cannot be made to
     work in this theme at all, by either route.
   - Use a real <i>, which the kit converts to <svg> and which demonstrably works
     (the header globe and user chips). Where there is no element to use -- as
     between the <li>s of markup the helper owns -- draw the shape in CSS, which
     is what the separator below now does.

   SPECIFICITY. Joy reported on 2026-10-22 that the crumb links were still
   rendering as default links -- #56215d, the legacy --clr-secondary-140 purple
   that css-reset.css:205 paints on `a:not([class])`, which claims these anchors
   because the helper gives them no class. Her screenshot was of this rebuild and
   not the block it replaced (the house still rendered as a real icon and the
   first crumb's label was visible, which only the rebuilt structure produced),
   so the rebuild was live and the colour was genuinely losing. Scoping the rules
   as described below fixed it -- confirmed in preview the same day.

   What is established, and worth fixing on its own merits: `:not([class])` takes
   the specificity of its argument, so that reset rule is (0,1,1) -- and a plain
   `.breadcrumbs a` is also (0,1,1). They were exactly tied, with nothing but
   source order between them, and the same was true of the two hover rules at
   (0,2,1) each. An earlier version of the rule below recorded the reset as
   (0,1,0) and concluded it was beaten on specificity; that arithmetic was wrong,
   and a tie is not something this block should be resting on either way.

   So every anchor rule below now carries the `.kb-breadcrumbs` wrapper, which
   buys (0,2,1) against the reset's (0,1,1) and (0,3,1) against its nested
   `a:not([class]):hover` at (0,2,1) -- `:hover` counts in the class column, the
   same place `[class]` counts on the other side. (This read (0,2,2) until
   2026-10-25, which put `:hover` in the element column and disagreed with the
   paragraph above it. The figure was wrong; the conclusion was not.)
   That wins under any load order, which is the point:
   it removes the dependency rather than betting on it. The structural rules
   (.breadcrumbs, its <li>s, the separator) stay unscoped -- nothing in the theme
   competes with them, so the wrapper would be noise. If a rule here is about an
   anchor it carries the wrapper; if it is about a box it does not.

   AND THE TIE WENT TO THE RESET, which is the part worth carrying out of this
   file. Raising specificity was the only colour change made, and it fixed the
   purple, so css-reset.css:205 was beating a tied rule declared here. That is
   a measurement, not a deduction, and it contradicts the assumption the footer
   note at the bottom of this file rests on -- that Zendesk serves this file
   after every <link> in document_head.hbs, so anything declared here wins every
   tie against the per-page stylesheets. It does not. That note's own evidence
   (`.footer-wrapper`, same selector in both files, this file's legacy colour
   winning) was read off a symptom rather than measured, and whatever explains it,
   it is not a blanket "style.css wins ties".

   The practical rule to take from this: **do not rely on this file's position in
   the cascade in either direction.** Win on specificity or declare it in the
   per-page stylesheet. Do not "simplify" the `.kb-breadcrumbs` wrapper back out
   of the rules below -- it is the only reason they apply.

   The token was never the problem, for the record: --neutral-text-soft is on
   :root at css-brand-tokens.css:466 (#4f5f63), with #b2c3d2 in the dark tier at
   :952, which is why dark mode came out right with no rule here.

   Rewriting `a:not([class])` instead is NOT a breadcrumb-sized change and was
   not done from here. It paints every unclassed anchor in every article body,
   which is the one thing this project has promised not to redefine -- see the
   hard constraints in docs/brand-refresh/plan.md. It did need doing, for the
   reason given at the time: that ramp having no dark tier meant unclassed links
   read light-mode purple on a dark page everywhere, not just here.

   DONE, 2026-10-24, as its own sitewide pass on Joy's instruction -- the rule is
   --hyperlink-link now, with the hover tint removed in the follow-up. The trail
   was not touched by either half of it, which is the point of the wrapper.

   Three values deliberately differ from Codex:

   - Font size is --step-0 (14.22px), not Codex's --font-size-xs (12px). Joy,
     2026-10-22: "We need to bump up the font size." Codex's 12px maps onto
     --step--1 (12.44px), which css-root.css:128 fixes as the theme's
     accessibility floor and tells you not to go below -- so the trail was
     sitting at the smallest size the theme permits anywhere, under a page of
     --step-0 body text. --step-0 is that body and nav size, so the trail now
     matches what it sits above. Leading moves with it to --leading-body-0,
     the pairing css-root.css:144-146 sets up. This resizes the house too, which
     is deliberate: nothing sizes the house but the row's font-size.
   - the 8px gap is a literal 0.5rem. Codex's is `gap-2`, which computes from
     Tailwind's --spacing to a fixed 8px, whereas this theme's --space-* scale
     is fluid: --space-2xs runs 8px to 12px and would render 12 at any desktop
     width. The header does the same wherever a frame fixes a component's
     internal spacing.
   - text-underline-offset is left alone rather than pinned to Codex's 2px.
     css-reset.css:197 sets it to 0.15em sitewide, deliberately relative, which
     computes to 1.87px at this font size. 0.13px is not worth breaking the
     reset's idiom for. */
.kb-breadcrumbs {
  /* Still a flex container with one item in it, which is what makes the
     `min-inline-size: 0` on that item below mean anything. The `gap` that used
     to be here went with the house -- there is nothing left for it to space. */
  display: flex;
  align-items: center;
  font-family: var(--brand-font-family-sans);
  font-size: var(--step-0);
  /* One line-height for the whole row, not one per crumb. Codex puts a separate
     1.0 leading on the current-page crumb alone; at this size that would make
     one box ~5px shorter than its neighbours' for no visible gain, and it was
     already not worth doing at Codex's own 12px. */
  line-height: var(--leading-body-0);
  /* Not from Codex: a breadcrumb component says nothing about the space around
     it. These are the two values this block already used, kept so page rhythm
     on seven templates does not move for a reason the design never asked for.
     They sit on this wrapper rather than the <ol>, because the <ol> belongs to
     the helper and the <nav> around it is not ours to margin either. */
  margin-block-start: 1.5rem;
  margin-block-end: 3rem;
}

/* The helper's own <nav>, which sits between this wrapper and the <ol> and so
   is the flex item that has to give. `min-inline-size: 0` defeats the automatic
   minimum size -- without it the nav is pinned at the trail's min-content width
   and a long article title pushes the row past the content column instead of
   wrapping. (The same reason .navbar-search carries it in
   css-page-header.css:2077.) Wrapping belongs on the <ol>, which is where it is,
   and this is what lets it happen. */
.kb-breadcrumbs > nav {
  min-inline-size: 0;
}

/* The crumb list. The reset already gives every <ol> margin: 0, padding: 0 and
   list-style: none (css-reset.css:104-124), so none of that is repeated here. */
.breadcrumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

/* The chevron lives inside the <li>, so the <li> needs its own gap as well as
   the list's: the list's 8px separates crumb from crumb, this one separates the
   chevron from the text beside it. Codex nests them the same way -- one flex
   row per crumb, inside a flex row of crumbs. */
.breadcrumbs li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* Link crumbs = Codex's .kb-breadcrumb-link.
   Two of these declarations exist only to beat the reset's `a:not([class])`,
   which claims these anchors because the helper gives them no class: it sets
   text-decoration-skip-ink: auto, where Codex wants the underline unbroken
   through descenders, and it sets a colour -- --hyperlink-link since the
   sitewide link pass of 2026-10-24, the legacy --clr-secondary-140 purple
   before that. The colour is the reason the crumbs have to say their own:
   --neutral-text-soft is a quieter grey than the default link's ink, and the
   trail is the one place in the theme still on brand. An earlier version noted
   that reset as (0,1,0) and so believed a bare `.breadcrumbs a` beat it on
   specificity. It does not: `:not([class])` contributes (0,1,0) and the `a`
   another (0,0,1), so the reset is (0,1,1) and the two were exactly tied. Hence
   the wrapper; see the SPECIFICITY note above.
   border-radius is only ever visible on the focus ring, which is what it is
   for: an outline follows the border radius, so this is what makes the ring
   read as rounded the way Codex's does. */
.kb-breadcrumbs .breadcrumbs a {
  border-radius: var(--radius-sm);
  color: var(--neutral-text-soft);
  font-weight: var(--font-weight-regular);
  text-decoration: underline;
  text-decoration-skip-ink: none;
  transition: color var(--motion-duration-control) var(--ease-in-out);
}

/* No :focus-visible appearance rule, matching Codex: in their DevTools every
   declaration on .kb-breadcrumb-link:focus-visible is struck through, so the
   component takes the global ring untouched. Ours is css-reset.css:19, and it
   already resolves --form-focus-ring -- the same token name Codex's ring uses.
   The offset is pinned to Codex's 2px rather than left to the reset's
   max(2px, 0.15em), which is exactly what css-reset.css:16 asks components that
   care about the offset to do. */
.kb-breadcrumbs .breadcrumbs a:focus-visible {
  --outline-offset: 2px;
  /* The sitewide ring pairs its outline with a same-coloured `border: 2px solid`
     (css-reset.css:40). A crumb anchor has no border at rest, so that border is
     2px of new box on all four sides the moment it is focused -- it widens the
     focused crumb and shoves the rest of the trail along, and on a trail that
     wraps it can push the last crumb onto a new line. Same defect, same fix, as
     the dropdown rows in 81fd7cd and the share menu in css-page-article.css.
     Safe to drop here for the plainest version of the reason that rule keeps it:
     nothing in this trail has `overflow: hidden`, so the outline is never
     clipped and is the whole cue on its own. `border: 0` rather than a
     transparent border, so the box does not move. */
  border: 0;
}

/* Codex's Breadcrumb hover is a colour change to brand, with the underline
   staying put. That is still exactly what this does -- but as of 2026-10-25 it
   is no longer special.

   THE TRAIL IS NO LONGER THE ONLY BRAND-COLOURED LINK IN THE THEME, and this
   rule now agrees with the sitewide default instead of departing from it. For
   one day it was the exception: Joy, 2026-10-24, "the only link where we'd see
   the brand colors would be the breadcrumbs", with every other link taking
   Codex's underline thickening. She reversed that on 2026-10-25 after
   previewing it -- "the hover states are not distinguishable enough from the
   standard text [...] make the default on link hover the same color that we are
   using for breadcrumbs" -- so --brand-text on hover is now what
   `a:not([class])` gives every link in css-reset.css, and the trail's hover is
   the model the rest of the theme was pointed at rather than an exception to it.

   WHAT WENT WITH THAT: a `text-decoration-thickness: var(--link-underline)`
   declaration, which existed only to pin the trail BACK to the rest weight
   against the sitewide thickening. Nothing thickens any more, so it was dead
   code and is gone. If a thickening hover ever returns sitewide, this is the
   rule that has to pin against it again -- and the `.kb-breadcrumbs` wrapper is
   what makes that possible, since the pin only won on specificity:
   (0,3,1) here against the reset hover's (0,2,1), counting `:hover` and
   `[class]` into the class column. (An earlier version of this comment gave
   those as (0,2,2) and (0,2,1); the figures were off, the conclusion was not.)

   All three remaining declarations are deliberately kept even though the
   sitewide rule would now supply the colour and the defaults would supply the
   rest. They are cheap, they state what this component's hover IS rather than
   what it inherits, and they mean a future change to the sitewide link hover
   does not silently redecorate the trail -- which is precisely the failure this
   rule has already been on both ends of. background-color and text-decoration
   also still earn their place historically: both were here to beat a reset
   `:hover` that set `text-decoration: none` and painted --neutral-bg-highlight
   behind the anchor, which on a wrapping trail draws a ragged rectangle broken
   across the line. */
.kb-breadcrumbs .breadcrumbs a:hover {
  background-color: transparent;
  color: var(--brand-text);
  text-decoration: underline;
}

/* The separator. It sits between <li>s in markup we do not own, so there is no
   element to hang an <i> on -- which rules out the one icon mechanism this theme
   has that demonstrably works.

   So it is drawn, not typed. Two codepoint attempts have now failed in preview
   and neither is worth a third: `font: var(--fa-font-regular)` was dead because
   that variable is never defined (the ICONS note above), and naming the family
   outright -- `font-family: var(--fa-family-classic, 'Font Awesome 7 Pro')` --
   rendered a tofu box on 2026-10-22, which is what Joy reported. There is no
   webfont for that family to resolve to, and the kit's
   `data-search-pseudo-elements` did not swap an <svg> in either. Not worth
   debugging which of the two halves failed: both roads lead back to loading FA's
   webfont CSS theme-wide, and that is the central fix the ICONS note defers
   because it would light up 26 dead rules in css-icons.css at the same time.

   A rotated square's two borders is the whole chevron, with no font, no kit and
   nothing to resolve. It is sized in em so it tracks the row's font-size exactly
   as the codepoint would have, and it takes its colour from a semantic token, so
   dark mode needs no rule here. 0.375em is 5.3px square at --step-0, which draws
   ~7.5px corner to corner -- the height FA's chevron renders at this size.
   If the central FA fix lands later, this can go back to a codepoint; until then
   this is the version that actually appears. */
.breadcrumbs li + li::before {
  flex: none;
  content: '';
  inline-size: 0.375em;
  block-size: 0.375em;
  /* Physical sides, not logical: the shape is defined by which two edges are
     drawn *before* it is rotated, so flipping the edges and the rotation
     together (which logical properties would do under [dir='rtl']) cancels out.
     The RTL case is handled by the rotation alone, below. */
  border-top: 1.5px solid var(--neutral-icon-soft);
  border-right: 1.5px solid var(--neutral-icon-soft);
  transform: rotate(45deg);
}

/* The chevron points along the reading direction, so it mirrors rather than
   staying put. `rotate(-135deg)` and not `scaleX(-1)`: transform is one
   property, so a mirror here would replace the 45deg rotation rather than
   compose with it and leave the corner pointing up. -135deg is the same two
   drawn edges turned the other way, which points them left. */
[dir='rtl'] .breadcrumbs li + li::before {
  transform: rotate(-135deg);
}

/* The current page: darker, and not underlined. Inter, like every crumb before
   it -- so there is no font-family here at all, and it inherits the wrapper's
   --brand-font-family-sans.

   It was Sora (--ff-logo) until Joy checked it in preview on 2026-10-22: "There
   is a mistake (from the Figma file) -- the last breadcrumb, i.e. active page,
   should be Inter font, not Sora." Worth recording why the mistake was
   believable rather than just deleting the declaration, because the same two
   sources will say the same thing next time: Codex's own link rule names
   --font-family-secondary for the *preceding* crumbs, and the Figma frame binds
   the current crumb to body/component/regular/sm, whose family is
   font/family/primary. Read together those two look like a deliberate contrast
   between the trail and the page you are on. They are not -- the frame is wrong,
   and Joy owns that call. **The design file is reference, not truth; where it
   disagrees with her it loses.** The note already in this block that the
   distinction was "a thin distinction" doing little work was the clue.

   So the colour step does all of the "you are here" work, which is the whole
   job: --neutral-text against the trail's --neutral-text-soft, plus no
   underline.

   It is no longer a working link either, as of Joy's note on 2026-10-22 that the
   active-page crumb "shouldn't behave as a link". The helper emits it as one on
   some templates, so the href is stripped at runtime by
   assets/breadcrumb-current-page.js (loaded from footer.hbs) and the element is
   left in place, which is why the selectors below still say `a`. Read that file
   before changing these rules -- the two halves are deliberately split, and the
   comment on `cursor` below says which half does what.

   One rule rather than two, and it covers three selectors because the helper is
   not consistent about the last crumb: on some templates it is an <a> and on
   others it is bare text. The bare `li` catches the bare-text case; the <a> and
   its :hover are still needed on top because the rest-state and hover anchor
   rules above would otherwise beat an inherited value. `text-decoration` on the
   bare <li> is inert, which is cheaper than a second rule to avoid it.
   All three carry the wrapper, for the reason in the SPECIFICITY note: they only
   ever needed to outrank rules in this same file, which they did on source order
   alone, but leaving them unscoped would have made them the exception to "anchor
   rules carry the wrapper" and the next tie would be found the hard way. */
.kb-breadcrumbs .breadcrumbs li:last-child,
.kb-breadcrumbs .breadcrumbs li:last-child a,
.kb-breadcrumbs .breadcrumbs li:last-child a:hover {
  color: var(--neutral-text);
  text-decoration: none;
  /* The other half of "stop behaving like a link", and the half CSS owns.
     assets/breadcrumb-current-page.js strips the href, which is what takes the
     crumb out of the tab order and stops it being announced as a link -- but
     css-reset.css:206 sets `cursor: pointer` on `a:not([class])`, and that
     matches any <a> element whether or not it has an href. So without this the
     crumb would still claim to be clickable on hover after the href was gone.
     Scoped through the wrapper like every other anchor rule here, so it beats
     the reset's (0,1,1) outright rather than on source order. */
  cursor: default;
}

/*!SECTION - Breadcrumbs */

/* SECTION - Footer

   Deliberately empty. The footer is owned entirely by
   assets/css-page-footer.css as of the 2026-10-19 rebuild, and it has to be
   owned somewhere other than here: a declaration in this file competing with the
   per-page stylesheet is decided by nothing but cascade position, and this file's
   position is not something to build on. That is what the removed block was
   doing.

   CORRECTED 2026-10-22. This note used to say that Zendesk injects this file
   after every <link> in document_head.hbs, so anything declared here wins every
   specificity tie and silently outranks the per-page stylesheets. That is not
   true, or at least not reliably: the breadcrumb work above *measured* the
   opposite -- css-reset.css:205 was beating a rule declared here at identical
   specificity, and raising specificity was what fixed it. The evidence this
   paragraph used to cite (the border-top below: same `.footer-wrapper` selector
   in both files, this file's legacy colour winning) was read off a symptom and
   is not safe to generalise from.

   The conclusion for the footer is unchanged and if anything firmer -- own it in
   css-page-footer.css, where it is not subject to this question at all. What
   changes is the reason: not "this file outranks, so move out" but "this file's
   rank is unknown, so do not compete from it."

   What was here, and why none of it came across:

   Dead against the new markup -- .footer-support, .terms-wrapper, .social,
   .social p, .social svg, .footer-logo, .footer-links, .terms, .terms a,
   .btn-theme-footer, .social-link. Every one of those class names is gone from
   templates/footer.hbs, which now uses the .kb-footer-* set. `#footer .nav` went
   the same way: #footer is still the <footer>, but there is no .nav inside it any
   more. The remaining orphans of this group still sitting in css-components.css,
   css-links.css, css-buttons.css and css-icons.css are a separate sweep.

   Already declared, better, in css-page-footer.css:
   - .footer-wrapper's border-top. The rule here was 1px solid --clr-neutral-40
     (#c2c2c2), a legacy-tier token, and it was winning over the intended
     --neutral-border-soft (#c9d7d9) at css-page-footer.css:85 -- same selector
     in both files, so specificity was not the difference. Deleting it is what
     lets the intended colour apply, and that much is observed. "Because this
     file loads later" was the explanation offered at the time and it is the
     claim the CORRECTED note above withdraws; the fix stands either way, since
     one of the two duplicates had to go.

   Actively wrong, and the reason this got looked at:
   - `footer { margin-block-end: var(--space-2xl) }` put 48-72px inside the band,
     below the footer content, on top of .kb-footer's symmetric padding-block.
     The band was meant to be evenly padded and was not.
   - `#footer-nav { gap: 2rem }` under max-width: 44.9em overrode
     .kb-footer-nav's 8px gap -- an id beating a class -- and spread the mobile
     nav rows to a 68px pitch against the frame's 44px.
   - `#footer-nav, .terms-wrapper { margin-block-start: 2rem !important }` added
     32px above the nav and nothing below it, which is why the gap under the
     Contact Support button did not match the gap above the social row.

   That 44.9em block was the footer's old breakpoint. css-page-footer.css's
   Mobile section notes it only ever governed which duplicate copyright row was
   hidden; the duplicates are gone, so the breakpoint goes with them and the
   footer has one breakpoint at 54.9em. */

/*!SECTION - Footer */

.notification {
  display: inline-block;
  background-color: #333;
  color: #fff;
  padding: 5px 10px;
  border-radius: 4px;
  font-size: 14px;
  margin-left: 10px;
  opacity: 0;
  animation: fadeIn 0.3s ease-in forwards;
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* Hide hubspot sales popup */
#hs-overlay-cta-191597628448 {
  display: none;
}
