/* =============================================================================
   SynapCTX shared components
   =============================================================================

   Rules for components whose MARKUP is shipped by this module, so their styling has to
   travel with them. tokens.css is the vocabulary; this is the small set of finished
   components built from it.

   IT EXISTS BECAUSE THE CONSENT BANNER SHIPPED UNSTYLED. The partial was shared through
   ui-design-system but its CSS was written only into marketing.css, so on the console and
   the auth pages the banner rendered as raw text at the viewport edge with plain buttons
   clipped at the bottom. Shared markup with unshared styling is a broken component by
   construction.

   CONSUMERS LOAD THIS AFTER tokens.css AND BEFORE THEIR OWN COMPONENT LAYER, so a surface
   can still override a shared component but never accidentally precede its tokens.

   WHAT BELONGS HERE: styling for markup this module ships. What does not: anything a
   single surface owns. A rule here is a commitment to every surface at once.
   ============================================================================= */

/* =============================================================================
   THE [hidden] RESET — read this before removing it.
   =============================================================================
   `hidden` is a semantic "this element is not relevant right now", and the UA stylesheet
   implements it as `[hidden] { display: none }`. But that is a UA rule, so ANY author rule
   setting `display` beats it — and a component almost always sets display.

   That cost real bugs, live: `<div class="nav-menu-head" hidden>` rendered anyway because
   `.nav-menu-head { display: flex }` won, so a signed-OUT visitor saw a menu saying "Signed
   in"; and `<img class="nav-avatar-img" hidden>` rendered as an empty circle because
   `.nav-avatar-img { display: block }` won. Both looked like logic bugs and were not.

   !important is warranted here and almost nowhere else: nothing should out-rank an author's
   statement that an element is not to be rendered. normalize.css does exactly this, for
   exactly this reason.

   IT DOES NOT HELP SVG. `hidden` is an HTMLElement IDL attribute, so `svg.hidden = true` in
   JavaScript sets a meaningless property and never produces the attribute this rule matches.
   For an <svg>, set the attribute explicitly or toggle a class on an HTML parent.
   ============================================================================= */
[hidden] {
  display: none !important;
}

/* =============================================================================
   COOKIE CONSENT
   =============================================================================
   A bar, not a modal. This estate sets five strictly necessary cookies and TWO
   non-essential ones, with no analytics and no third-party tracking anywhere — a
   full-screen interstitial for that would be disproportionate theatre, and it would
   block a first-time visitor from reading the page they came for.

   BOTH BUTTONS ARE THE SAME SIZE. "Accept" carries the filled treatment because it is
   the affirmative action, but "Essential only" is equally reachable, equally legible and
   on the same row — not behind a "manage preferences" second screen. Declining costs a
   remembered theme and nothing else, and the copy says so. */
.sctx-consent {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 400;
    border-top: 1px solid var(--md-sys-color-outline-variant);
    background: var(--md-sys-color-surface-container);
    box-shadow: var(--md-sys-elevation-3);
}

.sctx-consent-inner {
    max-width: 1080px;
    margin: 0 auto;
    padding: 1rem 1.5rem;
    display: flex;
    align-items: center;
    gap: 1.5rem;
}

.sctx-consent-text {
    margin: 0;
    flex: 1 1 auto;
    font-size: 0.8125rem;
    line-height: 1.5;
    color: var(--md-sys-color-on-surface-variant);
}

.sctx-consent-text strong { color: var(--md-sys-color-on-surface); font-weight: 600; }
.sctx-consent-text a { color: var(--md-sys-color-primary); }

.sctx-consent-actions {
    display: flex;
    flex: 0 0 auto;
    gap: 0.625rem;
}

.sctx-consent-btn {
    padding: 9px 18px;
    border: 1px solid var(--md-sys-color-outline);
    border-radius: 8px;
    background: transparent;
    font: inherit;
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--md-sys-color-on-surface);
    cursor: pointer;
    /* Buttons never underline — the site-wide standard. */
    text-decoration: none;
    white-space: nowrap;
}

.sctx-consent-btn:hover { background: var(--md-sys-color-surface-container-high); }

