/*
   AeterniUI.Sample — showcase styles shared by every /components page and the
   sidebar layout. These used to live in the scoped Pages/Components.razor.css,
   which cannot reach across the per-component pages, so they are a global sheet
   now. Class names stay page-scoped by prefix (showcase-, preview- and control-
   prefixed names only); no `.aeterni-` component rule is overridden here.

   Note: never write a comment terminator inside a comment body. A glob-looking
   path prefix followed immediately by a star and a slash would close the comment
   early, and the CSS parser then eats the whole next rule — which is how
   `.showcase-layout` silently lost its grid and every token it declared.
*/

/* 示例站自己也是一个宿主：库把滚动条收敛成三个 Token，宿主这边要写两处——
   `scrollbar-color` 是**继承**属性，写一次在根元素上，页内所有滚动容器都会跟随；
   `scrollbar-width` **不继承**，必须对元素本身声明，否则只改到根滚动条，其余容器仍是默认宽度
   （约 15px 的实色滑轨，在一片玻璃上格外显眼）。 */
:root {
    scrollbar-color: var(--aeterni-scrollbar-thumb) var(--aeterni-scrollbar-track);
}

* {
    scrollbar-width: thin;
}

/*
   AeterniUI.Sample — component page shell (/components/{id}).
   MainLayout owns the floating header, the brand and the top-level navigation;
   ComponentsLayout owns the left category sidebar (a Menu inside a Surface-like
   card) and the preview column. Width comes from the shared shell token so the
   header, the homepage and the icons page all line up with this layout.
*/

.showcase-layout {
    --showcase-sidebar-width: 264px;
    /* 卡片内边距只在这里定义一次：页头、demo 卡、API 段、说明段共用，任何一段单独写
       padding 都会让卡片的左右边界与侧栏错开。窄屏由 clamp 收窄，避免内容被挤到溢出。 */
    --showcase-card-padding: clamp(18px, 3vw, 32px);
    /* 段的纵向节奏：单独写在各段里时，任何一次 padding 重构都会把它清零；卡片底部的
       说明段还靠它拿到上边距，段与段之间因此不会贴在一起。 */
    --showcase-card-block: clamp(22px, 3vw, 30px);
    display: grid;
    grid-template-columns: var(--showcase-sidebar-width) minmax(0, 1fr);
    align-items: start;
    gap: 36px;
    width: var(--sample-shell-width);
    /* 与首页 / 图标页共用同一条中性页面底；容器只负责分组，不引入第二层背景。 */
    margin: calc(var(--sample-content-top) - var(--sample-header-inset)) auto 0;
}

/* 侧栏不再是第三张卡：它直接落在页面底上，用一条细分隔线与内容面分开。
   这样一屏只有「玻璃页头 + 内容面」两个面，右侧目录也就有了与正文同高的收边。 */
.showcase-sidebar {
    position: sticky;
    /* Rest and stick at the same offset, and measure the panel from it: the bottom
       edge then keeps --sample-header-gap clear of the fold at every scroll
       position, instead of only once the panel has stuck. */
    top: var(--sample-content-top);
    display: flex;
    flex-direction: column;
    box-sizing: border-box;
    width: var(--showcase-sidebar-width);
    height: calc(100vh - var(--sample-content-top) - var(--sample-page-bottom));
    height: calc(100dvh - var(--sample-content-top) - var(--sample-page-bottom));
    overflow: hidden;
    padding: 2px 18px 0 0;
    border: 0;
    border-inline-end: 1px solid var(--aeterni-border-subtle);
    border-radius: 0;
    background: transparent;
    box-shadow: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

.showcase-nav {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    margin-right: -18px;
    padding: 4px 18px 26px 0;
    scrollbar-gutter: stable;
    /* 列表被视口裁切时给一条淡出提示：读者知道下面还有条目，而不是内容突然消失。 */
    mask-image: linear-gradient(to bottom, #000 calc(100% - 26px), transparent);
}

/* The sidebar navigation is the library Menu component: it brings its own row
   rhythm, selected state and disclosure behaviour, so this sheet must not define
   a second set of nav item styles (the previous `showcase-nav__*` rules became
   dead the moment the sidebar switched to Menu). */

.showcase-main {
    grid-column: 2;
    min-width: 0;
    box-sizing: border-box;
}

/* 侧栏检索：57 个条目靠翻菜单找不现实，搜索框是文档站的常规入口。
   它与导航之间只留一条细线，不再用卡片底或说明句做分区。 */
.showcase-search {
    display: grid;
    margin-right: -18px;
    margin-bottom: 6px;
    padding: 4px 18px 12px 0;
    border-bottom: 1px solid var(--aeterni-border-subtle);
}

.showcase-nav__empty {
    margin: 0;
    padding: 10px 4px;
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
    line-height: var(--aeterni-line-height-normal);
}

/* 侧栏检索占满栏宽：宿主通过组件自己的 Class 参数给宽度，不覆写 .aeterni-* 规则。 */
.showcase-search__input {
    width: 100%;
}

/* 页面级文档栏：当前条目、源码入口，以及目录顺序里的前后一篇。 */
.showcase-doc-nav {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: var(--aeterni-spacing-3);
    margin-top: 22px;
    padding-top: 16px;
    border-top: 1px solid var(--aeterni-border-subtle);
}

.showcase-doc-nav__link {
    color: var(--aeterni-color-brand-text);
    font-size: var(--aeterni-font-size-sm);
    text-decoration: none;
}

.showcase-doc-nav__link--next {
    margin-inline-start: auto;
    text-align: end;
}

.showcase-doc-nav__link:hover {
    text-decoration: underline;
}

.showcase-doc-nav__link:focus-visible {
    outline: var(--aeterni-focus-width) solid var(--aeterni-focus-color);
    outline-offset: var(--aeterni-focus-offset);
    border-radius: var(--aeterni-radius-xs);
}

.showcase-preview-host {
    min-width: 0;
}

/* 安装步骤：内容住在组件页卡片里（`ComponentPage` 的 Demos 段），所以这里只剩步骤网格本身，
   没有第二层外框。代码块用共享的 `ShowcaseCode`，不另写一套代码样式。 */
.showcase-install__steps { display: grid; grid-template-columns: 1fr; gap: var(--aeterni-spacing-4); }
.showcase-install__steps section { min-width: 0; padding: 20px; border: 1px solid var(--aeterni-border-subtle); border-radius: var(--aeterni-radius-lg); background: var(--aeterni-bg-surface); }
.showcase-install__steps header { display: flex; align-items: center; gap: var(--aeterni-spacing-3); }
.showcase-install__steps span { color: var(--aeterni-color-brand-default); font-size: var(--aeterni-font-size-xs); font-weight: var(--aeterni-font-weight-bold); }
.showcase-install__steps h2 { display: flex; align-items: center; gap: var(--aeterni-spacing-2); margin: 0; color: var(--aeterni-text-primary); font-size: var(--aeterni-font-size-md); }
.showcase-install__steps p { margin: var(--aeterni-spacing-2) 0 0; max-width: 68ch; color: var(--aeterni-text-secondary); font-size: var(--aeterni-font-size-sm); line-height: var(--aeterni-line-height-normal); }
.showcase-install__steps pre { margin-top: var(--aeterni-spacing-3); }
.showcase-page-note {
    max-width: 68ch;
    margin: 18px 0 0;
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-base);
    line-height: 1.75;
    text-wrap: pretty;
}

/* Sample content shown inside the generic preview stages. */

.preview-overlay-demo {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--aeterni-spacing-4);
    width: 100%;
    min-height: 180px;
    padding: var(--aeterni-spacing-5);
    box-sizing: border-box;
    text-align: center;
}

.preview-overlay-demo__anchor {
    display: flex;
    align-items: center;
    gap: var(--aeterni-spacing-3);
}

.preview-overlay-demo__label,
.preview-overlay-demo__popover-title span {
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-xs);
}

.preview-overlay-demo__popover-title {
    display: flex;
    flex-direction: column;
    gap: var(--aeterni-spacing-1);
}

.preview-overlay-demo__popover-body {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--aeterni-spacing-3);
    min-width: min(320px, 70vw);
    line-height: var(--aeterni-line-height-normal);
    text-align: start;
}

.preview-overlay-demo__popover-body p,
.preview-overlay-demo__popover-body ul {
    margin: 0;
}

.preview-overlay-demo__popover-body ul {
    padding-inline-start: var(--aeterni-spacing-5);
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
}

.preview-overlay-demo__popover-actions {
    display: flex;
    align-items: center;
    gap: var(--aeterni-spacing-2);
}

.preview-overlay-demo__hint {
    max-width: 520px;
    margin: 0;
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
    line-height: 1.65;
}

.preview-stack {
    display: grid;
    gap: 14px;
    justify-items: center;
    width: min(100%, 440px);
    text-align: center;
}

/* The Menu demo keeps the menu left-aligned at a sidebar-like width. */
.preview-menu-demo {
    display: grid;
    gap: var(--aeterni-spacing-4);
    width: min(100%, 360px);
}

.preview-menu-demo .preview-feedback {
    text-align: start;
}

.preview-stack.preview-feedback-actions {
    width: min(100%, 520px);
}

/* State comparison rows used by the Button preview (loading and semantic
   colour matrices). */
.preview-state-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--aeterni-spacing-3);
    width: min(100%, 520px);
}

/* Labelled comparison matrix (Button variants/intents/loading). Each row keeps its
   caption so a wrapped or stacked row still says what it is comparing. */
.preview-matrix {
    gap: var(--aeterni-spacing-3);
    width: min(100%, 600px);
    justify-items: stretch;
    text-align: start;
}

.preview-matrix-row {
    display: grid;
    grid-template-columns: 40px minmax(0, 1fr);
    align-items: center;
    gap: var(--aeterni-spacing-3);
    width: 100%;
}

