@charset "utf-8";
/* 组件层：按钮 / 输入 / 窗口切换器 / 快捷指令 / 状态栏 / 命令面板 / toast / 弹窗 / 登录页。
 *
 * 动效原则（决定了这里几乎没有动画）：动作越高频，动画越该消失。
 *   发指令、切窗口、翻历史 —— 一天几百次，零动画，只留 120ms 的颜色过渡；
 *   命令面板、抽屉、toast、弹窗 —— 偶尔用一次，给 140~240ms 的入场。
 * 按压反馈是例外：它必须存在，否则界面像没听见。统一 scale(.97)。
 *
 * hover 效果一律关在 @media (hover: hover) and (pointer: fine) 里。
 * 触屏上 hover 会在点击后粘住，看起来像按钮坏了。
 */

/* ============================================================ 按钮 */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: .42em .8em;
  font-size: .88rem;
  font-weight: 500;
  line-height: 1.3;
  color: var(--fg-0);
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  white-space: nowrap;
  /* 只过渡明确列出的属性。transition:all 会把 width/height 一起带上，掉帧 */
  transition: background-color var(--t-press) ease,
              border-color var(--t-press) ease,
              color var(--t-press) ease,
              transform var(--t-press) var(--ease-out);
}

.btn:active:not(:disabled) { transform: scale(.97); }
.btn:disabled { opacity: .45; }

@media (hover: hover) and (pointer: fine) {
  .btn:hover:not(:disabled) {
    background: var(--bg-3);
    border-color: var(--border-strong);
  }
}

.btn-primary {
  color: var(--accent-fg);
  background: var(--accent);
  border-color: var(--accent);
}
@media (hover: hover) and (pointer: fine) {
  .btn-primary:hover:not(:disabled) {
    background: var(--accent-hover);
    border-color: var(--accent-hover);
  }
}

.btn-ghost {
  background: transparent;
  border-color: transparent;
  color: var(--fg-1);
}
@media (hover: hover) and (pointer: fine) {
  .btn-ghost:hover:not(:disabled) {
    background: var(--bg-hover);
    border-color: transparent;
    color: var(--fg-0);
  }
}

.btn-danger { color: var(--err); border-color: var(--border); }
@media (hover: hover) and (pointer: fine) {
  .btn-danger:hover:not(:disabled) {
    background: var(--err-soft);
    border-color: var(--err);
  }
}

.btn-sm { padding: .28em .6em; font-size: .82rem; }
.btn-block { width: 100%; }

/* 图标按钮：正方形，触摸目标不小于 32px（手机上 38px） */
.btn-icon {
  width: 32px;
  height: 32px;
  padding: 0;
  flex: none;
}
.btn-icon svg { width: 16px; height: 16px; }

@media (max-width: 719px) {
  .btn-icon { width: 38px; height: 38px; }
}

/* 顶栏那个"⌘K 打开面板"的入口。做成搜索框的样子，暗示"这里能搜" */
.palette-trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: .3em .5em .3em .6em;
  font-size: .82rem;
  color: var(--fg-1);
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  transition: background-color var(--t-press) ease, border-color var(--t-press) ease;
}
.palette-trigger kbd { margin-left: var(--sp-2); }
@media (hover: hover) and (pointer: fine) {
  .palette-trigger:hover { background: var(--bg-3); border-color: var(--border-strong); }
}

/* ============================================================ 输入 */

.field {
  width: 100%;
  padding: .5em .7em;
  color: var(--fg-0);
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  transition: border-color var(--t-press) ease, box-shadow var(--t-press) ease;
}

.field::placeholder { color: var(--fg-2); }

.field:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-ring);
}

.field-sm { padding: .34em .55em; font-size: .85rem; }
.field-mono { font-family: var(--font-mono); }

/* 弹窗里的多行输入（快捷指令可以一行一条）。只允许纵向拖，横向拖会把弹窗撑破 */
textarea.field {
  resize: vertical;
  min-height: 4.5em;
  line-height: 1.5;
}

