/* =========================================================================
   Chocola UI — "Liquid Aqua" material system
   Glass surfaces + Aqua gel, all driven by tokens from tokens.css.
   ========================================================================= */

/* ===== Shared material recipes =====
   Each raised surface / repeated pattern is defined exactly once here; the
   component rules below only carry their own deltas (size, radius, layout,
   state). Order matters: neutral recipes first, accent last, so accent wins. */

/* Neutral raised surface — bordered (cards, containers, controls, alert). */
.chocola-card,
.chocola-list,
.chocola-image__figure,
.chocola-user-menu__popover,
.chocola-checkbox__box,
.chocola-radio__dot,
.chocola-switch__track,
.chocola-alert {
    background: var(--chocola-glass-surface);
    border: 1px solid var(--chocola-glass-border);
    box-shadow: var(--chocola-glass-edge);
}
.chocola-checkbox__box,
.chocola-radio__dot {
    border-width: 1.5px;
}

/* Neutral raised surface — borderless (buttons carry no border). The text ink
   lives here (not on .chocola-button) so the accent recipe below can win. */
.chocola-button,
.chocola-button--secondary,
.chocola-button--danger {
    background: var(--chocola-glass-surface);
    color: var(--chocola-color-text);
    box-shadow: var(--chocola-glass-edge);
}

/* Inactive sidebar items start transparent so the accent recipe below wins. */
.chocola-sidebar__item {
    background: none;
    border: 1px solid transparent;
    color: var(--chocola-color-label);
}

/* Accent raised surface — primary buttons, checked controls, avatar, logo,
   active nav. Placed after the neutral recipes so accent wins. */
.chocola-button--primary,
.chocola-checkbox__field:checked + .chocola-checkbox__box,
.chocola-radio__field:checked + .chocola-radio__dot,
.chocola-switch__field:checked + .chocola-switch__track,
.chocola-avatar,
.chocola-header__logo-icon,
.chocola-sidebar__item--active {
    background: var(--chocola-glass-gloss), var(--chocola-accent-fill);
    color: var(--chocola-color-accent-ink);
    border-color: var(--chocola-accent-border);
    box-shadow: var(--chocola-accent-edge);
}

/* Shared containers: large radius + clipped content. */
.chocola-card,
.chocola-list,
.chocola-image__figure {
    border-radius: var(--chocola-radius-lg);
    overflow: hidden;
}

