/* wwwroot/css/site.css — hand-written modern CSS, committed to git as-is, no build step (docs/05 §6). */

@layer reset, tokens, base, layout, components;

@layer reset {
  *, *::before, *::after { box-sizing: border-box; }
  button {
    font: inherit;
    cursor: pointer;
    background: none;
    border: none;
    color: inherit;
    padding: 0;
  }
  ul { list-style: none; padding: 0; }
  h1, h2, h3, p, ul, figure, pre { margin: 0; }
}

@layer tokens {
  :root {
    color-scheme: light dark;                                            /* enables light-dark() automatic dark mode */
    /* Material Indigo accent — dark mode matches eax.org (#9FA8DA on #121212 / #1e1e1e
       surfaces, 87 % / 60 % white text); light mode uses Indigo 500 (#3F51B5) for
       accessible contrast on a near-white background. */
    --brand:         light-dark(#3F51B5, #9FA8DA);
    --brand-hover:   light-dark(#303F9F, #b1b9e1);
    --brand-text:    light-dark(#ffffff, #121212);                       /* text drawn ON a brand-coloured surface */
    --bg:            light-dark(#fafafa, #121212);                       /* Material backdrop */
    --fg:            light-dark(rgba(0,0,0,0.87), rgba(255,255,255,0.87));
    --fg-muted:      light-dark(rgba(0,0,0,0.60), rgba(255,255,255,0.60));
    --surface:       light-dark(#ffffff, #1e1e1e);                       /* cards, dropdown panels, inputs */
    --surface-hover: light-dark(rgba(0,0,0,0.04), rgba(255,255,255,0.04));
    --border:        light-dark(rgba(0,0,0,0.12), rgba(255,255,255,0.12));
    --radius:        0.25rem;                                            /* Material small radius (eax.org). rem so它随用户字体大小一起缩放——
                                                                            和余下的 spacing / typography 一致；hairline border / outline / shadow
                                                                            offset / 9999px pill 留 px（约定，详见 docs/05 §6）。 */
    --content-max:   72rem;
    --navbar-h:      2.75rem;                                            /* compact bar, matches Material dense / eax.org feel */
    --shadow-sm:     0 1px 2px rgb(0 0 0 / 0.06);
    --shadow-md:     0 4px 16px rgb(0 0 0 / 0.18);
    --shadow-lg:     0 10px 25px rgb(0 0 0 / 0.15);
  }
}

@layer base {
  body {
    margin: 0;
    min-block-size: 100vh;
    background: var(--bg);
    color: var(--fg);
    /* eax.org's font stack — Roboto on systems that have it, falls back through
       Helvetica Neue / Arial; no external font load, no build step (docs/05 §6). */
    font-family: Roboto, "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
    line-height: 1.5;
  }

  h1 { font-size: 1.75rem;  font-weight: 500; margin-block-end: 1rem; letter-spacing: -0.01em; }
  h2 { font-size: 1.375rem; font-weight: 500; margin-block: 1.5rem 0.75rem; }
  p  { margin-block-end: 1rem; }
  a  { color: var(--brand); text-decoration: none; }
  a:hover { text-decoration: underline; }

  :focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
}

@layer layout {
  .content {
    max-inline-size: var(--content-max);
    margin-inline: auto;
    padding-inline: 1rem;
    padding-block: 2rem;
  }
}

@layer components {

  /* === Site header — sticky banner, always pinned to viewport top === */
  .site-header {
    position: sticky;
    inset-block-start: 0;
    z-index: 100;
    background: var(--surface);
    border-block-end: 1px solid var(--border);
    box-shadow: var(--shadow-sm);
  }

  /* === Navbar — full-width edge-to-edge (mimics macOS menu bar / Kali Linux panel) ===
     No max-inline-size / margin-inline: auto — items hug both viewport edges; the
     .content container below stays max-w-bounded. Items provide their own inner padding. */
  .navbar {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    block-size: var(--navbar-h);
    padding-inline: 0;
  }
  .navbar__logo {
    font-weight: 700;
    font-size: 1.125rem;
    color: var(--fg);
    padding-inline: 1rem;
  }
  .navbar__logo:hover { text-decoration: none; }

  /* === Dropdown menus (Apps / Bookmarks / Language / User) === */
  .menu { position: relative; }
  .menu__trigger {
    padding-inline: 0.75rem;
    padding-block: 0.375rem;
    color: var(--fg);
    border-radius: var(--radius);
    font-weight: 500;
  }
  .menu__trigger:hover { background: var(--surface-hover); }

  /* === Theme toggle (compact icon button, cycles auto → light → dark) === */
  /* Placed before Language in the navbar, takes the margin-inline-start: auto so it
     and everything after it (Language / User) hugs the inline-end edge. */
  .theme-toggle {
    margin-inline-start: auto;
    inline-size: 2rem;
    block-size: 2rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--fg);
    border-radius: var(--radius);
    font-size: 1rem;
    line-height: 1;
  }
  .theme-toggle:hover { background: var(--surface-hover); }
  .theme-toggle__icon { font-family: "Apple Color Emoji", "Segoe UI Symbol", "Noto Sans Symbols2", sans-serif; }

  .menu__panel {
    position: absolute;
    inset-block-start: calc(100% + 0.25rem);
    inset-inline-start: 0;
    min-inline-size: 14rem;
    padding-block: 0.375rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-md);
    z-index: 200;
    /* overflow stays the default visible: cascade submenus are absolute-positioned
       descendants and must escape the panel's box. Per the CSS Overflow spec,
       setting overflow-y: auto forces overflow-x to auto too (clipping cascades).
       Long menus are rare; if a level ever needs scrolling, add a wrapper element. */
  }
  /* Theme toggle (above) carries margin-inline-start: auto; Language and User flow after it
     toward the inline-end edge — no extra margin needed on Language. */
  /* Right-edge menus open toward the leading edge so they don't overflow the viewport. */
  .menu[data-nav="language"] .menu__panel,
  .menu[data-nav="user"]     .menu__panel {
    inset-inline-start: auto;
    inset-inline-end: 0;
  }

  .menu__item {
    display: block;
    inline-size: 100%;
    padding-inline: 1rem;
    padding-block: 0.375rem;
    color: var(--fg);
    text-align: start;
    border-radius: 0;
  }
  .menu__item:hover {
    background: var(--surface-hover);
    color: var(--fg);
    text-decoration: none;
  }
  .menu__panel form { margin: 0; }

  /* === Inline SVG icons (sprite in _Layout) ===
     <svg class="icon"><use href="#i-xxx"/></svg> — stroke 跟随 currentColor，故随文字 / 主题色走；
     1em 见方、随行高对齐。所有图标都是 stroke-only（无填充）。 */
  .icon {
    inline-size: 1em;
    block-size: 1em;
    flex: 0 0 auto;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    vertical-align: -0.125em;
  }

  /* 下拉里的分隔线（如书签菜单「编辑书签」入口前）。 */
  .menu__sep {
    block-size: 0;
    margin-block: 0.375rem;
    border-block-start: 1px solid var(--border);
  }
  /* 管理类入口（书签菜单底部「编辑书签」）——淡色 + 前置图标，和上面的书签外链拉开层级。 */
  .menu__item--manage {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--fg-muted);
    font-size: 0.875rem;
  }
  .menu__item--manage:hover { color: var(--fg); }

  /* === Cascading submenus (Apps tools, Bookmarks branches) ===
     Each item with children gets .menu__item-wrap on its <li> for positioning;
     the nested <ul class="menu__panel menu__submenu"> flies out to the inline-end side. */
  .menu__item-wrap { position: relative; }
  /* Keep the parent item highlighted while the cursor is anywhere in its submenu
     (the submenu is a DOM descendant of .menu__item-wrap, so :hover propagates). */
  .menu__item-wrap:hover > .menu__item { background: var(--surface-hover); }

  .menu__submenu {
    inset-block-start: -0.375rem;        /* align with parent <li> top, offsetting panel padding */
    inset-inline-start: 100%;            /* fly to trailing edge of parent */
  }
  /* Right-side menus (language/user) sit at viewport's trailing edge — any submenu
     they might host must fly toward the leading edge to avoid overflow. */
  .menu[data-nav="language"] .menu__submenu,
  .menu[data-nav="user"]     .menu__submenu {
    inset-inline-start: auto;
    inset-inline-end: 100%;
  }

  /* Item that opens a submenu — chevron rendered after the label on the trailing side. */
  .menu__item--has-children {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
  }
  .menu__item--has-children::after {
    content: "▸";
    color: var(--fg-muted);
    font-size: 0.75rem;
    line-height: 1;
  }
  [dir="rtl"] .menu__item--has-children::after { transform: scaleX(-1); }

  /* === Home search launcher (Pages/_Content.cshtml) ===
     Google-style：顶上当前引擎名作品牌 <h1>，下面一行 pill 把 [engine ▾ | input | search]
     连成一体——共享 surface bg、外圆角，内部用 1px 竖线分隔。Engine 选择器仍是 .menu /
     .menu__panel / .menu__submenu cascade（与 navbar 共享样式）。整个 launcher 在视口
     纵向居中、宽到接近 50rem，避免顶上一坨小东西的局促感。 */
  .search-launcher {
    position: relative;            /* 设置入口绝对定位的容器 */
    max-inline-size: 48rem;
    margin-inline: auto;
    min-block-size: calc(78vh - var(--navbar-h));
    display: flex;
    flex-direction: column;
    justify-content: center;
  }

  /* 搜索引擎管理入口——主内容区右下角，淡灰不抢搜索框焦点（Google「设置」同位）。
     绝对定位到 launcher 块的 block-end / inline-end 角；logical props → RTL 自动落到左下角。 */
  .search-launcher__settings {
    position: absolute;
    inset-block-end: 1rem;
    inset-inline-end: 0;
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.375rem 0.625rem;
    border-radius: var(--radius);
    color: var(--fg-muted);
    font-size: 0.875rem;
  }
  .search-launcher__settings:hover {
    color: var(--fg);
    background: var(--surface-hover);
    text-decoration: none;
  }
  @media (width < 32rem) {
    /* 窄屏：角落空间紧张，改贴底居中、与搜索框拉开。 */
    .search-launcher__settings {
      position: static;
      align-self: center;
      margin-block-start: 1.5rem;
    }
  }
  .search-launcher__brand {
    text-align: center;
    font-size: 4.5rem;
    font-weight: 400;
    letter-spacing: -0.03em;
    margin-block: 0 2rem;
  }

  /* 整条 pill：连体外观——容器持边框 + 圆角；子元素背景透明、无边框，靠 divider 分段。 */
  .search-launcher__bar {
    display: flex;
    align-items: stretch;
    block-size: 3.5rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 9999px;
    box-shadow: var(--shadow-sm);
    transition: box-shadow 0.15s, border-color 0.15s;
  }
  .search-launcher__bar:hover,
  .search-launcher__bar:focus-within {
    border-color: var(--brand);
    box-shadow: var(--shadow-md);
  }

  /* 故意不写 .search-launcher__engine { position: relative }——.menu 类已带；也不写
     .search-launcher__engine .menu__panel { inset-... }——会以 0,2,0 的 specificity
     盖过 .menu__submenu（0,1,0），导致 cascade 子菜单不能朝侧面飞、被强按到下方。
     交由全局 .menu__panel + .menu__submenu 默认规则处理：顶层挂下方、子级飞 inline-end。 */
  .search-launcher__engine-btn {
    background: transparent;
    border: none;
    block-size: 100%;
    padding-inline: 1.5rem;
    padding-block: 0;
    border-start-start-radius: 9999px;
    border-end-start-radius: 9999px;
    white-space: nowrap;
    font-weight: 500;
    color: var(--fg);
    cursor: pointer;
  }
  .search-launcher__engine-btn:hover { background: var(--surface-hover); }

  .search-launcher__divider {
    inline-size: 1px;
    background: var(--border);
    margin-block: 0.625rem;       /* 上下留呼吸位、不贴 pill 边 */
    flex: 0 0 auto;
  }

  /* 输入框：透明、无边框、无内边距——铺满 flex 剩余空间。focus 时不显示自带 outline
     （pill 的 :focus-within 已把外框染成品牌色，那就是焦点指示）。 */
  .search-launcher__bar .search-launcher__input {
    flex: 1 1 auto;
    inline-size: auto;
    background: transparent;
    border: none;
    border-radius: 0;
    font-size: 1.125rem;
    padding-inline: 1.25rem;
    padding-block: 0;
    color: var(--fg);
  }
  .search-launcher__bar .search-launcher__input:focus,
  .search-launcher__bar .search-launcher__input:focus-visible {
    outline: none;
    border: none;
  }
  .search-launcher__bar .search-launcher__input::placeholder { color: var(--fg-muted); }

  /* Submit 按钮：pill 右端的实色 CTA——品牌色底 + brand-text 字（亮色模式白字、
     暗色模式深字，对比度都达标）。hover 加深到 brand-hover。比全局
     button[type="submit"] 更具体——靠 .search-launcher__bar 前缀提升 specificity
     压住那条全局规则。
     box-sizing: border-box 全局生效——pill 子项 stretch 后填的是 content box
     （pill 高 - 2×border），实色按钮会在右端漏出 pill 的 1px 边框圈一周。用
     -1px 的 block / inline-end margin 让按钮越过边框贴到 pill 外缘；按钮右端
     与 pill 右端半径都是 9999px（半圆），覆盖后曲线完全重合。 */
  .search-launcher__bar .search-launcher__submit {
    background: var(--brand);
    color: var(--brand-text);
    border: none;
    padding-inline: 1.75rem;
    padding-block: 0;
    margin-block: -1px;
    margin-inline-end: -1px;
    border-start-end-radius: 9999px;
    border-end-end-radius: 9999px;
    font-weight: 500;
    font-size: 1rem;
    text-transform: none;
    letter-spacing: 0;
    cursor: pointer;
    white-space: nowrap;
  }
  .search-launcher__bar .search-launcher__submit:hover {
    background: var(--brand-hover);
    color: var(--brand-text);
  }

  /* === Suite workspace (per-suite grid page; docs/04 §3.2、docs/05 §1） ===
     四区 grid（grid-template-areas）：
       header header header   ← _WorkspaceHeader（面包屑 + Run / Copy / Clear）
       ops    input  output   ← _WorkspaceOps · workbench · 输出区
     窄屏 (<60rem) 折叠为单列垂直堆叠。 */
  .workspace {
    display: grid;
    grid-template-columns: 12rem minmax(0, 1fr) minmax(0, 1fr);
    grid-template-rows: auto 1fr;
    grid-template-areas:
      "header header header"
      "ops    input  output";
    gap: 1.25rem;
    min-block-size: calc(100vh - var(--navbar-h) - 4rem);
  }

  /* 宽输出模式（docs/04b §3 / §13）：当 op 的 Renderer 是 Dashboard / CandidateList
     时（text-count / magic 等），把 grid 改成 2 列——input 与 output 共享右侧并
     垂直堆叠，让仪表盘卡片 / 候选列表横向铺开（重要：6 个数字卡 / 多候选行长在窄
     右列里硬挤会丑）。MultiCard 不进这条——random-generator 已 bespoke 不用 workspace。 */
  .workspace:has(:is(.dashboard, .candidate-list)) {
    grid-template-columns: 12rem minmax(0, 1fr);
    grid-template-rows: auto auto 1fr;
    grid-template-areas:
      "header header"
      "ops    input"
      "ops    output";
  }

  /* Workspace header banner：面包屑（App ▸ Op）+ 操作按钮组（Run / Copy / Clear）。
     视觉上轻——透明背景融入页面，仅靠字号 / 颜色对比定位重心。
     高度只占自身内容（grid-template-rows: auto），不抢 input/output 主区空间。 */
  .workspace__header {
    grid-area: header;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding-block: 0.25rem;
    min-block-size: 2.5rem;
  }
  .workspace__breadcrumb {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.9375rem;
    min-inline-size: 0;
  }
  .workspace__app-name { color: var(--fg-muted); }
  .workspace__bc-sep { color: var(--fg-muted); font-size: 0.75rem; }
  .workspace__op-name { color: var(--fg); font-weight: 500; }

  /* Action 按钮组——三个等大 36×36 icon button；primary（Run）实色填充，其余 ghost 边框。
     base 层 button[type="submit"] 规则用 :not(.workspace__action) 排除了 Run，所以这里
     不需要再 reset padding / text-transform 等。 */
  .workspace__actions { display: flex; gap: 0.375rem; }
  .workspace__action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 2.25rem;
    block-size: 2.25rem;
    padding: 0;
    background: transparent;
    color: var(--fg-muted);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: pointer;
    transition: background 100ms ease, color 100ms ease, border-color 100ms ease;
  }
  .workspace__action:hover { background: var(--surface-hover); color: var(--fg); }
  .workspace__action--primary {
    background: var(--brand);
    border-color: var(--brand);
    color: var(--brand-text);
  }
  .workspace__action--primary:hover {
    background: var(--brand-hover);
    border-color: var(--brand-hover);
    color: var(--brand-text);
  }
  .workspace__action svg { inline-size: 1.125rem; block-size: 1.125rem; }

  /* Cascade 侧栏（docs/05 §3.1）：左栏只列组名按钮；hover/click 把当前组 op 列表
     绝对定位 cascade 飞到 inline-end 端。Alpine 状态 openGroup 由 _WorkspaceOps.cshtml
     内的 aside 自管，外层 suiteWorkspace 仍持有 op/selectOp。 */
  .workspace__ops {
    grid-area: ops;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0.375rem 0.25rem;
    align-self: start;
  }
  .workspace__ops-group {
    position: relative;
  }
  .workspace__ops-group + .workspace__ops-group {
    margin-block-start: 0.125rem;
  }
  .workspace__ops-group-trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    inline-size: 100%;
    padding-inline: 0.625rem;
    padding-block: 0.5rem;
    background: transparent;
    border: 0;
    border-radius: var(--radius);
    color: var(--fg);
    font: inherit;
    font-size: 0.875rem;
    text-align: start;
    cursor: pointer;
  }
  .workspace__ops-group-trigger:hover,
  .workspace__ops-group.is-open > .workspace__ops-group-trigger {
    background: var(--surface-hover);
  }
  /* 当前选中 op 所在的组：label 上色锚定位置 */
  .workspace__ops-group.is-current > .workspace__ops-group-trigger > .workspace__ops-group-label {
    color: var(--brand);
    font-weight: 500;
  }
  .workspace__ops-group-label { flex: 1 1 auto; min-inline-size: 0; }
  .workspace__ops-group-chevron {
    font-size: 0.75rem;
    color: var(--fg-muted);
    flex: 0 0 auto;
    margin-inline-start: 0.375rem;
  }
  [dir="rtl"] .workspace__ops-group-chevron { transform: scaleX(-1); }

  /* cascade 面板飞出：inset-inline-start: 100% 紧贴侧栏外缘，间距 0.25rem 由 ::before
     做透明 hover 桥；与 .menu__submenu 同款风格但层级独立。 */
  .workspace__ops-cascade {
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: calc(100% + 0.25rem);
    min-inline-size: 14rem;
    max-inline-size: 22rem;
    margin: 0;
    padding: 0.25rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
    list-style: none;
    z-index: 10;
  }
  /* hover 桥——把侧栏与 cascade 间的 0.25rem 空隙也算作 hover 区，
     避免鼠标穿越时触发 mouseleave debounce 不必要的关闭。 */
  .workspace__ops-cascade::before {
    content: "";
    position: absolute;
    inset-block: 0;
    inline-size: 0.375rem;
    inset-inline-start: -0.375rem;
  }
  .workspace__ops-cascade > li { margin: 0; }
  .workspace__op {
    display: block;
    padding-inline: 0.75rem;
    padding-block: 0.4rem;
    color: var(--fg);
    font-size: 0.875rem;
    text-decoration: none;
    border-radius: var(--radius);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .workspace__op:hover { background: var(--surface-hover); color: var(--fg); text-decoration: none; }
  .workspace__op.is-active { background: var(--surface-hover); color: var(--brand); font-weight: 500; }

  /* form 包裹 input 卡片，本身不带视觉边框（边框在 .workspace__input-card 上）。 */
  .workspace__main {
    grid-area: input;
    display: flex;
    flex-direction: column;
    min-inline-size: 0;
  }

  /* Workbench card——params + input 合体的单一带边卡片。
     params 段薄背景区分；与 textarea 间有 1px 分隔线，但仅当 textarea 真存在时
     （:not(:only-child)），用于 random-generator 这种无 textarea 的变体自然消失。 */
  .workspace__input-card {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-block-size: 16rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
  }
  .workspace__input-card:focus-within {
    border-color: var(--brand);
  }

  .workspace__params {
    padding: 0.75rem 1rem;
    background: light-dark(rgba(0, 0, 0, 0.025), rgba(255, 255, 255, 0.03));
    min-block-size: 2.5rem;
  }
  .workspace__params:not(:only-child) {
    border-block-end: 1px solid var(--border);
  }
  .workspace__params-row { display: flex; gap: 1rem; align-items: center; flex-wrap: wrap; }
  .workspace__params-row--empty { color: var(--fg-muted); font-size: 0.875rem; }
  .workspace__param { display: inline-flex; flex-direction: column; gap: 0.25rem; font-size: 0.875rem; }
  .workspace__param > span { color: var(--fg-muted); }
  .workspace__param--inline { flex-direction: row; align-items: center; gap: 0.375rem; }
  .workspace__param select { inline-size: auto; min-inline-size: 12rem; }
  .workspace__param input[type="checkbox"] { inline-size: auto; }

  /* input 卡内 textarea：无独立边框（卡边即边）、无圆角、占满剩余高度。 */
  .workspace__input {
    flex: 1 1 auto;
    min-block-size: 12rem;
    padding: 0.875rem 1rem;
    background: transparent;
    border: 0;
    border-radius: 0;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.875rem;
    resize: none;
  }
  .workspace__input:focus { outline: 0; }

  /* Output 视觉降权——背景透明融入页面、边框仍存以勾勒边界，让 input 卡视觉上是
     用户主动操作的对象、output 是被动派生的结果。落结果时短暂 .is-pulsing 高亮。 */
  .workspace__output-pane {
    grid-area: output;
    background: transparent;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0.75rem 1rem;
    display: flex;
    flex-direction: column;
    min-inline-size: 0;
    min-block-size: 18rem;
    position: relative;
    overflow: hidden;
  }

  /* 落结果脉冲：顶边 brand-color 一闪 + 文本淡入。
     ::before 做绝对定位顶边 bar；动画完成后透明，等下次触发。 */
  .workspace__output-pane::before {
    content: "";
    position: absolute;
    inset-block-start: 0;
    inset-inline: 0;
    block-size: 2px;
    background: var(--brand);
    transform: scaleX(0);
    transform-origin: center;
    pointer-events: none;
  }
  .workspace__output-pane.is-pulsing::before {
    animation: workspace-result-flash 600ms cubic-bezier(0.4, 0, 0.2, 1);
  }
  .workspace__output-pane.is-pulsing > #output {
    animation: workspace-result-fade 200ms ease-out;
  }
  @keyframes workspace-result-flash {
    0%   { transform: scaleX(0); opacity: 1; }
    30%  { transform: scaleX(1); opacity: 1; }
    100% { transform: scaleX(1); opacity: 0; }
  }
  @keyframes workspace-result-fade {
    from { opacity: 0; }
    to   { opacity: 1; }
  }
  /* 减少动效偏好：尊重 prefers-reduced-motion，关掉脉冲与淡入。 */
  @media (prefers-reduced-motion: reduce) {
    .workspace__output-pane.is-pulsing::before,
    .workspace__output-pane.is-pulsing > #output { animation: none; }
  }
  .workspace__output-pane > #output {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-block-size: 0;
  }
  /* Output 空态：居中 icon + 引导文字，比单行小字更可读、提示更明确。 */
  .workspace__placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    margin: auto;
    padding-block: 1rem;
    color: var(--fg-muted);
    font-size: 0.9375rem;
    text-align: center;
    max-inline-size: 22rem;
  }
  .workspace__placeholder-icon {
    inline-size: 2.5rem;
    block-size: 2.5rem;
    opacity: 0.45;
    stroke-width: 1.25;
  }
  /* RTL：箭头方向（指向 input）需镜像；LTR 默认指左，RTL 指右。 */
  [dir="rtl"] .workspace__placeholder-icon { transform: scaleX(-1); }
  .workspace__placeholder p { margin: 0; }
  .workspace__error { color: light-dark(#b00020, #f88a82); font-size: 0.875rem; }
  /* .workspace__stats 已废除——text-count 升级到 Shell v2 Dashboard renderer
     （.dashboard__*），见 docs/04b §3 与 site.css 末尾。 */
  .workspace__result { display: flex; flex-direction: column; flex: 1 1 auto; min-block-size: 0; }
  .workspace__result-text {
    flex: 1 1 auto;
    margin: 0;
    background: transparent;
    border: none;
    padding: 0;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.875rem;
    overflow: auto;
    min-block-size: 0;
    white-space: pre-wrap;
    word-break: break-word;
  }

  @media (width < 60rem) {
    /* 窄屏：四区垂直堆叠（header / ops / input / output），不再 12rem 侧栏。
       宽输出 `:has()` 在桌面成立但在移动端要被这条覆盖——具体 selector 同上 +
       :has 变体，让 desktop 改的 grid 也回归单列。 */
    .workspace,
    .workspace:has(:is(.dashboard, .candidate-list)) {
      grid-template-columns: 1fr;
      grid-template-rows: none;
      grid-template-areas:
        "header"
        "ops"
        "input"
        "output";
      min-block-size: 0;
      gap: 0.75rem;
    }
    /* 窄屏：cascade 走回行内（static），不再绝对飞出——避免溢出视口。 */
    .workspace__ops-cascade {
      position: static;
      margin-inline-start: 1rem;
      box-shadow: none;
      border: 0;
      background: transparent;
      padding-block: 0.125rem;
    }
    .workspace__ops-cascade::before { content: none; }
    /* 窄屏顶栏黏在 navbar 下，确保 Run / Clear 始终触手可及。 */
    .workspace__header {
      position: sticky;
      inset-block-start: var(--navbar-h, 3rem);
      z-index: 5;
      background: var(--bg);
      padding-block: 0.5rem;
    }
  }

  /* === Form controls (workspace 内的 input/textarea/select) === */
  input, textarea, select {
    inline-size: 100%;
    padding-inline: 0.75rem;
    padding-block: 0.5rem;
    font: inherit;
    color: var(--fg);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
  }
  textarea {
    resize: vertical;
    min-block-size: 6rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.875rem;
  }
  input:focus, textarea:focus, select:focus {
    outline: 2px solid var(--brand);
    outline-offset: 1px;
    border-color: var(--brand);
  }

  /* 通用 submit 按钮——brand 色实色按钮，大写字 + 文字尺寸。:not(.workspace__action)
     排除 workspace header 里的 Run icon 按钮（它另走 .workspace__action 36×36 icon
     button 范式）；否则本规则 element+attr 特异性 (0,1,1) 高过 .workspace__action
     的 (0,1,0)，会把 padding-inline:1.25rem / text-transform:uppercase 灌进 icon
     button，把 36px 方框撑成 76×36 大胖子并把 SVG 淹没。 */
  button[type="submit"]:not(.workspace__action) {
    background: var(--brand);
    color: var(--brand-text);   /* dark-on-lavender in dark mode (eax.org), white-on-indigo in light */
    padding-inline: 1.25rem;
    padding-block: 0.5rem;
    border-radius: var(--radius);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    font-size: 0.875rem;
  }
  button[type="submit"]:not(.workspace__action):hover { background: var(--brand-hover); }

  /* Logout 走 POST 表单，渲染成 <button type="submit">，但它在用户下拉里只是一个普通
     菜单项，不该套通用 submit 的 brand 实色 + 大写。拉平成与「我的账号」<a> 完全一致的
     menu__item（透明背、常规字、同 padding）。element+双类 (0,2,1) 与 base 同特异性，
     靠排在 base 之后由源码顺序胜出（同 .auth-card__submit 的覆盖手法）。 */
  button[type="submit"].menu__item {
    background: transparent;
    color: var(--fg);
    font: inherit;
    text-transform: none;
    letter-spacing: 0;
    padding-inline: 1rem;
    padding-block: 0.375rem;
  }
  button[type="submit"].menu__item:hover { background: var(--surface-hover); }

  /* === Output preformatted blocks (tool results) === */
  pre {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1rem;
    overflow-x: auto;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.875rem;
  }

  /* Alpine `x-cloak`：避免初渲染时 x-show 元素闪现。 */
  [x-cloak] { display: none !important; }

  /* === Shell v2 input: Bytes（DataShape.Bytes，docs/04b §6） ===
     Tab 切 4 模式（Text/Hex/Base64/File）+ textarea 或文件 picker。 */
  .input-bytes {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    flex: 1 1 auto;
    min-block-size: 0;
  }
  .input-bytes__tabs {
    display: flex;
    gap: 0.25rem;
    flex-wrap: wrap;
  }
  .input-bytes__tab {
    padding-inline: 0.75rem;
    padding-block: 0.375rem;
    font-size: 0.8125rem;
    color: var(--fg-muted);
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 9999px;
    cursor: pointer;
  }
  .input-bytes__tab:hover { color: var(--fg); border-color: var(--brand); }
  .input-bytes__tab.is-active {
    color: var(--brand-text);
    background: var(--brand);
    border-color: var(--brand);
  }
  .input-bytes__textarea {
    flex: 1 1 auto;
    min-block-size: 6rem;
  }
  .input-bytes__file-zone {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 1 1 auto;
    min-block-size: 6rem;
    padding: 1rem;
    color: var(--fg-muted);
    background: var(--surface);
    border: 2px dashed var(--border);
    border-radius: var(--radius);
    cursor: pointer;
    text-align: center;
  }
  .input-bytes__file-zone:hover { border-color: var(--brand); }
  .input-bytes__file-zone input[type="file"] {
    /* 让整个 label 可点；视觉只显示提示文字。 */
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    opacity: 0;
    overflow: hidden;
  }

  /* === Shell v2 §8 命令面板（Ctrl/Cmd+K，docs/04b §8） ===
     固定全屏 modal：半透明 backdrop + 居中 panel + 搜索框 + 结果列表。
     结果列表超过视口高度时内部滚动。 */
  .command-palette {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding-block-start: 10vh;
  }
  .command-palette__backdrop {
    position: absolute;
    inset: 0;
    background: light-dark(rgb(0 0 0 / 0.30), rgb(0 0 0 / 0.55));
  }
  .command-palette__panel {
    position: relative;
    inline-size: min(40rem, 92vw);
    max-block-size: 70vh;
    display: flex;
    flex-direction: column;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 20px 50px rgb(0 0 0 / 0.25);
    overflow: hidden;
  }
  .command-palette__input {
    inline-size: 100%;
    padding: 0.875rem 1rem;
    font-size: 1rem;
    color: var(--fg);
    background: transparent;
    border: none;
    border-block-end: 1px solid var(--border);
    outline: none;
  }
  .command-palette__results {
    margin: 0;
    padding: 0.25rem 0;
    list-style: none;
    overflow-y: auto;
    flex: 1 1 auto;
    min-block-size: 0;
  }
  .command-palette__item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 1rem;
    cursor: pointer;
    color: var(--fg);
  }
  .command-palette__item.is-active {
    background: light-dark(rgb(63 81 181 / 0.10), rgb(159 168 218 / 0.16));
    color: var(--brand);
  }
  .command-palette__label {
    flex: 1 1 auto;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.875rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .command-palette__group {
    flex: 0 0 auto;
    color: var(--fg-muted);
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
  }
  .command-palette__empty {
    margin: 0;
    padding: 0.875rem 1rem;
    color: var(--fg-muted);
    font-size: 0.875rem;
    font-style: italic;
  }

  /* === Shell v2 renderer: CandidateList（OutputRenderer.CandidateList，docs/04b §3） ===
     magic 自动解码 / cipher-id 等的输出：N 个候选按 score 降序排列；每候选 = scheme +
     score 百分比 + 解码预览（等宽 pre）+ 可选 note。 */
  .candidate-list {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }
  .candidate-list-empty { color: var(--fg-muted); font-style: italic; margin: 0; }
  .candidate {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0.625rem 0.75rem;
  }
  .candidate__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-block-end: 0.375rem;
  }
  .candidate__scheme {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--fg);
  }
  .candidate__score {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.75rem;
    color: var(--fg-muted);
    padding-inline: 0.5rem;
    padding-block: 0.125rem;
    border: 1px solid var(--border);
    border-radius: 9999px;
  }
  .candidate__preview {
    margin: 0;
    padding: 0.5rem 0.625rem;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.8125rem;
    overflow-x: auto;
    white-space: pre-wrap;
    word-break: break-all;
    max-block-size: 8rem;
  }
  .candidate__note {
    margin: 0.375rem 0 0;
    font-size: 0.75rem;
    color: var(--fg-muted);
  }

  /* === Shell v2 renderer: MultiCard（OutputRenderer.MultiCard，docs/04b §3 / §13） ===
     random-generator 每次 POST 单卡，hx-swap=afterbegin 塞进 #card-list 顶端形成
     历史栈。每卡含标题 + 可选 note + 等宽 value + Copy / Remove。 */
  .multi-card-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }
  .multi-card-empty {
    margin: 1rem 0 0;
    color: var(--fg-muted);
    font-style: italic;
  }
  /* card-list 非空时隐藏 empty 提示。:has() 是 baseline-widely-available（2024）。 */
  #output:has(.multi-card-list > .multi-card) .multi-card-empty { display: none; }

  .multi-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
  }
  .multi-card__header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    border-block-end: 1px solid var(--border);
  }
  .multi-card__title {
    margin: 0;
    font-size: 0.8125rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--fg-muted);
  }
  .multi-card__note {
    font-size: 0.75rem;
    color: var(--fg-muted);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  }
  .multi-card__actions {
    margin-inline-start: auto;
    display: flex;
    gap: 0.25rem;
  }
  .multi-card__action {
    padding-inline: 0.5rem;
    padding-block: 0.125rem;
    font-size: 0.75rem;
    color: var(--fg-muted);
    background: transparent;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: pointer;
    min-inline-size: 2.25rem;
  }
  .multi-card__action:hover { color: var(--fg); border-color: var(--brand); }
  .multi-card__action[aria-pressed="true"] { color: var(--brand); border-color: var(--brand); }
  .multi-card__value {
    margin: 0;
    padding: 0.75rem;
    background: transparent;
    border: none;
    border-radius: 0;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.8125rem;
    overflow-x: auto;
    white-space: pre-wrap;
    word-break: break-all;
  }

  /* === Shell v2 renderer: Structured（OutputRenderer.Structured，docs/04b §3） ===
     字段卡片列表，每字段 label + 等宽 value + Copy 按钮。AES envelope / RSA keypair
     等多字段输出走它。 */
  .structured {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin: 0;
  }
  .structured__field {
    padding: 0.625rem 0.75rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
  }
  .structured__label {
    margin: 0 0 0.25rem;
    font-size: 0.75rem;
    color: var(--fg-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
  }
  .structured__value-row {
    margin: 0;
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
  }
  .structured__value {
    flex: 1 1 auto;
    overflow-x: auto;
    overflow-y: hidden;
    word-break: break-all;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.8125rem;
    line-height: 1.4;
    color: var(--fg);
  }
  .structured__copy {
    flex: 0 0 auto;
    padding-inline: 0.5rem;
    padding-block: 0.125rem;
    font-size: 0.75rem;
    color: var(--fg-muted);
    background: transparent;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: pointer;
    min-inline-size: 3rem;
    text-align: center;
  }
  .structured__copy:hover { color: var(--fg); border-color: var(--brand); }
  .structured__copy[aria-pressed="true"] { color: var(--brand); border-color: var(--brand); }

  /* === Shell v2 renderer: HashHex（OutputRenderer.HashHex，docs/04b §3） ===
     等宽 hex + 字节长度 badge + Base64 切显按钮。 */
  .hashhex {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-block-size: 0;
    gap: 0.5rem;
  }
  .hashhex__meta {
    display: flex;
    align-items: center;
    gap: 0.5rem;
  }
  .hashhex__badge {
    padding-inline: 0.5rem;
    padding-block: 0.125rem;
    border-radius: 9999px;
    background: var(--brand);
    color: var(--brand-text);
    font-size: 0.75rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  }
  .hashhex__toggle {
    padding-inline: 0.5rem;
    padding-block: 0.125rem;
    font-size: 0.75rem;
    color: var(--fg-muted);
    background: transparent;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: pointer;
  }
  .hashhex__toggle:hover { color: var(--fg); border-color: var(--brand); }
  .hashhex__value {
    flex: 1 1 auto;
    margin: 0;
    overflow: auto;
    word-break: break-all;
    white-space: pre-wrap;
  }

  /* === Shell v2 renderer: Dashboard（OutputRenderer.Dashboard，docs/04b §3） ===
     适用 inspect 类 op（text-count / entropy / freq-analysis 等）：grid 数字卡，
     每卡大字号 Value + 小字号 Label。auto-fit 让宽屏 4-6 卡一行、窄屏单列。 */
  .dashboard {
    display: grid;
    gap: 0.75rem;
    grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  }
  .dashboard__stat {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    padding: 0.875rem 1rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
  }
  .dashboard__stat-value {
    font-size: 1.75rem;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    line-height: 1.1;
    color: var(--fg);
  }
  .dashboard__stat-label {
    font-size: 0.8125rem;
    color: var(--fg-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-block-start: 0.25rem;
  }
  .dashboard__stat-detail {
    font-size: 0.75rem;
    color: var(--fg-muted);
    margin-block-start: 0.125rem;
  }

  /* === bespoke App: random-generator（Layout=Bespoke，docs/04b §13） ===
     顶部 header（标题 + Clear）+ 横向 op tabs + 参数面板 + 全宽 #card-list。
     不套 workspace 三栏——切 op 模型与「同屏并存多卡」用例不匹配，bespoke 后
     用户可以同时盯着多张 UUID / Password / Lorem 卡而不互相覆盖。 */
  .rand-gen {
    max-inline-size: 80rem;
    margin-inline: auto;
    padding-inline: 1rem;
    padding-block: 1.5rem;
    display: flex;
    flex-direction: column;
    gap: 1rem;
  }
  .rand-gen__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
  }
  .rand-gen__heading { flex: 1 1 auto; min-inline-size: 0; }
  .rand-gen__title {
    margin: 0 0 0.25rem;
    font-size: 1.5rem;
    font-weight: 500;
  }
  .rand-gen__subtitle {
    margin: 0;
    color: var(--fg-muted);
    font-size: 0.9375rem;
  }
  .rand-gen__clear {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding-inline: 0.75rem;
    padding-block: 0.375rem;
    font-size: 0.8125rem;
    color: var(--fg-muted);
    background: transparent;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: pointer;
  }
  .rand-gen__clear:hover { color: var(--fg); border-color: var(--brand); }
  .rand-gen__clear svg { inline-size: 1rem; block-size: 1rem; }
  /* grouped 下拉 op 选择器：替代横向 tab，扩展到 30+ op 不挤。
     trigger 按钮 + 弹层 panel，按 GroupKey 分段列出全部 op。 */
  .rand-gen__op-picker { position: relative; align-self: flex-start; }
  .rand-gen__op-picker-trigger {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding-inline: 0.875rem;
    padding-block: 0.5rem;
    background: var(--surface);
    color: var(--fg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: pointer;
    font-size: 0.9375rem;
    min-inline-size: 14rem;
  }
  .rand-gen__op-picker-trigger:hover { border-color: var(--brand); }
  .rand-gen__op-picker-label {
    font-size: 0.75rem;
    color: var(--fg-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
  }
  .rand-gen__op-picker-current { font-weight: 500; flex: 1 1 auto; }
  .rand-gen__op-picker-chevron {
    inline-size: 1rem;
    block-size: 1rem;
    color: var(--fg-muted);
    transition: transform 150ms;
  }
  .rand-gen__op-picker-chevron.is-flipped { transform: rotate(180deg); }
  .rand-gen__op-picker-panel {
    position: absolute;
    inset-block-start: calc(100% + 0.25rem);
    inset-inline-start: 0;
    z-index: 10;
    min-inline-size: 16rem;
    max-block-size: 24rem;
    overflow-y: auto;
    padding-block: 0.375rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
  }
  .rand-gen__op-picker-group + .rand-gen__op-picker-group {
    margin-block-start: 0.25rem;
    border-block-start: 1px solid var(--border);
    padding-block-start: 0.25rem;
  }
  .rand-gen__op-picker-group-title {
    margin: 0;
    padding: 0.375rem 0.875rem 0.125rem;
    font-size: 0.6875rem;
    font-weight: 600;
    color: var(--fg-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
  }
  .rand-gen__op-picker-list {
    margin: 0;
    padding: 0;
    list-style: none;
  }
  .rand-gen__op-picker-item {
    display: block;
    padding-inline: 0.875rem;
    padding-block: 0.5rem;
    color: var(--fg);
    text-decoration: none;
    font-size: 0.875rem;
    cursor: pointer;
  }
  .rand-gen__op-picker-item:hover { background: light-dark(rgb(63 81 181 / 0.08), rgb(159 168 218 / 0.14)); }
  .rand-gen__op-picker-item.is-active {
    background: light-dark(rgb(63 81 181 / 0.10), rgb(159 168 218 / 0.18));
    color: var(--brand);
    font-weight: 500;
  }
  .rand-gen__form {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding: 0.875rem 1rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
  }
  .rand-gen__params { display: flex; flex-direction: column; gap: 0.5rem; }
  .rand-gen__generate {
    align-self: flex-start;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding-inline: 1.25rem;
    padding-block: 0.5rem;
    background: var(--brand);
    color: var(--brand-text);
    border: 1px solid var(--brand);
    border-radius: var(--radius);
    font-weight: 500;
    cursor: pointer;
  }
  .rand-gen__generate:hover { background: var(--brand-hover); }
  .rand-gen__generate svg { inline-size: 1rem; block-size: 1rem; }
  .rand-gen__output { min-block-size: 6rem; }

  /* === bespoke App: jwt（首个不套 workspace 模板的 App，docs/05a + 注册表 §7.1） ===
     顶部 token 输入框 + 下方三段卡片（header / payload / signature）+ 安全告警。
     此处样式只服务 jwt——若以后第二个 App 用同样的「输入 + 多卡片输出」形态，再抽
     通用类。 */
  .jwt-app {
    max-inline-size: 80rem;
    margin-inline: auto;
    padding-inline: 1rem;
    padding-block: 1.5rem;
  }
  .jwt-app__header { margin-block-end: 1.5rem; }
  .jwt-app__title {
    margin: 0 0 0.25rem;
    font-size: 1.5rem;
    font-weight: 500;
  }
  .jwt-app__description {
    margin: 0;
    color: var(--fg-muted);
    font-size: 0.9375rem;
  }
  .jwt-app__form { margin-block-end: 1.5rem; }
  .jwt-app__label {
    display: block;
    margin-block-end: 0.5rem;
    font-size: 0.875rem;
    color: var(--fg-muted);
  }
  .jwt-app__token {
    inline-size: 100%;
    block-size: 8rem;
    resize: vertical;
    padding: 0.75rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--fg);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.875rem;
    word-break: break-all;
  }
  .jwt-app__empty {
    margin: 0;
    color: var(--fg-muted);
    font-style: italic;
  }
  .jwt-app__error {
    margin: 0;
    padding: 0.75rem 1rem;
    border-radius: var(--radius);
    color: light-dark(#b00020, #cf6679);
    border: 1px solid currentColor;
    background: light-dark(rgb(176 0 32 / 0.06), rgb(207 102 121 / 0.08));
  }
  .jwt-app__warnings {
    margin-block-end: 1rem;
    padding: 0.75rem 1rem;
    border-radius: var(--radius);
    background: light-dark(#fff8e1, #3a3000);
    border-inline-start: 4px solid light-dark(#f9a825, #ffc107);
  }
  .jwt-app__warnings-title {
    margin: 0 0 0.5rem;
    font-size: 0.875rem;
    font-weight: 600;
  }
  .jwt-app__warnings-list {
    margin: 0;
    padding-inline-start: 1.25rem;
    font-size: 0.875rem;
  }
  .jwt-app__cards {
    display: grid;
    gap: 1rem;
    grid-template-columns: 1fr;
  }
  @media (width >= 60rem) {
    .jwt-app__cards { grid-template-columns: 1fr 1.5fr 1fr; }
  }
  .jwt-card {
    display: flex;
    flex-direction: column;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
  }
  .jwt-card__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.5rem 0.75rem;
    border-block-end: 1px solid var(--border);
  }
  .jwt-card__title {
    margin: 0;
    font-size: 0.8125rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--fg-muted);
  }
  .jwt-card__badge {
    padding: 0.125rem 0.5rem;
    border-radius: 9999px;
    background: var(--brand);
    color: var(--brand-text);
    font-size: 0.75rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  }
  .jwt-card__body {
    margin: 0;
    padding: 0.75rem;
    flex: 1;
    background: transparent;
    border: none;
    border-radius: 0;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.8125rem;
    overflow-x: auto;
    white-space: pre-wrap;
    word-break: break-all;
  }
  .jwt-card__body--mono { color: var(--fg-muted); }
  .jwt-card__body--muted {
    color: var(--fg-muted);
    font-style: italic;
    font-family: inherit;
    white-space: normal;
  }
  .jwt-card__claims {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.25rem 0.75rem;
    padding: 0.5rem 0.75rem 0.75rem;
    font-size: 0.8125rem;
    border-block-start: 1px solid var(--border);
  }
  .jwt-card__claims dt {
    color: var(--fg-muted);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  }
  .jwt-card__claims dd {
    margin: 0;
    word-break: break-all;
  }

  /* === Auth card — Login / Register / ForgotPassword (Pages/Account/) ===
     居中的 28rem 卡片：顶部 Login/Register tab + 表单字段 + 底部辅助链接。
     与 navbar 共享 --brand / --surface / --border tokens；black/dark 模式自动跟随。
     Tab 切换走 HTMX GET 换 #content；表单 POST 是普通整页提交。 */
  .auth-card {
    max-inline-size: 28rem;
    margin-inline: auto;
    margin-block-start: 2rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
  }
  .auth-card__tabs {
    display: flex;
    border-block-end: 1px solid var(--border);
  }
  .auth-card__tab {
    flex: 1 1 0;
    padding-block: 0.875rem;
    text-align: center;
    color: var(--fg-muted);
    font-weight: 500;
    background: light-dark(rgb(0 0 0 / 0.02), rgb(255 255 255 / 0.03));
    border: 0;
    border-block-end: 2px solid transparent;
    cursor: pointer;
  }
  .auth-card__tab:hover { color: var(--fg); text-decoration: none; background: var(--surface-hover); }
  .auth-card__tab.is-active {
    color: var(--brand);
    background: var(--surface);
    border-block-end-color: var(--brand);
    cursor: default;
  }
  .auth-card__tab.is-active:hover { background: var(--surface); }
  .auth-card__heading {
    margin: 0;
    padding: 1.25rem 1.5rem 0;
    font-size: 1.25rem;
    font-weight: 500;
  }
  .auth-card__form {
    display: flex;
    flex-direction: column;
    gap: 0.875rem;
    padding: 1.5rem;
  }
  .auth-card__field { display: flex; flex-direction: column; gap: 0.375rem; }
  .auth-card__label {
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--fg-muted);
  }
  .auth-card__check {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.875rem;
    color: var(--fg);
  }
  .auth-card__check input[type="checkbox"] { inline-size: auto; margin: 0; }
  /* submit 按钮全宽——比通用 brand 按钮拍扁、靠 padding 撑高，整页比例更稳。
     不走 button[type="submit"] 通用样式（uppercase + tracking），登录场景更适合
     mixed-case 自然字。:not(.workspace__action) 选择器在 base 层已让出特异性，但
     auth-card 内嵌套也能覆盖——靠类名 + 元素双选择器。 */
  button[type="submit"].auth-card__submit {
    background: var(--brand);
    color: var(--brand-text);
    padding-block: 0.625rem;
    padding-inline: 1rem;
    border: 0;
    border-radius: var(--radius);
    font-weight: 500;
    font-size: 0.9375rem;
    text-transform: none;
    letter-spacing: 0;
    cursor: pointer;
  }
  button[type="submit"].auth-card__submit:hover { background: var(--brand-hover); }
  .auth-card__errors {
    margin: 0;
    padding: 0.625rem 0.875rem;
    list-style: none;
    border-radius: var(--radius);
    background: light-dark(rgb(176 0 32 / 0.06), rgb(207 102 121 / 0.08));
    border: 1px solid light-dark(rgb(176 0 32 / 0.35), rgb(207 102 121 / 0.35));
    color: light-dark(#b00020, #f88a82);
    font-size: 0.875rem;
  }
  .auth-card__errors li { padding-block: 0.125rem; }
  .auth-card__aux {
    margin: 0;
    padding: 0.5rem 1.5rem;
    font-size: 0.875rem;
    color: var(--fg-muted);
    text-align: center;
  }
  .auth-card__aux:last-child { padding-block-end: 1.25rem; }
  .auth-card__notice {
    margin: 0;
    padding: 0.5rem 1.5rem;
    color: var(--fg);
    font-size: 0.9375rem;
  }
  .auth-card__notice:first-of-type { padding-block-start: 1rem; }
  .auth-card__notice:last-child { padding-block-end: 1.25rem; }
  /* 「检查垃圾箱」类辅助提示——比 notice 更弱（muted + 偏小），收在确认页正文之后。 */
  .auth-card__hint {
    margin: 0;
    padding: 0.25rem 1.5rem 0.5rem;
    font-size: 0.8125rem;
    color: var(--fg-muted);
  }
  /* 邮箱验证徽章——Manage 总览页用，紧贴邮箱地址后。两种语义：ok=已验证、warn=未验证。 */
  .auth-card__badge {
    display: inline-block;
    margin-inline-start: 0.5rem;
    padding: 0.0625rem 0.5rem;
    border-radius: 0.75rem;
    font-size: 0.75rem;
    font-weight: 500;
    border: 1px solid var(--border);
    background: var(--surface-hover);
    color: var(--fg-muted);
  }
  .auth-card__badge--ok { color: var(--brand); border-color: var(--brand); }
  /* 未验证等告警态：复用全站 danger 色（同 .auth-card__action--danger / .manage__nav-link--danger）。 */
  .auth-card__badge--warn { color: light-dark(#b00020, #cf6679); border-color: light-dark(#b00020, #cf6679); }

  /* === full-width 操作行（Manage/Sessions 的撤销按钮）===
     每项是 full-width 可点击的边框行，hover 抬高（背景换浅 surface）。撤销当前 /
     全部会话作为风险操作走 danger 变体。（Manage 总览页原先的入口列表已迁到左侧
     persistent 导航，见 _ManageLayout + .manage__nav。） */
  .auth-card__action {
    display: block;
    padding: 0.75rem 1rem;
    border: 1px solid var(--border);
    border-radius: 0.375rem;
    color: var(--fg);
    background: var(--surface);
    font-size: 0.9375rem;
    text-align: start;
  }
  .auth-card__action:hover {
    background: var(--surface-hover);
    color: var(--fg);
    border-color: var(--brand);
    text-decoration: none;
  }
  /* 注销变体——hover 时边线 + 文本变 destructive 提示色（用 light-dark() 适配主题）。
     不上 destructive bg / fill——避免误点感太强；只 hint 风险。 */
  .auth-card__action--danger {
    margin-block-start: 0.5rem;
    color: light-dark(#b00020, #cf6679);
  }
  .auth-card__action--danger:hover {
    color: light-dark(#b00020, #cf6679);
    border-color: light-dark(#b00020, #cf6679);
  }

  /* === 账户管理区两栏骨架（Pages/Account/Manage/_ManageLayout）===
     左侧 persistent 导航列 + 右侧内容面板。用户反馈：逐项进出总览页切换太繁——
     导航集中到左栏后，改密 / 改邮 / 会话 / 注销可直接横跳，不必回总览。
     视觉沿用 workspace 左栏 op-list 的语言（is-active = 浅 surface 背 + brand 字），
     但自成一套 .manage__* 类（账户区与 App workspace 语义独立）。
     窄屏（width < 40rem）退化为上下堆叠、导航横向 wrap。 */
  .manage {
    display: flex;
    gap: 1.5rem;
    align-items: flex-start;
    max-inline-size: 52rem;
    margin-inline: auto;
  }
  .manage__sidebar {
    flex: 0 0 13rem;
    position: sticky;
    inset-block-start: calc(var(--navbar-h) + 1rem);
  }
  .manage__title {
    margin: 0 0 0.5rem;
    padding-inline: 0.75rem;
    font-size: 0.8125rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--fg-muted);
  }
  .manage__nav {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
  }
  .manage__nav-link {
    display: block;
    padding-inline: 0.75rem;
    padding-block: 0.5rem;
    color: var(--fg);
    font-size: 0.9375rem;
    border-radius: var(--radius);
  }
  .manage__nav-link:hover {
    background: var(--surface-hover);
    color: var(--fg);
    text-decoration: none;
  }
  .manage__nav-link.is-active {
    background: var(--surface-hover);
    color: var(--brand);
    font-weight: 500;
  }
  /* 删除账号——不可逆操作，与上面常规项隔一档：顶部细分隔线 + hover/active 透出
     destructive 提示色（light-dark() 适配主题）。 */
  .manage__nav-link--danger {
    margin-block-start: 0.5rem;
    padding-block-start: 0.625rem;
    border-block-start: 1px solid var(--border);
    border-start-start-radius: 0;
    border-start-end-radius: 0;
  }
  .manage__nav-link--danger:hover,
  .manage__nav-link--danger.is-active {
    color: light-dark(#b00020, #cf6679);
  }
  .manage__body { flex: 1 1 auto; min-inline-size: 0; }
  /* 卡片在内容栏内左对齐、不再视口居中——侧栏已占左侧，卡片紧随其后更自然。 */
  .manage__body .auth-card {
    margin-inline: 0;
    margin-block-start: 0;
  }
  @media (width < 40rem) {
    .manage { flex-direction: column; gap: 1rem; }
    .manage__sidebar {
      flex-basis: auto;
      position: static;
      inline-size: 100%;
    }
    .manage__nav { flex-direction: row; flex-wrap: wrap; }
    /* 横排时分隔线语义失效——退回普通圆角项。 */
    .manage__nav-link--danger {
      margin-block-start: 0;
      padding-block-start: 0.5rem;
      border-block-start: 0;
      border-radius: var(--radius);
    }
  }

  /* === 导航编辑器（Manage/Bookmarks、Manage/SearchEngines 共用）=== */
  /* 独立页壳：标题 + 说明 + 返回首页链接，居中、适中宽度。 */
  .nav-editor-page {
    max-inline-size: 42rem;
    margin-inline: auto;
    padding-inline: 1rem;
    padding-block: 1.5rem 3rem;
    display: flex;
    flex-direction: column;
  }
  .nav-editor-page__back {
    align-self: flex-start;
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    color: var(--fg-muted);
    font-size: 0.875rem;
    margin-block-end: 1rem;
  }
  .nav-editor-page__back:hover { color: var(--fg); text-decoration: none; }
  /* 返回箭头随书写方向镜像——RTL 下「返回首页」应指 inline-start（视觉右）。 */
  [dir="rtl"] .nav-editor-page__back .icon { transform: scaleX(-1); }
  .nav-editor-page__heading { margin: 0 0 0.25rem; font-size: 1.5rem; }
  .nav-editor-page__intro { margin: 0 0 1.5rem; color: var(--fg-muted); font-size: 0.9375rem; line-height: 1.5; }

  /* 形态：每个节点一行（名称 + url + 末端图标动作簇 ✎ 🗑 ↑ ↓）；点 ✎/🗑 的 <details> 就地展开。
     键盘可达、无拖拽；HTMX swap 后凭稳定按钮 id 复焦。全用 logical properties，RTL 自动镜像。 */
  .nav-editor {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }
  .nav-editor__empty {
    color: var(--fg-muted);
    font-style: italic;
    margin: 0;
    padding-inline-start: 0.25rem;
    font-size: 0.875rem;
  }
  /* 干掉所有 <summary> 的默认三角标——图标 / 胶囊自带语义。 */
  .nav-editor summary { list-style: none; cursor: pointer; }
  .nav-editor summary::-webkit-details-marker { display: none; }

  .nav-editor__tree,
  .nav-editor__children {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }
  /* 子层缩进 + inline-start 引导线。 */
  .nav-editor__children {
    margin-inline-start: 1rem;
    margin-block-start: 0.5rem;
    padding-inline-start: 0.75rem;
    border-inline-start: 2px solid var(--border);
  }

  /* 可折叠分类组（子项收纳进 <details>；JS 默认收起 + 按分类记忆，见 eax-shell.js / docs/07 §6）。
     折叠态只见「▸ N items」摘要 + 分类行的增项/动作，驯服默认书签树上百条全展开。 */
  .nav-editor__kids-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    margin-block-start: 0.375rem;
    padding: 0.125rem 0.375rem;
    color: var(--fg-muted);
    font-size: 0.8125rem;
    user-select: none;
    border-radius: var(--radius);
  }
  .nav-editor__kids-toggle:hover { background: var(--surface-hover); color: var(--fg); }
  /* chevron：收起指 inline-end（›），展开转 90° 指下（⌄）。RTL 收起态镜像指 inline-start。 */
  .nav-editor__kids-chevron { transition: transform 0.12s ease; }
  .nav-editor__kids[open] > .nav-editor__kids-toggle .nav-editor__kids-chevron { transform: rotate(90deg); }
  [dir="rtl"] .nav-editor__kids:not([open]) > .nav-editor__kids-toggle .nav-editor__kids-chevron { transform: scaleX(-1); }

  .nav-editor__node { display: flex; flex-direction: column; }
  /* 节点行：flex-wrap 让展开的动作 details（flex-basis:100%）换到整行下方 = 「就地展开」。 */
  .nav-editor__row {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    flex-wrap: wrap;
    padding: 0.375rem 0.5rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
  }
  .nav-editor__name {
    font-weight: 600;
    flex: 0 1 auto;
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* url/模板 = 可伸缩填充物：flex-basis:0 不参与换行计算（否则长 url 会把动作图标挤到下一行），
     吃掉中间剩余空间并把图标簇推到 inline-end，超长截断省略。 */
  .nav-editor__link,
  .nav-editor__url {
    flex: 1 1 0;
    min-inline-size: 0;
    color: var(--fg-muted);
    font-size: 0.8125rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .nav-editor__url { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
  /* 无 url 的分类行没有填充物——用 spacer 把图标簇推到 inline-end。order 默认 0 恒在第一行。 */
  .nav-editor__spacer { flex: 1 1 0; }
  /* move 表单与编辑/删除 details：固定尺寸、不参与收缩，故图标簇永不换行。 */
  .nav-editor__inline { display: inline-flex; flex: 0 0 auto; margin: 0; }

  /* 方形图标按钮——move 的 <button> 与 edit/delete 的 <summary> 共用。 */
  .nav-editor__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    border: 1px solid transparent;
    background: transparent;
    color: var(--fg-muted);
    border-radius: var(--radius);
    inline-size: 1.875rem;
    block-size: 1.875rem;
    font-size: 1rem;
  }
  .nav-editor__icon:hover {
    background: var(--surface-hover);
    color: var(--fg);
    border-color: var(--border);
  }
  /* move 的 ↑↓ 是 <button type="submit">——压住通用 submit 规则的 brand 实色 + 宽 padding
     + 大写（base 选择器特异性 (0,2,1)）。element+attr+class 同特异性、靠源码顺序在后胜出
     （同 .menu__item / .auth-card__submit 的覆盖手法），拉平成与 edit/delete 的 <summary>
     图标完全一致的幽灵图标按钮。 */
  button[type="submit"].nav-editor__icon {
    background: transparent;
    color: var(--fg-muted);
    padding: 0;
    text-transform: none;
    letter-spacing: 0;
    font-size: 1rem;
    font-weight: 400;
  }
  button[type="submit"].nav-editor__icon:hover {
    background: var(--surface-hover);
    color: var(--fg);
    border-color: var(--border);
  }

  /* 编辑 / 删除动作的 details：闭合时只占图标宽（不收缩）；展开时占满整行换到下方。 */
  .nav-editor__act { display: inline-flex; flex: 0 0 auto; }
  .nav-editor__act[open] {
    flex-basis: 100%;
    order: 5;
    flex-direction: column;
  }
  /* 展开后藏掉那个孤零零浮在面板上方的图标 summary——靠面板内的 Cancel 收起
     （edit/delete 面板都有 Cancel）。面板自身的 margin 已提供与行的间距。 */
  .nav-editor__act[open] > summary { display: none; }
  .nav-editor__act--danger > .nav-editor__icon:hover {
    color: light-dark(#b00020, #cf6679);
    border-color: light-dark(#b00020, #cf6679);
  }

  /* 展开后的表单卡（编辑 / 删除确认 / 增项共用）。 */
  .nav-editor__panel {
    display: flex;
    flex-direction: column;
    gap: 0.625rem;
    margin-block-start: 0.5rem;
    padding: 0.875rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    max-inline-size: 30rem;
  }
  .nav-editor__panel-actions { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
  .nav-editor__field { display: flex; flex-direction: column; gap: 0.25rem; }
  .nav-editor__label { font-size: 0.8125rem; color: var(--fg-muted); }
  .nav-editor__input {
    inline-size: 100%;
    padding: 0.4375rem 0.5rem;
    background: var(--bg);
    color: var(--fg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
  }
  .nav-editor__input:focus,
  .nav-editor__input:focus-visible { outline: none; border-color: var(--brand); }
  .nav-editor__hint { font-size: 0.75rem; color: var(--fg-muted); }
  .nav-editor__confirm { margin: 0; font-size: 0.875rem; }

  .nav-editor__btn {
    cursor: pointer;
    padding: 0.4375rem 0.875rem;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--fg);
    font-weight: 600;
    font-size: 0.875rem;
  }
  .nav-editor__btn--primary { background: var(--brand); color: var(--brand-text); border-color: var(--brand); }
  .nav-editor__btn--primary:hover { background: var(--brand-hover); }
  .nav-editor__btn--danger { background: light-dark(#b00020, #cf6679); color: #fff; border-color: transparent; }
  /* 取消——无边框幽灵按钮，弱于主操作。 */
  .nav-editor__btn--ghost { background: transparent; border-color: transparent; color: var(--fg-muted); font-weight: 500; }
  .nav-editor__btn--ghost:hover { background: var(--surface-hover); color: var(--fg); text-decoration: none; }

  /* 分类底部的增项胶囊行（+ 加链接 / + 加子类 / + 加引擎）。 */
  .nav-editor__adds {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-block-start: 0.5rem;
    margin-inline-start: 1rem;
  }
  .nav-editor__adds .nav-editor__add[open] { flex-basis: 100%; }

  .nav-editor__add-summary {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    color: var(--brand);
    font-size: 0.8125rem;
    padding: 0.25rem 0.5rem;
    border-radius: var(--radius);
    user-select: none;
  }
  .nav-editor__add-summary:hover { background: var(--surface-hover); }

  /* 顶层「加分类」「重置」分区——与树拉开、加分隔线。 */
  .nav-editor__footer {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5rem;
    margin-block-start: 1.25rem;
    padding-block-start: 1.25rem;
    border-block-start: 1px solid var(--border);
  }
  /* 顶层「加分类」更显眼——虚线描边的 add 按钮。 */
  .nav-editor__add--primary > .nav-editor__add-summary {
    border: 1px dashed var(--border);
    color: var(--fg);
    padding: 0.5rem 0.875rem;
    font-size: 0.875rem;
    font-weight: 600;
  }
  .nav-editor__add--primary > .nav-editor__add-summary:hover { border-color: var(--brand); color: var(--brand); background: transparent; }
  .nav-editor__reset-summary {
    cursor: pointer;
    display: inline-block;
    color: light-dark(#b00020, #cf6679);
    font-size: 0.8125rem;
    padding: 0.25rem 0.5rem;
    border-radius: var(--radius);
    user-select: none;
  }
  .nav-editor__reset-summary:hover { background: var(--surface-hover); }

  /* === 在线会话列表（Manage/Sessions）=== */
  .session-list {
    list-style: none;
    margin: 0;
    padding: 0.5rem 1.5rem;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
  }
  .session {
    padding: 0.75rem 1rem;
    border: 1px solid var(--border);
    border-radius: 0.375rem;
    background: var(--surface);
  }
  .session__head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    justify-content: space-between;
  }
  .session__device {
    font-weight: 500;
    font-size: 0.875rem;
    overflow-wrap: anywhere;
  }
  .session__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 1rem;
    margin-block-start: 0.375rem;
    font-size: 0.8125rem;
    color: var(--fg-muted);
  }
  .session__action {
    margin-block-start: 0.5rem;
  }
  /* 列表内的撤销按钮不要 auth-card__action 的整块边框样式占满宽——收成内联小按钮。 */
  .session__action .auth-card__action {
    display: inline-block;
    margin-block-start: 0;
    padding: 0.25rem 0.75rem;
    font-size: 0.8125rem;
  }

  /* === PRG flash banner === */
  /* PRG 重定向后顶部一行短状态：成功改密 / 改邮 / 删账户等。无 dismiss 按钮——TempData
     一次性消费，重渲即消失（避免 dismissable notice 视觉噪声，与 cookie 信息条决策一致）。 */
  .flash {
    margin-block-start: 1rem;
    padding: 0.75rem 1rem;
    border: 1px solid var(--brand);
    border-radius: 0.375rem;
    background: var(--surface-hover);
    color: var(--fg);
    font-size: 0.9375rem;
  }

  /* === Legal pages — Privacy / Terms === */
  /* 单栏窄版易读宽度 + 紧凑 h2 节奏；与 .content 共享外宽，自己控制内栏宽。 */
  .legal-page {
    max-inline-size: 48rem;
    margin-inline: auto;
  }
  .legal-page h2 {
    margin-block: 2rem 0.5rem;
    padding-block-end: 0.25rem;
    border-block-end: 1px solid var(--border);
  }
  .legal-page__meta {
    color: var(--fg-muted);
    font-size: 0.875rem;
  }
  .legal-page ul {
    padding-inline-start: 1.5rem;
    list-style: disc;
    margin-block-end: 1rem;
  }
  .legal-page li { margin-block-end: 0.25rem; }

  /* === Error page (Pages/Error.cshtml) === */
  .error-page__code {
    font-size: 2.5rem;
    color: light-dark(#b00020, #cf6679);
  }
  .error-page__message {
    font-size: 1.125rem;
    color: var(--fg-muted);
    margin-block-end: 1rem;
  }
}