.form-row { margin-bottom: var(--sp-4); }
.form-row:last-child { margin-bottom: 0; }

.label {
  display: block;
  margin-bottom: var(--sp-1);
  font-size: .82rem;
  font-weight: 500;
  color: var(--fg-1);
}

.hint {
  margin-top: var(--sp-1);
  font-size: .8rem;
  line-height: 1.5;
  color: var(--fg-2);
}
.hint code {
  padding: 0 .25em;
  font-size: .95em;
  color: var(--fg-1);
  background: var(--bg-3);
  border-radius: 3px;
}

.check {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  font-size: .85rem;
  cursor: pointer;
}
.check input { margin: .18em 0 0; accent-color: var(--accent); flex: none; }

.err-text { color: var(--err); font-size: .85rem; }

/* ============================================================ 窗口切换器
 * 分段控件。六个区共享同一条主机会话（见 PROJECT.md §7.4），
 * 所以这不是"标签页"而是"六张工作台"，视觉上要像一个整体。
 *
 * 高频动作（一天几十次，还有 Alt+1..6 键盘直达）—— 不做滑块位移，
 * 只给 120ms 颜色过渡。位移动画在第 20 次就开始烦人了。 */

.areas {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 2px;
  min-width: 0;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow-x: auto;
  scrollbar-width: none;
}
.areas::-webkit-scrollbar { height: 0; }

.area {
  position: relative;
  display: flex;
  align-items: center;
  gap: 5px;
  padding: .3em .58em;
  flex: none;
  font-family: var(--font-mono);
  font-size: .88rem;
  font-weight: 600;
  color: var(--fg-1);
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  transition: background-color var(--t-press) ease,
              color var(--t-press) ease,
              border-color var(--t-press) ease;
}

@media (hover: hover) and (pointer: fine) {
  .area:not(:disabled):not(.is-active):hover { background: var(--bg-hover); color: var(--fg-0); }
}

.area.is-active {
  color: var(--fg-0);
  background: var(--bg-0);
  border-color: var(--border-strong);
}

.area:disabled {
  opacity: .4;
  border-style: dashed;
  border-color: var(--border);
}

/* 占用状态点：绿=我在用，琥珀=别人在用，无点=空闲。
   谁在用写在 tooltip 里，不占横向空间 —— 六个格子要能挤进窄顶栏。 */
.area-dot {
  width: 6px;
  height: 6px;
  flex: none;
  border-radius: var(--r-full);
  background: transparent;
}
.area.is-mine .area-dot { background: var(--ok); }
.area.is-busy .area-dot { background: var(--warn); }
.area.is-locked .area-dot { background: var(--fg-2); opacity: .6; }

/* ============================================================ 上游状态灯 */

.host-state {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: .26em .6em;
  flex: none;
  font-size: .8rem;
  color: var(--fg-1);
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  white-space: nowrap;
}

.dot {
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: var(--r-full);
  background: var(--fg-2);
}
.dot.is-live { background: var(--ok); }
.dot.is-busy { background: var(--warn); }
.dot.is-off { background: var(--fg-2); }
.dot.is-err { background: var(--err); }

/* 忙碌时轻微呼吸。只动透明度，不动位移或尺寸 —— 位移会把视线从回文上勾走。 */
.dot.is-busy { animation: dot-pulse 1.4s ease-in-out infinite; }

@keyframes dot-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: .38; }
}

@media (prefers-reduced-motion: reduce) {
  .dot.is-busy { animation: none; }
}

/* ============================================================ 输入行
 * 和终端同宽同位（layout.css 负责居中），看起来像屏幕的最后一行。 */

.inputbar {
  display: flex;
  align-items: stretch;
  gap: var(--sp-2);
  width: 100%;
  max-width: var(--term-max, 84ch);
  min-width: 0;
}