/* Hidden native inputs behind the custom controls. */
.chocola-checkbox__field,
.chocola-radio__field,
.chocola-switch__field {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

/* Control labels. */
.chocola-checkbox__label,
.chocola-radio__label,
.chocola-switch__label {
    display: inline-flex;
    align-items: center;
    cursor: pointer;
    user-select: none;
}
.chocola-checkbox__label,
.chocola-radio__label { gap: var(--chocola-space-2); }
.chocola-switch__label { gap: var(--chocola-space-3); }

/* Toggle visual base (checkbox box / radio dot / switch track). */
.chocola-checkbox__box,
.chocola-radio__dot,
.chocola-switch__track {
    position: relative;
    flex-shrink: 0;
    transition: background var(--chocola-transition), border-color var(--chocola-transition), box-shadow var(--chocola-transition);
}

/* Form-field labels. */
.chocola-input__label,
.chocola-textarea__label,
.chocola-select__label {
    display: block;
    margin-bottom: var(--chocola-space-1);
    font-size: var(--chocola-font-size-sm);
    color: var(--chocola-color-label);
    font-weight: 500;
}

/* Block-level control wrappers. */
.chocola-input,
.chocola-search,
.chocola-textarea,
.chocola-select,
.chocola-checkbox,
.chocola-radio,
.chocola-switch {
    display: block;
    margin: var(--chocola-space-2) 0;
    font-size: var(--chocola-font-size-md);
}

/* Single-line truncation. */
.chocola-list-item__title,
.chocola-list-item__subtitle,
.chocola-header__logo-label,
.chocola-sidebar__label {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Inset form-field surface (input / textarea / select).
   The fill is the shared flat surface on purpose -- a field belongs to the panel it sits on
   -- which leaves the stroke as the field's only resting cue. It therefore has a token of
   its own (--chocola-color-border-field, per theme) rather than the shared hairline: on the
   light theme that hairline is a white veil over a white card (the stroke rendered 1.03:1
   against the field's own interior, so the field all but vanished there), while the field's
   own grey step renders 1.64:1 -- the edge the dark theme already reads at (1.77:1). The search bar goes the other way, with a weaker stroke of its
   own; see the search section below. The focus state still replaces this stroke with the
   accent. */
.chocola-input__field,
.chocola-textarea__field,
.chocola-select__field {
    width: 100%;
    padding: var(--chocola-space-3) var(--chocola-space-4);
    background: var(--chocola-glass-bg-subtle);
    color: var(--chocola-color-text);
    border: 1px solid var(--chocola-color-border-field, var(--chocola-glass-border));
    border-radius: var(--chocola-radius-md);
    box-shadow: var(--chocola-field-inset);
    outline: none;
    font-size: max(16px, var(--chocola-font-size-md));
    transition: border-color var(--chocola-transition), box-shadow var(--chocola-transition), background-color var(--chocola-transition);
}
.chocola-input__field:focus,
.chocola-textarea__field:focus,
.chocola-select__field:focus {
    border-color: var(--chocola-color-accent);
    background-color: var(--chocola-glass-bg);
    box-shadow: var(--chocola-field-focus);
}
.chocola-input__field::placeholder,
.chocola-textarea__field::placeholder {
    color: var(--chocola-color-placeholder);
    opacity: 1;
}

@supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
    /* Default: blur only the surfaces that sit over content which actually moves
       beneath them — the fixed header, the sidebar rail/drawer and the user-menu
       popover. Every other surface is in-flow over the fixed wallpaper, so its
       blur bought almost nothing while costing a backdrop capture, a blur pass
       and a render surface per element, per frame. Measured in Firefox on this
       sample page with the previous default (~32 blurred elements): 209-557 draw
       calls per frame, constant 210% overdraw, ~50 pooled render surfaces and
       ~300ms/s of renderer-thread CPU, which presented scroll payloads 2-4 frames
       late. See elements/README.md -> "Performance & the glass cost switch".
       :where() keeps this rule at (0,1,0) so the opt-in refraction rule below
       (same specificity, later in source) still wins wherever a host enables
       it -- and stays out of the way everywhere else. */
    :where(html:not([data-chocola-glass="off"])) :is(
        .chocola-header,
        .chocola-sidebar,
        .chocola-user-menu__popover) {
        -webkit-backdrop-filter: var(--chocola-glass-filter);
        backdrop-filter: var(--chocola-glass-filter);
    }

    /* Opt-in: the previous material, where every surface blurs. Correct when the
       page has genuinely moving content behind in-flow surfaces (carousel,
       video, animated wallpaper); costs ~30 extra render tasks per frame here. */
    :where(html[data-chocola-glass="full"]) :is(
        .chocola-card,
        .chocola-list,
        .chocola-input__field,
        .chocola-textarea__field,
        .chocola-select__field,
        .chocola-button--primary,
        .chocola-button--secondary,
        .chocola-button--danger,
        .chocola-alert,
        .chocola-checkbox__box,
        .chocola-radio__dot,
        .chocola-switch__track) {
        -webkit-backdrop-filter: var(--chocola-glass-filter-sm);
        backdrop-filter: var(--chocola-glass-filter-sm);
    }
}

/* Progressive edge refraction + chromatic aberration -- OPT-IN, and rendered by
   no shipping engine today. Read this before flipping the switch.
   The guard is deliberately the PREFIXED property. Gecko accepts url() in
   backdrop-filter, but when the SVG chain has no CSS-filter equivalent it gives
   up and drops the WHOLE declaration -- blur included -- so the unprefixed test
   would silently leave Firefox unblurred (https://bugzil.la/1961378). Gecko
   exposes no -webkit-backdrop-filter alias, so this inclusion test keeps every
   Gecko engine on the plain chain from the rule above. Blink dropped the prefixed
   alias as well (verified on Chrome 152: CSS.supports("-webkit-backdrop-filter",
   "blur(1px)") is false), so Chrome also stays on the plain chain.
   WebKit is the one engine that PARSES this value -- which is all @supports can
   ever prove -- and then silently drops the whole filter at paint time whenever
   the chain contains a url() reference: bugs.webkit.org 245510 (open since 2022;
   see also 317059 and 297770 -- "accelerated filters (including backdrop-filter)
   can't use SVG filters"). The dropped declaration still WINS the cascade over
   the plain chain, so on Safari the old default-on refraction left these three
   surfaces with no blur at all instead of a plain blur. A parse-time probe cannot
   tell "parses" from "renders", which is why the refraction is now opt-in:
   data-chocola-refraction="on" on <html>, default off, verified engines: none.
   The same :where() excludes data-chocola-glass="off" (the glass switch still
   turns refraction off with the blur) and the media query keeps reduced
   transparency winning -- url() plus a "none" filter chain would otherwise
   re-add an effect for a user whose platform asked for less transparency. */
@media (prefers-reduced-transparency: no-preference) {
    @supports (-webkit-backdrop-filter: url(#chocola-glass-refract)) {
        :where(html[data-chocola-refraction="on"]:not([data-chocola-glass="off"])) :is(.chocola-header, .chocola-sidebar, .chocola-user-menu__popover) {
            -webkit-backdrop-filter: url(#chocola-glass-refract) var(--chocola-glass-filter);
            backdrop-filter: url(#chocola-glass-refract) var(--chocola-glass-filter);
        }
    }
}

/* ===== Reveal highlight =====
   Pointer-proximity light (see elements/chocola-reveal). The helper sets
   --chocola-reveal-x / -y, --chocola-reveal-spot, --chocola-reveal-intensity and
   the quantised --chocola-reveal-step (the only one that may feed a transitioned
   property — see the toggle border rule below)
   on the host; these low-specificity (:where) rules paint the light so component
   position/state rules always win.
   Targets: buttons (danger, ghost and disabled excluded), badges (the light
   follows the badge's own color), avatars, the user-menu trigger, the active
   sidebar item, and toggles only while checked and enabled.
   Two pseudo layers per target:
     - the "core" (::after, or ::before on toggles/sidebar): a one-device-pixel
       masked band with a bright center and a smooth falloff, plus a faint surface
       wash. One pixel on purpose: a two-pixel band reads as a border, not light.
     - the "halo" (::before, or ::after on the switch): the same band one pixel
       wider and dimmer. That extra pixel is what makes the thin core look even --
       being wider, the halo's own coverage is constant along the edge, so it feeds
       the core a steady half-light instead of letting the core's pixel-to-pixel
       coverage ripple show (see --chocola-reveal-bloom-opacity).
       Additive on dark, plain on light.
   Checkbox, radio and the active sidebar item get only the core layer, because
   their component already owns the other pseudo. */
:where(
    .chocola-button:not(.chocola-button--danger):not(.chocola-button--ghost):not([disabled]),
    .chocola-badge,
    .chocola-avatar:not(.chocola-user-menu__trigger *),
    .chocola-user-menu__trigger,
    .chocola-sidebar__item--active,
    .chocola-checkbox__field:checked:not(:disabled) + .chocola-checkbox__box,
    .chocola-radio__field:checked:not(:disabled) + .chocola-radio__dot,
    .chocola-switch__field:checked:not(:disabled) + .chocola-switch__track
) {
    position: relative;
    isolation: isolate;
}

/* Core layer: ring + faint surface wash */
:where(
    .chocola-button:not(.chocola-button--danger):not(.chocola-button--ghost):not([disabled]),
    .chocola-badge,
    .chocola-avatar:not(.chocola-user-menu__trigger *),
    .chocola-user-menu__trigger
)::after,
:where(
    .chocola-sidebar__item--active,
    .chocola-checkbox__field:checked:not(:disabled) + .chocola-checkbox__box,
    .chocola-radio__field:checked:not(:disabled) + .chocola-radio__dot,
    .chocola-switch__field:checked:not(:disabled) + .chocola-switch__track
)::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    padding: var(--chocola-reveal-thickness);
    background: radial-gradient(
        circle var(--chocola-reveal-spot) at
        var(--chocola-reveal-x, 50%) var(--chocola-reveal-y, 50%),
        var(--chocola-reveal-core) 0%,
        var(--chocola-reveal-color) 28%,
        color-mix(in srgb, var(--chocola-reveal-color) 55%, transparent) 55%,
        color-mix(in srgb, var(--chocola-reveal-color) 16%, transparent) 78%,
        color-mix(in srgb, var(--chocola-reveal-color) 0%, transparent) 100%);
    /* A full border-box mask XORed with an almost-opaque content-box copy leaves
       the 1px ring at full strength and a faint (--wash) spread over the face. */
    -webkit-mask-image: linear-gradient(#fff 0 0), linear-gradient(rgba(255, 255, 255, calc(1 - var(--chocola-reveal-wash, 0.1))) 0 0);
    -webkit-mask-clip: border-box, content-box;
    -webkit-mask-composite: xor;
    mask-image: linear-gradient(#fff 0 0), linear-gradient(rgba(255, 255, 255, calc(1 - var(--chocola-reveal-wash, 0.1))) 0 0);
    mask-clip: border-box, content-box;
    mask-composite: exclude;
    opacity: calc(var(--chocola-reveal-intensity, 0) * var(--chocola-reveal-strength));
    mix-blend-mode: var(--chocola-reveal-blend);
    pointer-events: none;
    z-index: 1;
}

/* Halo layer: the band one pixel wider and dimmer, hugging the lit border */
:where(
    .chocola-button:not(.chocola-button--danger):not(.chocola-button--ghost):not([disabled]),
    .chocola-badge,
    .chocola-avatar:not(.chocola-user-menu__trigger *),
    .chocola-user-menu__trigger
)::before,
:where(.chocola-switch__field:checked:not(:disabled) + .chocola-switch__track)::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    padding: var(--chocola-reveal-bloom-thickness);
    background: radial-gradient(
        circle var(--chocola-reveal-spot) at
        var(--chocola-reveal-x, 50%) var(--chocola-reveal-y, 50%),
        color-mix(in srgb, var(--chocola-reveal-color) 80%, transparent),
        color-mix(in srgb, var(--chocola-reveal-color) 0%, transparent) 100%);
    -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
    -webkit-mask-composite: xor;
    mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
    mask-composite: exclude;
    opacity: calc(
        var(--chocola-reveal-intensity, 0) *
        var(--chocola-reveal-bloom-opacity) *
        var(--chocola-reveal-strength));
    mix-blend-mode: var(--chocola-reveal-blend);
    pointer-events: none;
    z-index: 0;
}

/* The blur is the costly part, so spend it only on elements the helper flags as
   lit this frame. The flag is intentionally absent from the observer's
   attributeFilter, so writing it cannot feed back into a refresh loop. */
:where(
    .chocola-button:not(.chocola-button--danger):not(.chocola-button--ghost):not([disabled]),
    .chocola-badge,
    .chocola-avatar:not(.chocola-user-menu__trigger *),
    .chocola-user-menu__trigger
)[data-chocola-lit]::before,
:where(.chocola-switch__field:checked:not(:disabled) + .chocola-switch__track)[data-chocola-lit]::after {
    filter: blur(var(--chocola-reveal-bloom-blur));
}

/* Badges tint the light to their own variant color. */
.chocola-badge {
    --chocola-reveal-color: var(--badge-color);
    --chocola-reveal-core: var(--badge-color);
}

/* Targets that carry a real border. The core band is an absolutely positioned
   pseudo-element with `inset: 0`, and `inset` resolves against the PADDING box --
   so on a bordered target the band lands 1px inside the silhouette and leaves the
   border as an unlit hairline between the light and the element's own edge. Extend
   it over the border instead, so the target's own edge is what lights up.
   The `inset` here anchors the band to the control's own border and the `padding`
   follows --chocola-reveal-thickness, so the light covers that border and then
   reaches inward -- never wider than the token says.
   Bordered targets today: the toggles, the active sidebar item. An avatar carries
   no border -- see .chocola-avatar below, which draws its accent ring as an inset
   shadow inside the box for exactly this reason. */
:where(
    .chocola-checkbox__field:checked:not(:disabled) + .chocola-checkbox__box,
    .chocola-radio__field:checked:not(:disabled) + .chocola-radio__dot
)::before {
    inset: -2px;
    padding: var(--chocola-reveal-thickness);
}
:where(.chocola-switch__field:checked:not(:disabled) + .chocola-switch__track)::before {
    inset: -1px;
    padding: var(--chocola-reveal-thickness);
}
:where(.chocola-switch__field:checked:not(:disabled) + .chocola-switch__track) {
    --chocola-reveal-bloom-blur: 3px;
}
/* The active item carries a 1px border (transparent when inactive), so its core
   ring needs the same treatment as the switch track's. */
:where(.chocola-sidebar__item--active)::before {
    inset: -1px;
    padding: var(--chocola-reveal-thickness);
}

/* As a toggle's reveal light fades in, cross-fade its own border out so the two
   never show at once (the ring already sits exactly over the border). The
   checked state supplies the accent border color instead of the glass one.
   This is the ONE reveal-driven value that feeds a transitioned property
   (transition: border-color above), so it reads the quantised
   --chocola-reveal-step instead of the continuous --chocola-reveal-intensity:
   a value that changes on every pointer frame would retarget that 180ms
   transition forever and keep the whole page repainting at vsync (measured: 96
   all-canceled border-color transitions and 51-75 full repaints per second). */
.chocola-checkbox__box,
.chocola-radio__dot,
.chocola-switch__track {
    --chocola-toggle-border: var(--chocola-glass-border);
}
.chocola-checkbox__field:checked + .chocola-checkbox__box,
.chocola-radio__field:checked + .chocola-radio__dot,
.chocola-switch__field:checked + .chocola-switch__track {
    --chocola-toggle-border: var(--chocola-accent-border);
}
.chocola-checkbox__box,
.chocola-radio__dot,
.chocola-switch__track,
.chocola-checkbox__field:checked + .chocola-checkbox__box,
.chocola-radio__field:checked + .chocola-radio__dot,
.chocola-switch__field:checked + .chocola-switch__track {
    border-color: color-mix(in srgb, var(--chocola-toggle-border) calc((1 - var(--chocola-reveal-step, 0)) * 100%), transparent);
}

/* ===== chocola-label ===== */
.chocola-label {
    display: block;
    font-size: var(--chocola-font-size-sm);
    color: var(--chocola-color-label);
    margin-bottom: var(--chocola-space-2);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-weight: 600;
}

/* ===== chocola-input ===== */
/* Wrapper, label, surface, focus ring and placeholder come from the shared
   recipes above; the input has no element-specific deltas. */

/* ===== chocola-search ===== */
/* A search bar: a <chocola-input> restyled as a pill. Only the deltas that make it a
   search bar live here -- the material, the focus ring and the 16px floor that keeps a
   phone from zooming on focus stay the input element's own, and every rule is scoped
   through .chocola-search, so no other host form changes. The height is the padding: the
   font size is deliberately not part of the delta, or the floor would go with it.

   The reference is the macOS search field, and what makes that one read as a search bar
   rather than as a form control is how FEW cues it wears: a flat fill and a round wall,
   and nothing else. The shared recipe above hands a field four at once -- fill, stroke,
   carved inside, walls -- and a bar wearing all four looks dropped into a nav rail whose
   rows carry no stroke at all. So the stroke and the carved inside come off at rest and
   come back on focus, which is the state where they answer something: :not(:focus) is how
   they are taken off without flattening the shared focus recipe, whose specificity is
   equal and which a rule without the guard would silently beat. */
.chocola-search {
    position: relative;
}
.chocola-search .chocola-input__field {
    padding: var(--chocola-space-2) var(--chocola-space-3);
    border-radius: var(--chocola-radius-pill);
    /* A surface of its own, and the only cue left at rest: the shared field tint is the
       sidebar's own panel colour (--chocola-glass-surface is that token), so a pill
       without a stroke would dissolve into the rail it sits in. This rule is also why the
       fill no longer answers focus with a colour change: the shared focus recipe sets one,
       and this one comes later at the same specificity and wins -- the stroke and the ring
       are what answer focus here, as they do in the reference. */
    background: var(--chocola-color-surface-search, var(--chocola-glass-bg-subtle));
}
.chocola-search .chocola-input__field:not(:focus) {
    /* A stroke of the pill's own, one step up from its fill: the bar keeps a discreet
       outline of itself at rest. It is NOT the shared field stroke -- that one is the
       form-field cue, and it comes back with the focus ring. */
    border-color: var(--chocola-color-border-search, var(--chocola-glass-border-soft));
    box-shadow: none;
}
/* A search bar leads with a magnifier. The glyph is the host's own, the way the sidebar's
   and the tabs' icons are (a `bi-*` class, in the element's `icon` attribute): a host that
   ships no icon font loses a glyph instead of gaining an unexplained indent, because the
   room for it is reserved off this class, which is only set when a glyph was drawn. The
   box is the one .chocola-sidebar__icon gives a row, which is what lands the glyph in a
   sidebar's icon column; the SIZE is not, because a row icon reads beside a 15px label and
   this one reads beside the field's own text -- at the row's 1.1rem the magnifier was the
   largest thing in the box, and on the rail, where the text drops to the small step, by a
   wide margin. The glyph is decoration -- the label is the accessible name -- and it must
   not swallow the click that belongs to the field under it. */
.chocola-search__icon {
    position: absolute;
    left: var(--chocola-space-3);
    top: 50%;
    transform: translateY(-50%);
    width: 20px;
    height: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--chocola-font-size-md);
    color: var(--chocola-color-label);
    pointer-events: none;
}
/* The glyph brightens with the field, the way a row does when the rail is over it. */
.chocola-search:focus-within .chocola-search__icon {
    color: var(--chocola-color-text);
}
/* The room the glyph needs and no more: the pill's own leading inset (12px), the 20px box,
   and the 12px a row leaves between its icon and its label. Minus the field's own 1px
   border, which sits inside the padding -- without that the hint lands a pixel past the
   column the row labels are drawn on. */
.chocola-search--icon .chocola-input__field {
    padding-left: calc(var(--chocola-space-3) + 20px + var(--chocola-space-3) - 1px);
}
/* A softer hint than a form field's: the token is defined per theme in tokens.css, and
   the fallback keeps a host that ships an older tokens.css from losing the colour
   altogether (an undefined custom property would make the hint inherit the field's own
   text colour -- a placeholder that reads as typed). */
.chocola-search .chocola-input__field::placeholder {
    color: var(--chocola-color-placeholder-search, var(--chocola-color-placeholder));
}
/* The visible hint of a search bar is its placeholder, so the label is the accessible
   name only: it stays in the accessibility tree and out of sight. */
.chocola-search .chocola-input__label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* ===== chocola-textarea ===== */
.chocola-textarea__field {
    resize: vertical;
    font-family: inherit;
}

/* ===== chocola-button (Aqua gel + glass) ===== */
.chocola-button {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--chocola-space-2);
    padding: var(--chocola-space-3) var(--chocola-space-5);
    margin: var(--chocola-space-2) 0;
    border-radius: var(--chocola-radius-pill);
    font-size: var(--chocola-font-size-md);
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    transition:
        transform var(--chocola-transition-spring),
        box-shadow var(--chocola-transition-press),
        background var(--chocola-transition),
        color var(--chocola-transition),
        border-color var(--chocola-transition);
    user-select: none;
    -webkit-user-select: none;
}
/* A mouse press gets :active natively; a touch or pen press gets the marker
   Chocola.press sets (WebKit never applies :active on touch -- see chocola.js).
   Both spellings of a press are listed on every press rule in this file. */
.chocola-button:active:not([disabled]),
.chocola-button[data-chocola-pressed]:not([disabled]) {
    transform: translateY(1px) scale(0.97);
    box-shadow:
        inset 0 2px 4px var(--chocola-aqua-rim-dark),
        inset 0 -1px 0 var(--chocola-aqua-rim),
        0 1px 2px var(--chocola-glass-shadow),
        0 4px 12px -8px var(--chocola-glass-shadow);
}
.chocola-button[disabled] {
    opacity: 0.55;
    cursor: not-allowed;
    color: var(--chocola-color-text-muted);
    background: var(--chocola-glass-bg-subtle);
    border-color: var(--chocola-glass-border-soft);
    box-shadow: none;
    filter: saturate(0.15);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}
.chocola-button:focus-visible {
    outline: none;
    box-shadow: var(--chocola-glass-edge), var(--chocola-focus-ring);
}
@media (hover: hover) {
    .chocola-button:hover:not([disabled]) { transform: translateY(-1px); }
    .chocola-button:hover:not([disabled]):active { transform: translateY(1px) scale(0.97); }
}
/* The native stand-in a submit button keeps inside itself for the browser's implicit
   submission (Enter in a field -- see _submitProxyMarkup in chocola-button.js). It has
   to stay RENDERED, not `display: none`: the user agent looks the form's default button
   up by its element, and hiding it the way this library hides a control it owns -- the
   one-pixel clipped recipe .chocola-search uses for its label -- keeps it a button while
   taking it out of sight. Never hit-tested (the pixel belongs to the host) and never a
   tab stop: the host is the visible button, the focus and the accessible name. */
.chocola-button__submit {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    pointer-events: none;
}

/* Primary takes its fill, border and rim from the shared accent recipe above,
   but casts no colored glow: --chocola-accent-edge-flat keeps the rim and the
   contact shadow and drops the accent-tinted blur. */
.chocola-button--primary {
    box-shadow: var(--chocola-accent-edge-flat);
}
@media (hover: hover) {
    .chocola-button--primary:hover:not([disabled]) {
        box-shadow:
            inset 0 1px 0 var(--chocola-aqua-rim),
            0 2px 4px rgba(0, 0, 0, 0.12);
    }
}
.chocola-button--primary:active:not([disabled]),
.chocola-button--primary[data-chocola-pressed]:not([disabled]) {
    box-shadow:
        inset 0 2px 4px var(--chocola-aqua-rim-dark),
        0 1px 2px rgba(0, 0, 0, 0.1);
}
/* Secondary matches the base neutral recipe; no deltas. */
.chocola-button--danger {
    color: var(--chocola-color-danger-ink);
    outline: 2px dashed var(--chocola-color-danger-ink);
    outline-offset: -2px;
}
@media (hover: hover) {
    .chocola-button--danger:hover:not([disabled]) {
        background: var(--chocola-color-danger-soft);
    }
}
.chocola-button--danger:active:not([disabled]),
.chocola-button--danger[data-chocola-pressed]:not([disabled]) {
    background: var(--chocola-color-danger-soft);
}
.chocola-button--danger:focus-visible {
    outline: 2px dashed var(--chocola-color-danger-ink);
    outline-offset: -2px;
    box-shadow: var(--chocola-glass-edge), 0 0 0 3px var(--chocola-color-danger-soft);
}
.chocola-button--ghost {
    background: transparent;
    color: var(--chocola-color-accent);
    box-shadow:
        inset 0 0 0 transparent,
        inset 0 0 0 transparent,
        0 0 0 transparent,
        0 0 0 transparent;
    border-color: transparent;
}
@media (hover: hover) {
    .chocola-button--ghost:hover:not([disabled]) { background: var(--chocola-color-accent-soft); }
}

/* ===== chocola-select ===== */
/* Wrapper, label, surface and focus come from the shared recipes above. */
.chocola-select__field {
    padding-right: var(--chocola-space-6);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%236e6e73' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right var(--chocola-space-4) center;
    appearance: none;
    -webkit-appearance: none;
}
[data-theme="dark"] .chocola-select__field {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%23c9c9cf' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* ===== chocola-checkbox ===== */
/* Wrapper, label, hidden field, box surface and checked accent state all come
   from the shared recipes above. */
.chocola-checkbox__box {
    width: 20px;
    height: 20px;
    border-radius: var(--chocola-radius-sm);
}
.chocola-checkbox__field:checked + .chocola-checkbox__box::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 5px;
    height: 9px;
    border: solid var(--chocola-color-accent-ink);
    border-width: 0 2px 2px 0;
    transform: translate(-50%, -50%) rotate(45deg) translate(-1px, -1px);
}
.chocola-checkbox__field:focus-visible + .chocola-checkbox__box {
    box-shadow: var(--chocola-focus-ring);
}

/* ===== chocola-radio ===== */
/* Wrapper, label, hidden field, dot surface and checked accent state all come
   from the shared recipes above. */
.chocola-radio__dot {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.chocola-radio__dot::after {
    content: "";
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--chocola-color-accent-ink);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
    transform: scale(0);
    transition: transform var(--chocola-transition-spring);
}
.chocola-radio__field:checked + .chocola-radio__dot::after { transform: scale(1); }
.chocola-radio__field:focus-visible + .chocola-radio__dot {
    box-shadow: var(--chocola-focus-ring);
}

/* ===== chocola-switch ===== */
/* Wrapper, label, hidden field, track surface and checked accent state all come
   from the shared recipes above. */
.chocola-switch__track {
    width: 46px;
    height: 28px;
    border-radius: var(--chocola-radius-pill);
    display: inline-block;
}
.chocola-switch__thumb {
    position: absolute;
    top: 2px;
    left: 2px;
    width: 22px;
    height: 22px;
    background: var(--chocola-switch-thumb);
    border-radius: 50%;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.28), inset 0 1px 0 rgba(255, 255, 255, 0.95);
    transition: transform var(--chocola-transition-spring);
    pointer-events: none;
}
.chocola-switch__field:checked + .chocola-switch__track .chocola-switch__thumb { transform: translateX(18px); }
.chocola-switch__field:focus-visible + .chocola-switch__track { box-shadow: var(--chocola-focus-ring); }
.chocola-switch__text { font-size: var(--chocola-font-size-md); }

/* ===== Disabled form controls ===== */
.chocola-input__field:disabled,
.chocola-textarea__field:disabled,
.chocola-select__field:disabled {
    background: var(--chocola-color-neutral-soft);
    color: var(--chocola-color-text-muted);
    opacity: 1;
    cursor: not-allowed;
}
.chocola-checkbox__field:disabled + .chocola-checkbox__box,
.chocola-radio__field:disabled + .chocola-radio__dot,
.chocola-switch__field:disabled + .chocola-switch__track {
    opacity: 0.5;
    filter: saturate(0.2);
    cursor: not-allowed;
}

/* ===== chocola-list / chocola-list-item ===== */
.chocola-list {
    /* Block, like .chocola-card: an inline box would be split around its block
       child (.chocola-list__items), and the author's indentation whitespace
       would then paint two empty line-box bands with the list's own surface. */
    display: block;
    margin: var(--chocola-space-3) 0;
}
.chocola-list__items { display: flex; flex-direction: column; }
.chocola-list-item {
    display: flex;
    align-items: center;
    gap: var(--chocola-space-3);
    padding: var(--chocola-space-3) var(--chocola-space-4);
    border-bottom: 1px solid var(--chocola-glass-border-soft);
    transition: background var(--chocola-transition);
}
.chocola-list-item:last-child { border-bottom: none; }
@media (hover: hover) {
    .chocola-list-item:hover { background: var(--chocola-glass-bg-subtle); }
}
.chocola-list-item__icon {
    width: 36px;
    height: 36px;
    border-radius: var(--chocola-radius-md);
    object-fit: cover;
    flex-shrink: 0;
    background: var(--chocola-color-accent-soft);
    box-shadow: inset 0 1px 0 var(--chocola-glass-highlight);
}
.chocola-list-item__body { flex: 1; min-width: 0; }
.chocola-list-item__title {
    font-size: var(--chocola-font-size-md);
    font-weight: 500;
    color: var(--chocola-color-text);
}
.chocola-list-item__subtitle {
    font-size: var(--chocola-font-size-sm);
    color: var(--chocola-color-label);
}
.chocola-list-item__trailing {
    color: var(--chocola-color-label);
    font-size: var(--chocola-font-size-sm);
    flex-shrink: 0;
}

/* ===== chocola-table =====
   A data table reads its content from the `columns` and `rows` JSON attributes
   (the same way the sidebar reads `sidebar`), so a host can render it from
   server data without building markup. The element places every value with
   textContent -- never through innerHTML. */
.chocola-table {
    display: block;
    margin: var(--chocola-space-3) 0;
}
.chocola-table__scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}
.chocola-table__grid {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--chocola-font-size-md);
    color: var(--chocola-color-text);
}
.chocola-table__heading {
    padding: var(--chocola-space-2) var(--chocola-space-3);
    text-align: left;
    font-size: var(--chocola-font-size-sm);
    font-weight: 600;
    color: var(--chocola-color-label);
    white-space: nowrap;
    border-bottom: 1px solid var(--chocola-divider-color);
}
.chocola-table__heading--center,
.chocola-table__cell--center { text-align: center; }
.chocola-table__heading--end,
.chocola-table__cell--end { text-align: right; }
.chocola-table__cell {
    padding: var(--chocola-space-3);
    vertical-align: middle;
    border-bottom: 1px solid var(--chocola-glass-border-soft);
}
.chocola-table__row:last-child .chocola-table__cell { border-bottom: none; }
.chocola-table__cell--empty {
    color: var(--chocola-color-label);
    text-align: center;
}
/* The row highlight is a pointer affordance and lives inside (hover: hover), so
   a touch device never leaves a row stuck highlighted after a tap. */
