/* THE PRIMARY BUTTON IS ON CODEX ROLES AS OF 2026-10-24, which is a sitewide
   change made deliberately rather than a request-page one. Joy asked for the
   request page's Submit to be fixed and then chose this scope over scoping it
   to the two form pages, on the same argument she had just made for the site
   link colour: a shared primitive fixed in one place beats the same fix
   arriving page by page. So this repaints buttons on the header, article,
   category and section pages too, and all four need re-previewing.

   The values come from Codex's Button page (node 6738:55124): brand/bg #d73312
   resting, brand/gradient-r-hover #d73312 and brand/gradient-l-hover #992008
   for the hover sweep, brand/gradient-r-active #992008 on press. They replace
   --clr-primary-100 / -120 / -140, and the note that used to sit on :active --
   deferring this to docs/brand-refresh/plan.md -- is what has just been done.

   ANY VARIANT THAT OVERRIDES --bg MUST RESTATE :hover AND :active. The two
   state rules below are (0,2,0) and a variant's resting rule is (0,1,0), so
   without its own states a white button flashes brand red under the pointer.
   Every variant in this file does restate them; css-page-error.css and
   css-page-header.css both cite this paragraph for the same reason. As of
   2026-10-24 the same now goes for --bg-image, which is the other half of the
   brand treatment -- see below.

   THE GRADIENT IS TAKEN TOO, as of the second pass the same day. The first
   pass flattened Codex's hover to the dark end of its gradient and said why:
   a gradient has to be set as `background-image`, which is not part of the
   --bg/--fg/--border-color variable API that .btn-theme, .btn-dropdown,
   .btn-user and .btn-secondary restyle themselves through, so it would have
   painted straight over four white buttons with no way to switch it off.

   That objection is real and the answer is to widen the API rather than drop
   the gradient: `--bg-image` joins it, and the four white variants set
   `--bg-image: none` exactly as they already set `--bg`. A variant now turns
   the brand treatment off the same way it turns the brand fill off, which is
   the pattern the file already had.

   Doing it at all is only worth the trouble because this theme already
   implements the technique and documents it at length -- css-page-header.css
   has the header's own navbar pill on it, reconstructed from Codex's shipped
   `.kb-button-strong`. Read the comment there for the full reasoning; the
   short version is that **gradients cannot be interpolated by a transition**,
   so the gradient is declared once at 300% of the button's width in three
   panels and only the window onto it moves:

     0% ------------ 33.3% ---------- 66.6% ------------ 100%
     #992008         #992008   ~~~~>  #d73312            #d73312
     \__ panel 1 __/ \___ panel 2 ___/ \___ panel 3 ___/
      flat dark        the gradient      flat brand
      :active (0%)     :hover (50%)      resting (100%)

   Resting is position 100%, which shows flat #d73312 == --brand-bg -- so a
   resting button is pixel-identical to what it was before any of this, and
   --bg stays declared as the fallback under the image.

   THE LIFT SHADOW IS STILL NOT TAKEN. Codex's strong button does not lift:
   `.kb-button-strong:hover` sets background-position and nothing else. The
   0 6px 16px lift on the header pill is explicitly a borrow from
   `.kb-button-regular:hover`, made in that one local scope. Borrowing it for
   every button in the theme is a bigger claim than fixing the gradient, and
   not one Codex supports, so it stays where it is.

   Hover and press exclude disabled via `:where(:not(...))`, which contributes
   no specificity -- so both rules stay at (0,2,0) and the variant states below
   keep winning on load order exactly as they did. Getting that wrong is the
   hazard this file keeps flagging: a (0,3,0) hover here would beat
   .btn-theme:hover at (0,2,0) and flash a white button brand red. Both
   `:disabled` and `[aria-disabled='true']` are listed because Codex's own
   selector lists both, and an <a class="btn"> cannot carry the real attribute.

   TYPE IS SORA AND GEOMETRY IS NOT CODEX'S. Codex's md button is Sora SemiBold
   at 14px with 10px/16px padding; this is Sora at --step-1/--font-bolder with
   4px/20px. The family came in on 2026-10-24 after Joy previewed the request
   page -- "the submit button does not have the correct font--it should be
   Sora" -- and it had to come from here, because this file is the only thing
   that styles that button: the old `.btn-submit` rule set no family either, and
   css-reset.css:379 gives every input `font-family: inherit`, which on the
   request page is the body's Inter. The header's own brand pill already states
   the same two values (css-page-header.css:1574), so this is that rule's font
   moved to the shared base rather than a new decision.

   It is `--family`, not a bare declaration, because the variants have to be
   able to opt out -- and all the ones that must be Inter already do, by
   stating it at a higher specificity than this rule rather than through the
   variable: .header-nav's nav rows (css-page-header.css:933), the desktop
   locale and user triggers (:1727), and the dropdown panel itself
   (css-buttons.css:404). That was true before this change and is what makes it
   safe; `--family` exists for the next variant, which will not have a
   two-class selector to win with.

   Sizing is still untouched on purpose. Resizing every button in the theme is
   a separate, deliberate change and not one Joy has previewed.

   `transition` with properties, where :hover had `transition-duration` on its
   own and therefore animated nothing -- the same correction css-reset.css:359
   and css-components.css:1854 both carry now. It moves up here because a
   transition declared only in the hover state does not ease on the way out.
   The durations are Codex's motion tokens rather than the legacy 300ms
   --transition-duration, for the two reasons the header pill gives: the sweep
   needs the full --motion-duration-slow (0.6s) or it reads as abrupt, the
   colours want --motion-duration-control (0.2s) so the button acknowledges the
   pointer immediately -- and unlike --transition-duration, all four motion
   tokens collapse to 0s under prefers-reduced-motion
   (css-brand-tokens.css:1131). */