.inputbar-shell {
  display: flex;
  align-items: center;
  flex: 1 1 auto;
  min-width: 0;
  /* 单行时靠这个撑出正常高度；多行时由 textarea 自己顶高（JS 量 scrollHeight 设的） */
  min-height: var(--h-input);
  background: var(--term-bg);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  transition: border-color var(--t-press) ease, box-shadow var(--t-press) ease;
}

.inputbar-shell:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-ring);
}

/* 当前窗口字母。贴在输入框左侧，回答"我这条指令要发到哪个区" —— 
   这是发错区最容易出事的地方，所以常驻显示，不靠记忆。 */
.inputbar-area {
  display: grid;
  place-items: center;
  align-self: stretch;
  width: 2.2em;
  flex: none;
  font-family: var(--font-mono);
  font-size: .9rem;
  font-weight: 700;
  color: var(--term-c1);
  border-right: 1px solid var(--term-line);
  user-select: none;
}

.inputbar-input {
  flex: 1 1 auto;
  min-width: 0;
  /* 高度由 JS 按内容设（见 main.js 的 autoGrow）。11em 上限约等于 8 行，
     再多就内部滚动 —— 否则贴进 30 行会把终端挤没了。 */
  height: auto;
  max-height: 11em;
  padding: .55em .7em;
  font-family: var(--font-mono);
  font-size: var(--term-fs, 15px);
  line-height: 1.45;
  letter-spacing: .01em;
  color: var(--term-fg);
  background: transparent;
  border: 0;
  /* textarea 的默认拖拽把手在这个布局里只会碍事，高度已经自动了 */
  resize: none;
  overflow-y: auto;
  /* 主机指令一律大写。这里只管显示，实际值由 JS 转成大写 —— 
     光靠 text-transform 会出现"屏幕显示大写、发出去还是小写"的错位。 */
  text-transform: uppercase;
}
.inputbar-input::placeholder { color: var(--fg-2); text-transform: none; }

/* 多行时窗口字母贴着顶端，像行号栏；单行时 flex 居中自然生效 */
.inputbar-shell.is-multiline { align-items: flex-start; }
.inputbar-shell.is-multiline .inputbar-area { padding-top: .62em; align-items: flex-start; }

/* 多行时右侧提示"这是几条指令"，避免误发一大批 */
.inputbar-count {
  flex: none;
  align-self: flex-start;
  padding: .62em .5em 0 0;
  font-family: var(--font-ui);
  font-size: .74rem;
  color: var(--fg-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  user-select: none;
}

.inputbar-send { flex: none; padding-inline: 1.1em; }

@media (max-width: 719px) {
  /* 手机上按钮只留图标，把宽度让给输入框 */
  .inputbar-send { padding-inline: .8em; }
  .inputbar-send .btn-text { display: none; }
}

/* ============================================================ 快捷指令 · 横条 */

.pin {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: .3em .62em;
  flex: none;
  max-width: 15em;
  font-size: .82rem;
  color: var(--fg-1);
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  transition: background-color var(--t-press) ease,
              border-color var(--t-press) ease,
              color var(--t-press) ease,
              transform var(--t-press) var(--ease-out);
}
.pin-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pin:active { transform: scale(.97); }
@media (hover: hover) and (pointer: fine) {
  .pin:hover { background: var(--bg-3); border-color: var(--border-strong); color: var(--fg-0); }
}

.pins-more { flex: none; }

.pins-empty { font-size: .8rem; color: var(--fg-2); }

/* ============================================================ 快捷指令 · 侧栏 */

.sc-group {
  margin: var(--sp-3) var(--sp-1) var(--sp-1);
  font-size: .74rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--fg-2);
}
.sc-group:first-child { margin-top: var(--sp-1); }

.sc-row {
  display: flex;
  align-items: stretch;
  gap: 2px;
  margin-bottom: 2px;
}

.sc-item {
  flex: 1 1 auto;
  min-width: 0;
  padding: .42em .55em;
  text-align: left;
  border: 1px solid transparent;
  border-radius: var(--r-md);
  transition: background-color var(--t-press) ease,
              border-color var(--t-press) ease,
              transform var(--t-press) var(--ease-out);
}
.sc-item:active { transform: scale(.985); }

