/* 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); }

  /* === Command-palette trigger (visible Search affordance in the navbar) === */
  /* First item of the inline-end cluster: carries margin-inline-start: auto, so it
     and everything after it (theme / language / user) hugs the inline-end edge. */
  .navbar__search {
    margin-inline-start: auto;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.3125rem 0.625rem;
    color: var(--fg-muted);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-size: 0.875rem;
    line-height: 1;
  }
  .navbar__search:hover { background: var(--surface-hover); color: var(--fg); }
  .navbar__search-kbd {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.6875rem;
    padding: 0.1rem 0.3rem;
    color: var(--fg-muted);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 0.25rem;
  }
  @media (max-width: 40rem) {
    .navbar__search-text, .navbar__search-kbd { display: none; }
  }

  /* === Theme toggle (compact icon button, cycles auto → light → dark) === */
  /* Flows after .navbar__search (which carries the margin-inline-start: auto). */
  .theme-toggle {
    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--stacked，由 WorkspaceShellViewModel.StackedOutput 驱动）：
     同上两栏布局，但由 App 显式选用（不靠 output 内容 :has 探测）。给「输入极短、输出多字段」
     的 App（network-suite）——紧凑输入置于右上，多字段输出占满其下整宽，免去中栏大片空白。 */
  .workspace--stacked {
    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 的变体自然消失。
     默认填满列高（成块文本输入的 App 要大输入框）；紧凑模式下收缩见 .workspace--compact-input。 */
  .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; }
  /* TextArea 参数（PEM key 等多行）——等宽、可竖向拉伸、最小高度容下一段 PEM。 */
  .workspace__param-textarea {
    inline-size: 100%;
    min-block-size: 6rem;
    resize: vertical;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.8125rem;
    line-height: 1.4;
  }
  /* 含 TextArea 的参数（如 RSA 的 PEM key）占满整行——否则 inline-flex 的 .workspace__param
     收缩到内容宽度，textarea 只剩 placeholder 那么宽，又小又丑（用户反馈）。 */
  .workspace__param:has(.workspace__param-textarea) { flex: 1 1 100%; }

  /* 方向开关（encode/decode、encrypt/decrypt…）——分段 pill 组，置于 input 卡顶部，
     与 params 段同款薄背景 + 下分隔线。radio 视觉隐藏、label pill 承担视觉与点击；
     选中态 .is-active 上品牌填充。数据驱动渲染见 _WorkspaceShell + docs/04b §6。 */
  .workspace__directions {
    display: flex;
    gap: 0.375rem;
    flex-wrap: wrap;
    padding: 0.625rem 1rem;
    border-block-end: 1px solid var(--border);
    background: light-dark(rgba(0, 0, 0, 0.025), rgba(255, 255, 255, 0.03));
  }
  .workspace__direction {
    display: inline-flex;
    align-items: center;
    padding: 0.3125rem 0.875rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    font-size: 0.8125rem;
    color: var(--fg-muted);
    cursor: pointer;
    user-select: none;
    transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
  }
  .workspace__direction:hover { background: var(--surface-hover); color: var(--fg); }
  .workspace__direction.is-active {
    background: var(--brand);
    border-color: var(--brand);
    color: var(--brand-text);
    font-weight: 500;
  }
  /* radio 仅承担语义与键盘可达——视觉隐藏（保留可聚焦），焦点环画在 label 上。 */
  .workspace__direction-input {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }
  .workspace__direction:has(.workspace__direction-input:focus-visible) {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
  }

  /* input 卡内 textarea：无独立边框（卡边即边）、无圆角。
     默认填满卡片剩余高度、内部滚动——成块文本（cipher-suite / data-converter / text-processor）
     输入本就可能很多，要大输入框，不收缩。 */
  .workspace__input {
    flex: 1 1 auto;
    box-sizing: border-box;
    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; }

  /* 紧凑输入模式（.workspace--compact-input，由 WorkspaceShellViewModel.CompactInput 驱动）：
     给「输入本就很短」的 App（network-suite）和「只有参数、无主输入」的 App（key-forge）。
     卡片收缩到内容高度、不再填满列；textarea 塌成一行、按 scrollHeight 自增长（_WorkspaceShell
     的 x-effect），超 max-block-size 滚动。box-sizing:border-box + border:0 → height==scrollHeight 精确。 */
  .workspace--compact-input .workspace__main { align-self: start; }
  .workspace--compact-input .workspace__input-card { flex: 0 0 auto; min-block-size: 0; }
  .workspace__input--compact {
    flex: 0 0 auto;
    min-block-size: 2.75rem;
    max-block-size: 28rem;
    overflow-y: auto;
  }
  /* 大输入 op（粘 PEM / 响应头 / CIDR 列表）：起始更高，明确是「贴一整块」的区域。
     min-block-size 会顶住 x-effect 写的内联 height（min 优先），故空框也保持此高度、内容更多再长。 */
  .workspace__input--roomy { min-block-size: 11rem; }

  /* 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--stacked .workspace__placeholder-icon { display: none; }

  /* 手动运行 op（dns/whois 等）的提示：按 Enter / Run。实时 op 不显（x-show）。 */
  .workspace__run-hint {
    margin: 0.4rem 0 0;
    font-size: 0.75rem;
    color: var(--fg-muted);
  }

  /* 慢请求加载态：盖在输出之上的「Looking up…」遮罩，避免「先闪一串错误再出数据」的观感。
     form 发请求期间 htmx 给它挂 .htmx-request；相邻兄弟选择器点亮其后 output-pane 的遮罩。
     关键：transition-delay 只在「显示」一侧 0.35s——请求若在 0.35s 内完成则遮罩根本不淡入，
     快的本地计算 op 因此不闪；隐藏无 delay、瞬时撤。 */
  .workspace__loading {
    position: absolute;
    inset: 0;
    z-index: 3;
    display: flex;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--bg) 85%, transparent);
    color: var(--fg-muted);
    font-size: 0.875rem;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.12s ease;
  }
  #workspace-form.htmx-request ~ .workspace__output-pane .workspace__loading {
    opacity: 1;
    transition-delay: 0.35s;
  }
  @media (prefers-reduced-motion: reduce) {
    .workspace__loading { transition: opacity 0.12s ease; transition-delay: 0.35s; }
  }
  /* .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--stacked,
    .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
     等多字段输出走它。 */
  /* 单一带边容器 + 行分隔线（而非一堆独立小盒子，旧版显得「一个个的」不工整，用户反馈）。
     每行两列对齐：label 列定宽、value 列吃剩余宽——label / value 各自纵向对齐成表格感。 */
  .structured {
    display: flex;
    flex-direction: column;
    gap: 0;
    margin: 0;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
  }
  .structured__field {
    display: grid;
    grid-template-columns: minmax(4.5rem, 10rem) minmax(0, 1fr);
    align-items: baseline;
    gap: 0.25rem 1rem;
    padding: 0.4rem 0.75rem;
    border-block-end: 1px solid var(--border);
  }
  .structured__field:last-child { border-block-end: 0; }
  .structured__label {
    margin: 0;
    font-size: 0.75rem;
    color: var(--fg-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    word-break: break-word;
  }
  .structured__value-row {
    margin: 0;
    min-inline-size: 0;          /* 让长 value 能在网格列里收缩/换行而不撑破布局 */
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
  }
  /* 窄屏退化为单列堆叠（label 在上、value 在下），避免两列硬挤。 */
  @media (width < 32rem) {
    .structured__field { grid-template-columns: 1fr; gap: 0.15rem; }
  }
  .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;
  }

  /* === Regex Playground (Pages/Apps/RegexPlayground/) — bespoke 自治区 ===
     pattern + flags + 测试文本 → 高亮 + 捕获组表。复用 navbar/workspace 同套 tokens。 */
  .regex-app { display: flex; flex-direction: column; gap: 1rem; }
  .regex-app__header { display: flex; flex-direction: column; gap: 0.25rem; }
  .regex-app__title { margin: 0; font-size: 1.25rem; }
  .regex-app__description { margin: 0; color: var(--fg-muted); font-size: 0.9375rem; }
  .regex-app__form { display: flex; flex-direction: column; gap: 0.75rem; }
  .regex-app__label { font-size: 0.875rem; color: var(--fg-muted); }
  .regex-app__pattern,
  .regex-app__text {
    inline-size: 100%;
    padding: 0.625rem 0.875rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.875rem;
  }
  .regex-app__pattern:focus,
  .regex-app__text:focus { outline: 0; border-color: var(--brand); }
  .regex-app__text { min-block-size: 9rem; resize: vertical; }
  /* fieldset 自身保持 block（不设 display:flex——否则 legend 在 flex 容器里渲染错乱）；
     legend 单独一行，内层 .regex-app__flags-row 才做 flex。 */
  .regex-app__flags { border: 0; padding: 0; margin: 0; min-inline-size: 0; }
  .regex-app__flags-legend {
    display: block;
    padding: 0;
    margin-block-end: 0.5rem;
    font-size: 0.875rem;
    color: var(--fg-muted);
  }
  .regex-app__flags-row { display: flex; gap: 1.25rem; flex-wrap: wrap; }
  .regex-app__flag {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.875rem;
    cursor: pointer;
    white-space: nowrap;
  }
  /* 全局 `input { inline-size: 100% }`（§表单基样式）会把 checkbox 也撑满 → 复位 auto
     （同 .workspace__param / .auth-card__check 的处理）。 */
  .regex-app__flag input[type="checkbox"] { inline-size: auto; margin: 0; flex: none; }
  .regex-app__flag-key {
    padding: 0.0625rem 0.3125rem;
    background: light-dark(rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.08));
    border-radius: 3px;
    font-size: 0.75rem;
  }
  .regex-app__flag code,
  .regex-app__flag-key,
  .regex-app__group-name code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
  .regex-app__output { display: flex; flex-direction: column; gap: 0.75rem; }
  .regex-app__empty { color: var(--fg-muted); }
  .regex-app__error { color: light-dark(#b3261e, #f2b8b5); }
  .regex-app__count { margin: 0; font-size: 0.875rem; color: var(--fg-muted); }
  .regex-app__highlight {
    margin: 0;
    white-space: pre-wrap;
    word-break: break-word;
    padding: 0.875rem 1rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    max-block-size: 20rem;
    overflow: auto;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.875rem;
  }
  .regex-app__hit {
    background: light-dark(#fff1a8, #5b4a00);
    color: inherit;
    border-radius: 3px;
    padding-block: 1px;
  }
  .regex-app__table { inline-size: 100%; border-collapse: collapse; font-size: 0.875rem; }
  .regex-app__table th,
  .regex-app__table td {
    text-align: start;
    padding: 0.375rem 0.5rem;
    border-block-end: 1px solid var(--border);
    vertical-align: top;
  }
  .regex-app__table th { color: var(--fg-muted); font-weight: 500; }
  .regex-app__idx { color: var(--fg-muted); font-variant-numeric: tabular-nums; }
  .regex-app__match-val { word-break: break-all; }
  .regex-app__group { display: inline-flex; gap: 0.25rem; margin-inline-end: 0.625rem; }
  .regex-app__group-name { color: var(--fg-muted); }
  .regex-app__muted { color: var(--fg-muted); }

  /* === Diff Compare (Pages/Apps/DiffCompare/) — bespoke 自治区 ===
     两份文本 → 行级并排差异。输入两栏 grid；输出每行两侧（删=左红 / 增=右绿 / 等=中性）。 */
  .diff-app { display: flex; flex-direction: column; gap: 1rem; }
  .diff-app__header { display: flex; flex-direction: column; gap: 0.25rem; }
  .diff-app__title { margin: 0; font-size: 1.25rem; }
  .diff-app__description { margin: 0; color: var(--fg-muted); font-size: 0.9375rem; }
  .diff-app__inputs { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
  .diff-app__input-col { display: flex; flex-direction: column; gap: 0.375rem; min-inline-size: 0; }
  .diff-app__label { font-size: 0.875rem; color: var(--fg-muted); }
  .diff-app__input {
    inline-size: 100%;
    min-block-size: 12rem;
    padding: 0.625rem 0.875rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.875rem;
    resize: vertical;
  }
  .diff-app__input:focus { outline: 0; border-color: var(--brand); }
  .diff-app__empty { color: var(--fg-muted); }
  .diff-app__error { color: light-dark(#b3261e, #f2b8b5); }
  .diff-app__summary { margin: 0; display: flex; gap: 1rem; font-size: 0.875rem; align-items: baseline; }
  .diff-app__added { color: light-dark(#1a7f37, #3fb950); font-variant-numeric: tabular-nums; }
  .diff-app__removed { color: light-dark(#cf222e, #f85149); font-variant-numeric: tabular-nums; }
  .diff-app__muted { color: var(--fg-muted); }
  .diff-app__view {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: auto;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.8125rem;
    max-block-size: 32rem;
  }
  .diff-app__row { display: grid; grid-template-columns: 1fr 1fr; }
  .diff-app__cell {
    display: grid;
    grid-template-columns: 2.5rem 1rem 1fr;
    gap: 0.25rem;
    padding: 0.0625rem 0.25rem;
    border-block-end: 1px solid light-dark(rgba(0, 0, 0, 0.04), rgba(255, 255, 255, 0.04));
    min-inline-size: 0;
  }
  .diff-app__cell--left { border-inline-end: 1px solid var(--border); }
  .diff-app__row--delete .diff-app__cell--left { background: light-dark(#ffebe9, #3a1418); }
  .diff-app__row--insert .diff-app__cell--right { background: light-dark(#e6ffec, #12261c); }
  .diff-app__num { color: var(--fg-muted); text-align: end; font-variant-numeric: tabular-nums; user-select: none; }
  .diff-app__sign { text-align: center; user-select: none; color: var(--fg-muted); }
  .diff-app__line { white-space: pre-wrap; word-break: break-word; }

  /* === QR Coder (Pages/Apps/QrCoder/) — bespoke 自治区 ===
     文本 + 纠错等级 → 内联 SVG 二维码。左输入 / 右预览（窄屏堆叠）。 */
  .qr-app { display: flex; flex-direction: column; gap: 1rem; }
  .qr-app__header { display: flex; flex-direction: column; gap: 0.25rem; }
  .qr-app__title { margin: 0; font-size: 1.25rem; }
  .qr-app__description { margin: 0; color: var(--fg-muted); font-size: 0.9375rem; }
  .qr-app__layout { display: grid; grid-template-columns: 1fr minmax(0, 22rem); gap: 1.5rem; align-items: start; }
  .qr-app__form { display: flex; flex-direction: column; gap: 0.375rem; min-inline-size: 0; }
  .qr-app__label { font-size: 0.875rem; color: var(--fg-muted); }
  .qr-app__text,
  .qr-app__ecc {
    inline-size: 100%;
    padding: 0.625rem 0.875rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-size: 0.875rem;
  }
  .qr-app__text {
    min-block-size: 8rem;
    resize: vertical;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  }
  .qr-app__text:focus,
  .qr-app__ecc:focus { outline: 0; border-color: var(--brand); }
  .qr-app__ecc { margin-block-end: 0.5rem; }
  /* generate / decode 模式开关——pill 组（同 workspace 方向开关观感）。 */
  .qr-app__modes {
    display: inline-flex;
    gap: 0.25rem;
    padding: 0.25rem;
    margin-block-end: 0.5rem;
    align-self: start;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
  }
  .qr-app__mode {
    display: inline-flex;
    align-items: center;
    padding: 0.3125rem 0.875rem;
    border-radius: calc(var(--radius) - 2px);
    font-size: 0.875rem;
    color: var(--fg-muted);
    cursor: pointer;
  }
  .qr-app__mode.is-active { background: var(--brand); color: #fff; }
  .qr-app__mode-input { position: absolute; opacity: 0; pointer-events: none; }
  .qr-app__file { font-size: 0.875rem; color: var(--fg); padding-block: 0.375rem; }
  .qr-app__output { display: flex; flex-direction: column; align-items: center; gap: 0.75rem; }
  .qr-app__empty { color: var(--fg-muted); align-self: start; }
  .qr-app__error { color: light-dark(#b3261e, #f2b8b5); align-self: start; }
  /* decode 结果——解码文本块（等宽、可换行、可全选复制）。 */
  .qr-app__decoded { display: flex; flex-direction: column; gap: 0.375rem; inline-size: 100%; }
  .qr-app__decoded-label { font-size: 0.875rem; color: var(--fg-muted); }
  .qr-app__decoded-text {
    margin: 0;
    padding: 0.625rem 0.75rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.875rem;
    white-space: pre-wrap;
    word-break: break-all;
  }
  /* 白底容器——QR 始终黑模块 / 白底，暗色模式下也可扫。
     padding 为 0：SVG 自带 4 模块 quiet zone（QR 规范要求、扫描必需），不再叠加 CSS
     白边，否则白框套白框（用户反馈「周围一大圈空白」）。 */
  .qr-app__code {
    background: #ffffff;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    line-height: 0;
    overflow: hidden;
  }
  /* 放大到 20rem（原 16rem 太小、密一点的码手机扫不动）；窄屏下整列折叠为全宽（见底部
     media query），码可铺到屏宽，扫描更稳。 */
  .qr-app__code svg {
    display: block;
    inline-size: 100%;
    max-inline-size: 20rem;
    block-size: auto;
  }
  /* 下载按钮组：PNG（首选，实色）+ SVG（次要，ghost）。 */
  .qr-app__downloads { display: flex; gap: 0.5rem; flex-wrap: wrap; justify-content: center; }
  .qr-app__download {
    display: inline-flex;
    align-items: center;
    padding: 0.4375rem 0.875rem;
    border: 1px solid var(--brand);
    border-radius: var(--radius);
    font-size: 0.875rem;
    background: var(--brand);
    color: var(--brand-text);
  }
  .qr-app__download:hover { background: var(--brand-hover); border-color: var(--brand-hover); text-decoration: none; }
  .qr-app__download--ghost {
    background: transparent;
    border-color: var(--border);
    color: var(--fg);
  }
  .qr-app__download--ghost:hover { background: var(--surface-hover); border-color: var(--border); }
  @media (max-width: 40rem) {
    .qr-app__layout { grid-template-columns: 1fr; }
  }

  /* === 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; }

  /* 形态：紧凑树（参 PrimeVue Tree）——每节点一行（chevron + 名称 + 计数/url + 末端操作簇 ✎ 🗑 ↑ ↓ ＋）。
     行扁平密排、悬停高亮，操作簇悬停 / 聚焦时浮现（触屏恒显）。折叠用「隐藏 checkbox」纯 CSS：无 JS 默认
     展开、点 chevron 也能折叠，JS（eaxApplyCollapse）接管后默认收起 + 按分类记忆。点 ✎/🗑/＋ 的 <details>
     靠 .row 的 flex-wrap + [open]{flex-basis:100%} 就地展开到整行下方。键盘可达，全 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: 2.125rem;   /* 对齐到 chevron 之后 */
    padding-block: 0.25rem;
    font-size: 0.8125rem;
  }
  /* 干掉所有 <summary> 的默认三角标——图标 / 胶囊自带语义。 */
  .nav-editor summary { list-style: none; cursor: pointer; }
  .nav-editor summary::-webkit-details-marker { display: none; }

  /* === 草稿工具条（保存 / 撤销 / 放弃 + 脏标记），编辑器顶部 ===
     flex-wrap：放弃确认面板（details[open] flex-basis:100%）掉到工具条整行下方。 */
  .nav-editor__toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.375rem 0.5rem;
    padding-block: 0.25rem 0.5rem;
    margin-block-end: 0.25rem;
    border-block-end: 1px solid var(--border);
  }
  .nav-editor__status {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.8125rem;
    color: var(--fg-muted);
  }
  .nav-editor__status--dirty { color: var(--fg); font-weight: 500; }
  .nav-editor__status-dot {
    inline-size: 0.5rem;
    block-size: 0.5rem;
    border-radius: 50%;
    background: light-dark(#b8860b, #e0a83e);   /* amber = 未保存 */
    flex: 0 0 auto;
  }
  .nav-editor__tbtn {
    display: inline-flex;
    align-items: center;
    gap: 0.3125rem;
    cursor: pointer;
    padding: 0.375rem 0.75rem;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--fg);
    font-weight: 600;
    font-size: 0.8125rem;
    user-select: none;
  }
  .nav-editor__tbtn:hover { background: var(--surface-hover); }
  .nav-editor__tbtn--danger { color: light-dark(#b00020, #cf6679); }
  /* Undo / Save 是 <button type=submit>——压住通用 submit 的 brand 实色 + 大写 + 宽 padding
     （base 选择器 (0,2,1)，同 .nav-editor__icon / .menu__item 的源码靠后覆盖手法）。 */
  button[type="submit"].nav-editor__tbtn {
    background: var(--surface);
    color: var(--fg);
    padding: 0.375rem 0.75rem;
    text-transform: none;
    letter-spacing: 0;
    font-size: 0.8125rem;
    font-weight: 600;
  }
  button[type="submit"].nav-editor__tbtn:hover { background: var(--surface-hover); }
  button[type="submit"].nav-editor__tbtn:disabled,
  .nav-editor__tbtn:disabled { opacity: 0.45; cursor: default; }
  button[type="submit"].nav-editor__tbtn:disabled:hover { background: var(--surface); }
  /* 保存：主操作，brand 实色（但用本组 padding / 不大写）。 */
  button[type="submit"].nav-editor__tbtn--primary {
    background: var(--brand);
    color: var(--brand-text);
    border-color: var(--brand);
  }
  button[type="submit"].nav-editor__tbtn--primary:hover { background: var(--brand-hover); }
  button[type="submit"].nav-editor__tbtn--primary:disabled:hover { background: var(--brand); }
  /* 放弃确认 details：闭合占按钮宽；展开占满工具条整行、确认面板掉到下方。 */
  .nav-editor__discard { display: inline-flex; flex: 0 0 auto; }
  .nav-editor__discard[open] { flex-basis: 100%; order: 5; flex-direction: column; }
  .nav-editor__discard[open] > summary { display: none; }

  .nav-editor__tree,
  .nav-editor__children {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0;                            /* 密排：行与行不留缝 */
  }
  /* 子层缩进 + 淡 inline-start 引导线（比旧版细、轻）。 */
  .nav-editor__children {
    margin-inline-start: 0.8125rem;
    padding-inline-start: 1.25rem;
    border-inline-start: 1px solid var(--border);
  }

  .nav-editor__node { display: flex; flex-direction: column; position: relative; }

  /* 折叠开关 checkbox：视觉裁切但保持可聚焦（键盘 Tab + Space 切换）；鼠标点击由 label(chevron) 驱动。
     与 .nav-editor__row / .nav-editor__children 同为 <li> 的兄弟，故 `:checked ~` 纯 CSS 折叠。 */
  .nav-editor__twist-state {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    margin: 0;
    opacity: 0;
    pointer-events: none;
  }
  .nav-editor__twist-state:checked ~ .nav-editor__children { display: none; }

  /* 节点行：flex-wrap 让展开的 details（flex-basis:100%）换到整行下方 = 「就地展开」。扁平密排。 */
  .nav-editor__row {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    flex-wrap: wrap;
    padding: 0.1875rem 0.375rem;
    border-radius: var(--radius);
    min-block-size: 1.875rem;
  }
  /* 悬停 / 聚焦 / 内含展开面板时高亮该行。 */
  .nav-editor__row:hover,
  .nav-editor__row:focus-within,
  .nav-editor__row:has(.nav-editor__act[open], .nav-editor__add--inline[open]) {
    background: var(--surface-hover);
  }

  /* chevron 折叠开关（分类的 label）/ 叶子占位（保持名称对齐）。 */
  .nav-editor__twist {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    inline-size: 1.25rem;
    block-size: 1.25rem;
    color: var(--fg-muted);
    cursor: pointer;
    border-radius: var(--radius);
  }
  .nav-editor__twist:hover { color: var(--fg); }
  .nav-editor__twist--leaf { cursor: default; }
  /* chevron：展开（checkbox 未选）转 90° 指下（⌄）；收起（:checked）回到指 inline-end（›）。RTL 收起态镜像。 */
  .nav-editor__twist-chevron { transition: transform 0.12s ease; transform: rotate(90deg); font-size: 0.875rem; }
  .nav-editor__twist-state:checked ~ .nav-editor__row .nav-editor__twist-chevron { transform: none; }
  [dir="rtl"] .nav-editor__twist-state:checked ~ .nav-editor__row .nav-editor__twist-chevron { transform: scaleX(-1); }
  /* 键盘聚焦裁切的 checkbox 时，把焦点环画到可见的 chevron 上。 */
  .nav-editor__twist-state:focus-visible ~ .nav-editor__row .nav-editor__twist {
    outline: 2px solid var(--brand);
    outline-offset: 1px;
  }

  .nav-editor__name {
    font-weight: 500;
    flex: 0 1 auto;
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* 分类名略重，与链接 / 引擎区分。 */
  .nav-editor__node--branch > .nav-editor__row > .nav-editor__name { font-weight: 600; }

  /* 分类子项计数徽标（小药丸）。 */
  .nav-editor__count {
    flex: 0 0 auto;
    font-size: 0.75rem;
    color: var(--fg-muted);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding-inline: 0.4375rem;
    line-height: 1.5;
  }

  /* 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; }
  /* 分类行 count 之后用 spacer 把操作簇推到 inline-end。 */
  .nav-editor__spacer { flex: 1 1 0; min-inline-size: 0.5rem; }
  /* move 表单与编辑/删除/加项 details：固定尺寸、不参与收缩，故图标簇永不换行。 */
  .nav-editor__inline { display: inline-flex; flex: 0 0 auto; margin: 0; }

  /* 操作簇悬停浮现：有 hover 能力的设备默认藏（仍在 DOM、键盘可聚焦），行 hover / focus-within /
     含展开面板时显；保留布局位（opacity 而非 display，避免浮现时行宽抖动）。触屏（无 hover）恒显。 */
  @media (hover: hover) {
    .nav-editor__row > .nav-editor__act,
    .nav-editor__row > .nav-editor__inline,
    .nav-editor__row > .nav-editor__add--inline {
      opacity: 0;
      pointer-events: none;
      transition: opacity 0.1s ease;
    }
    .nav-editor__row:hover > .nav-editor__act,
    .nav-editor__row:hover > .nav-editor__inline,
    .nav-editor__row:hover > .nav-editor__add--inline,
    .nav-editor__row:focus-within > .nav-editor__act,
    .nav-editor__row:focus-within > .nav-editor__inline,
    .nav-editor__row:focus-within > .nav-editor__add--inline,
    .nav-editor__row:has(.nav-editor__act[open], .nav-editor__add--inline[open]) > .nav-editor__act,
    .nav-editor__row:has(.nav-editor__act[open], .nav-editor__add--inline[open]) > .nav-editor__inline,
    .nav-editor__row:has(.nav-editor__act[open], .nav-editor__add--inline[open]) > .nav-editor__add--inline {
      opacity: 1;
      pointer-events: auto;
    }
  }

  /* 方形图标按钮——move 的 <button> 与 edit/delete/add 的 <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.625rem;
    block-size: 1.625rem;
    font-size: 0.9375rem;
  }
  .nav-editor__icon:hover {
    background: var(--surface);
    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: 0.9375rem;
    font-weight: 400;
  }
  button[type="submit"].nav-editor__icon:hover {
    background: var(--surface);
    color: var(--fg);
    border-color: var(--border);
  }

  /* 编辑 / 删除 / 加项的 details：闭合时只占图标宽（不收缩）；展开时占满整行换到下方。 */
  .nav-editor__act,
  .nav-editor__add--inline { display: inline-flex; flex: 0 0 auto; }
  .nav-editor__act[open],
  .nav-editor__add--inline[open] {
    flex-basis: 100%;
    order: 5;
    flex-direction: column;
  }
  /* 展开后藏掉那个孤零零浮在面板上方的图标 summary——靠面板内的 Cancel 收起（编辑/删除/加项面板都有 Cancel）。 */
  .nav-editor__act[open] > summary,
  .nav-editor__add--inline[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; }

  /* footer 顶层「加分类」摘要胶囊（用 .nav-editor__add--primary 加强为虚线描边）。 */
  .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;
  }

  /* === bespoke App: color-studio（Pages/Apps/ColorStudio/）===
     convert（输入色 → 全格式 + 大色块）+ contrast（前景/背景 → WCAG 比率 + AA/AAA 徽章）。
     色块 / 预览框的填色来自用户输入的颜色数据（内联 style），其余 chrome 全走 tokens。 */
  .color-studio {
    max-inline-size: 60rem;
    margin-inline: auto;
    padding-inline: 1rem;
    padding-block: 1.5rem;
  }
  .color-studio__header { margin-block-end: 1.5rem; }
  .color-studio__title {
    margin: 0 0 0.25rem;
    font-size: 1.5rem;
    font-weight: 500;
  }
  .color-studio__description {
    margin: 0;
    color: var(--fg-muted);
    font-size: 0.9375rem;
  }
  .color-studio__modes {
    display: inline-flex;
    gap: 0.25rem;
    padding: 0.25rem;
    margin-block-end: 1.25rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
  }
  .color-studio__mode {
    display: inline-flex;
    align-items: center;
    padding: 0.375rem 0.875rem;
    border-radius: var(--radius);
    font-size: 0.875rem;
    color: var(--fg-muted);
    cursor: pointer;
    user-select: none;
  }
  .color-studio__mode.is-active {
    background: var(--brand);
    color: var(--brand-text);
  }
  .color-studio__mode:has(:focus-visible) {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
  }
  .color-studio__mode-input {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    opacity: 0;
    pointer-events: none;
  }
  .color-studio__form { margin-block-end: 1.25rem; }
  .color-studio__form--pair {
    display: grid;
    gap: 1rem;
  }
  @media (width >= 36rem) {
    .color-studio__form--pair { grid-template-columns: 1fr 1fr; }
  }
  .color-studio__label {
    display: block;
    margin-block-end: 0.5rem;
    font-size: 0.875rem;
    color: var(--fg-muted);
  }
  .color-studio__input {
    inline-size: 100%;
    padding: 0.625rem 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.9375rem;
  }
  .color-studio__empty {
    margin: 0;
    color: var(--fg-muted);
    font-style: italic;
  }
  .color-studio__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));
  }

  /* convert 结果：大色块 + 各格式行 */
  .color-studio__result {
    display: grid;
    gap: 1.25rem;
    grid-template-columns: 1fr;
  }
  @media (width >= 40rem) {
    .color-studio__result { grid-template-columns: 12rem 1fr; align-items: start; }
  }
  .color-studio__swatch {
    block-size: 8rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
  }
  @media (width >= 40rem) {
    .color-studio__swatch { block-size: 100%; min-block-size: 8rem; }
  }
  .color-rows { margin: 0; display: grid; gap: 0.5rem; }
  .color-row {
    display: grid;
    grid-template-columns: 5.5rem 1fr;
    align-items: center;
    gap: 0.25rem 0.75rem;
  }
  .color-row__label {
    margin: 0;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--fg-muted);
  }
  .color-row__value-row {
    margin: 0;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-inline-size: 0;
  }
  .color-row__value {
    flex: 1;
    min-inline-size: 0;
    overflow-x: auto;
    padding: 0.375rem 0.5rem;
    border-radius: var(--radius);
    background: var(--surface-hover);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.8125rem;
    white-space: nowrap;
  }
  .color-row__copy {
    flex: none;
    padding: 0.25rem 0.5rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--fg-muted);
    font-size: 0.75rem;
    cursor: pointer;
  }
  .color-row__copy:hover { background: var(--surface-hover); color: var(--fg); }

  /* contrast 结果：预览 + 比率 + 四档徽章 */
  .contrast-result { display: grid; gap: 1.25rem; }
  .contrast-preview {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    align-items: center;
    justify-content: center;
    min-block-size: 8rem;
    padding: 1.5rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    text-align: center;
  }
  .contrast-preview__large { font-size: 2rem; font-weight: 600; }
  .contrast-preview__normal { font-size: 1rem; }
  .contrast-score {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.25rem;
  }
  .contrast-score__ratio {
    font-size: 2.5rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
  }
  .contrast-score__suffix { color: var(--fg-muted); font-size: 1.5rem; font-weight: 400; }
  .contrast-score__caption {
    font-size: 0.8125rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--fg-muted);
  }
  .contrast-badges {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    justify-content: center;
  }
  .contrast-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.375rem 0.75rem;
    border-radius: 9999px;
    border: 1px solid currentColor;
    font-size: 0.8125rem;
    font-weight: 600;
  }
  .contrast-badge.is-pass {
    color: light-dark(#2e7d32, #81c784);
    background: light-dark(rgb(46 125 50 / 0.08), rgb(129 199 132 / 0.1));
  }
  .contrast-badge.is-fail {
    color: light-dark(#b00020, #cf6679);
    background: light-dark(rgb(176 0 32 / 0.06), rgb(207 102 121 / 0.08));
  }
  .contrast-badge__mark { font-size: 0.875rem; }
}