.preview-matrix-caption {
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-xs);
}

.preview-matrix .preview-state-row {
    width: 100%;
    justify-content: flex-start;
}

@media (max-width: 600px) {
    .preview-matrix-row {
        grid-template-columns: minmax(0, 1fr);
        gap: 6px;
    }

    .preview-matrix .preview-state-row {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: var(--aeterni-spacing-2);
        justify-items: start;
    }
}

.preview-feedback {
    display: block;
    max-width: 100%;
    min-height: 1.25em;
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-compact);
    line-height: 1.6;
    text-align: center;
}

.preview-surface-content,
.preview-card-copy,
.preview-card-footer {
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-compact);
    line-height: 1.55;
}

.preview-surface-content {
    display: grid;
    gap: 6px;
}

/* 玻璃演示场景。backdrop-filter 只采样元素「背后」的内容，所以在一个背景平坦的预览框里，
   模糊与不模糊长得一模一样。这一层是「被模糊的背景内容」，不是容器背景：它带彩色、带斜纹，
   因为彩色和高频细节才是能看出模糊对象。 */
.preview-glass-scene {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    min-height: 180px;
    padding: var(--aeterni-spacing-4);
}

.preview-glass-scene__backdrop {
    position: absolute;
    inset: 0;
    overflow: hidden;
    border-radius: var(--aeterni-radius-surface);
    background-color: var(--aeterni-bg-secondary);
    background-image:
        repeating-linear-gradient(112deg,
            color-mix(in srgb, var(--aeterni-text-primary) 16%, transparent) 0 9px,
            transparent 9px 30px),
        radial-gradient(circle at 22% 26%,
            color-mix(in srgb, var(--aeterni-color-brand-default) 74%, transparent) 0%,
            transparent 64%),
        radial-gradient(circle at 80% 74%,
            color-mix(in srgb, var(--aeterni-color-info-default) 66%, transparent) 0%,
            transparent 64%);
    pointer-events: none;
    user-select: none;
}

/* 背景副本是绝对定位，预览组件是静态的 flex 子项：定位元素画在普通流内容之上，
   于是副本会把面板整个盖住。只有带 backdrop-filter 的变体自己生成层叠上下文才浮出来 ——
   这正是「除了 Glass 其他变体都不显示」的原因。给面板一个属于自己的层，让它按 DOM 顺序
   压在副本之上。 */
.preview-glass-scene > *:not(.preview-glass-scene__backdrop) {
    position: relative;
    z-index: 1;
}

.preview-label,
.preview-card-title {
    color: var(--aeterni-text-primary);
    font-weight: var(--aeterni-font-weight-semibold);
}

.preview-card-title {
    margin: 0;
    font-size: var(--aeterni-font-size-lg);
}

.preview-card-copy {
    margin: 8px 0 0;
}

.preview-card-footer {
    font-size: var(--aeterni-font-size-xs);
}

.preview-icon-wrap {
    display: grid;
    place-items: center;
    min-height: 96px;
    color: var(--aeterni-color-brand-text);
}

.preview-form-control {
    display: grid;
    gap: 12px;
    justify-items: center;
    width: min(100%, 460px);
    text-align: center;
}

/* FormField 自带标签与说明：整组居中会让标签、输入与说明错开中线，只有纯单控件
   的预览（输入、滑块、分页……）才需要居中的展示台效果。 */
.preview-form-control:has(.aeterni-form-field) {
    justify-items: stretch;
    text-align: start;
}

/* FormField/ComboBox fill the preview row (their layout is width-driven);
   default-width inputs stay centered. */
.preview-form-control--fill {
    justify-items: stretch;
    text-align: start;
}

.preview-value {
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-xs);
}

.preview-list-wrap {
    width: min(100%, 520px);
}

.preview-empty {
    display: grid;
    place-items: center;
    gap: 12px;
    min-height: 120px;
    color: var(--aeterni-text-secondary);
    text-align: center;
}

.preview-action-row,
.preview-feedback-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 10px;
}

.preview-feedback-actions {
    display: grid;
    gap: 16px;
    justify-items: center;
}

/* Text and numeric fields remain native inputs; enum and boolean properties
   use the library ComboBox and Checkbox components directly. */

.control-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-column: 1 / -1;
    gap: 12px;
}

.control-field {
    display: grid;
    gap: 6px;
    min-width: 0;
}

.control-field > label,
.control-field > span {
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-xs);
}

.control-field input {
    box-sizing: border-box;
    width: 100%;
    min-height: 34px;
    padding: 7px 9px;
    border: 1px solid var(--aeterni-border-default);
    border-radius: var(--aeterni-radius-md);
    background: var(--aeterni-bg-primary);
    color: var(--aeterni-text-primary);
    font: inherit;
    font-size: var(--aeterni-font-size-xs);
}

.control-field input:focus-visible {
    outline: 2px solid var(--aeterni-focus-color);
    outline-offset: 2px;
}

.control-status {
    display: block;
    color: var(--aeterni-text-muted);
    font-size: var(--aeterni-font-size-xs);
    line-height: 1.45;
}

@media (max-width: 1080px) {
    .showcase-layout {
        --showcase-sidebar-width: 240px;
        grid-template-columns: var(--showcase-sidebar-width) minmax(0, 1fr);
        gap: 22px;
    }
}

/* Sidebar beside the content, matching the header column, from the desktop layout
   all the way down to tablet width. Only below 700px does the shell stack the
   sidebar above the content, because a 240px column plus a readable preview card
   no longer fit; the stacked block still keeps the header's width. */
@media (max-width: 700px) {
    .showcase-layout {
        display: block;
    }

    .showcase-sidebar {
        position: static;
        width: auto;
        height: auto;
        max-height: none;
        overflow: visible;
        margin-bottom: 22px;
    }

    .showcase-nav {
        overflow: visible;
        margin-right: 0;
        padding-right: 0;
    }

    .showcase-main {
        grid-column: auto;
    }
}

@media (max-width: 600px) {
    .showcase-sidebar {
        padding: 14px;
    }

    .control-grid {
        grid-template-columns: 1fr;
    }
}

/* 色彩与语义 (/components/colors) -------------------------------------------
   页面级设计基础验收页：色族色卡、文字墨阶、字体、表面、圆角、阴影和间距全部
   手绘，只引用 `--aeterni-*` Token，且不覆写任何 `.aeterni-*` 组件规则。

   版式按设计规格表组织：每一组基础各自成卡片，卡片之间走网格，卡片内部只放
   标尺本身（色块、形状、条形）与 Token 名。容器表面保持无彩色：彩色只出现在
   展示色值本身的小尺寸内容表面上，不会铺满卡片或整页。 */
/* 规格表只负责内部排版：外层卡片由页面骨架（`.component-preview`）承担，所以这里不再自带
   边框、背景与整页内边距——否则会卡片套卡片。原来给 h1 的字号也删了，标题由骨架渲染。 */
.showcase-colors__subtitle {
    margin: 36px 0 10px;
    color: var(--aeterni-text-primary);
    font-family: var(--aeterni-font-family-display);
    font-size: var(--aeterni-font-size-xl);
    font-weight: var(--aeterni-font-weight-semibold);
    letter-spacing: var(--aeterni-letter-spacing-tight);
    scroll-margin-top: var(--sample-content-top);
}

/* 规格表里的第一个小节标题紧贴段首：顶部的块间距已经由 Demos 段给出。 */
.showcase-colors__subtitle:first-child {
    margin-top: 0;
}

/* 页面说明段：保留 .showcase-page-note 的基础样式，只收紧它紧跟在标题后
   的间距并限制行长。同权重、后定义，因此这里覆盖的是示例页自己的类。 */
.showcase-colors__note {
    max-width: 660px;
    margin-top: var(--aeterni-spacing-2);
}

/* 卡片基线：色卡、墨阶、字体元信息、表面与圆角卡片共用同一套边界、圆角与
   内边距，内容不同但骨架一致，整页才读成一张规格表。 */
.showcase-colors__card,
.showcase-colors__type,
.showcase-colors__meta,
.showcase-colors__surface,
.showcase-colors__radius-item {
    display: grid;
    align-content: start;
    gap: var(--aeterni-spacing-3);
    min-width: 0;
    padding: var(--aeterni-spacing-4);
    border: 1px solid var(--aeterni-border-subtle);
    border-radius: var(--aeterni-radius-lg);
    background: var(--aeterni-bg-surface);
}

/* Token 名一律等宽小字，只落在卡片内部，避免把页首与说明段里的行内代码缩小。 */
.showcase-colors__card code,
.showcase-colors__type code,
.showcase-colors__meta code,
.showcase-colors__surface code,
.showcase-colors__radius-item code,
.showcase-colors__shadow-item code,
.showcase-colors__display code,
.showcase-colors__scale-row code,
.showcase-colors__spacing-row code,
.showcase-colors__table-row code {
    color: var(--aeterni-text-muted);
    font-family: var(--aeterni-font-family-mono);
    font-size: var(--aeterni-font-size-xs);
    overflow-wrap: anywhere;
}

/* --- 色族色卡 ------------------------------------------------------------ */
.showcase-colors__families {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: var(--aeterni-spacing-4);
    margin-top: var(--aeterni-spacing-4);
}

/* 每张色卡把自己的色族收敛成三个页面局部别名，卡内所有色块都从别名取色；
   加一个色族只需要补一个 data-family 块，色块规则一行都不用改。 */
.showcase-colors__card {
    --family-solid: var(--aeterni-color-neutral-default);
    --family-solid-ink: var(--aeterni-color-on-semantic);
    --family-ink: var(--aeterni-color-neutral-text);
    --family-soft: var(--aeterni-color-neutral-soft);
}