@media (hover: hover) and (pointer: fine) {
  .sc-item:hover { background: var(--bg-hover); border-color: var(--border); }
}

.sc-title {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: .86rem;
  color: var(--fg-0);
  overflow: hidden;
}
.sc-title > span:first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 多行快捷指令的条数徽标。点一下会连发好几条，这件事必须看得出来。 */
.sc-badge {
  flex: none;
  min-width: 1.25em;
  padding: 0 .28em;
  font-family: var(--font-ui);
  font-size: .68rem;
  line-height: 1.5;
  text-align: center;
  color: var(--fg-1);
  background: var(--bg-3);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  font-variant-numeric: tabular-nums;
  user-select: none;
}
.pin .sc-badge { font-size: .64rem; }

.sc-cmd {
  display: block;
  margin-top: 1px;
  font-family: var(--font-mono);
  font-size: .76rem;
  color: var(--fg-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 行尾的操作键（编辑 / 删除）。只有自己建的快捷指令才有这两个 —— 
   管理员发布的全局指令员工改不了。 */
.sc-act {
  width: 24px;
  flex: none;
  display: grid;
  place-items: center;
  color: var(--fg-2);
  border: 1px solid transparent;
  border-radius: var(--r-md);
  opacity: 0;
  transition: opacity var(--t-press) ease, color var(--t-press) ease,
              background-color var(--t-press) ease;
}
.sc-act svg { width: 13px; height: 13px; }

/* 平时隐身，hover/键盘聚焦时才出现 —— 侧栏很窄，常显会把标题挤没。
   触屏没有 hover，所以那边一直显示（下面的 pointer:coarse 分支）。 */
@media (hover: hover) and (pointer: fine) {
  .sc-row:hover .sc-act, .sc-act:focus-visible { opacity: 1; }
  .sc-edit:hover { color: var(--accent); background: var(--accent-soft); }
  .sc-del:hover { color: var(--err); background: var(--err-soft); }
}
@media (pointer: coarse) {
  .sc-act { opacity: 1; }
  /* 触屏上目标要够大 */
  .sc-act { width: 34px; height: 34px; }
}

.sc-empty {
  padding: var(--sp-4) var(--sp-2);
  font-size: .82rem;
  line-height: 1.6;
  color: var(--fg-2);
  text-align: center;
}

/* ============================================================ 状态栏项 */

.status-item {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex: none;
  white-space: nowrap;
  max-width: 40vw;
  overflow: hidden;
  text-overflow: ellipsis;
}

.status-item b { color: var(--fg-0); font-weight: 600; }

.status-sep {
  width: 1px;
  height: 12px;
  flex: none;
  background: var(--border);
}

.status-item.is-warn { color: var(--warn); }
.status-item.is-err { color: var(--err); }

/* 状态栏里可点的项（比如"清屏"）不要看着像纯文本 */
button.status-item {
  padding: 0 var(--sp-1);
  border-radius: var(--r-sm);
  transition: background-color var(--t-press) ease, color var(--t-press) ease;
}
@media (hover: hover) and (pointer: fine) {
  button.status-item:hover { background: var(--bg-hover); color: var(--fg-0); }
}

/* ============================================================ 命令面板
 * 一天用几十次 —— 入场压到 140ms，只做 scale(.98)→1 + 淡入。
 * 完全不做动画也是合理选项（Raycast 就没有），但这是覆盖全屏的层，
 * 硬切会让人一瞬间失去方位感，140ms 是能保住方位感的下限。
 * 从 scale(.98) 起而不是 scale(0)：现实里没有东西从虚无中长出来。 */

.palette-scrim {
  position: fixed;
  inset: 0;
  z-index: var(--z-palette);
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding: min(12vh, 96px) var(--sp-4) var(--sp-4);
  background: rgba(0, 0, 0, .5);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-fast) var(--ease-out);
}

.palette-scrim.is-open { opacity: 1; pointer-events: auto; }

.palette {
  display: flex;
  flex-direction: column;
  width: min(560px, 100%);
  max-height: min(60vh, 480px);
  background: var(--bg-1);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  transform: scale(.98);
  opacity: 0;
  /* 覆盖层不锚定在某个触发点上，所以从中心缩放（这点和 popover 相反） */
  transform-origin: center;
  transition: transform var(--t-fast) var(--ease-out),
              opacity var(--t-fast) var(--ease-out);
}

.palette-scrim.is-open .palette { transform: scale(1); opacity: 1; }

.palette-head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-3);
  flex: none;
  border-bottom: 1px solid var(--border);
}
.palette-head svg { width: 16px; height: 16px; flex: none; color: var(--fg-2); }