@media (hover: hover) {
    .chocola-table__row:hover .chocola-table__cell { background: var(--chocola-glass-bg-subtle); }
}

/* ===== chocola-image ===== */
.chocola-image {
    display: inline-block;
    margin: var(--chocola-space-3) 0;
    max-width: 100%;
}
.chocola-image__figure {
    margin: 0;
}
.chocola-image__img {
    display: block;
    max-width: 100%;
    height: auto;
}
.chocola-image__caption {
    padding: var(--chocola-space-2) var(--chocola-space-3);
    font-size: var(--chocola-font-size-sm);
    color: var(--chocola-color-label);
    text-align: center;
    border-top: 1px solid var(--chocola-glass-border-soft);
}

/* ===== chocola-card ===== */
/* Deliberately no hover state: a card is a passive container, so it keeps its
   resting surface, border and shadow and never moves or lights up under the
   pointer. */
.chocola-card {
    display: block;
    margin: var(--chocola-space-3) 0;
}
.chocola-card__header {
    padding: var(--chocola-space-4);
    border-bottom: 1px solid var(--chocola-glass-border-soft);
    background: var(--chocola-glass-surface);
}
.chocola-card__title {
    font-size: var(--chocola-font-size-lg);
    font-weight: 600;
    color: var(--chocola-color-text);
}
.chocola-card__subtitle {
    margin-top: var(--chocola-space-1);
    font-size: var(--chocola-font-size-sm);
    color: var(--chocola-color-label);
}
.chocola-card__body {
    padding: var(--chocola-space-4);
    font-size: var(--chocola-font-size-md);
    color: var(--chocola-color-text);
}