.btn {
  --fg: var(--fixed-white);
  --bg: var(--brand-bg);
  --bg-image: linear-gradient(
    90deg,
    var(--brand-gradient-l-hover) 0%,
    var(--brand-gradient-l-hover) 33.333%,
    var(--brand-gradient-r-hover) 66.666%,
    var(--brand-gradient-r-hover) 100%
  );
  --radius: 6.25rem;
  --padding: 0.25rem 1.25rem;
  --border-width: 1px;
  --border-style: solid;
  --border-color: transparent;
  --weight: var(--font-bolder);
  --size: var(--step-1);
  --family: var(--font-family-primary), system-ui, sans-serif;
  --text-align: center;
  font-family: var(--family);
  font-size: var(--size);
  border-radius: var(--radius);
  padding: var(--padding);
  color: var(--fg);
  font-weight: var(--weight);
  background-color: var(--bg);
  background-image: var(--bg-image);
  background-size: 300% 100%;
  background-position: 100% 0;
  text-align: var(--text-align);
  text-decoration: none;
  border: var(--border-width) var(--border-style) var(--border-color);
  transition:
    background-position var(--motion-duration-slow) var(--ease-in-out),
    background-color var(--motion-duration-control) var(--ease-in-out),
    border-color var(--motion-duration-control) var(--ease-in-out),
    color var(--motion-duration-control) var(--ease-in-out);
}

.btn:hover:where(:not(:disabled, [aria-disabled='true'])) {
  --bg: var(--brand-gradient-r-hover);
  background-position: 50% 0;
  cursor: pointer;
}

/* Press is immediate -- a click should not feel like it is catching up with
   the pointer -- while release settles back over the full 0.6s, because the
   duration reverts to the base rule's. --bg tracks --brand-gradient-r-active
   (#992008), which is the same hex as panel 1, so the fallback agrees with
   the image it sits under. */
.btn:active:where(:not(:disabled, [aria-disabled='true'])) {
  --bg: var(--brand-gradient-r-active);
  background-position: 0 0;
  transition-duration: var(--motion-duration-instant);
}

/* THE DISABLED STATE EXISTS BECAUSE page-request.js NOW SETS IT. Joy,
   2026-10-24: "it looks like you can submit even if there are no comments or
   files uploaded. Is there a way you can make the button disabled if nothing
   is entered?" -- so the request page's Submit is now `disabled` whenever the
   comment is empty and nothing is attached, and until this rule a disabled
   Submit looked exactly like an active one.

   The treatment is the theme's existing one, lifted verbatim from
   css-utilities.css:1395 (`.form input[type='submit']:disabled`) so the two
   agree. That rule could not do this job: the comment form is
   `.comment-form.hbs-form`, not `.form`, so it never matched the only button
   in the theme that is ever actually disabled.

   Codex does carry proper disabled roles -- kb/bg/disabled, kb/text/disabled,
   kb/border/disabled in its Styling & Grids library -- but none of the three
   is in css-brand-tokens.css, because they are not in the :root dump the token
   file was built from, and Codex's Button page does not draw a disabled
   variant to read them off. So this is deliberately the local convention and
   not an invented set of values; swap it for the roles when they land. */