.showcase-colors__card[data-family="brand"] {
    --family-solid: var(--aeterni-color-brand-default);
    --family-solid-ink: var(--aeterni-button-intent-default-foreground);
    --family-ink: var(--aeterni-color-brand-text);
    --family-soft: var(--aeterni-color-brand-soft);
}

.showcase-colors__card[data-family="success"] {
    --family-solid: var(--aeterni-color-success-default);
    --family-ink: var(--aeterni-color-success-text);
    --family-soft: var(--aeterni-color-success-soft);
}

.showcase-colors__card[data-family="warning"] {
    --family-solid: var(--aeterni-color-warning-default);
    --family-ink: var(--aeterni-color-warning-text);
    --family-soft: var(--aeterni-color-warning-soft);
}

.showcase-colors__card[data-family="danger"] {
    --family-solid: var(--aeterni-color-danger-default);
    --family-ink: var(--aeterni-color-danger-text);
    --family-soft: var(--aeterni-color-danger-soft);
}

.showcase-colors__card[data-family="info"] {
    --family-solid: var(--aeterni-color-info-default);
    --family-ink: var(--aeterni-color-info-text);
    --family-soft: var(--aeterni-color-info-soft);
}

.showcase-colors__card[data-family="neutral"] {
    --family-solid: var(--aeterni-color-neutral-default);
    --family-ink: var(--aeterni-color-neutral-text);
    --family-soft: var(--aeterni-color-neutral-soft);
}

.showcase-colors__card-head {
    display: grid;
    gap: 2px;
}

.showcase-colors__card-name {
    color: var(--aeterni-text-primary);
    font-size: var(--aeterni-font-size-md);
    font-weight: var(--aeterni-font-weight-semibold);
}

.showcase-colors__card-use {
    color: var(--aeterni-text-muted);
    font-size: var(--aeterni-font-size-xs);
}

.showcase-colors__swatches {
    display: grid;
    gap: var(--aeterni-spacing-3);
    padding-top: var(--aeterni-spacing-3);
    border-top: 1px solid var(--aeterni-separator);
}

.showcase-colors__swatch {
    display: grid;
    grid-template-columns: 104px minmax(0, 1fr);
    align-items: center;
    gap: var(--aeterni-spacing-3);
    min-width: 0;
}

.showcase-colors__swatch-fill {
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    min-height: 48px;
    border: 1px solid transparent;
    border-radius: var(--aeterni-radius-md);
    font-size: var(--aeterni-font-size-xs);
    font-weight: var(--aeterni-font-weight-semibold);
    letter-spacing: var(--aeterni-letter-spacing-wide);
}

.showcase-colors__swatch-fill--solid {
    background: var(--family-solid);
    color: var(--family-solid-ink);
}

.showcase-colors__swatch-fill--text {
    border-color: currentColor;
    color: var(--family-ink);
}

.showcase-colors__swatch-fill--soft {
    background: var(--family-soft);
    color: var(--family-ink);
}

.showcase-colors__swatch-meta {
    display: grid;
    gap: 2px;
    min-width: 0;
}

.showcase-colors__swatch-variant {
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
}

/* --- 文字墨阶 ------------------------------------------------------------ */
.showcase-colors__types {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--aeterni-spacing-4);
    margin-top: var(--aeterni-spacing-4);
}

.showcase-colors__type {
    gap: var(--aeterni-spacing-2);
}

.showcase-colors__type-sample {
    font-size: var(--aeterni-font-size-xl);
    font-weight: var(--aeterni-font-weight-medium);
    line-height: var(--aeterni-line-height-tight);
}

.showcase-colors__type-use {
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
}

.showcase-colors__ink--primary {
    color: var(--aeterni-text-primary);
}

.showcase-colors__ink--secondary {
    color: var(--aeterni-text-secondary);
}

.showcase-colors__ink--placeholder {
    color: var(--aeterni-text-placeholder);
}

.showcase-colors__ink--tertiary {
    color: var(--aeterni-text-tertiary);
}

.showcase-colors__ink--disabled {
    color: var(--aeterni-text-disabled);
}

/* --- 字体与字号 ---------------------------------------------------------- */
.showcase-colors__typography {
    display: grid;
    grid-template-columns: minmax(0, 0.75fr) minmax(0, 1.25fr);
    gap: var(--aeterni-spacing-4);
    margin-top: var(--aeterni-spacing-4);
}

.showcase-colors__display,
.showcase-colors__scale {
    border: 1px solid var(--aeterni-border-subtle);
    border-radius: var(--aeterni-radius-lg);
    background: var(--aeterni-bg-surface);
}

.showcase-colors__display {
    display: grid;
    align-self: start;
    align-content: start;
    gap: var(--aeterni-spacing-3);
    padding: var(--aeterni-spacing-4);
}

.showcase-colors__display-eyebrow {
    color: var(--aeterni-text-muted);
    font-size: var(--aeterni-font-size-xs);
    letter-spacing: var(--aeterni-letter-spacing-wide);
    text-transform: uppercase;
}

.showcase-colors__display-sample {
    color: var(--aeterni-text-primary);
    font-family: var(--aeterni-font-family-display);
    font-size: clamp(var(--aeterni-font-size-6xl), 10vw, var(--aeterni-font-size-display-lg));
    font-weight: var(--aeterni-font-weight-bold);
    letter-spacing: var(--aeterni-letter-spacing-tight);
    line-height: 0.85;
}

.showcase-colors__scale {
    display: grid;
    padding: var(--aeterni-spacing-2) var(--aeterni-spacing-4);
}

.showcase-colors__scale-row {
    display: grid;
    grid-template-columns: minmax(0, 180px) minmax(0, 1fr);
    align-items: baseline;
    gap: var(--aeterni-spacing-4);
    padding: var(--aeterni-spacing-1) 0;
}

.showcase-colors__scale-row + .showcase-colors__scale-row {
    border-top: 1px solid var(--aeterni-separator);
}

.showcase-colors__scale-row span {
    color: var(--aeterni-text-primary);
    line-height: var(--aeterni-line-height-tight);
}

.showcase-colors__size--6xl { font-size: var(--aeterni-font-size-6xl); }
.showcase-colors__size--5xl { font-size: var(--aeterni-font-size-5xl); }
.showcase-colors__size--4xl { font-size: var(--aeterni-font-size-4xl); }
.showcase-colors__size--3xl { font-size: var(--aeterni-font-size-3xl); }
.showcase-colors__size--2xl { font-size: var(--aeterni-font-size-2xl); }
.showcase-colors__size--xl { font-size: var(--aeterni-font-size-xl); }
.showcase-colors__size--lg { font-size: var(--aeterni-font-size-lg); }
.showcase-colors__size--md { font-size: var(--aeterni-font-size-md); }
.showcase-colors__size--sm { font-size: var(--aeterni-font-size-sm); }
.showcase-colors__size--xs { font-size: var(--aeterni-font-size-xs); }
.showcase-colors__size--compact { font-size: var(--aeterni-font-size-compact); }
.showcase-colors__size--6xl,
.showcase-colors__size--5xl { white-space: nowrap; }

/* Display role scale: above the 12–60px text ladder, so it is registered as its
   own group instead of being mixed into the numbered rows (where a 144px line
   would break the table's rhythm). The values are labels, not rendered sizes —
   the specimen above is the display-lg consumer and the home hero is display-sm. */
.showcase-colors__display-scale {
    display: grid;
    gap: var(--aeterni-spacing-1);
    padding-top: var(--aeterni-spacing-2);
    border-top: 1px solid var(--aeterni-separator);
}

/* The token name is the long line here (a mono string in a ~270px card), so the
   value sits under it instead of beside it: a two-track flex row would wrap the
   token mid-name. */
.showcase-colors__display-scale-row {
    display: grid;
    gap: 1px;
}

.showcase-colors__display-scale-row span {
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-xs);
    font-variant-numeric: tabular-nums;
}

.showcase-colors__font-meta {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: var(--aeterni-spacing-4);
    margin-top: var(--aeterni-spacing-4);
}

.showcase-colors__meta {
    gap: var(--aeterni-spacing-2);
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
}

.showcase-colors__meta-title {
    color: var(--aeterni-text-muted);
    font-size: var(--aeterni-font-size-xs);
    font-weight: var(--aeterni-font-weight-semibold);
    letter-spacing: var(--aeterni-letter-spacing-wider);
    text-transform: uppercase;
}

.showcase-colors__weight--regular { color: var(--aeterni-text-primary); font-weight: var(--aeterni-font-weight-regular); }
.showcase-colors__weight--medium { color: var(--aeterni-text-primary); font-weight: var(--aeterni-font-weight-medium); }
.showcase-colors__weight--semibold { color: var(--aeterni-text-primary); font-weight: var(--aeterni-font-weight-semibold); }
.showcase-colors__weight--bold { color: var(--aeterni-text-primary); font-weight: var(--aeterni-font-weight-bold); }

.showcase-colors__family--base { color: var(--aeterni-text-primary); font-family: var(--aeterni-font-family-base); }
.showcase-colors__family--mono { color: var(--aeterni-text-primary); font-family: var(--aeterni-font-family-mono); }
.showcase-colors__family--display { color: var(--aeterni-text-primary); font-family: var(--aeterni-font-family-display); }

.showcase-colors__leading--tight { line-height: var(--aeterni-line-height-tight); }
.showcase-colors__leading--normal { line-height: var(--aeterni-line-height-normal); }
.showcase-colors__leading--relaxed { line-height: var(--aeterni-line-height-relaxed); }

/* --- 中性容器表面 -------------------------------------------------------- */
.showcase-colors__surfaces {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: var(--aeterni-spacing-4);
    margin-top: var(--aeterni-spacing-4);
}

.showcase-colors__surface {
    gap: var(--aeterni-spacing-2);
}