.palette-input {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 1rem;
  color: var(--fg-0);
  background: transparent;
  border: 0;
}
.palette-input::placeholder { color: var(--fg-2); }

.palette-list {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: var(--sp-2);
  /* 键盘上下移动时不要平滑滚动 —— 高频操作，平滑会让人觉得跟不上手 */
  scroll-behavior: auto;
}

.palette-group {
  padding: var(--sp-3) var(--sp-2) var(--sp-1);
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--fg-2);
}
.palette-group:first-child { padding-top: var(--sp-1); }

.palette-item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  padding: .5em .6em;
  text-align: left;
  border-radius: var(--r-md);
  color: var(--fg-0);
}

/* 选中态由键盘/鼠标共同驱动，统一用 is-sel，不用 :hover —— 
   否则鼠标停在别处会出现"两个选中项"。 */
.palette-item.is-sel { background: var(--accent-soft); }

.palette-icon {
  display: grid;
  place-items: center;
  width: 20px;
  flex: none;
  color: var(--fg-2);
  font-family: var(--font-mono);
  font-size: .82rem;
}
.palette-icon svg { width: 15px; height: 15px; }
.palette-item.is-sel .palette-icon { color: var(--accent); }

.palette-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.palette-sub {
  display: block;
  font-family: var(--font-mono);
  font-size: .76rem;
  color: var(--fg-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.palette-hint { flex: none; font-size: .78rem; color: var(--fg-2); }

.palette-empty {
  padding: var(--sp-6) var(--sp-3);
  text-align: center;
  font-size: .86rem;
  color: var(--fg-2);
}

.palette-foot {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  padding: var(--sp-2) var(--sp-3);
  flex: none;
  font-size: .76rem;
  color: var(--fg-2);
  background: var(--bg-2);
  border-top: 1px solid var(--border);
}
.palette-foot span { display: inline-flex; align-items: center; gap: 5px; }

@media (max-width: 719px) {
  .palette-scrim { padding: var(--sp-2); align-items: stretch; }
  .palette { max-height: none; width: 100%; }
  .palette-foot { display: none; }
}

/* ============================================================ 下拉菜单
 * 锚定在触发按钮上，所以从触发点缩放（transform-origin 由 JS 设成右上/左上）。 */

.menu {
  position: fixed;
  z-index: var(--z-modal);
  min-width: 200px;
  padding: var(--sp-1);
  background: var(--bg-1);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-md);
  transform: scale(.97);
  opacity: 0;
  transform-origin: var(--menu-origin, top right);
  transition: transform var(--t-fast) var(--ease-out),
              opacity var(--t-fast) var(--ease-out);
}
.menu.is-open { transform: scale(1); opacity: 1; }

.menu-item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  padding: .46em .6em;
  font-size: .86rem;
  text-align: left;
  color: var(--fg-0);
  border-radius: var(--r-md);
}
.menu-item svg { width: 15px; height: 15px; flex: none; color: var(--fg-2); }
.menu-item .menu-hint { margin-left: auto; font-size: .78rem; color: var(--fg-2); }
@media (hover: hover) and (pointer: fine) {
  .menu-item:hover { background: var(--bg-hover); }
}
.menu-item.is-danger { color: var(--err); }
.menu-item.is-danger svg { color: var(--err); }