/* ===== chocola-divider ===== */
.chocola-divider {
    display: flex;
    align-items: center;
    gap: var(--chocola-space-3);
    margin: var(--chocola-space-4) 0;
    color: var(--chocola-color-label);
    font-size: var(--chocola-font-size-sm);
}
.chocola-divider__line {
    flex: 1;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--chocola-divider-color), transparent);
    border: none;
    margin: 0;
}
.chocola-divider__label { white-space: nowrap; }

/* ===== chocola-alert ===== */
/* Surface, border and shadow come from the shared neutral recipe above. */
.chocola-alert {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--chocola-space-3);
    padding: var(--chocola-space-3) var(--chocola-space-4);
    margin: var(--chocola-space-3) 0;
    border-radius: var(--chocola-radius-lg);
    --alert-fg: var(--chocola-color-text);
    --alert-tint: color-mix(in srgb, var(--alert-color) 12%, transparent);
    background-image: linear-gradient(var(--alert-tint), var(--alert-tint));
    color: var(--alert-fg);
}
.chocola-alert--info    { --alert-color: var(--chocola-color-info); }
.chocola-alert--success { --alert-color: var(--chocola-color-success); }
.chocola-alert--warning { --alert-color: var(--chocola-color-warning); }
.chocola-alert--danger  { --alert-color: var(--chocola-color-danger); }
.chocola-alert__icon {
    flex-shrink: 0;
    width: 28px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--alert-color);
    font-weight: 700;
    font-size: 1.5rem;
    line-height: 1;
}
.chocola-alert__body { flex: 1; }
.chocola-alert__close {
    background: none;
    border: none;
    color: var(--alert-fg);
    font-size: 1.4rem;
    line-height: 1;
    cursor: pointer;
    padding: 0 var(--chocola-space-2);
    opacity: 0.6;
    transition: opacity var(--chocola-transition), transform var(--chocola-transition-spring);
}
/* Hover is a desktop affordance; a tap answers with the press state below. */
@media (hover: hover) {
    .chocola-alert__close:hover { opacity: 1; }
}
.chocola-alert__close:active,
.chocola-alert__close[data-chocola-pressed] {
    opacity: 1;
    transform: scale(0.9);
}