/* 色块用「二级底打底 + 一层渐变当上层」画出来：不透明档看不到打底，两档半透明
   （磨砂、叠色）则能看出它们叠在下方表面上之后的结果。 */
.showcase-colors__surface-chip {
    display: block;
    height: 64px;
    border: 1px solid var(--aeterni-border-subtle);
    border-radius: var(--aeterni-radius-md);
    background-color: var(--aeterni-bg-tertiary);
    background-image: linear-gradient(var(--surface-layer), var(--surface-layer));
}

.showcase-colors__surface-chip--page { --surface-layer: var(--aeterni-bg-primary); }
.showcase-colors__surface-chip--secondary { --surface-layer: var(--aeterni-bg-secondary); }
.showcase-colors__surface-chip--tertiary { --surface-layer: var(--aeterni-bg-tertiary); }
.showcase-colors__surface-chip--elevated { --surface-layer: var(--aeterni-bg-elevated); }
.showcase-colors__surface-chip--soft { --surface-layer: var(--aeterni-surface-soft); }
.showcase-colors__surface-chip--hover { --surface-layer: var(--aeterni-state-background-hover); }

.showcase-colors__surface-name {
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
}

/* --- 圆角阶梯 ------------------------------------------------------------ */
.showcase-colors__radius {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--aeterni-spacing-4);
    margin-top: var(--aeterni-spacing-4);
}

.showcase-colors__radius-item {
    gap: var(--aeterni-spacing-2);
}

.showcase-colors__radius-name,
.showcase-colors__shadow-name {
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
    font-weight: var(--aeterni-font-weight-semibold);
}

.showcase-colors__radius-shape {
    display: block;
    height: 68px;
    border: 1px solid var(--aeterni-border-strong);
    background: var(--aeterni-bg-tertiary);
}

.showcase-colors__radius-shape--xs { border-radius: var(--aeterni-radius-xs); }
.showcase-colors__radius-shape--sm { border-radius: var(--aeterni-radius-sm); }
.showcase-colors__radius-shape--md { border-radius: var(--aeterni-radius-md); }
.showcase-colors__radius-shape--lg { border-radius: var(--aeterni-radius-lg); }
.showcase-colors__radius-shape--button { border-radius: var(--aeterni-radius-button); }
.showcase-colors__radius-shape--xl { border-radius: var(--aeterni-radius-xl); }
.showcase-colors__radius-shape--2xl { border-radius: var(--aeterni-radius-2xl); }
.showcase-colors__radius-shape--3xl { border-radius: var(--aeterni-radius-3xl); }
.showcase-colors__radius-shape--full { border-radius: var(--aeterni-radius-full); }

/* --- 阴影层级 ------------------------------------------------------------ */
.showcase-colors__shadows {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--aeterni-spacing-5);
    margin-top: var(--aeterni-spacing-4);
    padding: var(--aeterni-spacing-5);
    border: 1px solid var(--aeterni-border-subtle);
    border-radius: var(--aeterni-radius-lg);
    background: var(--aeterni-bg-secondary);
}

.showcase-colors__shadow-item {
    display: grid;
    gap: var(--aeterni-spacing-2);
    min-width: 0;
}

.showcase-colors__shadow-tile {
    display: block;
    height: 72px;
    border-radius: var(--aeterni-radius-lg);
    background: var(--aeterni-bg-surface);
}

.showcase-colors__shadow-tile--xs { box-shadow: var(--aeterni-shadow-xs); }
.showcase-colors__shadow-tile--sm { box-shadow: var(--aeterni-shadow-sm); }
.showcase-colors__shadow-tile--md { box-shadow: var(--aeterni-shadow-md); }
.showcase-colors__shadow-tile--lg { box-shadow: var(--aeterni-shadow-lg); }
.showcase-colors__shadow-tile--xl { box-shadow: var(--aeterni-shadow-xl); }

/* --- 间距节奏 ------------------------------------------------------------ */
.showcase-colors__spacing {
    display: grid;
    gap: var(--aeterni-spacing-3);
    margin-top: var(--aeterni-spacing-4);
    padding: var(--aeterni-spacing-5);
    border: 1px solid var(--aeterni-border-subtle);
    border-radius: var(--aeterni-radius-lg);
    background: var(--aeterni-bg-surface);
}

.showcase-colors__spacing-row {
    display: grid;
    grid-template-columns: minmax(0, 200px) minmax(0, 1fr) 56px;
    align-items: center;
    gap: var(--aeterni-spacing-4);
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-xs);
}

.showcase-colors__spacing-bar {
    display: block;
    width: var(--spacing-width);
    max-width: 100%;
    height: 12px;
    border-radius: var(--aeterni-radius-full);
    background: var(--aeterni-color-brand-default);
}

.showcase-colors__spacing-bar--1 { --spacing-width: var(--aeterni-spacing-1); }
.showcase-colors__spacing-bar--2 { --spacing-width: var(--aeterni-spacing-2); }
.showcase-colors__spacing-bar--3 { --spacing-width: var(--aeterni-spacing-3); }
.showcase-colors__spacing-bar--4 { --spacing-width: var(--aeterni-spacing-4); }
.showcase-colors__spacing-bar--6 { --spacing-width: var(--aeterni-spacing-6); }
.showcase-colors__spacing-bar--8 { --spacing-width: var(--aeterni-spacing-8); }
.showcase-colors__spacing-bar--12 { --spacing-width: var(--aeterni-spacing-12); }

/* --- 对比度验收组合 ------------------------------------------------------ */
.showcase-colors__table {
    margin-top: var(--aeterni-spacing-4);
    overflow: hidden;
    border: 1px solid var(--aeterni-border-subtle);
    border-radius: var(--aeterni-radius-lg);
}

.showcase-colors__table-row {
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 1.35fr) minmax(0, 1.35fr) minmax(0, 0.55fr);
    gap: var(--aeterni-spacing-3);
    padding: var(--aeterni-spacing-3) var(--aeterni-spacing-4);
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
}

.showcase-colors__table-row + .showcase-colors__table-row {
    border-top: 1px solid var(--aeterni-border-subtle);
}

.showcase-colors__table-row--head {
    background: var(--aeterni-surface-soft);
    color: var(--aeterni-text-muted);
    font-size: var(--aeterni-font-size-xs);
    font-weight: var(--aeterni-font-weight-semibold);
    letter-spacing: var(--aeterni-letter-spacing-wide);
    text-transform: uppercase;
}

@media (max-width: 1100px) {
    .showcase-colors__table-row {
        font-size: var(--aeterni-font-size-xs);
    }
}

@media (max-width: 1000px) {
    .showcase-colors__typography {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 700px) {
    .showcase-colors__swatch {
        grid-template-columns: 88px minmax(0, 1fr);
    }

    .showcase-colors__scale-row,
    .showcase-colors__spacing-row {
        grid-template-columns: 1fr;
        gap: var(--aeterni-spacing-1);
    }
}

/* Tab preview: the strip should span the preview width so the horizontal scroll
   behaviour is visible, which the centred default stack does not do. */
.preview-stack--fill {
    align-items: stretch;
    width: 100%;
    text-align: start;
}

.preview-tab-text {
    margin: 0;
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
    line-height: var(--aeterni-line-height-relaxed);
}

/*
   Divider preview: the labelled and vertical forms need a column with real gaps
   and a row that stretches, because a vertical separator takes its length from
   the flex box around it.
*/
.preview-divider-demo {
    display: grid;
    gap: var(--aeterni-spacing-4);
    width: min(100%, 460px);
    text-align: start;
}

.preview-divider-demo p {
    margin: 0;
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-xs);
}

.preview-divider-row {
    display: flex;
    align-items: stretch;
    gap: var(--aeterni-spacing-4);
    min-height: 56px;
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
}

.preview-divider-row span {
    display: inline-flex;
    align-items: center;
}

/* Empty preview: the placeholder is transparent by design, so the demo shows it
   inside the container that owns the surface. */
.preview-empty-host {
    display: block;
    width: min(100%, 520px);
}

.preview-empty-illustration {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 64px;
    height: 64px;
    border-radius: var(--aeterni-radius-full);
    background: var(--aeterni-color-brand-soft);
    font-size: var(--aeterni-font-size-3xl);
}

/* Spinner preview: one row for sizes, one for colours, one host box that shows
   the indicator in context. */
.preview-spinner-demo {
    display: grid;
    gap: var(--aeterni-spacing-5);
    justify-items: center;
    width: min(100%, 520px);
}

.preview-spinner-cell,
.preview-badge-cell {
    display: grid;
    justify-items: center;
    gap: var(--aeterni-spacing-2);
}

.preview-spinner-host {
    display: flex;
    align-items: center;
    gap: var(--aeterni-spacing-3);
    width: min(100%, 320px);
    padding: var(--aeterni-spacing-4);
    border: 1px solid var(--aeterni-border);
    border-radius: var(--aeterni-radius-lg);
    background: var(--aeterni-bg-surface);
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
}

/* Skeleton preview: the blocks stack so the line/gap rhythm is visible. */
.preview-skeleton-demo {
    display: grid;
    gap: var(--aeterni-spacing-5);
    width: min(100%, 460px);
    text-align: start;
}

.preview-skeleton-block {
    display: grid;
    gap: var(--aeterni-spacing-2);
}

.preview-skeleton-row {
    display: flex;
    align-items: center;
    gap: var(--aeterni-spacing-3);
}

.preview-skeleton-copy {
    flex: 1 1 auto;
    min-width: 0;
}

/* Badge preview: the indicator overflows its anchor, so cells need room around
   the corner it sits on. */
.preview-badge-demo {
    display: grid;
    gap: var(--aeterni-spacing-6);
    justify-items: center;
    width: min(100%, 520px);
}

.preview-badge-demo .preview-state-row {
    gap: var(--aeterni-spacing-6);
}