.sctx-consent-btn.is-primary {
    border-color: var(--md-sys-color-primary);
    background: var(--md-sys-color-primary);
    color: var(--md-sys-color-on-primary);
}

.sctx-consent-btn.is-primary:hover { background: var(--sct-color-primary-hover); }

@media (max-width: 720px) {
    .sctx-consent-inner { flex-direction: column; align-items: stretch; gap: 0.875rem; padding: 1rem 1.25rem; }
    /* Full-width buttons side by side, still equal — a stacked pair invites a stray tap
       on whichever is under the thumb. */
    .sctx-consent-actions { }
    .sctx-consent-btn { flex: 1 1 0; text-align: center; }
}

/* =============================================================================
   THE HEADER DROPDOWN MENU — one definition, two surfaces.
   =============================================================================
   The console had `.sx-menu-*` and the marketing site had `.nav-menu-*`: the same
   component built twice, which is how they came to disagree. Today's appearance
   control had to be written into both, and the `.is-static` row rule was hand-copied
   between them within the hour — that is the duplication tax, paid in real time.

   DENSITY IS PARAMETERISED, WHICH IS WHY THIS COULD BE SHARED AT ALL. The two
   surfaces genuinely disagreed on metrics — 240px vs 216px wide, 6px vs 10px offset,
   20px vs 18px icons, a different surface level — and unifying them by picking a
   winner would have been a VISUAL change to somebody's product dressed up as a
   refactor. Instead every difference is a custom property with a default, so each
   surface keeps exactly the rendering it has today and there is still one component.

   The defaults are the marketing site's, because it already speaks `--md-sys-*`
   natively; the console overrides the handful it needs from its own layer. A consumer
   that sets nothing gets a correct menu.

   WHAT IS NOT HERE: each surface's own furniture — the console's submenu, caret,
   check and text-size rows, the marketing site's account head and avatar. The rule
   for this file is that a rule in it is a commitment to every surface at once.
   ============================================================================= */
.sctx-menu-anchor {
    position: relative;
    display: inline-flex;
}

.sctx-menu {
    /* --- density hooks; defaults are the marketing header -------------------- */
    --sctx-menu-min-width: 216px;
    --sctx-menu-offset: 10px;
    --sctx-menu-pad: 8px;
    --sctx-menu-radius: 12px;
    --sctx-menu-surface: var(--md-sys-color-surface-container);
    --sctx-menu-row-radius: 8px;
    --sctx-menu-row-pad: 9px 12px;
    --sctx-menu-icon-size: 18px;

    position: absolute;
    top: calc(100% + var(--sctx-menu-offset));
    right: 0;
    /* Above the page, below a modal or slide-over. The console used 70 and the
       marketing site 200; both mean "above everything this page has", so the higher
       wins and neither surface has a stacking neighbour in between. */
    z-index: 200;
    min-width: var(--sctx-menu-min-width);
    padding: var(--sctx-menu-pad);
    border: 1px solid var(--md-sys-color-outline-variant);
    border-radius: var(--sctx-menu-radius);
    background: var(--sctx-menu-surface);
    box-shadow: var(--md-sys-elevation-3);
}

/* A <form> wrapping a menu row must add no box of its own, or the row inside it sits
   lower than every sibling. The console learned this from a sign-out row whose inline
   `all:unset` was compensating for exactly that. */
.sctx-menu form { margin: 0; padding: 0; }

.sctx-menu-title {
    padding: 6px 12px 8px;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--md-sys-color-on-surface-variant);
}

.sctx-menu-divider {
    height: 1px;
    margin: 4px 0 6px;
    background: var(--md-sys-color-outline-variant);
}

.sctx-menu-row {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: var(--sctx-menu-row-pad);
    border: none;
    border-radius: var(--sctx-menu-row-radius);
    background: transparent;
    font: inherit;
    font-size: 0.875rem;
    text-align: left;
    color: var(--md-sys-color-on-surface);
    cursor: pointer;
    /* Rows are <a> as well as <button>, and a site-wide `a:hover` underline would
       otherwise strike through a menu item. The estate's standing rule: no button or
       menu row underlines on hover, anywhere. */
    text-decoration: none;
}