.btn:disabled,
.btn[aria-disabled='true'] {
  cursor: not-allowed;
  opacity: 0.4;
}

.btn:where(:has(svg)) {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

/* `--bg-image: none` is the half of the variable API added 2026-10-24 with the
   brand gradient -- see the note at the top of this file. Every white-bodied
   variant needs it, or .btn's gradient paints over the --bg it just set:
   background-image draws above background-color, so this is not something the
   cascade would sort out. */
.btn-theme,
.btn-theme-footer {
  --fg: var(--clr-neutral-100);
  --bg: var(--clr-white);
  --bg-image: none;
  --border-width: 1px;
  --radius: 0.25rem;
  --padding: 0.25rem 0.5rem;
  --border-color: var(--clr-neutral-100);
  --weight: var(--font-bold);
}
.btn-theme-footer {
  --size: var(--step-0);
  border-radius: 0.25rem;
}

@media screen and (max-width: 44.9em) {
  .btn-theme-footer[data-display='mobile-display'] {
    display: block;
  }
  .btn-theme-footer[data-display='full-display'] {
    display: none;
  }
}
@media screen and (min-width: 45em) {
  .btn-theme-footer[data-display='mobile-display'] {
    display: none;
  }
  .btn-theme-footer[data-display='full-display'] {
    display: block;
  }
}
.btn-theme:hover,
.btn-theme-footer:hover {
  --fg: var(--clr-neutral-160);
  --bg: var(--clr-neutral-20);
  --border-color: var(--clr-neutral-160);
}

/* The neutral ramp has no step between 20 and 40, so press is a bigger jump
   here than on .btn. Still legible -- #c2c2c2 against --clr-neutral-160 text. */
.btn-theme:active,
.btn-theme-footer:active {
  --fg: var(--clr-neutral-160);
  --bg: var(--clr-neutral-40);
  --border-color: var(--clr-neutral-160);
}

.btn-dropdown,
.btn-user {
  --bg: var(--clr-white);
  --bg-image: none;
  --fg: var(--clr-neutral-160);
  --weight: var(--font-regular);
  --radius: 0.5rem;
  --padding: 0.5rem;
  --text-align: start;
  height: 3rem;
}

.btn-dropdown:hover,
.btn-user:hover {
  --bg: var(--clr-neutral-5);
  --border-color: var(--clr-neutral-160);
}

.btn-dropdown:focus {
  --bg: transparent;
}

/* Ordered after :focus on purpose. Both are (0,2,0), and a mouse press also
   focuses the button, so source order is what lets the press tint show while
   the button is held and hands back to the flat open-state treatment above on
   release. */
.btn-dropdown:active,
.btn-user:active {
  --bg: var(--clr-neutral-10);
  --border-color: var(--clr-neutral-160);
}

/* THE REQUEST PAGE'S SUBMIT, and the button Joy asked to have fixed for our
   styles. It is the only element in templates/ carrying this class
   (request_page.hbs:128, `{{input type='submit' class="btn btn-submit"}}`), so
   everything here is about one control.

   Three legacy values came off: --clr-white for the label, which is
   --fixed-white now because the brand fill is one colour in both tiers so its
   label must be too; and `border: 1px solid var(--clr-primary-100)` -- a
   hardcoded shorthand that bypassed .btn's --border-color and therefore could
   not be restyled by anything, drawing the old plum-era primary as a visible
   ring around the button. Codex's strong button has no edge of its own, so the
   whole declaration is gone rather than converted, and .btn's transparent 1px
   is what remains.

   GEOMETRY IS DELIBERATELY DELETED RATHER THAN CONVERTED. The --radius,
   --padding, --weight and --size overrides are all gone, so this inherits
   .btn's pill, 4px/20px and --step-1. The note at the top of this file says
   resizing every button in the theme is a separate change, and it still does
   -- but this is one button on one page, and the thing being fixed is that a
   square 4px-radius --step-2 block was the only button on the site that did
   not look like the pill in the header. Dropping the overrides is how it
   matches, and it is also three fewer values to convert later.

   THAT LEFT NO DECLARATIONS AT ALL and the rule was deleted on 2026-10-24,
   which was half right: every legacy value it carried did need to go, and the
   .btn base it fell back to turned out to be the wrong size. Joy, previewing
   the same day: "can we make the submit button have the same font size and
   padding as the buttons in the header and footer? I think the font size might
   be off." It was: .btn's base is --step-1 at --font-bolder (700), where both
   of the theme's other brand-filled controls are --step-0 at
   --font-weight-strong (600).

   SO THE RULE IS BACK, AND IT IS GEOMETRY ONLY. The five values below are
   copied from the header's primary pill (css-page-header.css:1559) and agree
   with the footer's CTA (css-page-footer.css:407) value for value -- --step-0,
   600, 0/1.25rem, 2.5rem tall, --leading-control. Those two were already
   identical to each other and this is the third control joining them, not a
   new size.

   The copy is deliberate rather than moved into .btn. .btn's base sizing
   reaches exactly two other things -- the article page's CTA and nothing else,
   because every header variant pins its own padding and font-size above .btn's
   specificity -- and changing the article CTA's height is a separate preview
   on a page that is already signed off. If Joy wants that one to match too,
   move these five lines up into .btn and delete the header and footer copies;
   that is the tidier end state, it just is not this change.

   NOTHING HERE TOUCHES --bg OR --bg-image, which is why this rule does not
   have to restate :hover and :active the way the warning at the top of this
   file demands. It only moves the box; the gradient sweep is still .btn's and
   still works.

   The class is also the markup hook for anything else the form needs -- a
   placement rule from css-components.css's shared form section, say -- because
   `{{input}}` gives us no other handle on this element.

   THERE IS A SECOND COPY OF THIS RECIPE, added 2026-10-25, and it cannot be
   shared: css-page-new-request.css restates `.btn` plus these five values with
   `!important` on every declaration, for the new request form's Submit. Joy
   asked for that button to match this one. It is Garden-rendered from the React
   bundle, so there is no template to add a class to, and Garden injects its own
   primary-button colours, radius, padding and 40px height at runtime -- which
   `!important` is the only way past, and `!important` cannot go into `.btn`
   without breaking the load-order wins this file's header warns about.

   SO IF THIS RULE OR `.btn` IS RETUNED, THAT BLOCK NEEDS THE SAME EDIT. Nothing
   in the cascade will catch it. The grep is `--brand-gradient-r-hover`, which
   only the brand-filled controls use. */
.btn-submit {
  --radius: var(--radius-round);
  --padding: 0 1.25rem;
  --weight: var(--font-weight-strong);
  --size: var(--step-0);
  height: 2.5rem;
  line-height: var(--leading-control);
}

.avatar-img {
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
}

.btn-user {
  gap: 0;
  a.dropdown-item {
    padding: 0;
  }
}

.btn-secondary {
  --padding: 0.75rem 1rem;
  --border-color: var(--clr-neutral-160);
  --radius: 0.25rem;
  --bg: var(--clr-white);
  --bg-image: none;
  --fg: var(--clr-neutral-160);
  --size: var(--step-2);
  line-height: 1.5;

  &:hover {
    --bg: var(--clr-neutral-5);
    --border-color: var(--clr-neutral-160);
    --fg: var(--clr-neutral-160);
  }

  &:active {
    --bg: var(--clr-neutral-10);
    --border-color: var(--clr-neutral-160);
    --fg: var(--clr-neutral-160);
  }
}

/* SECTION - Dropdown

   Rebuilt 2026-10-22 against the search autocomplete panel, which is now the
   theme's reference dropdown: `.aa-dropdown-menu` and `.aa-suggestion` in
   css-search.css, themselves drawn from Codex's search panel and its
   .kb-option-item / .kb-option-item-flush pair. The instruction was that
   wherever there is a dropdown, this is the styling -- so the two header
   popovers are drawn from the same declarations rather than each carrying its
   own card. (The article share menu is the third one and gets the same
   treatment in css-page-article.css; it does not share these class names.)

   How the elements map:

     .aa-dropdown-menu  (card + scroller)  ->  .dropdown
     .aa-suggestions    (the p-1 inset)    ->  .dropdown, same element
     .aa-suggestion     (one row)          ->  a.dropdown-item,
                                               a.dropdown-language-item

   .dropdown is card and list at once, so it carries the 0.25rem inset itself
   rather than passing it to a child. That is safe here where it was not in the
   search panel: a scroll container's scrollport is its *padding* box, so a row's
   focus ring is drawn into that inset instead of being clipped by it. The search
   panel keeps its inset on a child for an unrelated reason -- autocomplete.js
   reads the menu's height() + padding as the viewport height when it scrolls the
   keyboard cursor into view, so padding there would corrupt that maths. Nothing
   measures these two.

   What came off, all of it legacy --clr-* with no dark tier:
   - the --clr-neutral-40 border, --clr-white fill and 0.25rem radius on the card
   - --clr-neutral-160 ink and the --clr-neutral-5 hover fill on the rows
   - the card's 0.5rem gap. Rows sit flush now, as they do in the search panel: a
     gap between rounded hover fills reads as a hole in the menu rather than as
     breathing room.
   - `max-height: 48vh; overflow-y: scroll` on .languages-list, superseded by the
     cap below. `scroll` reserved a track even with two locales; `auto` shows one
     only when there is something to scroll.
   - `max-height: 10rem` on a single row, which could only ever have clipped a
     long locale name.
   - --font-bolder on the user menu's last row (Sign Out). The hamburger rebuild
     already dropped that emphasis when it set every row to --font-weight-regular
     from frame 6643:7113, so keeping it on desktop alone would have left the two
     breakpoints disagreeing about the same menu.
   - .dropdown-user:active's `border: none; background: unset`, which unpainted
     the card itself on mousedown.

   Because every colour here is a semantic role with a dark-tier value, three
   patches in the `:root[data-theme='dark']` block at the foot of this file are
   gone -- `:where(.dropdown)`, `:where(.dropdown-item, ...)` and its `:hover`.
   Same move .aa-dropdown-menu made off the legacy patch list in
   css-utilities.css:1476. The .btn-dropdown/.btn-user patches there stay; those
   triggers are still built on --clr-*.

   ONE KNOWN DISAGREEMENT, flagged rather than decided. The rows hover to
   --neutral-bg-component-soft-hover, which is what the search panel uses. The
   hamburger submenu rows and both triggers use --neutral-bg-component-soft-active
   instead, one step darker, taken from frame 6643:7256. Those rules are
   .header-nav-scoped at (0,2,0) and up, so they still win below 54.9em -- which
   means the same language list hovers very slightly darker in the hamburger than
   in the desktop popover. Which of the two wins is a design call. */
.dropdown {
  position: relative;
  /* Was inline-flex. Not for the rows' sake -- a column flex container stretches
     its children either way, so the hover fills spanned the card under both
     values. It is so that the card's width is decided by the box it is
     positioned in rather than by its own longest label, which is the same thing
     the search panel does with the field it hangs off.
     That shift is what exposed the oversized .dropdown-container-user; see the
     note on the media query at the foot of this section. */
  display: flex;
  flex-direction: column;
  /* Was 0.5rem, zeroed 2026-10-27 to match what the article's share menu now
     does and what Codex's Dropdown measures at: the panel's top border on the
     first pixel after the trigger, no gap. See the long note in
     css-page-article.css on .share-dropdown's margin for the measurement and for
     why the floating shadow falling on the trigger is the thing that makes it
     read as nested rather than merely adjacent.
     This reaches the language and user popovers only. The hamburger already
     zeroed it at css-page-header.css:1181, and the search autocomplete keeps its
     own 0.5rem in css-search.css:103 -- deliberately, because Joy called that one
     correct and its trigger is a straight-edged full-width field, which is the
     case where 8px reads as 8px.
     ON ITS OWN THIS DOES NOT CLOSE THE GAP HERE; see the note below. */
  margin-block-start: 0;
  padding: 0.25rem;
  background-color: var(--neutral-bg);
  /* Stated rather than inherited, for the reason the search panel states it: a
     card that floats over arbitrary content should not take its ink from
     whatever it happens to be nested in. */
  color: var(--neutral-text);
  border: var(--border-width-regular) solid var(--neutral-border-soft);
  border-radius: var(--radius-sm);
  box-shadow: 0 var(--shadow-floating-y-offset) var(--shadow-floating-blur)
    var(--shadow-floating-spread) var(--shadow-floating-color);
  font-family: var(--brand-font-family-sans);
  font-size: var(--step-0);
  text-align: start;
  /* The same two limits as the search panel: the smaller of 60% of the viewport
     and 28rem. Twelve locales overflow a short window, and on a tall monitor an
     uncapped list is longer than it is scannable. overscroll-behavior keeps a
     trackpad flick inside the list once it runs out instead of scrolling the
     page behind it.
     scrollbar-color is the only route to the thumb colour in Firefox, and
     setting either standard property makes Chrome drop ::-webkit-scrollbar
     wholesale -- so the webkit pseudo-elements are deliberately absent rather
     than written and silently ignored. Same call as the hamburger lists. */
  max-block-size: min(60vh, 28rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--scroll-thumb) transparent;
}

/* Both popovers hang at their *static position* -- `top: auto` on an absolutely
   positioned box means "where this would have sat in flow", which for a
   block-level container following the inline-flex trigger inside a block
   .navbar-item puts it under the trigger's line box.

   UNDER ITS LINE BOX, NOT UNDER THE TRIGGER, and the difference is 7px. This
   comment used to claim the gap below the control was "the card's own
   margin-block-start and nothing else, in one place, for every menu", which was
   wrong, and wrong in the direction that matters: it said there was one number
   to tune when there were two. Joy reported the user menu still hanging low on
   2026-10-27 after the article's share panel was fixed, and the measurement off
   the live header settled it --

     trigger      top  98.0   bottom 138.0   40px tall, padding 0 both ends
     avatar       top  98.0   bottom 138.0   fills the trigger exactly
     wrapper      top 145.0                  static position, 0 tall
     card         top 153.0                  = 145 + its 8px margin

   -- so the avatar's bottom edge and the card's top edge were 15px apart, of
   which the margin was only ever eight. The other 7px is line-box descent:
   .btn-dropdown is `display: inline-flex`, so it is an inline-level box sitting
   on its parent's baseline, and the parent's line box runs on below it by the
   strut's descender (lineHeight computes to 18.4685px there). The wrapper is a
   block and starts after the whole line box.

   WHY IT READS AS WORSE HERE THAN ANYWHERE ELSE even though the margin was the
   same 0.5rem the search panel uses: these two triggers paint no box at all at
   desktop width, so there is no border for the eye to measure from and it
   measures from the avatar or the label instead -- picking up the 7px of
   invisible line box as if it were gap.

   The 7px is still here. Removing it means the trigger stops being inline-level
   or stops being baseline-aligned, and either way .navbar-item.user gets 7px
   shorter, which is a header layout change rather than a gap change -- nothing
   in this theme pins the nav row's height, so it is not obviously free. Held
   back deliberately for that reason, and not because it is hard. */
.dropdown-container {
  position: absolute;
  z-index: 999;
  top: auto !important;
  bottom: auto !important;
}

.dropdown-container-user {
  left: auto !important;
  position: static;
  width: 100%;
}

/* `.dropdown-user { top: 100% }` was here, and with it the user menu hung lower
   than the language menu -- Joy reported the mismatch 2026-10-22. It was a
   second, compounding offset: .dropdown is `position: relative`, so a
   percentage `top` shifts the card down by its containing block's height on top
   of wherever the container had already placed it, which is a measurement the
   language card never takes. Removing it is what makes the two menus the same
   mechanism rather than two mechanisms tuned to agree. The matching
   `top: 100% !important` on the container comes off in the 45em block below.

   Nothing restores it in the hamburger, and nothing should: the submenus are
   drawn in flow there (see the note at css-page-header.css:1100), so a relative
   nudge was wrong at that width too. */

/* One row, and the counterpart of .aa-suggestion: --radius-sm, 0.5rem of block
   and 0.75rem of inline padding, 1.4 leading, and a transition on the fill
   alone.
   Both selectors keep the type qualifier they already had, so specificity
   against the rest of this file does not move. In particular `.btn-user
   a.dropdown-item { padding: 0 }` at :142 still out-specifies this at (0,2,1)
   and still flattens the signed-out "Sign in" link, which sits inside .btn-user
   rather than inside a panel and is deliberately not a menu row. */
a.dropdown-item,
a.dropdown-language-item {
  display: flex;
  align-items: center;
  border-radius: var(--radius-sm);
  color: var(--neutral-text);
  cursor: pointer;
  font-weight: var(--font-weight-regular);
  line-height: var(--leading-body-0);
  padding-block: 0.5rem;
  padding-inline: 0.75rem;
  text-decoration: none;
  transition: background-color var(--motion-duration-control) var(--ease-in-out);
}

/* Hover and keyboard focus take the same fill, so arrowing through the menu
   looks like pointing at it. The ring itself is the sitewide one from
   css-reset.css:19; only the offset is pinned, which is exactly what :16 there
   asks components that care about the offset to do. 2px of offset and 2px of
   width is the 4px the card's inset was sized for. */
a.dropdown-item:hover,
a.dropdown-item:focus-visible,
a.dropdown-language-item:hover,
a.dropdown-language-item:focus-visible {
  background-color: var(--neutral-bg-component-soft-hover);
}

a.dropdown-item:focus-visible,
a.dropdown-language-item:focus-visible {
  /* The `border: 0` that used to sit here is gone, 2026-10-25, AND THIS RULE IS
     THE HISTORY OF THE DEFECT THAT FINALLY GOT FIXED AT SOURCE. Joy reported a
     doubled focus ring on these rows on 2026-10-22 -- the reset paired its
     outline with `border: 2px solid var(--form-focus-ring)`, so a focused row
     drew the brand colour twice, a border hugging the text and an outline 2px
     outside it. It was cancelled here rather than at source because the border
     was load-bearing elsewhere, and that scoping is why the same defect kept
     turning up on other controls for three more days until Joy reported it
     again, on the requests table, with the reset's rule on screen.

     The border has now left css-reset.css; see the comment there for the five
     clipped controls that depended on it and what they get instead. Nothing is
     left to cancel, so what remains of this rule is the offset alone.

     Keeping the offset: the reset falls back to max(2px, 0.15em), and Codex uses
     a flat 2px. The 4px the ring needs -- 2px offset plus 2px width -- is drawn
     into .dropdown's existing `padding: 0.25rem`, since a scroll container's
     scrollport is its padding box. That inset was sized for this. */
  --outline-offset: 2px;
}

/* Press is the one step darker, and snaps rather than eases -- the pair the
   hamburger rows and both triggers already use, so a tap feels the same
   wherever in the header it lands. */
a.dropdown-item:active,
a.dropdown-language-item:active {
  background-color: var(--neutral-bg-component-active);
  transition-duration: var(--motion-duration-instant);
}

@media (min-width: 45em) {
  /* `width: auto` added 2026-10-22, fixing a user menu that ran off the right of
     the viewport.

     The `width: 100%` above is a *mobile* declaration: there the container is
     `position: static` and should fill the hamburger card. This rule flips it
     back to absolute and the percentage then resolves against the containing
     block, which is not the trigger -- .dropdown-container-wrapper and
     .navbar-item are both unpositioned, so the search walks all the way up and
     the container comes out roughly viewport-wide.

     It has been that wide all along. It only became visible when .dropdown
     changed from `inline-flex` to `flex` in the rebuild above, because an
     inline-flex card shrink-wrapped to its longest row and so hid how big the
     box around it was. `auto` on an absolutely positioned box with auto insets
     shrink-to-fits, which is what the card needed in the first place -- and it
     also stops an invisible full-width div sitting over the header swallowing
     clicks whenever the menu is open. */
  /* No `top` here any more either. It was `top: 100% !important`, which read as
     "sit below the trigger" but resolves against the nearest *positioned*
     ancestor -- and as the note above says, .navbar-item is not one, so the
     100% was a share of something much taller than the control. Letting
     .dropdown-container's `top: auto !important` through puts this container at
     its static position, which is exactly where the language container already
     sits. */
  .dropdown-container-user {
    position: absolute;
    width: auto;
  }
}

/* Display button based on user type */
.agent,
.manager,
.anonymous,
.end_user {
  display: none;
}
@media screen and (max-width: 54.89em) {
  /* `--bg-image: none` next to the transparent fill, and it is doing real work:
     this rule draws the support row as a plain underlined link, and a
     transparent background-color with .btn's brand gradient still on top is a
     brand-red pill. css-page-header.css:900 also sets it for the three
     .header-nav controls at (0,2,0); this is the lower-specificity backstop for
     a .navbar-btn rendered outside that wrapper. */
  .navbar-btn {
    background-color: transparent;
    --bg-image: none;
    padding: 0;
    border: 0;
    color: var(--clr-secondary-140);
    font-weight: 400;
    text-decoration: underline;
    font-size: var(--step-1) !important;
    &:hover {
      background-color: var(--clr-secondary-5);
      text-decoration: none;
      transition-duration: var(--transition-duration);
    }
  }

  .btn-dropdown {
    border: none;
    border-radius: 0;
  }
  .btn-dropdown-user {
    position: static;
    border: none;
    padding: 0;
    background-color: transparent;
  }

  .dropdown-container-language {
    inset-inline-end: 20px;
  }

  .btn-dropdown {
    padding: 0;
    height: 1.5rem;
  }

  .requests-link {
    padding: 0;
  }

  .dropdown-user {
    a.dropdown-item {
      margin-block-start: 1.5rem 0 0 0;
    }
  }

  .dropdown-language {
    .dropdown {
      max-height: 20rem;
      overflow: scroll;
    }
  }
}

/* SECTION - Dark tier
   Added 2026-10-20. Everything above is still on the legacy --clr-* ramp, and
   the migration of this file proper is a later phase (docs/brand-refresh/plan.md),
   so this is a dark-only correction rather than a rewrite: nothing here changes a
   single light-mode pixel.

   Only the variants a template actually renders are listed. `.btn-theme`,
   `.btn-theme-footer` and `.btn-secondary` are the other three white-bodied
   variants in this file and they are all dead CSS -- nothing in templates/ carries
   those classes -- so theming them would mean inventing a dark treatment for
   something nobody can see. Left for whoever revives or deletes them.

   Why .btn is absent: it is already correct in dark. It is coral with white text,
   and the coral is brand, which is one colour in both themes by definition. The
   Codex screenshots confirm the same thing from the other side -- .kb-button-strong's
   label is var(--fixed-white), sampled as a literal #ffffff out of the dark
   screenshot, not a neutral that flips. That now covers the request page's Submit
   as well, which used to be named here alongside .btn: `.btn-submit` carries
   nothing but geometry now (see the comment above it), and geometry does not
   flip, so there is nothing left for a dark patch to correct.

   What was actually wrong. `.btn-dropdown` and `.btn-user` -- the locale and user
   controls in the header -- resting at `--bg: var(--clr-white)` with
   `--fg: var(--clr-neutral-160)`. In light that is a white pill on a white header,
   which is why it has never been reported; in dark it is a white block with near
   black text sitting in the middle of a dark header. Note this is the *desktop*
   header only: css-page-header.css:899 already gives these three controls a
   transparent fill and --neutral-text inside `max-width: 54.9em`, so the hamburger
   nav has been right all along and only the wide layout was wrong. The resting
   value here is `transparent` for the same reason that block chose it -- the
   control's shape comes from its hover fill, and a resting pill the colour of the
   header is just an invisible pill.

   Specificity, which is the only subtle thing in this block. `:root[data-theme=
   'dark']` is (0,2,0) on its own, and the targets sit in `:where()`, which
   contributes nothing -- so each base compound is exactly (0,2,0) and each state
   compound is (0,3,0).
   That is deliberately *just* enough. At (0,2,0) it clears the legacy `.btn-*`
   rules above and, being later in this same file, it also wins the tie against
   `.btn:hover` and `.btn:active` -- which it has to, or pressing the locale button
   in dark would flash it brand coral, the hazard the comment at :15 describes. But
   it stays low enough that the migrated `.header-nav` rules in css-page-header.css
   keep winning on load order. The state pseudo-classes are left outside `:where()`
   on purpose, so hover and press genuinely outrank the resting rule instead of
   depending on their order here.
   (The `:where()` originally also kept `.dropdown-language-item` from reaching
   (0,3,0) and repainting the hamburger rows. Those targets have since left this
   block -- see the note where they were.) */
:root[data-theme='dark'] {
  :where(.btn-dropdown, .btn-user) {
    --bg: transparent;
    --fg: var(--neutral-text);
  }

  /* Both state fills are the pair css-page-header.css:1232/1245 already uses for
     the rows inside these menus, so a trigger and the rows it opens respond with
     one set of colours across both breakpoints. The hover border is what gives the
     control an edge once it has a fill; the base rule reserves a transparent 1px
     for it, so nothing shifts as the pointer arrives. */
  :where(.btn-dropdown, .btn-user):hover {
    --bg: var(--neutral-bg-component-soft-active);
    --border-color: var(--neutral-border);
  }

  :where(.btn-dropdown, .btn-user):active {
    --bg: var(--neutral-bg-component-active);
    --border-color: var(--neutral-border);
  }

  /* The panel and its rows used to be patched here too -- `:where(.dropdown)`
     for the card's fill and border, `:where(.dropdown-item,
     .dropdown-language-item, .dropdown-user a)` for the ink, and a `:hover` for
     the row fill. All three are gone as of the 2026-10-22 rebuild of the
     Dropdown section above, which put the card and the rows on semantic roles
     that already carry a dark tier. There is nothing left to correct: a patch
     restating a token that flips on its own is just a second place to change it.
     The .btn-dropdown/.btn-user rules above stay, because those triggers are
     still on --clr-*. */
}