.preview-badge-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    padding: 0;
    border-radius: var(--aeterni-radius-full);
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-xs);
    font-weight: var(--aeterni-font-weight-semibold);
}

/* Segmented preview: the control is inline, so the demo stacks several of them and
   keeps every row centred. */
.preview-segmented-demo {
    display: grid;
    gap: var(--aeterni-spacing-4);
    justify-items: center;
    width: min(100%, 520px);
}

.preview-segmented-option {
    display: inline-flex;
    align-items: center;
    gap: var(--aeterni-spacing-1);
    min-width: 0;
}

/* Drawer preview: the trigger row plus the state readout; the panel itself is
   rendered outside the preview card (a fixed panel inside the blurred card would be
   positioned against the card). */
.preview-drawer-demo {
    display: grid;
    gap: var(--aeterni-spacing-4);
    justify-items: center;
    width: min(100%, 560px);
}

.preview-drawer-status {
    display: grid;
    gap: var(--aeterni-spacing-1);
}

.preview-drawer-content {
    display: grid;
    gap: var(--aeterni-spacing-3);
}

.preview-drawer-content p {
    margin: 0;
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
    line-height: var(--aeterni-line-height-relaxed);
}

/*
   组件文档页的排版：页头、demo 卡片、代码块、API 表与说明区。

   这些规则原在 ComponentPreview.razor.css 里（CSS 隔离）。批 3 把一页一段 demo 拆成
   多个 DemoCard，并由 ComponentPage 组织页头/API/相关组件，于是同一套类名要跨多个组件
   复用——隔离样式只作用于声明它的组件，所以整块搬到文档样式表里，保持单一来源。
*/
.component-preview { position: relative; }
.component-preview {
    position: relative;
    overflow: visible;
    background: transparent;
    /* 面的责任移到 .component-page：页头之后只有一张内容面，正文与右栏目录同属它，
       右边线因此与页头右缘对齐。卡片不再自带边框、圆角、阴影与玻璃。
       这里也刻意不写 `isolation: isolate`：卡片里没有任何玻璃/滤镜需要隔离，
       而弹层（Popover 的 z-index 1060）必须能压过同级的右栏目录（position: sticky、
       z-index auto）。一旦隔离，卡片内的 z-index 就被关在卡片这个层叠上下文里，
       日期/下拉弹层会被后绘制的目录盖住。 */
}

.component-preview__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 24px;
    padding: 30px var(--showcase-card-padding) 22px;
    border-bottom: 1px solid var(--aeterni-border-subtle);
}

.component-preview__eyebrow,
.component-preview__section-kicker {
    margin: 0;
    color: var(--aeterni-color-brand-text);
    font-size: var(--aeterni-font-size-xs);
    font-weight: var(--aeterni-font-weight-semibold);
    letter-spacing: var(--aeterni-letter-spacing-wider);
    text-transform: uppercase;
}

.component-preview__header h1,
.component-preview__header h2 {
    margin: 8px 0;
    color: var(--aeterni-text-primary);
    font-family: var(--aeterni-font-family-display);
    font-size: clamp(var(--aeterni-font-size-3xl), 2.6vw, var(--aeterni-font-size-4xl));
    font-weight: var(--aeterni-font-weight-semibold);
    line-height: 1.08;
    letter-spacing: var(--aeterni-letter-spacing-tight);
}

.component-preview__description {
    max-width: 62ch;
    margin: 0;
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-md);
    line-height: var(--aeterni-line-height-relaxed);
    text-wrap: pretty;
}

.component-preview__name {
    flex: 0 0 auto;
    padding: 7px 10px;
    border: 1px solid var(--aeterni-border);
    border-radius: var(--aeterni-radius-md);
    background: var(--aeterni-bg-secondary);
    color: var(--aeterni-text-secondary);
    font-family: var(--aeterni-font-family-mono);
    font-size: var(--aeterni-font-size-xs);
}

.component-preview__demo-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.4fr) minmax(270px, .6fr);
    border-bottom: 1px solid var(--aeterni-border-subtle);
}

.component-preview__stage,
.component-preview__controls {
    min-width: 0;
    padding: 24px 28px 28px;
}

.component-preview__stage {
    border-right: 1px solid var(--aeterni-border-subtle);
}

.component-preview__section-heading {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 18px;
}

.component-preview__section-heading > div {
    display: flex;
    align-items: baseline;
    gap: 10px;
}

.component-preview__section-heading h3 {
    margin: 0;
    color: var(--aeterni-text-primary);
    font-family: var(--aeterni-font-family-display);
    font-size: var(--aeterni-font-size-lg);
    font-weight: var(--aeterni-font-weight-semibold);
    letter-spacing: var(--aeterni-letter-spacing-tight);
}

.component-preview__hint {
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-xs);
    white-space: nowrap;
}

.component-preview__canvas {
    display: flex;
    align-items: center;
    justify-content: center;
    /* Content-driven stage: border-box keeps the outer height close to the token
       (168 + 56 padding + border was 226px), so a single-control demo no longer
       reserves a display-case height. */
    box-sizing: border-box;
    min-height: clamp(96px, 12vh, 140px);
    padding: 24px;
    border: 1px solid var(--aeterni-border-subtle);
    border-radius: var(--aeterni-radius-lg);
    background-color: var(--aeterni-bg-primary);
    background-image: radial-gradient(circle, var(--aeterni-border) 1px, transparent 1.2px);
    background-size: 18px 18px;
    background-position: -1px -1px;
}

.component-preview__controls {
    align-self: stretch;
}

.component-preview__control-body {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
    align-content: start;
}

.component-preview__api {
    padding: 0 var(--showcase-card-padding);
}

.component-preview__api-grid {
    display: grid;
    gap: 22px;
}

.component-preview__api-group h4 {
    margin: 0 0 10px;
    color: var(--aeterni-text-primary);
    font-size: var(--aeterni-font-size-sm);
    font-weight: var(--aeterni-font-weight-semibold);
}

.component-preview__api-table {
    /* 表头在长表滚动时 sticky，本层就不能是滚动容器；窄屏的横向滚动在 ≤900px 的
       媒体查询里打开。 */
    position: relative;
    border: 1px solid var(--aeterni-border);
    border-radius: var(--aeterni-radius-md);
}

.component-preview__api-row {
    display: grid;
    grid-template-columns: minmax(170px, .9fr) minmax(150px, 1fr) minmax(220px, 2fr);
    gap: 14px;
    align-items: start;
    padding: 12px 14px;
    border-top: 1px solid var(--aeterni-border-subtle);
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
    line-height: 1.6;
}

.component-preview__api-row:first-child {
    border-top: 0;
}

.component-preview__api-row--header {
    /* 长表滚动时表头跟随，并在固定页头下方停住：参数名与「类型 / 默认值」的列义
       不会在滚动中丢掉。sticky 的参照是视口，因为外层不再滚动。 */
    position: sticky;
    top: var(--sample-content-top);
    z-index: 2;
    border-radius: var(--aeterni-radius-md) var(--aeterni-radius-md) 0 0;
    background: var(--aeterni-bg-secondary);
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-xs);
    font-weight: var(--aeterni-font-weight-semibold);
    letter-spacing: var(--aeterni-letter-spacing-wider);
}

/* 名称是代码标识符，按词折行会把 AdditionalAttributes 拆成两段；改成 nowrap，
   窄屏交给容器的横向滚动处理（见 ≤900px 的媒体查询）。 */
.component-preview__api-row > [role="cell"]:first-child {
    /* 名称可换行，但只允许在渲染时插入的 <wbr>（类型前缀的点号）处换；不做逐字符拆词。 */
    white-space: normal;
    min-width: 0;
}

.component-preview__api-row > [role="cell"]:first-child code {
    overflow-wrap: normal;
    word-break: normal;
}

.component-preview__api-row code,
.component-preview__contract code {
    color: var(--aeterni-color-brand-text);
    font-family: var(--aeterni-font-family-mono);
    font-size: var(--aeterni-font-size-xs);
    overflow-wrap: anywhere;
}

.component-preview__api-row span code + small {
    display: block;
    margin-top: 3px;
    color: var(--aeterni-text-secondary);
    font-family: var(--aeterni-font-family-base);
    font-size: var(--aeterni-font-size-xs);
}

.component-preview__contract-list {
    display: grid;
    gap: 8px;
}

.component-preview__contract {
    display: grid;
    gap: 3px;
    padding: 11px 14px;
    border: 1px solid var(--aeterni-border);
    border-radius: var(--aeterni-radius-md);
    background: var(--aeterni-bg-secondary);
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
    line-height: 1.6;
}

.component-preview__notes {
    display: flex;
    gap: 10px;
    margin-top: 0;
    padding: 14px 16px;
    border: 1px solid var(--aeterni-info-soft);
    border-radius: var(--aeterni-radius-md);
    background: var(--aeterni-info-soft);
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
    line-height: 1.7;
}

.component-preview__notes-mark {
    display: grid;
    flex: 0 0 18px;
    place-items: center;
    width: 18px;
    height: 18px;
    border-radius: var(--aeterni-radius-round);
    background: var(--aeterni-info);
    /* 语意实心上的字用 on-semantic，不用 text-inverse：深色主题里 info 是亮蓝，
       白字会掉到对比度下限以下。 */
    color: var(--aeterni-color-on-semantic);
    font-family: var(--aeterni-font-family-mono);
    font-size: var(--aeterni-font-size-xs);
    font-weight: var(--aeterni-font-weight-bold);
}

/* Below this width the preview card is a single column of stacked sections, so
   the API table collapses here too: its three tracks have a ~508px minimum, which
   is wider than the card once the sidebar occupies a column of the shell. */