.menu-sep { height: 1px; margin: var(--sp-1) 0; background: var(--border); }

.menu-head {
  padding: .4em .6em var(--sp-2);
  font-size: .8rem;
  color: var(--fg-2);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--sp-1);
}
.menu-head b { display: block; font-size: .9rem; color: var(--fg-0); font-weight: 600; }

/* 分段选择（主题、界面尺度）放在菜单里 */
.menu-seg {
  display: flex;
  gap: 2px;
  margin: var(--sp-1) .6em var(--sp-2);
  padding: 2px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
}
.menu-seg button {
  flex: 1 1 0;
  padding: .3em 0;
  font-size: .78rem;
  color: var(--fg-1);
  border-radius: var(--r-sm);
  transition: background-color var(--t-press) ease, color var(--t-press) ease;
}
.menu-seg button.is-on { color: var(--fg-0); background: var(--bg-0); }
@media (hover: hover) and (pointer: fine) {
  .menu-seg button:not(.is-on):hover { background: var(--bg-hover); color: var(--fg-0); }
}

/* ============================================================ 弹窗
 * 罕见操作（改密、确认接管）。居中出现，所以保持 transform-origin: center。 */

.modal-scrim {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: min(10vh, 80px) var(--sp-4) var(--sp-4);
  overflow-y: auto;
  background: rgba(0, 0, 0, .5);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-base) var(--ease-out);
}
.modal-scrim.is-open { opacity: 1; pointer-events: auto; }

.modal {
  width: min(440px, 100%);
  background: var(--bg-1);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-lg);
  transform: scale(.97) translateY(6px);
  opacity: 0;
  transform-origin: center;
  transition: transform var(--t-base) var(--ease-out),
              opacity var(--t-base) var(--ease-out);
}
.modal-scrim.is-open .modal { transform: none; opacity: 1; }

.modal-head {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-4) var(--sp-2);
}
.modal-title { flex: 1 1 auto; font-size: 1rem; font-weight: 600; }
.modal-body { padding: var(--sp-2) var(--sp-4) var(--sp-4); }
.modal-text { font-size: .88rem; line-height: 1.6; color: var(--fg-1); }
.modal-foot {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--border);
  background: var(--bg-2);
  border-radius: 0 0 var(--r-xl) var(--r-xl);
}
.modal-err { flex: 1 1 auto; min-width: 0; font-size: .82rem; color: var(--err); }

/* ============================================================ toast
 * 从右上角滑入。位置和消失方向一致，这样"划走"的手势才符合直觉。 */

.toasts {
  position: fixed;
  top: calc(var(--h-top) + var(--sp-2));
  right: var(--sp-3);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  width: min(340px, calc(100vw - var(--sp-4) * 2));
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  padding: var(--sp-3);
  font-size: .85rem;
  line-height: 1.5;
  color: var(--fg-0);
  background: var(--bg-1);
  border: 1px solid var(--border-strong);
  border-left: 3px solid var(--accent);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-md);
  pointer-events: auto;
  /* 用 transition 而不是 keyframes：toast 可能连着来，
     keyframes 被打断会从头播，transition 会平滑改道。 */
  opacity: 1;
  transform: translateX(0);
  transition: opacity var(--t-base) var(--ease-out),
              transform var(--t-base) var(--ease-out);
}

/* 入场初值。@starting-style 让元素一插入就能过渡，不用 JS 补一帧 */
@starting-style {
  .toast { opacity: 0; transform: translateX(12px); }
}

.toast.is-leaving { opacity: 0; transform: translateX(12px); }

.toast.is-ok { border-left-color: var(--ok); }
.toast.is-err { border-left-color: var(--err); }
.toast.is-warn { border-left-color: var(--warn); }

.toast-body { flex: 1 1 auto; min-width: 0; }
.toast-close { flex: none; color: var(--fg-2); }
.toast-close svg { width: 13px; height: 13px; }