/* ===== chocola-badge ===== */
.chocola-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--chocola-space-1);
    padding: 2px var(--chocola-space-2);
    border-radius: var(--chocola-radius-pill);
    font-size: var(--chocola-font-size-sm);
    font-weight: 600;
    --badge-color: var(--chocola-color-text);
    --badge-mix: 10%;
    --badge-fg: var(--chocola-color-text);
    --badge-bg: color-mix(in srgb, var(--badge-color) var(--badge-mix), var(--chocola-glass-solid-strong));
    background: var(--chocola-glass-gloss), var(--badge-bg);
    color: var(--badge-fg);
    box-shadow: inset 0 1px 0 var(--chocola-glass-highlight);
    line-height: 1.4;
}
.chocola-badge--accent  { --badge-color: var(--chocola-color-accent);  --badge-mix: 22%; --badge-fg: var(--chocola-color-accent-ink); }
.chocola-badge--success { --badge-color: var(--chocola-color-success); --badge-mix: 22%; --badge-fg: var(--chocola-color-success-ink); }
.chocola-badge--warning { --badge-color: var(--chocola-color-warning); --badge-mix: 22%; --badge-fg: var(--chocola-color-warning-ink); }
.chocola-badge--danger  { --badge-color: var(--chocola-color-danger);  --badge-mix: 22%; --badge-fg: var(--chocola-color-danger-ink); }
.chocola-badge__dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    box-shadow: 0 0 6px currentColor;
    flex-shrink: 0;
}

/* ===== chocola-avatar ===== */
/* Fill, ink, border color and shadow come from the shared accent recipe. */
.chocola-avatar {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    /* No real border: overflow: hidden clips descendants to the padding box, so a
       border would push the reveal ring (inset: 0) 1px inside the silhouette and
       leave the unreachable border as an unlit hairline. The same 1px accent ring
       is drawn inside the box instead, so the light lands on the avatar's own
       edge. box-sizing: border-box keeps the outer diameter unchanged. */
    border-style: none;
    border-width: 0;
    box-shadow: inset 0 0 0 1px var(--chocola-accent-border), var(--chocola-accent-edge);
    font-weight: 600;
    overflow: hidden;
    flex-shrink: 0;
}
.chocola-avatar--sm { width: 28px; height: 28px; font-size: 0.7rem; }
.chocola-avatar--md { width: 40px; height: 40px; font-size: 0.85rem; }
.chocola-avatar--lg { width: 64px; height: 64px; font-size: 1.1rem; }
.chocola-avatar__img { width: 100%; height: 100%; object-fit: cover; }
.chocola-avatar__initials { letter-spacing: 0.02em; position: relative; z-index: 1; }

/* ===== chocola-header ===== */
.chocola-header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: var(--chocola-header-offset);
    padding-top: env(safe-area-inset-top, 0px);
    display: flex;
    align-items: center;
    background: var(--chocola-glass-surface);
    border-bottom: 1px solid var(--chocola-glass-border);
    box-shadow: 0 10px 30px -20px var(--chocola-glass-shadow);
    z-index: 150;
}
.chocola-header__nav-toggle {
    display: none;
    align-items: center;
    justify-content: center;
    width: var(--chocola-touch-target);
    height: var(--chocola-touch-target);
    margin-left: var(--chocola-space-1);
    border: none;
    background: transparent;
    color: var(--chocola-color-text);
    font-size: 1.4rem;
    line-height: 1;
    cursor: pointer;
    border-radius: var(--chocola-radius-md);
    flex-shrink: 0;
    transition: background var(--chocola-transition), transform var(--chocola-transition-spring);
}
@media (hover: hover) {
    .chocola-header__nav-toggle:hover { background: var(--chocola-color-neutral-soft); }
}
.chocola-header__nav-toggle:active,
.chocola-header__nav-toggle[data-chocola-pressed] {
    background: var(--chocola-color-neutral-soft);
    transform: scale(0.94);
}
.chocola-header__nav-toggle:focus-visible {
    outline: none;
    box-shadow: var(--chocola-focus-ring);
}
.chocola-header__logo {
    display: flex;
    align-items: center;
    gap: var(--chocola-space-3);
    padding: 0 var(--chocola-space-4);
    min-width: 0;
}
/* Fill, ink, border color and shadow come from the shared accent recipe. */
.chocola-header__logo-icon {
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-style: solid;
    border-width: 1px;
    font-weight: 700;
    font-size: var(--chocola-font-size-lg);
    border-radius: var(--chocola-radius-md);
    flex-shrink: 0;
}
.chocola-header__logo-label {
    font-weight: 600;
    color: var(--chocola-color-text);
    font-size: var(--chocola-font-size-md);
}
.chocola-header__user {
    margin-left: auto;
    padding: 0 var(--chocola-space-3);
}

/* ===== chocola-user-menu ===== */
.chocola-user-menu {
    position: relative;
    display: inline-block;
}
.chocola-user-menu__trigger {
    border: none;
    padding: 0;
    background: transparent;
    cursor: pointer;
    border-radius: var(--chocola-radius-pill);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background var(--chocola-transition), box-shadow var(--chocola-transition), transform var(--chocola-transition-spring);
}
@media (hover: hover) {
    .chocola-user-menu__trigger:hover {
        background: var(--chocola-color-neutral-soft);
    }
}
.chocola-user-menu__trigger:active,
.chocola-user-menu__trigger[data-chocola-pressed] {
    background: var(--chocola-color-neutral-soft);
    transform: scale(0.94);
}
.chocola-user-menu__trigger:focus-visible {
    outline: none;
    box-shadow: var(--chocola-focus-ring);
}
/* Surface + border come from the shared neutral recipe; adds its own glow. */
.chocola-user-menu__popover {
    position: fixed;
    min-width: 180px;
    border-radius: var(--chocola-radius-md);
    box-shadow: var(--chocola-glass-edge), var(--chocola-shadow-glow);
    padding: var(--chocola-space-2);
    z-index: 200;
}
.chocola-user-menu__item {
    display: block;
    width: 100%;
    border: none;
    background: transparent;
    color: var(--chocola-color-text);
    padding: var(--chocola-space-2) var(--chocola-space-3);
    text-align: left;
    font-size: var(--chocola-font-size-md);
    font-family: inherit;
    border-radius: var(--chocola-radius-sm);
    cursor: pointer;
    transition: background var(--chocola-transition), color var(--chocola-transition);
}
@media (hover: hover) {
    .chocola-user-menu__item:hover {
        background: var(--chocola-color-accent-soft);
        color: var(--chocola-color-accent);
    }
}
.chocola-user-menu__item:active,
.chocola-user-menu__item[data-chocola-pressed],
.chocola-user-menu__item:focus-visible {
    background: var(--chocola-color-accent-soft);
    color: var(--chocola-color-accent);
    outline: none;
}