@media (max-width: 900px) {
    .component-preview__demo-grid {
        grid-template-columns: 1fr;
    }

    .component-preview__stage {
        border-right: 0;
        border-bottom: 1px solid var(--aeterni-border-subtle);
    }

    /* 名称列不折词，窄屏把超出的部分交给容器横向滚动。 */
    .component-preview__api-table {
        overflow-x: auto;
    }

    .component-preview__api-row {
        grid-template-columns: 1fr;
        gap: 6px;
    }

    /* 表头视觉收起，但保留 role=columnheader 供读屏使用（裁到 1px 仍在无障碍树里）；
       每一行的列义由 data-label 伪元素补成可见的微型标签。 */
    .component-preview__api-row--header {
        position: absolute;
        inline-size: 1px;
        block-size: 1px;
        overflow: hidden;
        padding: 0;
        border: 0;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .component-preview__api-row [role="cell"]::before {
        display: block;
        margin-bottom: 2px;
        content: attr(data-label);
        color: var(--aeterni-text-secondary);
        font-family: var(--aeterni-font-family-base);
        font-size: var(--aeterni-font-size-xs);
        font-weight: var(--aeterni-font-weight-semibold);
        letter-spacing: var(--aeterni-letter-spacing-wider);
    }
}

@media (max-width: 640px) {
    .component-preview__header,
    .component-preview__stage,
    .component-preview__controls,
    .component-preview__api {
        padding-right: 18px;
        padding-left: 18px;
    }

    .component-preview__header {
        display: block;
    }


    .component-preview__name {
        display: inline-block;
        margin-top: 14px;
    }

    .component-preview__canvas {
        min-height: 120px;
        padding: 18px 14px;
    }
}

/* 示例代码段。片段是消费者会复制的形态，而不是上面演示的逐行转写：演示用控件
   驱动十来个参数，片段只保留最小可用写法。代码块使用中性表面与等宽字体，不引入
   第二套配色。 */
.component-preview__code {
    padding: 0 var(--showcase-card-padding);
}

.component-preview__copy {
    min-height: var(--aeterni-touch-target-min);
    padding: 4px 12px;
    border: 1px solid var(--aeterni-border);
    border-radius: var(--aeterni-radius-sm);
    background: transparent;
    color: var(--aeterni-text-secondary);
    font: inherit;
    font-size: var(--aeterni-font-size-xs);
    cursor: pointer;
}

.component-preview__copy:hover {
    border-color: var(--aeterni-control-border-hover);
    color: var(--aeterni-text-primary);
}

.component-preview__copy:focus-visible {
    outline: var(--aeterni-focus-width) solid var(--aeterni-focus-color);
    outline-offset: var(--aeterni-focus-offset);
}

.component-preview__code-block {
    overflow-x: auto;
    margin: 0;
    padding: 16px 18px;
    border: 1px solid var(--aeterni-border-subtle);
    border-radius: var(--aeterni-radius-md);
    background: var(--aeterni-bg-tertiary);
    color: var(--aeterni-text-primary);
    font-family: var(--aeterni-font-family-mono);
    font-size: var(--aeterni-font-size-compact);
    line-height: 1.7;
    tab-size: 4;
}

/* 说明与边界现在是独立段：段标题负责与上一段的间距，notes 盒不再自带顶部外边距。 */
.component-preview__notes-section {
    padding: 0 var(--showcase-card-padding);
}

.component-preview__notes-section .component-preview__notes {
    margin-top: 0;
}

/* notes 里的每一条是独立的一句话：竖排、限制行长，不随卡片宽度拉成一整行。 */
.component-preview__notes > div {
    display: grid;
    gap: 8px;
    max-width: 68ch;
    text-wrap: pretty;
}

/* demo 卡片：一页多段演示的载体。每张卡自带锚点（右栏 TOC 与分享链接用），标题用 h3，
   说明紧跟其后；预览区沿用 .component-preview__canvas 的排版。 */
.component-demo + .component-demo {
    margin-top: 32px;
}

.component-demo__header {
    margin: 0 0 12px;
}

.component-demo__header h3 {
    margin: 0 0 6px;
    color: var(--aeterni-text-primary);
    font-family: var(--aeterni-font-family-display);
    font-size: var(--aeterni-font-size-lg);
    font-weight: var(--aeterni-font-weight-semibold);
    letter-spacing: var(--aeterni-letter-spacing-tight);
}

.component-demo__description {
    margin: 0;
    max-width: 60ch;
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
    line-height: 1.7;
    text-wrap: pretty;
}

.component-demo__controls {
    margin-top: 14px;
    padding-top: 14px;
    border-block-start: var(--aeterni-border-width) solid var(--aeterni-separator);
}

.component-demo__controls-label {
    margin: 0 0 10px;
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-xs);
    font-weight: var(--aeterni-font-weight-semibold);
    letter-spacing: var(--aeterni-letter-spacing-wide);
}

/* 复制按钮从段标题移到代码块上方后，需要自己撑起一行。 */
.component-preview__code-toolbar {
    display: flex;
    justify-content: flex-end;
    margin-bottom: 6px;
}

/* 组件页骨架：标题区、何时使用、demo 列表、API、相关组件、说明与边界。
   每一段的横向内边距都来自 --showcase-card-padding，纵向间距来自 --showcase-card-block；
   最后一段（说明与边界）还带底部内边距，卡片底部因此不会贴住文字。 */
.component-page__demos,
.component-page__when,
.component-page__related,
.component-preview__api {
    padding: var(--showcase-card-block) var(--showcase-card-padding) 0;
}

.component-page__section,
.component-preview__notes-section {
    padding: var(--showcase-card-block) var(--showcase-card-padding) var(--showcase-card-block);
}

/* 段锚点的落点：页头是固定定位的浮层，锚点跳到视口顶端会被它压住。给每个可跳转的段落一份
   顶部留白（= 页头占掉的高度），`scrollIntoView` 与浏览器自己的 hash 跳转都会遵守它，
   页头搜索框跨页跳转与右栏目录的锚点因此落在同一个位置。 */
.component-demo,
.component-page__when,
.component-page__related,
.component-page__section,
.component-preview__api {
    scroll-margin-top: var(--sample-content-top);
}

.component-page__section h2,
.component-page__when h2,
.component-page__related h2,
.component-page__notes-section h2 {
    margin: 0 0 10px;
    color: var(--aeterni-text-primary);
    font-family: var(--aeterni-font-family-display);
    font-size: var(--aeterni-font-size-xl);
    font-weight: var(--aeterni-font-weight-semibold);
    letter-spacing: var(--aeterni-letter-spacing-tight);
}

.component-page__when p {
    margin: 0 0 8px;
    max-width: 68ch;
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-md);
    line-height: 1.75;
    text-wrap: pretty;
}

.component-page__related ul {
    display: flex;
    flex-wrap: wrap;
    gap: var(--aeterni-spacing-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.component-page__related a {
    display: inline-block;
    padding: 5px 11px;
    border: 1px solid var(--aeterni-border-subtle);
    border-radius: var(--aeterni-radius-full);
    color: var(--aeterni-color-brand-text);
    font-size: var(--aeterni-font-size-compact);
    text-decoration: none;
}

.component-page__related a:hover {
    border-color: var(--aeterni-control-border-hover);
}

.component-page__related a:focus-visible {
    outline: var(--aeterni-focus-width) solid var(--aeterni-focus-color);
    outline-offset: var(--aeterni-focus-offset);
}

/* 相关组件与何时使用的内边距由上面的成组规则给出。 */

/* 正文 + 右栏目录：目录只在有位置时出现（1280px 以上），窄屏收成正文顶部的一份
   可展开列表。正文与目录同处一张内容面，右边线与页头右缘对齐。 */
.component-page {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 176px;
    align-items: start;
    gap: 32px;
    border: 1px solid var(--aeterni-border-subtle);
    border-radius: var(--aeterni-radius-xl);
    background: var(--aeterni-bg-surface);
    box-shadow: var(--aeterni-shadow-sm);
    animation: showcase-page-enter var(--aeterni-duration-slow) var(--aeterni-ease-out) both;
}

.component-page__toc {
    position: sticky;
    top: var(--sample-content-top);
    align-self: start;
    padding: 30px var(--showcase-card-padding) 30px 0;
    font-size: var(--aeterni-font-size-compact);
}

.component-page__toc-title {
    margin: 0 0 10px;
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-xs);
    font-weight: var(--aeterni-font-weight-semibold);
    letter-spacing: var(--aeterni-letter-spacing-wider);
}

.component-page__toc ul {
    display: grid;
    gap: 1px;
    margin: 0;
    padding: 0;
    list-style: none;
    border-inline-start: 1px solid var(--aeterni-border-subtle);
}

.component-page__toc-link {
    display: block;
    padding: 6px 10px;
    border-inline-start: 2px solid transparent;
    margin-inline-start: -1px;
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-compact);
    text-decoration: none;
}

.component-page__toc-link:hover {
    color: var(--aeterni-text-primary);
}

.component-page__toc-link.is-current {
    border-inline-start-color: var(--aeterni-color-brand-default);
    color: var(--aeterni-color-brand-text);
    font-weight: var(--aeterni-font-weight-medium);
}

.component-page__toc-link:focus-visible {
    outline: var(--aeterni-focus-width) solid var(--aeterni-focus-color);
    outline-offset: calc(-1 * var(--aeterni-focus-offset));
    border-radius: var(--aeterni-radius-xs);
}

.component-page__toc-mobile {
    display: none;
}