.sctx-menu-row:hover {
    background: var(--md-sys-color-surface-container-high);
    text-decoration: none;
}

/* A row that LABELS a control rather than being an action itself: no hover highlight,
   no pointer, because nothing happens when you click the word "Appearance". */
.sctx-menu-row.is-static { cursor: default; }
.sctx-menu-row.is-static:hover { background: transparent; }

.sctx-menu-row-icon {
    width: var(--sctx-menu-icon-size);
    height: var(--sctx-menu-icon-size);
    flex: 0 0 var(--sctx-menu-icon-size);
    fill: currentColor;
    color: var(--md-sys-color-on-surface-variant);
}

/* SELECTED BY CLASS, NEVER BY ELEMENT NAME. This was `.nav-menu-row span`, a (0,1,1)
   selector that beat the `flex: 0 0 38px` the old theme switch declared on itself at
   (0,1,0) — the track rendered 26% wider than it asked for and its knob stopped short
   of the end. An element-name descendant rule captures every future child of that
   type, including components that set the same property for themselves. */
.sctx-menu-row-label { flex: 1 1 auto; }

/* =============================================================================
   THE APPEARANCE CONTROL — three positions: system, light, dark.
   =============================================================================
   Sizes are LITERAL, not tokenised, and deliberately so: the thumb has to cover exactly
   one option for the track to read as a track, so the two measurements are one decision
   and splitting them across tokens is how they drift apart.

   THE TRAVEL IS `translateX(100%)`, A PERCENTAGE OF THE THUMB'S OWN WIDTH — never a
   pixel count. The switch this replaced hard-coded `translateX(16px)` against a 38px
   track, and when the track was stretched to 47.8px by an unrelated `flex: 1 1 auto` on
   a sibling selector, the knob kept travelling 16px and stopped a third of the way short
   with no rule anywhere being wrong on its own. A percentage of itself cannot come apart
   from the thing it is sliding over.

   POSITION COMES FROM THE ROOT ATTRIBUTE, not from a class this control maintains — see
   theme-control in templates/theme.html for why that is the whole point. */
.sctx-theme {
    position: relative;
    display: inline-flex;
    /* flex: none is REQUIRED, not defensive. This sits in flex menu rows on three
       surfaces and a `flex: 1 1 auto` inherited from a row's descendant selector is
       exactly what broke the switch before it. */
    flex: none;
    padding: 3px;
    border-radius: 999px;
    background: var(--md-sys-color-surface-container-highest);
}

.sctx-theme-opt {
    position: relative;   /* above the thumb, which is why it needs a stacking context */
    z-index: 1;
    display: grid;
    place-items: center;
    width: 30px;
    height: 24px;
    padding: 0;
    border: none;
    border-radius: 999px;
    background: none;
    color: var(--md-sys-color-on-surface-variant);
    cursor: pointer;
    /* No underline on hover, ever — the estate-wide button rule. */
    text-decoration: none;
    transition: color 0.18s ease;
}

.sctx-theme-opt svg { width: 16px; height: 16px; fill: currentColor; }
.sctx-theme-opt:hover { color: var(--md-sys-color-on-surface); }
.sctx-theme-opt[aria-checked="true"] { color: var(--md-sys-color-primary); }
.sctx-theme-opt:focus-visible {
    outline: 2px solid var(--md-sys-color-primary);
    outline-offset: 1px;
}

.sctx-theme-thumb {
    position: absolute;
    top: 3px;
    left: 3px;
    width: 30px;    /* == .sctx-theme-opt width; see above */
    height: 24px;
    border-radius: 999px;
    background: var(--md-sys-color-surface);
    box-shadow: var(--md-sys-elevation-1);
    transition: transform 0.18s ease;
}

/* The three positions. Written against `:root` so they resolve from the attribute
   theme-preload sets before first paint — no flash, no JS state to agree with. */