@media (max-width: 719px) {
  .toasts { left: var(--sp-2); right: var(--sp-2); width: auto; }
  @starting-style {
    .toast { transform: translateY(-8px); }
  }
  .toast.is-leaving { transform: translateY(-8px); }
}

/* ============================================================ tooltip
 * 纯 CSS。延迟 400ms 出现，防止扫过一排按钮时闪个不停。
 * 触屏（pointer: coarse）不出 —— 那边没有 hover，点完会粘住。 */

[data-tip] { position: relative; }

[data-tip]::after {
  content: attr(data-tip);
  position: absolute;
  top: calc(100% + 6px);
  left: 50%;
  z-index: var(--z-toast);
  padding: .3em .5em;
  font-family: var(--font-ui);
  font-size: .76rem;
  font-weight: 400;
  line-height: 1.4;
  color: var(--fg-0);
  background: var(--bg-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  box-shadow: var(--shadow-sm);
  white-space: pre;
  opacity: 0;
  transform: translate(-50%, -3px);
  transform-origin: top center;
  pointer-events: none;
  transition: opacity var(--t-fast) var(--ease-out),
              transform var(--t-fast) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  [data-tip]:hover::after,
  [data-tip]:focus-visible::after {
    opacity: 1;
    transform: translate(-50%, 0);
    transition-delay: 400ms;
  }
}

/* 顶栏右侧的按钮，tooltip 往左对齐，否则会被窗口边缘裁掉 */
[data-tip][data-tip-align="end"]::after {
  left: auto;
  right: 0;
  transform: translate(0, -3px);
  transform-origin: top right;
}
@media (hover: hover) and (pointer: fine) {
  [data-tip][data-tip-align="end"]:hover::after,
  [data-tip][data-tip-align="end"]:focus-visible::after { transform: translate(0, 0); }
}

/* 状态栏在最底部，tooltip 得朝上 */
[data-tip][data-tip-pos="top"]::after {
  top: auto;
  bottom: calc(100% + 6px);
  transform-origin: bottom center;
}

/* ============================================================ 快捷键说明表 */

.key-list { display: flex; flex-direction: column; gap: 2px; }

.key-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: .34em 0;
  font-size: .86rem;
}
.key-row + .key-row { border-top: 1px solid var(--border); }

.key-label { flex: 1 1 auto; min-width: 0; color: var(--fg-1); }

.key-keys {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 3px;
}

/* ============================================================ 登录页
 * 做成"一块终端屏"，不是"一张登录卡片"。
 *
 * 为什么：页面上一句说明文字都没有（客户明确要求去掉），那就只剩布局和质感能说话。
 * 而这个产品本身就是终端 —— 用等宽字体、小写的 login/password 提示符（Unix 登录
 * 就是这个样子）、聚焦行左侧亮起的竖线，员工一眼就知道自己进的是哪套系统，
 * 也和主界面的命令块（同样是左侧一条状态竖线）是同一套视觉语言。
 *
 * 表单语义保持标准（真的 input[type=password] + autocomplete），
 * 所以浏览器的密码管理器和自动填充照常工作 —— 不能为了"像终端"把这个牺牲掉。
 */

.signin {
  display: grid;
  place-items: center;
  min-height: 100vh;
  min-height: 100dvh;
  padding: var(--sp-8) var(--sp-4);
  overflow-y: auto;
  /* 中心一层极淡的光晕，给纯色页面一点纵深。跟着主题的 accent 走，
     所以三套主题下都是协调的。 */
  background:
    radial-gradient(68% 52% at 50% 36%, var(--accent-soft), transparent 72%),
    var(--bg-0);
}

.signin-panel { width: min(400px, 100%); }

/* 标识行：一条 accent 竖条 + 拉开字距的大写标识。
   没有 logo 图形，也不需要 —— 字距本身就是识别度。 */
.signin-id {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  font-family: var(--font-mono);
  font-size: .82rem;
  font-weight: 500;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--fg-1);
  user-select: none;
}