@keyframes showcase-page-enter {
    from {
        opacity: 0;
        transform: translateY(10px);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

@media (max-width: 1280px) {
    .component-page {
        grid-template-columns: minmax(0, 1fr);
        gap: 0;
    }

    .component-page__toc {
        display: none;
    }

    .component-page__toc-mobile {
        display: block;
        padding: 14px var(--showcase-card-padding);
        border-bottom: 1px solid var(--aeterni-border-subtle);
    }

    .component-page__toc-mobile summary {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: var(--aeterni-spacing-3);
        cursor: pointer;
        color: var(--aeterni-text-secondary);
        font-size: var(--aeterni-font-size-compact);
        font-weight: var(--aeterni-font-weight-medium);
        list-style: none;
    }

    .component-page__toc-mobile summary::-webkit-details-marker {
        display: none;
    }

    .component-page__toc-mobile summary::after {
        content: "▾";
        font-size: var(--aeterni-font-size-xs);
        transition: transform var(--aeterni-duration-fast) var(--aeterni-ease-standard);
    }

    .component-page__toc-mobile[open] summary::after {
        transform: rotate(180deg);
    }

    .component-page__toc-mobile ul {
        display: flex;
        flex-wrap: wrap;
        gap: 6px 16px;
        margin: 12px 0 0;
        padding: 0;
        list-style: none;
    }

    .component-page__toc-mobile a {
        color: var(--aeterni-text-secondary);
        font-size: var(--aeterni-font-size-compact);
        text-decoration: none;
    }

    .component-page__toc-mobile a:hover {
        color: var(--aeterni-color-brand-text);
    }
}

@media (prefers-reduced-motion: reduce) {
    .component-page {
        animation: none;
    }
}

/* 卡片内的页头元信息：类型名与"在 GitHub 编辑"竖排在右侧，跟标题区同一行。 */
.component-preview__meta {
    display: grid;
    justify-items: end;
    gap: 6px;
    text-align: end;
}

.component-page__edit {
    color: var(--aeterni-color-brand-text);
    font-size: var(--aeterni-font-size-compact);
    text-decoration: none;
}

.component-page__edit:hover {
    text-decoration: underline;
}

.component-page__edit:focus-visible {
    outline: var(--aeterni-focus-width) solid var(--aeterni-focus-color);
    outline-offset: var(--aeterni-focus-offset);
    border-radius: var(--aeterni-radius-xs);
}

/* 预览 / 代码切换是一组分段控件：轨道、滑块、焦点环与"整组一个 Tab 停留点"都归库内
   Segmented，示例只保留卡片里这一段的下间距，不再自绘轨道。 */
.component-demo__toolbar {
    width: fit-content;
    margin-bottom: 10px;
}

/* API 表的横向滚动只在 ≤900px 的单列布局里打开（见上面的媒体查询）；桌面保持
   普通文档流，长表才能让表头相对视口 sticky。 */

/* 窄屏把侧栏收成一份可展开的「组件目录」：桌面隐藏开关并强制展开内容，
   移动端默认折叠，展开状态由 ComponentsLayout 的 aria-expanded 与 .is-open 表达。 */
.showcase-nav-toggle {
    display: none;
    align-items: center;
    justify-content: space-between;
    gap: var(--aeterni-spacing-3);
    width: 100%;
    /* 「组件目录」是窄屏进导航的唯一入口，命中区取触控下限而不是 24px。 */
    min-height: var(--aeterni-touch-target);
    padding: 10px 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    color: var(--aeterni-text-primary);
    font: inherit;
    font-size: var(--aeterni-font-size-sm);
    font-weight: var(--aeterni-font-weight-semibold);
    text-align: start;
    cursor: pointer;
}

.showcase-nav-toggle:focus-visible {
    outline: var(--aeterni-focus-width) solid var(--aeterni-focus-color);
    outline-offset: var(--aeterni-focus-offset);
    border-radius: var(--aeterni-radius-sm);
}

.showcase-nav-toggle__chevron {
    width: 8px;
    height: 8px;
    margin-inline-end: 4px;
    border-right: 1.5px solid var(--aeterni-text-secondary);
    border-bottom: 1.5px solid var(--aeterni-text-secondary);
    transform: rotate(45deg) translateY(-2px);
    transition: transform var(--aeterni-duration-fast) var(--aeterni-ease-standard);
}

.showcase-nav-toggle[aria-expanded="true"] .showcase-nav-toggle__chevron {
    transform: rotate(225deg) translateY(-2px);
}

.showcase-nav-body {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    min-height: 0;
}

@media (max-width: 1000px) {
    .showcase-layout {
        grid-template-columns: minmax(0, 1fr);
        gap: var(--aeterni-spacing-5);
    }

    .showcase-sidebar {
        position: static;
        width: 100%;
        height: auto;
        padding: 0;
        border-inline-end: 0;
        border-bottom: 1px solid var(--aeterni-border-subtle);
    }

    .showcase-nav-toggle {
        display: flex;
    }

    .showcase-nav-body {
        display: none;
    }

    .showcase-nav-body.is-open {
        display: flex;
        padding-bottom: var(--aeterni-spacing-3);
    }

    .showcase-nav {
        max-height: 46vh;
        margin-right: 0;
        padding: 4px 0 12px;
    }

    .showcase-search {
        margin-right: 0;
        padding: 2px 0 12px;
    }
}

/* 移动端页头：搜索收成图标按钮，快捷键提示属于桌面逻辑，不放进来。 */
@media (max-width: 700px) {
    .sample-header__search {
        flex: 0 0 auto;
    }

    /* 图标按钮的可见尺寸保持 34px（页头第一行不被撑高），用按钮自己的伪元素把命中区
       扩到 40px；伪元素属于按钮，点击与 hover 都落到同一个元素上。 */
    .showcase-search-trigger {
        position: relative;
        width: 34px;
        min-height: 34px;
        padding: 0;
        justify-content: center;
    }

    .showcase-search-trigger::after {
        position: absolute;
        inset: -3px;
        content: "";
    }

    .showcase-search-trigger__label,
    .showcase-search-trigger__kbd {
        display: none;
    }
}

/* 头部搜索入口 + 居中搜索面板 -------------------------------------------------
   页头放的是"像输入框的按钮"：真正的输入框在居中面板里。面板必须渲染在页头玻璃卡片之外，
   否则它自己的 `backdrop-filter` 只能采样卡片内部那张透明背景。触发器直接取库内控件的字段
   token，与真实 Input 站在一起时看不出这是两套东西；本表不覆写任何 `.aeterni-` 组件规则。 */
.sample-header__search {
    /* 触发器是页头里第一个被挤的入口：给一段固定宽度，但不许把品牌与主导航挤变形。 */
    flex: 0 1 240px;
    min-width: 0;
}

.sample-header__settings {
    flex: 0 0 auto;
}

.showcase-search-trigger {
    display: flex;
    align-items: center;
    gap: var(--aeterni-spacing-2);
    box-sizing: border-box;
    width: 100%;
    min-height: 32px;
    padding: 0 var(--aeterni-spacing-3);
    border: var(--aeterni-border-width) solid var(--aeterni-control-border);
    border-radius: var(--aeterni-radius-input);
    background: var(--aeterni-control-background);
    color: var(--aeterni-control-foreground-placeholder);
    font-family: inherit;
    font-size: var(--aeterni-font-size-sm);
    text-align: start;
    cursor: pointer;
    transition: var(--aeterni-transition-border), var(--aeterni-transition-color);
}

.showcase-search-trigger:hover {
    border-color: var(--aeterni-control-border-hover);
}

/* 焦点环与库内字段同一条：`:focus-visible` 只在实际用键盘操作时出现。 */
.showcase-search-trigger:focus-visible {
    border-color: var(--aeterni-control-border-focus);
    outline: var(--aeterni-focus-width) solid var(--aeterni-focus-color);
    outline-offset: var(--aeterni-focus-offset);
}

.showcase-search-trigger__icon {
    display: grid;
    flex: 0 0 auto;
    place-items: center;
    font-size: var(--aeterni-font-size-sm);
}

.showcase-search-trigger__label {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* 键位提示只写给鼠标用户看：触发器的读屏名字来自可见文案，所以这个 kbd 标了 aria-hidden。 */
.showcase-search-trigger__kbd {
    flex: 0 0 auto;
    padding: 1px 6px;
    border: 1px solid var(--aeterni-border);
    border-radius: var(--aeterni-radius-sm);
    color: var(--aeterni-text-tertiary);
    font-family: var(--aeterni-font-family-mono);
    font-size: var(--aeterni-font-size-xs);
    line-height: 1.5;
}

/* 居中搜索面板：遮罩铺满视口、面板居中。两者都是 fixed 定位，所以页面滚动不会把面板带走，
   滚动锁（库内共享模块提供）只是不让背后跟着滚。面板是不透明内容表面（`--aeterni-bg-surface`），
   与 Dialog/Drawer 同一档，不再叠玻璃——玻璃面板上套白输入框会让层级读反，浅色主题下尤其明显。 */
.showcase-search-modal {
    position: fixed;
    z-index: var(--aeterni-z-modal);
    inset: 0;
    /* 滚动锁预留的滚动条槽不计入固定层的布局视口：把内联末端伸过去，遮罩才能铺满窗口，
       面板也回到窗口中心。覆盖式滚动条引擎上该变量是 0px，等于没有这条声明。 */
    inset-inline-end: calc(-1 * var(--aeterni-scroll-lock-gutter, 0px));
    display: grid;
    box-sizing: border-box;
    padding: var(--aeterni-spacing-5);
    place-items: center;
    /* 容器只负责居中：点击留给遮罩与面板，容器自己不吃事件。 */
    pointer-events: none;
}

.showcase-search-modal__backdrop {
    position: absolute;
    inset: 0;
    background: var(--aeterni-overlay);
    -webkit-backdrop-filter: var(--aeterni-blur-scrim);
    backdrop-filter: var(--aeterni-blur-scrim);
    pointer-events: auto;
    animation: showcase-search-backdrop-in var(--aeterni-duration-normal) var(--aeterni-ease-out);
}

.showcase-search-modal__panel {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    box-sizing: border-box;
    width: min(640px, 100%);
    max-height: min(70vh, var(--aeterni-overlay-height-md));
    overflow: hidden;
    border: var(--aeterni-border-width) solid var(--aeterni-border-default);
    border-radius: var(--aeterni-radius-modal);
    /* 不透明表面：不写 backdrop-filter，避免浅色下"灰玻璃面板里套白输入框"的层级反转；
       墨阶回到普通表面 token，不再需要 on-glass 别名。 */
    background: var(--aeterni-bg-surface);
    color: var(--aeterni-text-primary);
    box-shadow: var(--aeterni-shadow-modal);
    pointer-events: auto;
    animation: showcase-search-panel-in var(--aeterni-duration-fast) var(--aeterni-ease-out);
}

@keyframes showcase-search-backdrop-in {
    from {
        opacity: 0;
    }
}

@keyframes showcase-search-panel-in {
    from {
        opacity: 0;
        transform: translateY(-6px);
    }
}

/* 退场：与入场同一条轴、更短（100ms）。退场期间整层不再接受点击，滚动锁与焦点
   陷阱由 C# 等动画实测结束之后再释放；reduced-motion 下关闭动画被移除，等待立即完成。 */
.showcase-search-modal.is-closing,
.showcase-search-modal.is-closing .showcase-search-modal__backdrop,
.showcase-search-modal.is-closing .showcase-search-modal__panel {
    pointer-events: none;
}

.showcase-search-modal.is-closing .showcase-search-modal__backdrop {
    animation: showcase-search-backdrop-exit var(--aeterni-duration-fast) var(--aeterni-ease-in) both;
}

.showcase-search-modal.is-closing .showcase-search-modal__panel {
    animation: showcase-search-panel-exit var(--aeterni-duration-fast) var(--aeterni-ease-in) both;
}

@keyframes showcase-search-backdrop-exit {
    to {
        opacity: 0;
    }
}

@keyframes showcase-search-panel-exit {
    to {
        opacity: 0;
        transform: translateY(-4px) scale(.98);
    }
}

@media (prefers-reduced-motion: reduce) {
    .showcase-search-modal__backdrop,
    .showcase-search-modal__panel,
    .showcase-search-modal.is-closing .showcase-search-modal__backdrop,
    .showcase-search-modal.is-closing .showcase-search-modal__panel {
        animation: none;
    }
}

/* 输入框那一行：图标在字段外侧（字段自身的边框、内边距与焦点环归库内 Input，示例不伸手进去
   改），右侧是关闭按钮。 */
.showcase-search-modal__field {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    gap: var(--aeterni-spacing-2);
    padding: var(--aeterni-spacing-3);
    border-bottom: 1px solid var(--aeterni-border-subtle);
}

/* 命中数读数：查询非空时才有，作为结果区自己的状态行；`role=status` 已在标记里，
   每敲一个字它会更新一次，读屏不必再逐条数结果。 */
.showcase-search-modal__summary {
    flex: 0 0 auto;
    margin: 0;
    padding: var(--aeterni-spacing-2) var(--aeterni-spacing-3);
    border-bottom: 1px solid var(--aeterni-border-subtle);
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-xs);
    font-variant-numeric: tabular-nums;
}

.showcase-search-modal__icon {
    display: grid;
    flex: 0 0 auto;
    place-items: center;
    color: var(--aeterni-text-tertiary);
    font-size: var(--aeterni-font-size-sm);
}

/* 结果行之间必须有间隙：每行自带圆角背景，贴在一起时活动项与邻行的底色会连成一片，
   读者分不出那是两行还是一个大色块。间隙取库内 List 的同一档（--aeterni-spacing-1），
   列表外观因此与 `List` 组件一致。 */
.showcase-search-modal__list {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: var(--aeterni-spacing-1);
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--aeterni-spacing-2);
    scrollbar-gutter: stable;
}

/* 结果按页面分组：列表外层仍是一个 gap 4px 的 flex 列，组内条目保持同一档间隙；
   组与组之间多留一档，页面标题行因此读起来像"下一组"而不是"又一条结果"。 */
.showcase-search-modal__group {
    display: grid;
    gap: var(--aeterni-spacing-1);
    min-width: 0;
}

.showcase-search-modal__group + .showcase-search-modal__group {
    margin-top: var(--aeterni-spacing-2);
}

.showcase-search-modal__group-title {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--aeterni-spacing-2);
    margin: var(--aeterni-spacing-1) var(--aeterni-spacing-2) 0;
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-xs);
    font-weight: var(--aeterni-font-weight-semibold);
    letter-spacing: var(--aeterni-letter-spacing-wide);
}