:root[data-synapctx-theme-pref="system"] .sctx-theme-thumb { transform: translateX(0); }
:root[data-synapctx-theme-pref="light"]  .sctx-theme-thumb { transform: translateX(100%); }
:root[data-synapctx-theme-pref="dark"]   .sctx-theme-thumb { transform: translateX(200%); }

/* Honour a reduced-motion request: the thumb still moves, it just does not slide. */
@media (prefers-reduced-motion: reduce) {
    .sctx-theme-thumb { transition: none; }
}

/* The header's grouping rule: navigation on the left of it, session controls on the
   right. A border on an empty span rather than a "|" glyph — a pipe character inherits
   the font's line metrics and sits off-centre against 34px buttons, and it would be read
   aloud by a screen reader as content. */
.nav-divider {
    width: 1px;
    height: 22px;
    margin: 0 0.375rem;
    background: var(--md-sys-color-outline-variant);
    flex: 0 0 1px;
}

/* In the mobile panel the row is vertical, so a vertical rule makes no sense: it becomes
   a full-width horizontal one, which reads as the same grouping. */
@media (max-width: 768px) {
    .nav-divider {
        width: auto;
        height: 1px;
        align-self: stretch;
        margin: 0.5rem 0;
        flex: 0 0 1px;
    }
}

/* ============================================================================
   sctx-code — a command block with an integrated copy button

   WHY THIS IS SHARED. Both surfaces hand a developer a command to run: the
   console's API-keys page prints the MCP and `sctx setup` commands, and the
   marketing site's /sctx/ page prints the install commands. A command a reader
   has to select by hand is a command they mistype, and the two surfaces were
   about to grow two different answers to that — the console already had a
   panel-head Copy button driven by Alpine, and the marketing site has no
   Alpine at all. A code block with the button ON the block is the arrangement
   neither had, so it belongs here rather than in either stylesheet.

   The BEHAVIOUR ships with it (templates/code.html) for the same reason the
   consent banner's styling does: shared markup with unshared behaviour is a
   broken component. The script is plain delegated DOM, so it works on the
   marketing site's vanilla pages and inside the console's Alpine pages alike.

   DENSITY HOOKS, as with `sctx-menu`: a consumer sets the custom properties
   and never re-declares the structure.
   ============================================================================ */

.sctx-code {
    /* --- density hooks; defaults suit a marketing page ----------------------- */
    --sctx-code-pad: 20px;
    --sctx-code-radius: 12px;
    --sctx-code-font-size: 0.875em;

    /* THE COMPONENT OWNS ITS OWN SURFACE, and must.
       The first version set no background and coloured the button from the
       consuming site's `--code-text`. That worked on the marketing site, which
       happens to define both tokens, and would have shipped an INVISIBLE button
       to the console, which defines neither and styles `pre` not at all: the
       fallback was near-white, on a light panel. Shared styling that assumes a
       surface the consumer supplies is the same defect as shared markup with no
       styling — just harder to notice, because it looks right where it was built.
       The inverse-surface pair is the design system's own "dark block on a light
       page", identical in both themes, and every consumer already has it. */
    --sctx-code-bg: var(--md-sys-color-inverse-surface);
    --sctx-code-fg: var(--md-sys-color-inverse-on-surface);

    position: relative;
}

.sctx-code > pre {
    margin: 0;
    padding: var(--sctx-code-pad);
    /* Room for the button, so a long single-line command scrolls UNDER it rather
       than ending beneath it where it cannot be read. */
    padding-right: calc(var(--sctx-code-pad) + 44px);
    border-radius: var(--sctx-code-radius);
    background: var(--sctx-code-bg);
    color: var(--sctx-code-fg);
    font-size: var(--sctx-code-font-size);
    overflow-x: auto;
}

/* A `code` inside inherits the block. Consumers style bare `code` as an inline
   chip (tinted background, accent colour), and that chip rendering inside a dark
   block is what made the command unreadable on the console before this. */
.sctx-code > pre code {
    background: none;
    padding: 0;
    color: inherit;
    font-size: inherit;
}