/* ===== chocola-color-picker ===== */
.chocola-color-picker__row {
    display: flex;
    align-items: center;
    gap: var(--chocola-space-2);
    flex-wrap: wrap;
}
.chocola-color-picker__swatch {
    width: 28px;
    height: 28px;
    border: 1px solid var(--chocola-glass-border);
    background: var(--chocola-glass-bg-subtle);
    border-radius: var(--chocola-radius-pill);
    padding: 0;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-shadow: inset 0 1px 0 var(--chocola-glass-highlight), 0 1px 2px var(--chocola-glass-shadow);
    transition: transform var(--chocola-transition-spring), box-shadow var(--chocola-transition);
}
@media (hover: hover) {
    .chocola-color-picker__swatch:hover {
        transform: scale(1.1);
    }
}
.chocola-color-picker__swatch:active,
.chocola-color-picker__swatch[data-chocola-pressed] {
    transform: scale(0.9);
}
.chocola-color-picker__swatch:focus-visible {
    outline: none;
    box-shadow: var(--chocola-focus-ring);
}
.chocola-color-picker__swatch-dot {
    width: 16px;
    height: 16px;
    border-radius: 50%;
    display: inline-block;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.65), inset 0 -1px 1px rgba(0, 0, 0, 0.25);
}
.chocola-color-picker__swatch-dot[data-accent-dot="blue"]     { background: #007aff; }
.chocola-color-picker__swatch-dot[data-accent-dot="red"]      { background: #ff3b30; }
.chocola-color-picker__swatch-dot[data-accent-dot="orange"]   { background: #ff9500; }
.chocola-color-picker__swatch-dot[data-accent-dot="yellow"]   { background: #ffcc00; }
.chocola-color-picker__swatch-dot[data-accent-dot="green"]    { background: #34c759; }
.chocola-color-picker__swatch-dot[data-accent-dot="purple"]   { background: #af52de; }
.chocola-color-picker__swatch-dot[data-accent-dot="pink"]     { background: #ff2d92; }
.chocola-color-picker__swatch-dot[data-accent-dot="graphite"] { background: #4a4a4f; }
.chocola-color-picker__swatch--active {
    border-color: transparent;
}
.chocola-color-picker__swatch--active .chocola-color-picker__swatch-dot {
    box-shadow: inset 0 0 0 2px var(--chocola-color-surface), 0 0 0 2px var(--chocola-color-text), 0 0 10px -1px currentColor;
}

/* ===== chocola-sidebar ===== */
.chocola-sidebar {
    position: fixed;
    top: var(--chocola-header-offset);
    left: 0;
    bottom: 0;
    width: 56px;
    display: flex;
    flex-direction: column;
    background: var(--chocola-glass-surface);
    border-right: 1px solid var(--chocola-glass-border);
    box-shadow: inset -1px 0 0 var(--chocola-glass-border-soft);
    padding-bottom: env(safe-area-inset-bottom, 0px);
    transition: width 200ms var(--chocola-ease-out);
    overflow: hidden;
    z-index: 100;
}

/* Hover expansion is a desktop-only affordance. The mobile drawer owns its
   width (264px / 82vw) and must never resize under the pointer: .chocola-sidebar:hover
   is (0,2,0), so it would beat the mobile block's (0,1,0) on specificity
   whatever the source order. 48.0625rem is the complement of the mobile query's
   48rem term and `hover: hover` the complement of its `hover: none` term -- if
   the mobile query in chocola.js gains a term, add its exclusive twin here. */
@media (hover: hover) and (min-width: 48.0625rem) {
    .chocola-sidebar:hover,
    .chocola-sidebar--expanded {
        width: 240px;
    }
    /* The reveal runs on the rail's own clock: the box opens and the rail widens as one
       movement. There is no `visibility` in this list on purpose -- the box has to become
       focusable the moment the rail opens, and the collapsed rule below is what keeps it
       out of the tab order on the way out, once the collapse has played. */
    .chocola-sidebar:hover .chocola-sidebar__search,
    .chocola-sidebar--expanded .chocola-sidebar__search {
        grid-template-rows: 1fr;
        opacity: 1;
        visibility: visible;
        transition:
            grid-template-rows 200ms var(--chocola-ease-out),
            opacity 200ms var(--chocola-ease-out);
    }
}

/* Search box (opt-in through `searchable`): a fixed head over the item list, which
   scrolls under it. It is laid out only where the rail is expanded -- on the desktop rail
   that is hover OR keyboard focus (the element adds `--expanded` for both, so the field
   can be reached and typed into without a pointer), and the mobile drawer is always laid
   out expanded. The field is a <chocola-search>, whose own rules keep the label off
   screen and draw the compact pill.

   It is revealed, not switched on: the box is a one-row grid whose row animates
   0fr -> 1fr, so the rows below slide down instead of jumping when the rail opens, and it
   comes in on the same 200ms/ease-out the rail uses for its width. The clipping lives on
   the child: a grid item with `overflow: hidden; min-height: 0` shrinks to nothing, where
   the box itself cannot (padding is not part of the animated row, and the field has to
   keep its own). `visibility: hidden` is what keeps a clipped field out of the tab order
   while the rail is collapsed, and its transition is delayed so the box only leaves the
   tab order once the collapse has played. */
.chocola-sidebar__search {
    display: grid;
    grid-template-rows: 0fr;
    opacity: 0;
    visibility: hidden;
    flex: none;
    transition:
        grid-template-rows 200ms var(--chocola-ease-out),
        opacity 200ms var(--chocola-ease-out),
        visibility 0s linear 200ms;
}
.chocola-sidebar__search-reveal {
    overflow: hidden;
    min-height: 0;
}
/* The box's spacing sits inside the clipped wrapper, so it is clipped away with it: the
   room around a search bar belongs to the sidebar, not to the bar. The inner input
   brings a block margin of its own, which this rule takes back. The sides are the rows'
   own inset, not the wider one the box used to sit on: the pill has to start where a row
   box starts, or the rail reads as two columns that just miss each other. */
.chocola-sidebar__search .chocola-sidebar__search-field {
    margin: var(--chocola-space-2) var(--chocola-space-1) var(--chocola-space-1);
}
.chocola-sidebar__search .chocola-input { margin: 0; }
/* The rail reads 16px as oversized, and the shared field recipe floors the font there for
   a reason that does not apply to it: 16px is what stops iOS Safari from zooming a form
   field on focus, which is a *touch* floor. The rail is the desktop layout, and it is the
   one place a finger never reaches -- the drawer is the touch layout and keeps the floor
   -- so the box drops to the small step, on a device with no touch screen at all. (A
   device that reports no coarse pointer is the only kind that cannot zoom; a touch laptop
   or an iPad with a mouse keeps 16px and simply reads a little larger.) Deliberately NOT
   on .chocola-search: dropped into a form, the element is a form field. */
@media (hover: hover) and (min-width: 48.0625rem) and (not (any-pointer: coarse)) {
    .chocola-sidebar__search .chocola-input__field {
        font-size: var(--chocola-font-size-sm);
    }
    /* The magnifier steps down with the text it leads: at the field's own md it would still
       be the largest thing on the rail. Only the glyph's size moves -- the 20px box that
       holds it, and with it the column the hint starts on, must not. */
    .chocola-sidebar__search .chocola-search__icon {
        font-size: var(--chocola-font-size-sm);
    }
}
/* `__item` is display:flex, so [hidden] needs its own rule to hide a filtered
   row -- the same reason the host's stylesheet carries one. */
.chocola-sidebar__item[hidden],
.chocola-sidebar__group[hidden] { display: none; }

.chocola-sidebar__items {
    flex: 1;
    overflow-y: auto;
    overflow-x: hidden;
    padding: var(--chocola-space-2) 0;
}

/* ===== Sidebar Items ===== */
.chocola-sidebar__item {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0;
    padding: 10px var(--chocola-space-3) 10px var(--chocola-space-3);
    margin: 0 var(--chocola-space-1) var(--chocola-space-1) var(--chocola-space-1);
    border-radius: var(--chocola-radius-md);
    text-decoration: none;
    cursor: pointer;
    width: calc(100% - var(--chocola-space-2));
    font-size: var(--chocola-font-size-md);
    font-family: inherit;
    transition: background var(--chocola-transition), color var(--chocola-transition), box-shadow var(--chocola-transition);
    white-space: nowrap;
}

.chocola-sidebar--expanded .chocola-sidebar__item {
    justify-content: flex-start;
    gap: var(--chocola-space-3);
}

/* Every sidebar hover affordance is desktop-only; the drawer is a touch
   surface and stays inert under a pointer. */
@media (hover: hover) and (min-width: 48.0625rem) {
    .chocola-sidebar__item:hover {
        background: var(--chocola-glass-bg-subtle);
        color: var(--chocola-color-text);
        text-decoration: none;
    }
}

/* Active state comes from the shared accent recipe above. */
@media (hover: hover) and (min-width: 48.0625rem) {
    .chocola-sidebar__item--active:hover {
        color: var(--chocola-color-accent-ink);
        background: var(--chocola-glass-gloss), var(--chocola-accent-fill);
    }
}

/* A press -- in the drawer or on the rail -- answers with the same tint the
   desktop hover gives it. In the drawer this is the row's only feedback: a nav
   row is an <a>, and WebKit applies no :active to it on touch. */
.chocola-sidebar__item:active,
.chocola-sidebar__item[data-chocola-pressed] {
    background: var(--chocola-glass-bg-subtle);
    color: var(--chocola-color-text);
    text-decoration: none;
}

/* The current page keeps its accent fill while pressed. */
.chocola-sidebar__item--active:active,
.chocola-sidebar__item--active[data-chocola-pressed] {
    color: var(--chocola-color-accent-ink);
    background: var(--chocola-glass-gloss), var(--chocola-accent-fill);
}

.chocola-sidebar__icon {
    width: 20px;
    height: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    font-size: 1.1rem;
}

.chocola-sidebar__label {
    min-width: 0;
    width: 0;
    opacity: 0;
}

.chocola-sidebar--expanded .chocola-sidebar__label {
    flex: 1;
    min-width: 0;
    width: auto;
    opacity: 1;
    text-align: center;
    transition: opacity 200ms var(--chocola-ease-out) 50ms;
}

/* ===== Sidebar Groups ===== */
.chocola-sidebar__chevron {
    flex-shrink: 0;
    width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.75rem;
    opacity: 0;
    overflow: hidden;
}

.chocola-sidebar--expanded .chocola-sidebar__chevron {
    width: 20px;
    opacity: 1;
    transition: opacity 200ms var(--chocola-ease-out) 50ms;
}

.chocola-sidebar__group--open .chocola-sidebar__chevron {
    transform: rotate(180deg);
    transition: transform 200ms var(--chocola-ease-out);
}

.chocola-sidebar__item:not(.chocola-sidebar__toggle)::after {
    content: "";
    width: 0;
    flex-shrink: 0;
}

.chocola-sidebar--expanded .chocola-sidebar__item:not(.chocola-sidebar__toggle)::after {
    width: 20px;
}

.chocola-sidebar__children {
    display: none;
}

.chocola-sidebar--expanded .chocola-sidebar__group--open .chocola-sidebar__children {
    display: block;
}

.chocola-sidebar:not(.chocola-sidebar--expanded) .chocola-sidebar__children {
    display: none !important;
}

.chocola-sidebar__child {
    padding-left: var(--chocola-space-5);
    font-size: var(--chocola-font-size-sm);
}

.chocola-sidebar--expanded .chocola-sidebar__child .chocola-sidebar__label {
    text-align: left;
}

.chocola-sidebar__child + .chocola-sidebar__child {
    margin-top: 0;
}

/* ===== Backdrop (mobile drawer) =====
   Geometry, tint and the enter animation are unconditional so the overlay
   still covers the page when the glass switch turns the blur off; only the
   blur is gated. The tint is theme-aware through --chocola-overlay-scrim
   (white frost in light, dark wash in dark) -- never a hard-coded black. */
.chocola-sidebar__backdrop {
    position: fixed;
    top: var(--chocola-header-offset);
    left: 0;
    right: 0;
    bottom: 0;
    background: var(--chocola-overlay-scrim);
    z-index: 90;
    animation: chocola-backdrop-in var(--chocola-transition) both;
}

:where(html:not([data-chocola-glass="off"])) .chocola-sidebar__backdrop {
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
}

@keyframes chocola-backdrop-in {
    from { opacity: 0; }
    to { opacity: 1; }
}
html.chocola-nav-open,
html.chocola-nav-open body {
    overflow: hidden;
}

/* ===== chocola-tabs =====
   The strip of an application shell: the tabs shrink while there is room, each holds
   a minimum (its label truncates), and past that the strip scrolls horizontally -- a
   tab is never hidden and the strip never grows past the shell. The surface is the
   header's own, because the strip is the header's second line rather than a panel of
   its own: same glass, same bottom hairline, and a shadow falling on the content. */
.chocola-tabs {
    --chocola-tabs-tab-min: 8rem;  /* the smallest usable tab: an icon plus a few letters */
    --chocola-tabs-tab-max: 14rem; /* from here on the whole title fits */
    --chocola-tabs-gap: var(--chocola-space-2);
    /* No aura radius of its own: a tab lights up from the document's
       --chocola-reveal-radius, the way every other target does. The strip used to
       declare the gap as its radius, to keep the light off the neighbour a gap away --
       and that turned the light into a hit test: it appeared only while the pointer was
       inside the tab, and the tab the pointer left went dark at once. */
    display: flex;
    align-items: center;
    gap: var(--chocola-tabs-gap);
    padding: var(--chocola-space-2) var(--chocola-space-3);
    background: var(--chocola-glass-surface);
    border-bottom: 1px solid var(--chocola-glass-border);
    box-shadow: 0 10px 30px -20px var(--chocola-glass-shadow);
    overflow-x: auto;
    overflow-y: hidden;
}

/* A tab is a <chocola-button>, so only the instance deltas live here: a page button
   is centered and generously padded, while a tab reads left-aligned like a browser
   tab, is smaller, and stops at the two widths above. The material, the press spring,
   the focus ring and the pointer light stay the button's.

   Both button variants are light targets -- only ghost, danger and disabled are not --
   and that is why the state is carried by the variant (secondary behind, primary in
   front) instead of by a variant-free accent override: a tab has to light up under the
   pointer, and a ghost one never could. */
.chocola-tabs__tab {
    /* The anchor of the drop line (and of the light, which chocola-reveal positions the
       same way) -- the tab is <chocola-button>, whose own two pseudo-elements are the
       light's, so the reorder line is a real child element. */
    position: relative;
    flex: 0 1 auto;
    min-width: var(--chocola-tabs-tab-min);
    max-width: var(--chocola-tabs-tab-max);
    margin: 0;
    padding: var(--chocola-space-2) var(--chocola-space-3);
    border-radius: var(--chocola-radius-md);
    font-size: var(--chocola-font-size-sm);
    font-weight: 500;
    justify-content: flex-start;
}

/* The one place the label may give up width: the tab's floor, not the text. */
.chocola-tabs__label {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    text-align: left;
}
.chocola-tabs__icon {
    flex: 0 0 auto;
    font-size: var(--chocola-font-size-md);
    line-height: 1;
}

/* The close control sits inside the tab it closes, pushed to the far edge so the label
   truncates before it instead of under it. Its ink is the tab's own: the accent ink
   while the tab is active, the text ink while it is not. */
.chocola-tabs__close {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    margin-left: auto;
    padding: 0;
    border: none;
    border-radius: var(--chocola-radius-sm);
    background: transparent;
    color: currentColor;
    font-size: var(--chocola-font-size-md);
    line-height: 1;
    cursor: pointer;
    opacity: 0.7;
    transition: background var(--chocola-transition), opacity var(--chocola-transition);
}
@media (hover: hover) {
    .chocola-tabs__close:hover {
        background: var(--chocola-glass-bg-subtle);
        opacity: 1;
    }
}
/* A press -- mouse or touch -- answers with the same tint the hover gives. */
.chocola-tabs__close:active,
.chocola-tabs__close[data-chocola-pressed] {
    background: var(--chocola-glass-bg-subtle);
    opacity: 1;
}
.chocola-tabs__close:focus-visible {
    outline: none;
    box-shadow: var(--chocola-focus-ring);
    opacity: 1;
}
/* A press that lands on the close control is the close control's press. `:active`
   reaches every ancestor on its own -- the tab is active because a descendant of it is
   -- so without this the tab answered a close with its own press spring, and shutting a
   tab read as clicking it. :has() is what lets a rule read "a descendant of mine is
   being pressed"; both spellings are listed because the runtime's marker is what a
   touch press leaves behind (see chocola.js). The tab holds at its resting shadow for
   as long as the x is the one under the finger. */
.chocola-tabs__tab:has(.chocola-tabs__close:active):not([disabled]),
.chocola-tabs__tab:has(.chocola-tabs__close[data-chocola-pressed]):not([disabled]) {
    transform: none;
    box-shadow: var(--chocola-glass-edge);
}
.chocola-tabs__tab--active:has(.chocola-tabs__close:active):not([disabled]),
.chocola-tabs__tab--active:has(.chocola-tabs__close[data-chocola-pressed]):not([disabled]) {
    box-shadow: var(--chocola-accent-edge-flat);
}

/* Reordering (a `reorderable` strip): the tab in hand fades, and a line marks where it
   will land. The line is moved from tab to tab, so only one exists. */
.chocola-tabs__tab--dragging {
    opacity: 0.55;
}
.chocola-tabs__drop {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 2px;
    border-radius: var(--chocola-radius-sm);
    background: var(--chocola-color-accent);
    pointer-events: none;
    z-index: 2;
}
/* Centred in the gap the line separates, whatever --chocola-tabs-gap is. */
.chocola-tabs__drop--before { left: calc(var(--chocola-tabs-gap) / -2 - 1px); }
.chocola-tabs__drop--after { right: calc(var(--chocola-tabs-gap) / -2 - 1px); }

/* ===== Mobile mode: <= 48rem, or a no-hover coarse pointer =====
   The query is the literal MOBILE_QUERY in chocola.js, so a touch-only tablet
   (hover: none + pointer: coarse at 1024px, say) gets the drawer instead of the
   rail. The rules above gated on `(hover: hover) and (min-width: 48.0625rem)`
   stay the exact complement of both terms. */
@media (max-width: 48rem), (hover: none) and (pointer: coarse) {
    .chocola-header__nav-toggle { display: inline-flex; }
    .chocola-header__logo { padding: 0 var(--chocola-space-2); }

    .chocola-sidebar {
        width: 264px;
        max-width: 82vw;
        transform: translateX(-100%);
        transition: transform 200ms var(--chocola-ease-out);
        box-shadow: var(--chocola-shadow-lg);
    }
    .chocola-sidebar--open {
        transform: translateX(0);
    }

    /* The drawer is always laid out in the expanded form. */
    .chocola-sidebar .chocola-sidebar__item {
        justify-content: flex-start;
        gap: var(--chocola-space-3);
    }
    .chocola-sidebar .chocola-sidebar__label {
        flex: 1;
        width: auto;
        opacity: 1;
        text-align: left;
    }
    .chocola-sidebar .chocola-sidebar__chevron {
        width: 20px;
        opacity: 1;
    }
    .chocola-sidebar .chocola-sidebar__item:not(.chocola-sidebar__toggle)::after { width: 20px; }
    .chocola-sidebar .chocola-sidebar__group--open .chocola-sidebar__children {
        display: block !important;
    }
    /* The drawer is laid out expanded, so its search box is revealed too -- the same
       values as the desktop reveal's expanded state, without a transition: there is no
       expansion to animate here, and the drawer is already open at first paint. */
    .chocola-sidebar .chocola-sidebar__search {
        grid-template-rows: 1fr;
        opacity: 1;
        visibility: visible;
        transition: none;
    }

    .chocola-card__header,
    .chocola-card__body { padding: var(--chocola-space-3); }
    .chocola-list-item { padding: var(--chocola-space-3); }
    .chocola-alert { padding: var(--chocola-space-3); }

    /* A column grid does not fit a phone, so the head goes away, every row
       becomes a stacked block and each cell shows its own column name (written
       on the cell as data-label by the element). */
    .chocola-table__head { display: none; }
    .chocola-table__grid,
    .chocola-table__body,
    .chocola-table__row,
    .chocola-table__cell { display: block; width: 100%; }
    .chocola-table__row {
        padding: var(--chocola-space-2) 0;
        border-bottom: 1px solid var(--chocola-glass-border-soft);
    }
    .chocola-table__row:last-child { border-bottom: none; }
    .chocola-table__cell {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: var(--chocola-space-3);
        padding: var(--chocola-space-1) var(--chocola-space-3);
        border-bottom: none;
        text-align: left;
    }
    .chocola-table__cell::before {
        content: attr(data-label);
        font-size: var(--chocola-font-size-sm);
        color: var(--chocola-color-label);
    }
    .chocola-table__cell--empty { justify-content: flex-start; }
    .chocola-table__cell--empty::before { content: none; }
}

/* ===== Touch ergonomics =====
   Coarse pointers get bigger targets, and every visible shape inside one grows
   with it -- the swatch disc was the one that did not. Press feedback itself
   lives with each component, keyed on :active and [data-chocola-pressed]. */
@media (pointer: coarse) {
    .chocola-checkbox__box::before,
    .chocola-radio__dot::before {
        content: "";
        position: absolute;
        top: 50%;
        left: 50%;
        width: var(--chocola-touch-target);
        height: var(--chocola-touch-target);
        transform: translate(-50%, -50%);
    }
    .chocola-radio__dot { position: relative; }
    .chocola-switch__track::before {
        content: "";
        position: absolute;
        top: 50%;
        left: 50%;
        width: calc(100% + var(--chocola-space-2));
        height: var(--chocola-touch-target);
        transform: translate(-50%, -50%);
    }
    .chocola-color-picker__swatch {
        width: var(--chocola-touch-target);
        height: var(--chocola-touch-target);
    }
    /* The button grows to the touch target; the disc inside it has to grow with
       it, or the swatch reads as a large empty button with a small dot. */
    .chocola-color-picker__swatch-dot {
        width: calc(var(--chocola-touch-target) - var(--chocola-space-4));
        height: calc(var(--chocola-touch-target) - var(--chocola-space-4));
    }
    .chocola-alert__close {
        min-width: var(--chocola-touch-target);
        min-height: var(--chocola-touch-target);
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }
    .chocola-user-menu__trigger {
        min-width: var(--chocola-touch-target);
        min-height: var(--chocola-touch-target);
    }
    .chocola-sidebar__item { min-height: var(--chocola-touch-target); }
    /* The strip is a touch surface in mobile mode: the tab keeps its floor width and
       grows to the touch target, and the close control -- a small square under a
       mouse -- grows with it. The tab drops its vertical padding so the strip does
       not become two touch targets tall. */
    .chocola-tabs__tab {
        min-height: var(--chocola-touch-target);
        padding-top: 0;
        padding-bottom: 0;
    }
    .chocola-tabs__close {
        width: var(--chocola-touch-target);
        height: var(--chocola-touch-target);
    }
}

/* ===== Reduced motion ===== */
@media (prefers-reduced-motion: reduce) {
    .chocola-sidebar,
    .chocola-sidebar__search,
    .chocola-sidebar__label,
    .chocola-sidebar__chevron,
    .chocola-sidebar__item,
    .chocola-button,
    .chocola-switch__thumb,
    .chocola-header__nav-toggle,
    .chocola-user-menu__trigger,
    .chocola-alert__close,
    .chocola-color-picker__swatch,
    .chocola-tabs__close {
        transition: none;
    }
    .chocola-button:active:not([disabled]),
    .chocola-button[data-chocola-pressed]:not([disabled]),
    .chocola-color-picker__swatch:active,
    .chocola-color-picker__swatch[data-chocola-pressed],
    .chocola-header__nav-toggle:active,
    .chocola-header__nav-toggle[data-chocola-pressed],
    .chocola-user-menu__trigger:active,
    .chocola-user-menu__trigger[data-chocola-pressed],
    .chocola-alert__close:active,
    .chocola-alert__close[data-chocola-pressed] {
        transform: none;
    }
    .chocola-sidebar__backdrop { animation: none; }
}
/* A hover state only exists for a pointer that can hover, so the reset for it
   stays behind the same guard as every other hover rule. */
@media (prefers-reduced-motion: reduce) and (hover: hover) {
    .chocola-button:hover:not([disabled]),
    .chocola-color-picker__swatch:hover {
        transform: none;
    }
}

/* ===== chocola-wallpaper ===== */
.chocola-wallpaper {
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    overflow: hidden;
    background-color: var(--chocola-color-bg);
    background-image:
        radial-gradient(42% 58% at 12% 16%, var(--chocola-wallpaper-blob-1), transparent 70%),
        radial-gradient(48% 62% at 88% 12%, var(--chocola-wallpaper-blob-2), transparent 72%),
        radial-gradient(56% 66% at 78% 90%, var(--chocola-wallpaper-blob-3), transparent 72%),
        var(--chocola-wallpaper-base);
    background-size: cover;
    background-position: center;
    opacity: var(--chocola-wallpaper-opacity);
}
.chocola-wallpaper::after {
    content: "";
    position: absolute;
    inset: 0;
    background:
        linear-gradient(var(--chocola-wallpaper-wash), var(--chocola-wallpaper-wash)),
        linear-gradient(rgba(0, 0, 0, var(--chocola-wallpaper-dim, 0)), rgba(0, 0, 0, var(--chocola-wallpaper-dim, 0))),
        var(--chocola-wallpaper-vignette);
    pointer-events: none;
}
.chocola-wallpaper__image {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0.55;
    filter: blur(var(--chocola-wallpaper-blur, 0px));
    mix-blend-mode: luminosity;
}

/* The "waves" variant (variant="waves" on the element): the reference's fluid layers.
   Instead of the three soft blobs, four VERY wide overlapping ellipses -- two high, two
   low -- plus a diagonal light band; the way the ellipses cross is what draws the crests.
   Every layer is a gradient: no blur filter, no image. The reference is already a blurred
   fluid, so the soft stops read as waves without paying a blur pass per frame -- the cost
   the library default deliberately avoids (see elements/README.md, "Performance & the
   glass cost switch").
   Same specificity as .chocola-wallpaper, declared later: it only wins when the element
   carries the variant class. */
.chocola-wallpaper--waves {
    background-image:
        linear-gradient(203deg, transparent 14%, var(--chocola-wallpaper-waves-glow) 32%, transparent 54%),
        radial-gradient(150% 62% at 16% 74%, var(--chocola-wallpaper-waves-2), transparent 62%),
        radial-gradient(160% 76% at 70% 104%, var(--chocola-wallpaper-waves-3), transparent 76%),
        radial-gradient(118% 58% at 94% 28%, var(--chocola-wallpaper-waves-1), transparent 64%),
        radial-gradient(130% 54% at 28% 16%, var(--chocola-wallpaper-waves-1), transparent 68%),
        var(--chocola-wallpaper-waves-base);
    opacity: var(--chocola-wallpaper-waves-opacity);
}
/* The ::after repeats the default backdrop's varnish -- wash, the dim attribute's layer
   and the vignette -- with the variant's tokens only, because the variant needs a lighter
   wash and a softer vignette than the default. The dim layer stays generic on purpose, so
   the attribute keeps working with any variant. */
.chocola-wallpaper--waves::after {
    background:
        linear-gradient(var(--chocola-wallpaper-waves-wash), var(--chocola-wallpaper-waves-wash)),
        linear-gradient(rgba(0, 0, 0, var(--chocola-wallpaper-dim, 0)), rgba(0, 0, 0, var(--chocola-wallpaper-dim, 0))),
        var(--chocola-wallpaper-waves-vignette);
}