.showcase-search-modal__group-page {
    min-width: 0;
    color: var(--aeterni-text-primary);
    overflow-wrap: anywhere;
}

.showcase-search-modal__group-category {
    font-weight: var(--aeterni-font-weight-regular);
}

.showcase-search-modal__group-count {
    margin-inline-start: auto;
    font-weight: var(--aeterni-font-weight-regular);
    font-variant-numeric: tabular-nums;
}

/* 命中词高亮：只换底色与字重，不接管活动项/悬停的整行底。
   文字仍由 RenderFragment 逐段输出，不拼 HTML。 */
.showcase-search-modal__mark {
    padding: 0 1px;
    border-radius: var(--aeterni-radius-xs);
    background: var(--aeterni-color-brand-soft);
    color: var(--aeterni-text-primary);
    font-weight: var(--aeterni-font-weight-semibold);
}

.showcase-search-modal__option {
    display: grid;
    gap: 2px;
    padding: var(--aeterni-spacing-2) var(--aeterni-spacing-3);
    border-radius: var(--aeterni-radius-md);
    cursor: pointer;
}

/* 活动项是"已选中"，普通 hover 不能把它洗回未选中样：两个档位明确分开。 */
.showcase-search-modal__option:not(.is-active):hover {
    background: var(--aeterni-state-background-hover);
}

.showcase-search-modal__option.is-active {
    background: var(--aeterni-state-background-selected);
}

.showcase-search-modal__option-title {
    color: var(--aeterni-text-primary);
    font-size: var(--aeterni-font-size-sm);
    overflow-wrap: anywhere;
}

.showcase-search-modal__option-meta {
    /* 结果页码是正文信息（Timeline · 导航组件），用 secondary 而不是 tertiary。 */
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-xs);
    overflow-wrap: anywhere;
}

/* 查询为空时的引导：这是初始态，不是"没有结果"，所以文案只说明能搜什么。 */
.showcase-search-modal__prompt {
    margin: 0;
    padding: var(--aeterni-spacing-3) var(--aeterni-spacing-3) var(--aeterni-spacing-4);
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
    line-height: var(--aeterni-line-height-normal);
}

.showcase-search-modal__empty {
    margin: 0;
    padding: var(--aeterni-spacing-3) var(--aeterni-spacing-3) var(--aeterni-spacing-4);
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
}

/* 面板底部的键位提示：面板里的键盘路径不止一条，写出来读者才敢用（不用鼠标也能走完）。 */
.showcase-search-modal__hint {
    flex: 0 0 auto;
    margin: 0;
    padding: var(--aeterni-spacing-2) var(--aeterni-spacing-3);
    border-top: 1px solid var(--aeterni-border-subtle);
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-xs);
}

/* 设置浮层：页头是一张固定定位的玻璃卡片，锚点（触发器包裹元素）就在卡片里，库内默认的 8px
   间距会让浮层顶部压进卡片下沿约 12px，卡片的下边框于是横在磨砂面板背后。这里给浮层自己的
   margin 多留一段（锚定模式下由浮层模块写在 `top` 之外，margin 照常把盒子推开），浮层从卡片
   之外开始——用示例自己的类名做偏移，不去写 `.aeterni-popover` 的全局规则。 */
.showcase-settings__popover {
    margin-top: var(--aeterni-spacing-3);
}

/* 窄屏页头折成两行（第二行是主导航）：设置浮层按齿轮锚定，默认间距会压在第二行上。
   多让出一行导航的高度，并限制最大宽度，浮层就不会盖住导航与页头边缘。 */
@media (max-width: 700px) {
    .showcase-settings__popover {
        max-width: calc(100vw - var(--aeterni-spacing-4) * 2);
        margin-top: 64px;
    }
}

/* 设置浮层：可见标签 + 分段控件，两者说的是同一件事。 */
.showcase-settings {
    display: grid;
    gap: var(--aeterni-spacing-4);
    min-width: var(--aeterni-overlay-min-width-sm);
}

.showcase-settings__group {
    display: grid;
    gap: var(--aeterni-spacing-1);
}

.showcase-settings__label {
    margin: 0;
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-xs);
}

/* 页面反馈闭环：正文最末一行，投票与仓库出口分列两端；左右内边距与卡片
   其它段一致，否则这一行会贴着卡片边缘，读起来像渲染错误。 */
.component-feedback {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--aeterni-spacing-3);
    margin-block-start: var(--aeterni-spacing-8);
    padding: var(--aeterni-spacing-4) var(--showcase-card-padding) var(--showcase-card-padding);
    border-block-start: 1px solid var(--aeterni-border-subtle);
}

.component-feedback__vote {
    display: inline-flex;
    align-items: center;
    gap: var(--aeterni-spacing-1);
}

.component-feedback__question {
    margin-inline-end: var(--aeterni-spacing-1);
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
}

.component-feedback__links {
    display: inline-flex;
    align-items: center;
    gap: var(--aeterni-spacing-4);
    margin-inline-start: auto;
}

.component-feedback__link {
    color: var(--aeterni-text-secondary);
    font-size: var(--aeterni-font-size-sm);
    text-decoration: none;
    transition: var(--aeterni-transition-color);
}

.component-feedback__link:hover,
.component-feedback__link:focus-visible {
    color: var(--aeterni-color-brand-default);
}