.sctx-code-copy {
    /* HIDDEN UNTIL THE SCRIPT CLAIMS IT. A copy button is useless without
       JavaScript, and a control that does nothing when clicked is worse than an
       absent one — the reader assumes they misclicked and tries again. The script
       stamps `data-sctx-copy-ready` on the block, so with scripting disabled the
       command is still fully visible and selectable and no dead affordance is
       offered. */
    display: none;

    position: absolute;
    top: 10px;
    right: 10px;
    z-index: 1;

    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 1px solid transparent;
    border-radius: 8px;
    background: transparent;
    /* THE BLOCK'S OWN foreground, not the page's. The block is a dark surface in
       both themes, so `--md-sys-color-on-surface` here renders near-black on
       near-black in light mode — and reading the CONSUMER's `--code-text` renders
       near-white on a light panel wherever the consumer does not define it. Taking
       it from the component's own hook is what makes the contrast a property of the
       component rather than of whoever happens to be using it. */
    color: var(--sctx-code-fg);
    cursor: pointer;
    opacity: 0.65;
    transition: opacity 0.15s ease, background-color 0.15s ease;
}

.sctx-code[data-sctx-copy-ready] .sctx-code-copy { display: inline-flex; }

.sctx-code-copy:hover {
    opacity: 1;
    background: rgba(255, 255, 255, 0.12);
}

.sctx-code-copy:focus-visible {
    opacity: 1;
    outline: 2px solid var(--md-sys-color-primary);
    outline-offset: 2px;
}

.sctx-code-copy svg {
    width: 16px;
    height: 16px;
    fill: currentColor;
    pointer-events: none;
}

/* Two glyphs, one button: the tick replaces the sheets on success. Toggled by an
   attribute rather than by swapping markup, so the button never reflows and a
   screen reader's focus is not disturbed mid-announcement. */
.sctx-code-copy .sctx-code-copied-icon { display: none; }
.sctx-code-copy[data-copied] .sctx-code-copy-icon { display: none; }
.sctx-code-copy[data-copied] .sctx-code-copied-icon { display: block; }
.sctx-code-copy[data-copied] {
    opacity: 1;
    color: var(--md-sys-color-primary);
}

/* ============================================================================
   sctx-accordion — a disclosure built on <details>/<summary>

   NATIVE, NOT SCRIPTED, for the same reasons the install tabs are CSS-only:
   <details> is keyboard-operable, exposed to assistive technology as a
   disclosure, findable by the browser's own in-page search (Chrome and Safari
   expand a closed <details> to reveal a match — a div-and-JS accordion hides
   its content from Ctrl+F entirely), and it works before any script runs. A
   hand-rolled one has to reimplement all of that and usually reimplements none
   of it.

   The marker is drawn with a rotating chevron rather than the UA triangle, so
   it matches the rest of the estate; `list-style: none` plus the WebKit
   pseudo-element are BOTH required, because Safari draws its marker through a
   non-standard pseudo-element that `list-style` does not reach.
   ============================================================================ */

.sctx-accordion {
    --sctx-accordion-pad: 16px 0;
    --sctx-accordion-gap: 12px;

    /* A rule BETWEEN items, never around the set. A stack of disclosures wants
       separators, not a box: a border above the first one and below the last one read
       as an empty row rather than a divider — and in the install panels the last one
       met the following section's own border-top, drawing two lines with a gap between
       them. Doing this in the component means no consumer has to remember it. */
    border-bottom: 1px solid var(--md-sys-color-outline-variant);
}

/* `:last-of-type` rather than `:last-child`: a disclosure set is often followed by a
   footnote or a link, and `:last-child` would then match nothing and leave the rule in
   place. This asks "the last <details> among its siblings", which is the real question. */
.sctx-accordion:last-of-type { border-bottom: none; }

.sctx-accordion > summary {
    display: flex;
    align-items: center;
    gap: var(--sctx-accordion-gap);
    padding: var(--sctx-accordion-pad);
    /* A disclosure control must look like one. Without the pointer it reads as a
       heading that happens to move when clicked. */
    cursor: pointer;
    font-weight: 600;
    color: var(--md-sys-color-on-surface);
    /* Both are needed: `list-style` covers Firefox and Chrome, the WebKit
       pseudo-element below is the only thing that removes Safari's triangle. */
    list-style: none;
}