.signin-id::before {
  content: "";
  flex: none;
  width: 3px;
  height: 1.15em;
  background: var(--accent);
  border-radius: 1px;
}

/* 渐隐的分隔线，比一条实线精致，也暗示"屏幕从这里开始" */
.signin-rule {
  height: 1px;
  margin: var(--sp-4) 0 var(--sp-5);
  border: 0;
  background: linear-gradient(90deg, var(--border-strong), transparent);
}

/* 两个输入行是一个整体（像终端连着的两行），所以边框包在外层。
   overflow: hidden 让行的底色不会溢出圆角。 */
.signin-fields {
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--bg-1);
}

.signin-field {
  display: flex;
  align-items: center;
  height: 50px;
  padding-right: var(--sp-3);
  border-left: 2px solid transparent;
  transition: background-color var(--t-fast) ease,
              border-color var(--t-fast) ease;
}

.signin-field + .signin-field { border-top: 1px solid var(--border); }

/* 聚焦的那一行整行亮起、左侧竖线点亮 —— 和主界面命令块的状态线同一个语言。
   用 :focus-within 而不是给 input 加类，少一份 JS 状态。 */
.signin-field:focus-within {
  background: var(--bg-2);
  border-left-color: var(--accent);
}

.signin-label {
  flex: none;
  width: 6.2em;
  padding-left: var(--sp-3);
  font-family: var(--font-mono);
  font-size: .84rem;
  color: var(--fg-2);
  cursor: text;
  user-select: none;
  transition: color var(--t-fast) ease;
}

.signin-field:focus-within .signin-label { color: var(--accent); }

.signin-input {
  flex: 1 1 auto;
  min-width: 0;
  height: 100%;
  padding: 0;
  font-family: var(--font-mono);
  font-size: 1rem;
  letter-spacing: .02em;
  color: var(--fg-0);
  background: none;
  border: 0;
}

.signin-input::placeholder { color: var(--fg-2); opacity: .55; }

/* 错误行：左侧红竖线，和输入行的 accent 竖线呼应。
   空的时候完全不占视觉位置（只留一行高度，免得出错时布局往下跳）。 */
.signin-msg {
  min-height: 2.6em;
  margin-top: var(--sp-3);
  padding-left: var(--sp-3);
  font-family: var(--font-mono);
  font-size: .8rem;
  line-height: 1.55;
  color: var(--err);
  border-left: 2px solid transparent;
  transition: border-color var(--t-fast) ease;
}

.signin-msg:not(:empty) { border-left-color: var(--err); }

.signin-go {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
  width: 100%;
  height: 46px;
  font-family: var(--font-mono);
  font-size: .9rem;
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--accent-fg);
  background: var(--accent);
  border-radius: var(--r-md);
  transition: background-color var(--t-press) ease,
              transform var(--t-press) var(--ease-out);
}

.signin-go:active:not(:disabled) { transform: scale(.985); }
.signin-go:disabled { opacity: .6; }

@media (hover: hover) and (pointer: fine) {
  .signin-go:hover:not(:disabled) { background: var(--accent-hover); }
}

/* 按钮右侧的回车记号：暗示"直接按 Enter 就行"，不用挪手去点。
   透明度压低，是提示而不是装饰。 */
.signin-go-key {
  font-size: 1.05em;
  opacity: .6;
}

/* 手机上把输入行做高一点（触摸目标下限 44px 已满足，这里给到舒适区） */
@media (max-width: 719px) {
  .signin { padding: var(--sp-6) var(--sp-4); }
  .signin-field { height: 54px; }
  .signin-label { width: 5.6em; font-size: .82rem; }
  .signin-go { height: 50px; }
}

/* 按钮里的转圈。同一个 spinner 也给发送按钮用。
   转得快一点感觉整个系统更快 —— 感知速度和实际速度一样重要。 */
.spinner {
  width: 14px;
  height: 14px;
  flex: none;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: var(--r-full);
  opacity: .8;
  animation: spin 620ms linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .spinner { animation-duration: 1.6s; }
}