.sctx-accordion > summary::-webkit-details-marker { display: none; }

.sctx-accordion > summary:hover { color: var(--md-sys-color-primary); }

/* Focus goes on the summary, which is the focusable element — not the details. */
.sctx-accordion > summary:focus-visible {
    outline: 2px solid var(--md-sys-color-primary);
    outline-offset: 2px;
    border-radius: 6px;
}

/* The chevron. `flex: none` so a long label cannot squash it, and
   `margin-left: auto` puts it at the trailing edge regardless of label length. */
.sctx-accordion > summary::after {
    content: "";
    flex: none;
    margin-left: auto;
    width: 8px;
    height: 8px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg);
    transform-origin: center;
    transition: transform 0.32s cubic-bezier(0.2, 0, 0, 1);
}

.sctx-accordion[open] > summary::after { transform: rotate(-135deg); }

/* THE CONTENT ITSELF ANIMATES ONLY WHERE THE BROWSER CAN DO IT.
   A native <details> opens INSTANTLY — there is no transition to hook, which is why
   the disclosure felt abrupt even with an eased chevron: the marker moved smoothly
   and the panel snapped. `::details-content` plus `interpolate-size` is what finally
   made this animatable in CSS, and it is recent (Chromium 131+), so it goes behind
   @supports: browsers without it keep the instant open they have always had, which
   is correct behaviour rather than a broken one.

   `allow-keywords` is what lets `height` transition to and from `auto`; without it
   the keyword is not interpolable and the transition is silently ignored. */
@supports selector(::details-content) {
    .sctx-accordion {
        interpolate-size: allow-keywords;
    }

    .sctx-accordion::details-content {
        height: 0;
        overflow: hidden;
        /* content-visibility must be in the transition list AND carry
           `allow-discrete`, or the browser keeps the content `hidden` for the whole
           duration and the panel appears at the end instead of growing. */
        transition:
            height 0.32s cubic-bezier(0.2, 0, 0, 1),
            content-visibility 0.32s allow-discrete;
    }

    .sctx-accordion[open]::details-content {
        height: auto;
    }
}

/* Anyone who has asked for less motion gets none of it. */
@media (prefers-reduced-motion: reduce) {
    .sctx-accordion > summary::after { transition: none; }

    @supports selector(::details-content) {
        .sctx-accordion::details-content { transition: none; }
    }
}

.sctx-accordion-body {
    padding: 0 0 20px;
    color: var(--md-sys-color-on-surface-variant);
}

.sctx-accordion-body > :first-child { margin-top: 0; }
.sctx-accordion-body > :last-child { margin-bottom: 0; }

/* =============================================================================
   TABS — one appearance for every tabbed control on every surface.
   =============================================================================
   Promoted here because there were already TWO of these: the console's `.sct-tab`
   and the marketing site's `.mkt-tab`. Two implementations of one control is how
   the surfaces drift, and it is the dividing line this module exists on — if two
   surfaces would want it, it belongs here.

   THE COMPONENT OWNS ITS SURFACE THROUGH HOOKS, NOT BY READING THE CONSUMER'S.
   This is the lesson `sctx-code` already paid for. synapctx.com HARDCODES its dark
   palette and never redefines `--md-sys-color-*`, so a tablist styled directly
   from those tokens renders a surface-1 grey there in dark mode that belongs to a
   different palette entirely — correct on the console, subtly wrong on the site
   that has more tabs. Every colour below is a `--sctx-tab-*` hook with an md-sys
   default, so a surface with its own palette overrides five properties instead of
   forking the component.

   THIS MODULE DOES NOT OWN WHICH PANEL IS SHOWING. A CSS-only tab set keys that on
   the consumer's own input ids (`#os-mac:checked ~ …`), and ids are the consumer's
   namespace, so the reveal rules stay with the surface — switching on
   `--sctx-tab-active-*` rather than restating what "active" looks like.

   Works two ways, and both are here because both are legitimate:
     - RADIO-DRIVEN (`.sctx-tab-radio` + `<label class="sctx-tab">`) — no
       JavaScript, instant, but every panel ships. Right when the panels are small.
     - LINK-DRIVEN (`<a class="sctx-tab" aria-current="page">`) — one panel ships,
       server-rendered. Right when they are not; the consumer may enhance the click
       to swap in place, and the plain link is the no-JavaScript fallback. */

.sctx-tabs {
    --sctx-tablist-bg: var(--md-sys-color-surface-1, var(--md-sys-color-surface));
    --sctx-tablist-border: var(--md-sys-color-outline-variant);
    --sctx-tab-fg: var(--md-sys-color-on-surface-variant);
    --sctx-tab-hover-bg: var(--md-sys-color-surface-2, var(--md-sys-color-surface-1));
    --sctx-tab-hover-fg: var(--md-sys-color-on-surface);
    --sctx-tab-active-bg: var(--md-sys-color-primary);
    /* THE PAIRED TOKEN, never a literal white. The primary INVERTS with the theme,
       so a hardcoded `#fff` renders white on pale blue in dark mode — about 1.6:1,
       unreadable — while looking perfect in light. `on-primary` is the foreground
       defined as legible against that exact background in both themes, which is
       the whole reason the token exists in pairs. */
    --sctx-tab-active-fg: var(--md-sys-color-on-primary);
    --sctx-tab-focus: var(--md-sys-color-primary);
}

/* VISUALLY HIDDEN, NOT `display: none`.

   `display: none` and `visibility: hidden` both remove an input from the tab order,
   which would leave the labels unreachable by keyboard and the whole control
   operable only by mouse. This keeps each radio focusable so its :focus-visible
   state can be forwarded to the label. */
.sctx-tab-radio {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

.sctx-tablist {
    display: flex;
    gap: 4px;
    padding: 4px;
    border: 1px solid var(--sctx-tablist-border);
    border-radius: 12px;
    background: var(--sctx-tablist-bg);
    /* Scrollable rather than wrapping: a longer set must not reflow into two rows
       and shift the panel beneath it every time the selection changes. */
    overflow-x: auto;
}

.sctx-tab {
    flex: 1 1 auto;
    /* inline-flex so a leading glyph sits on the text's baseline row and centres
       with it; `text-align` cannot centre a flex row's contents. Tabs with no icon
       are unaffected — a flex row of one text node centres exactly as before. */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 10px 20px;
    border-radius: 9px;
    text-align: center;
    font-size: 0.9375rem;
    font-weight: 500;
    color: var(--sctx-tab-fg);
    cursor: pointer;
    white-space: nowrap;
    user-select: none;
    /* NEVER UNDERLINED, INCLUDING ON HOVER. A link-driven tab is an `<a>`, so any
       surface with the usual `a:hover { text-decoration: underline }` underlines it
       — and a tab that grows an underline on hover reads as a link sitting in a row
       of buttons. Declared on the component so no consumer has to remember, and
       restated on :hover below because the consumer's `a:hover` is equally specific
       and would otherwise win on source order. */
    text-decoration: none;
    transition: background-color 0.2s ease, color 0.2s ease;
}

.sctx-tab:hover {
    color: var(--sctx-tab-hover-fg);
    background: var(--sctx-tab-hover-bg);
    text-decoration: none;
}

.sctx-tab[aria-current="page"],
.sctx-tab.is-active {
    background: var(--sctx-tab-active-bg);
    color: var(--sctx-tab-active-fg);
}

/* A link tab carries its own focus ring, but the default is drawn around the
   full-width flex item rather than the text, so it is restated to match the
   radio-driven form, whose ring the consumer forwards from the off-screen input. */
.sctx-tab:focus-visible {
    outline: 2px solid var(--sctx-tab-focus);
    outline-offset: 2px;
}

.sctx-tab-icon {
    flex: none;
    width: 15px;
    height: 15px;
    fill: currentColor;
}

/* Hidden by DEFAULT, revealed by the consumer's own rules. A panel that defaulted
   to visible would show every tab's content at once before the rule that hides it
   applies — and on a surface whose reveal rules failed to load, all of them. */
.sctx-tab-panel { display: none; }
