/* ==========================================================================
   cyui —— 自研 UI 框架 v0.1（P0：令牌 + 按钮 + 卡片 + 基础件）
   --------------------------------------------------------------------------
   设计参照 MDUI 的「形态 / 语义 / 尺寸 / 形状」正交拆法，但不引入其代码与依赖。
   三条硬规矩（改这个文件前先读）：
     1. 只定义 .cy-* 组件，绝不出现裸标签选择器和业务类（.btn/.card/#id）——
        历史上 body.oa-skin .btn 把自定义按钮染黑，就是组件抢基础类造成的；
     2. 皮肤只改令牌值（见 [data-cy-skin]），不改组件里的 background/color；
     3. 浮层层级只能用 --cy-z-* 台阶，不允许再写 z-index: 10001 这类魔法数。
   另外刻意不做全局 reset（不写 * { box-sizing } / body 重置）：这个文件将来要和
   12854 行的 oal.css 共存，全局重置会立刻改变所有既有页面的版式。
   ========================================================================== */

/* ==========================================================================
   iOS 沉浸两套模型（互斥，全站统一用 A；完整推导见 doc/index.php「cyui 用法 · iOS 沉浸」）
   A 采样沉浸（现状）：theme-color / color-scheme / viewport-fit=cover 三条一律不写。
     iOS 26 的 Liquid Glass 自己采样系统背景 → 地址栏/工具栏半透明。
     手机实测补充：iOS Safari 的地址/标题栏在屏幕底部；顶部 sticky 栏可以半透明，
     但视口上沿那一层不要放 backdrop-filter（画在 ::before 也一样被采样）——
     毛玻璃不会让栏更透，只会把它钉实。
     代价（不是 bug，别去“修”）：布局视口已被 WebKit 缩进安全区，所以
     env(safe-area-inset-*) 恒为 0（是不需要，不是白写）；原生日历面板/下拉列表/
     滚动条不跟皮肤——原生控件配色一律靠 --cy-* 令牌 + ::-webkit-* 强接。
   B 铺满沉浸（已废弃）：写 cover + theme-color=页面底色，页面铺到栏下、env() 出真值，
     但栏被页面实色钉成不透明块。千万别为了“让 env 生效”单独补 cover，那是整体退回 B。
   本块故意放在 :root 外面：:root 里只留一行指针，这样按行删令牌时
   不可能削到多行注释的一半而把后面整段声明吞成注释。
   ========================================================================== */

:root {
    /* ---- 面与线 ---- */
    --cy-bg: #f1f5f9;
    --cy-surface: #ffffff;
    --cy-surface-2: #f8fafc;
    --cy-surface-3: #f1f5f9;
    --cy-line: #e2e8f0;
    --cy-line-2: #cbd5e1;
    --cy-line-3: #eef2f7;
    /* ---- 文字四级（业务里那种随手写的 hex 到此为止）---- */
    --cy-text: #0f172a;
    --cy-text-2: #334155;
    --cy-text-3: #64748b;
    --cy-text-4: #94a3b8;
    --cy-text-5: #cbd5e1;
    --cy-ph: #b6c2d1;                     /* 占位文色（深色皮肤下会跟着提亮） */
    --cy-focus-ring: rgba(37, 99, 235, .14);   /* 输入框聚焦外环 */
    /* iOS 沉浸：不写 theme-color / color-scheme / viewport-fit=cover（两套模型对比见文件顶部）*/
    /* ---- 语义色：每个都是 实底 / 悬停更深 / 浅底 / 浅底描边 / 浅底上的文字 ---- */
    --cy-primary: #2563eb;      --cy-primary-hover: #1d4ed8;
    --cy-primary-soft: #eff6ff; --cy-primary-soft-line: #bfdbfe; --cy-primary-ink: #1e40af;
    --cy-success: #059669;      --cy-success-hover: #047857;
    --cy-success-soft: #ecfdf5; --cy-success-soft-line: #a7f3d0; --cy-success-ink: #047857;
    --cy-warning: #f59e0b;      --cy-warning-hover: #d97706;
    --cy-warning-soft: #fffbeb; --cy-warning-soft-line: #fde68a; --cy-warning-ink: #b45309;
    --cy-danger: #dc2626;       --cy-danger-hover: #b91c1c;
    --cy-danger-soft: #fef2f2;  --cy-danger-soft-line: #fecaca;  --cy-danger-ink: #b91c1c;
    --cy-info: #0891b2;         --cy-info-hover: #0e7490;
    --cy-info-soft: #ecfeff;    --cy-info-soft-line: #a5f3fc;    --cy-info-ink: #0e7490;
    /* ---- 圆角：改 --cy-r-base 一个值，全站跟随（max() 兜底不会被算成负数）---- */
    --cy-r-base: 10px;
    --cy-r-1: max(2px, calc(var(--cy-r-base) - 4px));
    --cy-r-2: var(--cy-r-base);
    --cy-r-3: calc(var(--cy-r-base) + 4px);
    --cy-r-4: calc(var(--cy-r-base) + 10px);
    --cy-r-full: 9999px;
    /* ---- 间距 8 档 ---- */
    --cy-s-1: 4px; --cy-s-2: 6px; --cy-s-3: 8px; --cy-s-4: 10px;
    --cy-s-5: 12px; --cy-s-6: 16px; --cy-s-7: 20px; --cy-s-8: 28px;
    /* ---- 海拔（阴影）---- */
    --cy-e-1: 0 1px 2px rgba(15, 23, 42, .05);
    --cy-e-2: 0 1px 4px rgba(15, 23, 42, .06);
    --cy-e-3: 0 2px 10px rgba(15, 23, 42, .08);
    --cy-e-4: 0 8px 24px -6px rgba(15, 23, 42, .16);
    --cy-e-5: 0 20px 50px -12px rgba(15, 23, 42, .28);
    /* ---- 字阶 ---- */
    --cy-fs-1: 10.5px; --cy-fs-2: 11.5px; --cy-fs-3: 12.5px;
    --cy-fs-4: 14px;   --cy-fs-5: 16px;   --cy-fs-6: 20px;
    --cy-lh: 1.45;
    /* ---- 层级台阶：新增浮层只能从这里挑 ---- */
    --cy-z-sticky: 900; --cy-z-nav: 920; --cy-z-popover: 950; --cy-z-drawer: 2000; --cy-z-modal: 3000;
    --cy-z-modal-top: 3100; --cy-z-lightbox: 3200; --cy-z-blocker: 3300; --cy-z-toast: 3400;
    /* 920/950 已补进台阶：cy-tabbar 与 cy-suggest/cy-dd-panel 一直在用这两个令牌，
       原先台阶里没定义，z-index:var(--cy-z-popover) 回落 auto，下拉面板压不过 sticky 顶栏（900）、
       滚动到顶就被盖住。现已定义，弹层稳定高于顶栏。 */

    /* ---- 动效 ---- */
    --cy-dur: .15s; --cy-ease: cubic-bezier(.4, 0, .2, 1);
    /* ---- 组件局部可调旋钮（给默认值，调用处用 style="--cy-min:330px" 覆盖）---- */
    --cy-min: 280px;
    --cy-font: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
        "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
}

/* 皮肤：只覆盖令牌。深色先给一版，验证「换肤不碰组件」这条能不能立住 */
[data-cy-skin="dark"] {
    /* 不声明 color-scheme（与 :root 同一规矩）：iOS 26 上声明任何 color-scheme
       都会把地址栏/工具栏钉成对应方案的实色块。深色感全靠下面的令牌值 + 页面
       html 背景跟随变色，浏览器 chrome 留给 Liquid Glass 自己采样。
       已知代价：深色皮肤下系统原生日历面板/滚动条仍是浅色——这是选 A 换来的，
       要修它就得声明 color-scheme，地址栏沉浸会同步失去，二选一 */
    --cy-bg: #0b1220;
    --cy-surface: #121a29;
    --cy-surface-2: #18212f;
    --cy-surface-3: #1f2937;
    --cy-line: #273244;
    --cy-line-2: #384459;
    --cy-line-3: #212c3d;
    --cy-text: #e8eef7;
    --cy-text-2: #cbd5e1;
    --cy-text-3: #94a3b8;
    --cy-text-4: #7c8aa0;
    --cy-text-5: #55637a;
    --cy-primary-soft: #17233b; --cy-primary-soft-line: #2a4373; --cy-primary-ink: #93c5fd;
    --cy-success-soft: #10241d; --cy-success-soft-line: #1d4b3a; --cy-success-ink: #6ee7b7;
    --cy-warning-soft: #241a08; --cy-warning-soft-line: #4d3a12; --cy-warning-ink: #fcd34d;
    --cy-danger-soft: #261414;  --cy-danger-soft-line: #4d2424;  --cy-danger-ink: #fca5a5;
    --cy-info-soft: #0b2229;    --cy-info-soft-line: #17414f;    --cy-info-ink: #67e8f9;
    --cy-e-1: 0 1px 2px rgba(0, 0, 0, .4);
    --cy-e-2: 0 1px 4px rgba(0, 0, 0, .45);
    --cy-e-3: 0 2px 10px rgba(0, 0, 0, .5);
    --cy-e-4: 0 8px 24px -6px rgba(0, 0, 0, .6);
}

/* ==========================================================================
   按钮 .cy-btn
   四轴正交：形态(filled/tonal/outlined/text) × 语义(primary…) × 尺寸(xs/lg/block) × 形状(round/square/icon)
   默认形态 = 浅底描边（对应老项目的 btn-outline）；主 CTA 才用 filled
   ========================================================================== */
.cy-btn {
    box-sizing: border-box;
    display: inline-flex; align-items: center; justify-content: center; gap: var(--cy-btn-gap, var(--cy-s-2));
    /* 高度/内距/圆角走旋钮，但必须写在本体：尺寸与形状变体写在后面，能自然覆盖。
       以前这条放在文件末尾的“旋钮区”，同特异度靠后胜出，结果把
       .cy-btn-xs / -lg 的 height 与 padding 全部压掉了（xs 的 27px 其实从来没生效） */
    height: var(--cy-btn-h, 34px); min-width: 34px; padding: 0 var(--cy-btn-pad, var(--cy-s-6));
    border: 1px solid var(--cy-line); border-radius: var(--cy-btn-r, var(--cy-r-2));
    background: var(--cy-surface-2); color: var(--cy-text-2);
    font-family: var(--cy-font); font-size: var(--cy-fs-3); font-weight: 600; line-height: 1;
    white-space: nowrap; cursor: pointer; user-select: none; text-decoration: none;
    transition: background-color var(--cy-dur) var(--cy-ease), border-color var(--cy-dur) var(--cy-ease),
        color var(--cy-dur) var(--cy-ease), box-shadow var(--cy-dur) var(--cy-ease), transform var(--cy-dur) var(--cy-ease);
}
.cy-btn > i { font-size: 13px; line-height: 1; }
.cy-btn:hover { background: var(--cy-surface-3); border-color: var(--cy-line-2); color: var(--cy-text); }
.cy-btn:active { transform: translateY(1px); }
.cy-btn:focus-visible { outline: 2px solid var(--cy-primary); outline-offset: 2px; }

/* —— 形态 —— */
.cy-btn-filled { background: var(--cy-primary); border-color: var(--cy-primary); color: #fff; box-shadow: var(--cy-e-2); }
.cy-btn-filled:hover { background: var(--cy-primary-hover); border-color: var(--cy-primary-hover); color: #fff; box-shadow: var(--cy-e-3); }
.cy-btn-outlined { background: transparent; border-color: var(--cy-line-2); color: var(--cy-text-2); }
.cy-btn-outlined:hover { background: var(--cy-surface-2); color: var(--cy-text); }
.cy-btn-text { background: transparent; border-color: transparent; color: var(--cy-primary); }
.cy-btn-text:hover { background: var(--cy-primary-soft); border-color: transparent; color: var(--cy-primary-ink); }
/* tonal：语义浅底 + 浅底描边 + 同色系深字（老项目里 btn-success 那种就是它） */
.cy-btn-tonal { background: var(--cy-surface-2); border-color: var(--cy-line); color: var(--cy-text-2); }

/* —— 语义：可与任一形态组合（filled 换实底色，tonal/outlined/text 换浅底与文字）—— */
.cy-btn-primary.cy-btn-filled { background: var(--cy-primary); border-color: var(--cy-primary); }
.cy-btn-primary.cy-btn-filled:hover { background: var(--cy-primary-hover); border-color: var(--cy-primary-hover); }
.cy-btn-primary.cy-btn-tonal { background: var(--cy-primary-soft); border-color: var(--cy-primary-soft-line); color: var(--cy-primary-ink); }
.cy-btn-primary.cy-btn-outlined { border-color: var(--cy-primary-soft-line); color: var(--cy-primary); }
.cy-btn-primary.cy-btn-outlined:hover, .cy-btn-primary.cy-btn-text:hover { background: var(--cy-primary-soft); color: var(--cy-primary-ink); }
.cy-btn-primary.cy-btn-text { color: var(--cy-primary); }

.cy-btn-success.cy-btn-filled { background: var(--cy-success); border-color: var(--cy-success); }
.cy-btn-success.cy-btn-filled:hover { background: var(--cy-success-hover); border-color: var(--cy-success-hover); }
.cy-btn-success.cy-btn-tonal { background: var(--cy-success-soft); border-color: var(--cy-success-soft-line); color: var(--cy-success-ink); }
.cy-btn-success.cy-btn-outlined { border-color: var(--cy-success-soft-line); color: var(--cy-success); }
.cy-btn-success.cy-btn-text { color: var(--cy-success); }
.cy-btn-success.cy-btn-text:hover, .cy-btn-success.cy-btn-outlined:hover { background: var(--cy-success-soft); color: var(--cy-success-ink); }

.cy-btn-warning.cy-btn-filled { background: var(--cy-warning); border-color: var(--cy-warning); color: #42210b; }
.cy-btn-warning.cy-btn-tonal { background: var(--cy-warning-soft); border-color: var(--cy-warning-soft-line); color: var(--cy-warning-ink); }
.cy-btn-warning.cy-btn-outlined { border-color: var(--cy-warning-soft-line); color: var(--cy-warning-ink); }
.cy-btn-warning.cy-btn-text { color: var(--cy-warning-ink); }
.cy-btn-warning.cy-btn-text:hover, .cy-btn-warning.cy-btn-outlined:hover { background: var(--cy-warning-soft); }

.cy-btn-danger.cy-btn-filled { background: var(--cy-danger); border-color: var(--cy-danger); }
.cy-btn-danger.cy-btn-filled:hover { background: var(--cy-danger-hover); border-color: var(--cy-danger-hover); }
.cy-btn-danger.cy-btn-tonal { background: var(--cy-danger-soft); border-color: var(--cy-danger-soft-line); color: var(--cy-danger-ink); }
.cy-btn-danger.cy-btn-outlined { border-color: var(--cy-danger-soft-line); color: var(--cy-danger); }
.cy-btn-danger.cy-btn-text { color: var(--cy-danger); }
.cy-btn-danger.cy-btn-text:hover, .cy-btn-danger.cy-btn-outlined:hover { background: var(--cy-danger-soft); color: var(--cy-danger-ink); }

.cy-btn-info.cy-btn-tonal { background: var(--cy-info-soft); border-color: var(--cy-info-soft-line); color: var(--cy-info-ink); }
.cy-btn-info.cy-btn-outlined { border-color: var(--cy-info-soft-line); color: var(--cy-info); }
.cy-btn-info.cy-btn-text { color: var(--cy-info); }

/* —— 尺寸 —— */
.cy-btn-xs { height: 27px; padding: 0 var(--cy-s-4); font-size: var(--cy-fs-2); border-radius: var(--cy-r-1); }
.cy-btn-xs > i { font-size: 11px; }
.cy-btn-lg { height: 42px; padding: 0 var(--cy-s-8); font-size: var(--cy-fs-4); border-radius: var(--cy-r-3); }
.cy-btn-lg > i { font-size: 15px; }
.cy-btn-block { display: flex; width: 100%; }

/* —— 形状 —— */
.cy-btn-round { border-radius: var(--cy-r-full); padding: 0 var(--cy-s-7); }
/* 方块与纯图标钮：宽度 = 高度，不写死字面量。
   写死 34px 时，只要高度换了来源（窄屏抬到 40px、或业务改了 --cy-btn-h），
   按钮就变成 34×40 的竖向长方形；min-width:0 把基础那条 34px 下限关掉，
   否则 xs（高 27）会被下限顶回 34 宽；flex:none 防被父容器压窄。 */
.cy-btn-square { padding: 0; width: var(--cy-btn-h, 34px); min-width: 0; flex: none; }
.cy-btn-square.cy-btn-xs { width: 27px; }
.cy-btn-square.cy-btn-lg { width: 42px; }
/* 纯图标钮：只有 i，无文字。给足点击面积（触屏 34px 起）；xs 与方块统一 27，别一个 27 一个 28 */
.cy-btn-icon { padding: 0; width: var(--cy-btn-h, 34px); min-width: 0; flex: none; }
.cy-btn-icon.cy-btn-xs { width: 27px; }
.cy-btn-icon.cy-btn-lg { width: 42px; }

/* —— 状态 —— */
.cy-btn[disabled], .cy-btn.is-disabled {
    opacity: .5; cursor: not-allowed; box-shadow: none; transform: none;
    pointer-events: none;
}
/* 加载中：文字前转圈并淡出，防重复提交（样式自带，不依赖 JS） */
.cy-btn.is-loading { position: relative; color: transparent !important; pointer-events: none; }
.cy-btn.is-loading > * { opacity: 0; }
.cy-btn.is-loading::after {
    content: ""; position: absolute; left: 50%; top: 50%; width: 14px; height: 14px;
    margin: -7px 0 0 -7px; border: 2px solid currentColor; border-top-color: transparent;
    border-radius: 50%; animation: cy-spin .7s linear infinite; color: var(--cy-text-3);
}
.cy-btn-filled.cy-btn-primary.is-loading::after, .cy-btn-danger.cy-btn-filled.is-loading::after,
.cy-btn-success.cy-btn-filled.is-loading::after { color: #fff; }
@keyframes cy-spin { to { transform: rotate(360deg); } }

/* 按钮组：靠右成排（行内操作位） */
.cy-btn-group { display: inline-flex; align-items: center; gap: var(--cy-s-2); flex-wrap: wrap; }
.cy-btn-group--end { justify-content: flex-end; }

/* ==========================================================================
   卡片 .cy-card
   ========================================================================== */
.cy-card {
    box-sizing: border-box;
    background: var(--cy-surface); border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-3);
    box-shadow: var(--cy-e-1);
    /* 不用 overflow:hidden 裁圆角：那会把卡头 actions 里的 data-cy-tip 气泡一起裁掉（绝对定位的气泡只能靠祖先不裁剪才能露出去）；
       图片方角由 .cy-card-media:first-child 自己带圆角解决 */
}
.cy-card-outline { border-color: var(--cy-line); box-shadow: none; }
.cy-card-flat { box-shadow: none; border-color: transparent; background: var(--cy-surface-2); }
.cy-card-soft { background: var(--cy-surface-2); border-color: var(--cy-line-3); }
.cy-card-hoverable { transition: box-shadow var(--cy-dur) var(--cy-ease), border-color var(--cy-dur) var(--cy-ease), transform var(--cy-dur) var(--cy-ease); }
.cy-card-hoverable:hover { box-shadow: var(--cy-e-3); border-color: var(--cy-line-2); }
.cy-card-click { cursor: pointer; }

/* 卡片内边距/标题字号都走旋钮：--cy-card-pad-x / -pad-y / --cy-card-t-fs / --cy-card-foot-bg */
.cy-card-head {
    display: flex; align-items: center; gap: var(--cy-s-4); flex-wrap: wrap;
    padding: var(--cy-card-pad-y, var(--cy-s-5)) var(--cy-card-pad-x, var(--cy-s-6));
    border-bottom: 1px solid var(--cy-line-3);
}
.cy-card-title { font-size: var(--cy-card-t-fs, var(--cy-fs-4)); font-weight: 800; color: var(--cy-text); min-width: 0; }
.cy-card-sub { font-size: var(--cy-fs-2); color: var(--cy-text-4); margin-top: 2px; font-weight: 500; }
/* actions 常塞筛选控件（.cy-optset 一排单选 + 勾选），flex:none 时它按内容取宽、窄屏必然冲出卡片背景；
   夹住 max-width:100% 并允许内部换行：宽屏内容放得下 → 一行、外观不变；窄屏折成多行而不是溢出。
   控件文字钉死不折行：中文没有空格，被压缩时会按字断行（“仅显示已注册用/户”很难看），宁可整块掉到下一行 */
.cy-card-actions { margin-left: auto; display: inline-flex; align-items: center; justify-content: flex-end; gap: var(--cy-s-2); flex: none; flex-wrap: wrap; max-width: 100%; }
.cy-card-actions .cy-check, .cy-card-actions .cy-radio { white-space: nowrap; }
/* 窄屏下选项集吃掉整行剩余宽（actions 被夹成满宽时才有自由空间可长），
   否则居右对齐会让它比上方标题缩进去一截，看着像没对齐 */
.cy-card-actions > .cy-optset { flex: 1 1 auto; min-width: 0; }
.cy-card-body { padding: var(--cy-card-pad-y, var(--cy-s-6)) var(--cy-card-pad-x, var(--cy-s-6)); font-size: var(--cy-fs-3); color: var(--cy-text-2); line-height: var(--cy-lh); }
.cy-card-body--tight { padding: var(--cy-s-4) var(--cy-s-5); }
.cy-card-foot {
    display: flex; align-items: center; gap: var(--cy-s-3); flex-wrap: wrap;
    padding: var(--cy-card-pad-y, var(--cy-s-4)) var(--cy-card-pad-x, var(--cy-s-6));
    border-top: 1px dashed var(--cy-line);
    background: var(--cy-card-foot-bg, var(--cy-surface-2)); font-size: var(--cy-fs-2); color: var(--cy-text-3);
}
/* 卡片变体：无内边距（内容自己控）、纯白无框、可点整卡 */
.cy-card-flush { --cy-card-pad-x: 0; --cy-card-pad-y: 0; }
.cy-card-head--plain { background: transparent; }
.cy-card-media { position: relative; width: 100%; aspect-ratio: 16 / 9; background: var(--cy-surface-3); overflow: hidden; }
.cy-card-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* 图在卡顶时自己圆上角（不再依赖父级 overflow） */
.cy-card > .cy-card-media:first-child { border-radius: calc(var(--cy-card-r, var(--cy-r-3)) - 1px) calc(var(--cy-card-r, var(--cy-r-3)) - 1px) 0 0; }
.cy-card > .cy-card-strip:first-child { border-radius: calc(var(--cy-card-r, var(--cy-r-3)) - 1px) calc(var(--cy-card-r, var(--cy-r-3)) - 1px) 0 0; }
/* 卡片头部带主色小图标的（列表页常用） */
.cy-card-ic {
    display: flex; align-items: center; justify-content: center; width: 30px; height: 30px; flex: none;
    border-radius: var(--cy-r-1); background: var(--cy-surface-3); color: var(--cy-text-3); font-size: 13px;
}
.cy-card-ic-primary { background: var(--cy-primary-soft); color: var(--cy-primary); }
/* 卡片可点时整卡高亮 + 行内按钮组不响应自己的点击 */
.cy-card-link { cursor: pointer; text-decoration: none; display: block; color: inherit; }
.cy-card-link:hover { border-color: var(--cy-primary-soft-line); }
/* 内嵌区（卡中卡不再用双层边框，改浅底） */
.cy-inset { background: var(--cy-surface-2); border-radius: var(--cy-r-2); padding: var(--cy-s-5); }

/* ==========================================================================
   卡片扩展：形态变体 + 结构件 + 业务卡
   （放在 .cy-card 基础之后，同特异性下后定义自然覆盖，不需要 !important）
   ========================================================================== */
/* —— 形态 —— */
.cy-card--dashed { border-style: dashed; background: transparent; }
.cy-card--ring { border-color: transparent; box-shadow: inset 0 0 0 1px var(--cy-line-3); }
.cy-card--tonal { border-color: transparent; background: var(--cy-surface-2); box-shadow: none; }
.cy-card--elev { box-shadow: var(--cy-e-4); }
.cy-card--none { border-color: transparent; box-shadow: none; padding-left: 0; padding-right: 0; }
.cy-card--selected { border-color: var(--cy-primary); box-shadow: 0 0 0 2px var(--cy-primary-soft); }
.cy-card--tight { --cy-card-pad-x: var(--cy-s-4); --cy-card-pad-y: var(--cy-s-3); }
.cy-card--roomy { --cy-card-pad-x: var(--cy-s-8); --cy-card-pad-y: var(--cy-s-7); }
.cy-card--stretch { height: 100%; }
.cy-card--clickable:hover { transform: translateY(-2px); }
.cy-card--left { border-left: 3px solid var(--cy-primary); }
.cy-card--left-success { border-left-color: var(--cy-success); }
.cy-card--left-warning { border-left-color: var(--cy-warning); }
.cy-card--left-danger { border-left-color: var(--cy-danger); }
/* —— 结构件 —— */
.cy-card-strip { height: 4px; flex: none; background: var(--cy-primary); }
.cy-card-strip.s2 { background: var(--cy-success); } .cy-card-strip.s3 { background: var(--cy-warning); }
.cy-card-strip.s4 { background: var(--cy-danger); } .cy-card-strip.s5 { background: var(--cy-info); }
.cy-card-hd-sticky { position: sticky; top: 0; z-index: 1; }
.cy-card-corner { position: absolute; top: var(--cy-s-4); right: var(--cy-s-4); z-index: 1; }
.cy-card-wrap { position: relative; }
.cy-card-body-scroll { flex: 1 1 auto; min-height: 0; overflow: auto; -webkit-overflow-scrolling: touch; }
.cy-card-side { flex: none; width: var(--cy-side-w, 168px); border-right: 1px solid var(--cy-line-3); background: var(--cy-surface-2); display: flex; flex-direction: column; }
.cy-card-split { flex-direction: row; align-items: stretch; }
.cy-card-overlay {
    position: absolute; inset: auto 0 0 0; display: flex; align-items: flex-end; gap: var(--cy-s-3);
    padding: var(--cy-s-5); min-height: 58px; background: linear-gradient(transparent, rgba(15, 23, 42, .76)); color: #fff;
}
.cy-card-overlay .cy-card-title, .cy-card-overlay b { color: #fff; }
.cy-card-media--tall { aspect-ratio: 4 / 3; }
.cy-card-media--wide { aspect-ratio: 21 / 9; }
.cy-card-media--sq { aspect-ratio: 1 / 1; }
/* —— 特殊观感卡 —— */
.cy-card-note {
    position: relative; background: #fffbeb; border-color: #fde68a; border-radius: var(--cy-r-1);
    box-shadow: var(--cy-e-2); font-size: var(--cy-fs-3); color: #78350f;
}
.cy-card-note::before {
    content: ""; position: absolute; top: -9px; left: 50%; transform: translateX(-50%) rotate(-2deg);
    width: 74px; height: 18px; background: rgba(214, 211, 209, .55); border: 1px solid rgba(168, 162, 158, .4);
}
.cy-card-folder::before {
    content: ""; position: absolute; top: -1px; left: -1px; width: 62px; height: 14px;
    background: var(--cy-surface); border: 1px solid var(--cy-line-3); border-bottom: 0;
    border-radius: var(--cy-r-2) var(--cy-r-2) 0 0;
}
/* —— 业务卡 —— */
/* 企业卡本身就是卡根（.cy-card.cy-card-co），内容直接铺在卡面上：
   必须自己吃标准卡内边距（走旋钮，--flush/--dense 照常生效），否则内容怼着卡框 */
.cy-card-co {
    display: flex; flex-direction: column; gap: var(--cy-s-4);
    padding: var(--cy-card-pad-y, var(--cy-s-5)) var(--cy-card-pad-x, var(--cy-s-6));
}
.cy-card-logo {
    display: flex; align-items: center; justify-content: center; flex: none; width: 42px; height: 42px;
    border-radius: var(--cy-r-2); background: var(--cy-primary-soft); color: var(--cy-primary);
    font-size: var(--cy-fs-5); font-weight: 800; overflow: hidden;
}
.cy-card-logo img { width: 100%; height: 100%; object-fit: cover; }
.cy-card-co-stats { display: flex; gap: var(--cy-s-5); flex-wrap: wrap; font-size: var(--cy-fs-2); color: var(--cy-text-3); }
.cy-card-co-stats b { color: var(--cy-text); font-variant-numeric: tabular-nums; }
.cy-card-rp { display: flex; align-items: center; gap: var(--cy-s-4); }
/* 报告卡第一行直接铺在卡面上时（.cy-card > .cy-card-rp:first-child，下面跟 foot/callout 而非 body）
   自己吃标准卡内边距；放在 .cy-card-body / .cy-card-foot 里的不加（那里已有内边距，再加就是双倍） */
.cy-card > .cy-card-rp:first-child { padding: var(--cy-card-pad-y, var(--cy-s-5)) var(--cy-card-pad-x, var(--cy-s-6)); }
/* 提示块直接当卡身收尾时同理：不缩进去就三边怼着卡框 */
.cy-card > .cy-callout:last-child { margin: 0 var(--cy-card-pad-x, var(--cy-s-6)) var(--cy-card-pad-y, var(--cy-s-5)); }
.cy-card-rp-ic { display: flex; align-items: center; justify-content: center; width: 36px; height: 36px; flex: none; border-radius: var(--cy-r-1); background: var(--cy-surface-3); color: var(--cy-text-3); font-size: 14px; }
.cy-card-rp-docx { background: var(--cy-primary-soft); color: var(--cy-primary); }
.cy-card-rp-pdf { background: var(--cy-danger-soft); color: var(--cy-danger); }
.cy-card-rp-xlsx { background: var(--cy-success-soft); color: var(--cy-success); }
.cy-card-rp-b { flex: 1 1 auto; min-width: 0; }
/* 卡内小列表（与 cy-list 区别：跟着卡走，无外框） */
.cy-card-rows { display: flex; flex-direction: column; }
.cy-card-row { display: flex; align-items: center; gap: var(--cy-s-4); padding: var(--cy-s-3) 0; border-bottom: 1px dashed var(--cy-line-3); font-size: var(--cy-fs-3); min-width: 0; }
.cy-card-row:last-child { border-bottom: 0; }
.cy-card-row-k { flex: none; width: 88px; color: var(--cy-text-4); font-size: var(--cy-fs-2); }
.cy-card-row-v { flex: 1 1 auto; min-width: 0; color: var(--cy-text); font-weight: 600; text-align: right; font-variant-numeric: tabular-nums; }
/* 命名约定：以后一律用 -- 双横线形式做修饰类；早期单横线（.cy-card-flat 等）保留可用，
   两者等价，免得写错一个符号就没样式 */
.cy-card--flush { --cy-card-pad-x: 0; --cy-card-pad-y: 0; }
.cy-card--flat { background: var(--cy-surface); box-shadow: none; }
.cy-card--outlined { background: var(--cy-surface); box-shadow: none; border-color: var(--cy-line-2); }
.cy-card--soft { background: var(--cy-surface-2); border-color: transparent; box-shadow: none; }
@media (max-width: 640px) {
    .cy-card-split { flex-direction: column; }
    .cy-card-side { width: auto; border-right: 0; border-bottom: 1px solid var(--cy-line-3); }
    .cy-card--roomy { --cy-card-pad-x: var(--cy-s-5); }
}
.cy-card--h { display: flex; flex-direction: row; }
.cy-card--h .cy-card-media { width: 96px; flex: none; aspect-ratio: 1 / 1; }

/* ==========================================================================
   标签 / 徽章 / 点 / 统计 / 键值 / 分隔 / 空态 / 骨架
   ========================================================================== */
.cy-tag {
    display: inline-flex; align-items: center; gap: 4px; height: 20px; padding: 0 7px;
    border-radius: var(--cy-r-1); background: var(--cy-surface-3); color: var(--cy-text-3);
    font-size: var(--cy-fs-1); font-weight: 700; line-height: 1; white-space: nowrap;
}
.cy-tag-primary { background: var(--cy-primary-soft); color: var(--cy-primary-ink); }
.cy-tag-success { background: var(--cy-success-soft); color: var(--cy-success-ink); }
.cy-tag-warning { background: var(--cy-warning-soft); color: var(--cy-warning-ink); }
.cy-tag-danger { background: var(--cy-danger-soft); color: var(--cy-danger-ink); }
.cy-tag-info { background: var(--cy-info-soft); color: var(--cy-info-ink); }
.cy-tag-line { background: transparent; border: 1px solid var(--cy-line); color: var(--cy-text-3); }
.cy-tag-round { border-radius: var(--cy-r-full); }

.cy-badge {
    display: inline-flex; align-items: center; justify-content: center; min-width: 18px; height: 18px;
    padding: 0 5px; border-radius: var(--cy-r-full); background: var(--cy-danger); color: #fff;
    font-size: 10.5px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.cy-badge-dot { min-width: 8px; width: 8px; height: 8px; padding: 0; }
.cy-badge-muted { background: var(--cy-surface-3); color: var(--cy-text-3); }
.cy-dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--cy-text-5); flex: none; }
.cy-dot-success { background: var(--cy-success); } .cy-dot-warning { background: var(--cy-warning); }
.cy-dot-danger { background: var(--cy-danger); } .cy-dot-primary { background: var(--cy-primary); }

/* 筛选/开关型胶囊（对应旧的 .nf-chip / .oal-switch 家族里的选择器） */
.cy-chip {
    display: inline-flex; align-items: center; gap: 5px; height: 28px; padding: 0 var(--cy-s-5);
    border: 1px solid var(--cy-line); border-radius: var(--cy-r-full); background: var(--cy-surface);
    color: var(--cy-text-3); font-size: var(--cy-fs-2); font-weight: 600; cursor: pointer; white-space: nowrap;
    transition: all var(--cy-dur) var(--cy-ease);
}
.cy-chip:hover { border-color: var(--cy-line-2); color: var(--cy-text-2); }
.cy-chip.is-on { background: var(--cy-primary); border-color: var(--cy-primary); color: #fff; }
.cy-chip b { font-size: var(--cy-fs-1); opacity: .8; font-variant-numeric: tabular-nums; }

/* 统计卡：数字为主、标签为辅，数字必须等宽 */
.cy-stat {
    display: flex; align-items: center; gap: var(--cy-s-5); padding: var(--cy-s-6);
    background: var(--cy-surface); border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-3);
    box-shadow: var(--cy-e-1);
}
.cy-stat-ic {
    display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; flex: none;
    border-radius: var(--cy-r-2); background: var(--cy-primary-soft); color: var(--cy-primary); font-size: 16px;
}
.cy-stat-v { font-size: var(--cy-fs-6); font-weight: 800; color: var(--cy-text); line-height: 1.15; font-variant-numeric: tabular-nums; }
.cy-stat-l { font-size: var(--cy-fs-2); color: var(--cy-text-4); margin-top: 2px; }
.cy-stat-success .cy-stat-ic { background: var(--cy-success-soft); color: var(--cy-success); }
.cy-stat-warning .cy-stat-ic { background: var(--cy-warning-soft); color: var(--cy-warning-ink); }
.cy-stat-danger .cy-stat-ic { background: var(--cy-danger-soft); color: var(--cy-danger); }

/* 键值详情：窄屏自动「标签在上、值在下」（固化 .mt-table 的经验） */
.cy-desc { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--cy-s-5) var(--cy-s-6); }
.cy-desc-item { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cy-desc-item--full { grid-column: 1 / -1; }
.cy-desc-k { font-size: var(--cy-fs-1); color: var(--cy-text-4); font-weight: 600; }
.cy-desc-v { font-size: var(--cy-fs-3); color: var(--cy-text); font-weight: 600; overflow-wrap: anywhere; }

.cy-divider { height: 1px; background: var(--cy-line-3); margin: var(--cy-s-6) 0; }
.cy-divider--v { width: 1px; height: auto; align-self: stretch; margin: 0; }

.cy-empty { padding: var(--cy-s-8); text-align: center; color: var(--cy-text-4); font-size: var(--cy-fs-3); }
.cy-empty > i { display: block; font-size: 26px; color: var(--cy-text-5); margin-bottom: var(--cy-s-3); }

/* 骨架屏只留一套实现：统一在后面「骨架族」一节定义（.cy-sk，.cy-skeleton 作别名同时生效），
   这里只保留动画帧 */
@keyframes cy-shimmer { to { transform: translateX(100%); } }

/* ==========================================================================
   卡片旋钮化：所有卡片的关键值都开了局部旋钮，组件自身只给默认值
   用法：<div class="cy-card" style="--cy-card-r:8px;--cy-card-pad:18px;--cy-card-bg:#fff"> 或自己写一个类覆盖这些旋钮
   ========================================================================== */
.cy-card {
    background: var(--cy-card-bg, var(--cy-surface));
    border: 1px solid var(--cy-card-line, var(--cy-line-3));
    border-radius: var(--cy-card-r, var(--cy-r-3));
    box-shadow: var(--cy-card-e, var(--cy-e-1));
}

/* ==========================================================================
   表单控件族（对齐 Material / Fluent / Cupertino 的控件目录）
   尺寸统一 -xs / 默认 / -lg；状态统一 .is-error .is-valid [disabled] [readonly]
   ========================================================================== */
/* —— 字段壳：label + 控件 + 提示/错误，一个容器包起 —— */
.cy-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.cy-field-label {
    display: flex; align-items: center; gap: 5px;
    font-size: var(--cy-fs-2); font-weight: 700; color: var(--cy-text-2);
}
.cy-field-label .cy-req { color: var(--cy-danger); font-weight: 800; }
.cy-field-hint { font-size: var(--cy-fs-1); color: var(--cy-text-4); }
.cy-field-err { font-size: var(--cy-fs-1); color: var(--cy-danger); display: none; }
.cy-field.is-error .cy-field-err { display: block; }
.cy-field.is-error .cy-field-hint { display: none; }
.cy-field--row { flex-direction: row; align-items: center; gap: var(--cy-s-5); }
.cy-field--row > .cy-field-label { flex: none; width: 92px; }
.cy-field--row > .cy-input, .cy-field--row > .cy-select { flex: 1 1 auto; min-width: 0; }
.cy-field--end { align-items: flex-end; }
.cy-field-lg { gap: 7px; }

/* —— 输入框 ——
   重点：必须 appearance:none 干掉 iOS/Safari 自带的灰底圆角，否则永远跟我们的框打架；
   手机下字号抬到 16px（iOS 遇 <16px 会聚焦自动放大页面，一放大就“越看越丑”） */
.cy-input {
    box-sizing: border-box; width: 100%; height: var(--cy-in-h, 38px); padding: 0 var(--cy-s-5);
    -webkit-appearance: none; appearance: none;
    border: 1px solid var(--cy-line); border-radius: var(--cy-in-r, var(--cy-r-2));
    background: var(--cy-in-bg, var(--cy-surface)); color: var(--cy-text);
    font-family: inherit; font-size: var(--cy-fs-3); line-height: 1.2; box-shadow: none;
    transition: border-color var(--cy-dur) var(--cy-ease), box-shadow var(--cy-dur) var(--cy-ease), background-color var(--cy-dur) var(--cy-ease);
}
.cy-input::placeholder { color: var(--cy-ph); opacity: 1; }
.cy-input:hover:not(:disabled):not(:focus) { border-color: var(--cy-line-2); }
.cy-input:focus { outline: none; border-color: var(--cy-primary); box-shadow: 0 0 0 3px var(--cy-focus-ring); }
.cy-input:disabled, .cy-input.is-readonly { background: var(--cy-surface-2); color: var(--cy-text-4); cursor: not-allowed; }
.cy-input-xs { height: 30px; font-size: var(--cy-fs-2); padding: 0 var(--cy-s-4); border-radius: var(--cy-r-1); }
.cy-input-lg { height: 44px; font-size: var(--cy-fs-4); padding: 0 var(--cy-s-6); border-radius: var(--cy-r-3); }
.cy-input-pill { border-radius: var(--cy-r-full); }
.cy-input-filled { background: var(--cy-surface-2); border-color: transparent; }
.cy-input-filled:focus { background: var(--cy-in-bg, var(--cy-surface)); border-color: var(--cy-primary); }
/* 表格内编辑 / 只看不可编的字段用，无框无底 */
.cy-input-plain { border-color: transparent; background: transparent; padding-left: 0; padding-right: 0; box-shadow: none !important; }
.cy-input-plain:focus { padding-left: var(--cy-s-4); padding-right: var(--cy-s-4); border-color: var(--cy-line); }
.cy-input-num { text-align: right; font-variant-numeric: tabular-nums; }
.cy-input-num::-webkit-outer-spin-button, .cy-input-num::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.cy-input-num[type=number] { -moz-appearance: textfield; appearance: textfield; }
.cy-input-code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: .3px; }
.cy-input.is-error, .cy-field.is-error .cy-input, .cy-field.is-error .cy-select, .cy-field.is-error .cy-textarea { border-color: var(--cy-danger); }
.cy-input.is-error:focus, .cy-field.is-error .cy-input:focus { box-shadow: 0 0 0 3px rgba(220, 38, 38, .14); }
.cy-input.is-valid { border-color: var(--cy-success); }
.cy-input.is-valid:focus { box-shadow: 0 0 0 3px rgba(5, 150, 105, .14); }
/* 带前后缀的包裹器：图标 / 单位 / 行内按钮都靠它定位 */
.cy-input-wrap { position: relative; display: flex; align-items: center; width: 100%; }
.cy-input-wrap > .cy-input { padding-left: 34px; }
.cy-input-wrap > .cy-input--noicon { padding-left: var(--cy-s-5); }
.cy-input-ic {
    position: absolute; left: var(--cy-s-5); display: flex; align-items: center; gap: 5px;
    color: var(--cy-text-4); font-size: 13px; pointer-events: none;
}
.cy-input-wrap--end > .cy-input { padding-left: var(--cy-s-5); padding-right: 62px; }
.cy-input-suffix {
    position: absolute; right: var(--cy-s-4); display: inline-flex; align-items: center; gap: 4px;
    font-size: var(--cy-fs-2); color: var(--cy-text-4);
}
.cy-input-suffix .cy-btn { height: 24px; padding: 0 7px; font-size: var(--cy-fs-1); }
/* 搜索框：清空 + 回车由 JS 接（data-cy-search） */
.cy-search { position: relative; display: flex; align-items: center; width: 100%; }
/* 搜索框默认胶囊形（项目里搜索区几乎都是胶囊） */
.cy-search > .cy-input { border-radius: var(--cy-r-full); padding-left: 36px; padding-right: 34px; }
.cy-search-square > .cy-input { border-radius: var(--cy-in-r, var(--cy-r-2)); }
.cy-search > .cy-input-ic { left: var(--cy-s-5); }

/* —— 原生日期/时间类输入（iOS、Safari 重灾区）——
   不写这几行就会：日期文字不跟随 color、右侧黑色darker图标、高度被内部撑乱、深色下图标看不见 */
.cy-input[type=date], .cy-input[type=time], .cy-input[type=datetime-local],
.cy-input[type=month], .cy-input[type=week] {
    min-width: 0; -webkit-appearance: none; appearance: none;
    font-family: inherit; font-variant-numeric: tabular-nums;
    /* iOS 26 Safari 对纯 appearance:none 仍会留系统底色/错色，显式兜底背景与文字色；
       text-align:left 压住 iOS 默认把日期值右对齐的怪癖 */
    background: var(--cy-in-bg, var(--cy-surface)); color: var(--cy-text); text-align: left;
}
.cy-input::-webkit-date-and-time-value { text-align: left; margin: 0; min-height: 1em; color: inherit; font: inherit; line-height: normal; }
.cy-input::-webkit-calendar-picker-indicator {
    -webkit-appearance: none; appearance: none; margin: 0; cursor: pointer;
    width: 16px; height: 16px; opacity: .5; border-radius: 4px;
    transition: opacity var(--cy-dur) var(--cy-ease), background-color var(--cy-dur) var(--cy-ease);
}
.cy-input:hover::-webkit-calendar-picker-indicator { opacity: .85; }
.cy-input::-webkit-calendar-picker-indicator:hover { opacity: 1; background-color: var(--cy-surface-3); }
[data-cy-skin="dark"] .cy-input::-webkit-calendar-picker-indicator { filter: invert(.82); }
/* 带 required 且还没选值的日期框：Safari 拿 yyyy/mm/日 占位，看着像报错 → 提亮成占位灰；选上就恢复正常文字色 */
.cy-input[type=date]:required:invalid, .cy-input[type=month]:required:invalid,
.cy-input[type=time]:required:invalid, .cy-input[type=datetime-local]:required:invalid { color: var(--cy-ph); }
.cy-input[type=date]:valid, .cy-input[type=month]:valid,
.cy-input[type=time]:valid, .cy-input[type=datetime-local]:valid { color: var(--cy-text); }
/* 自动填充：不默认蓝底（深色皮肤下会闪白） */
.cy-input:-webkit-autofill, .cy-select:-webkit-autofill, .cy-textarea:-webkit-autofill {
    -webkit-text-fill-color: var(--cy-text);
    -webkit-box-shadow: 0 0 0 1000px var(--cy-in-bg, var(--cy-surface)) inset;
    caret-color: var(--cy-text);
}

/* —— 起止区间输入（cy-rng）：两个输入 + 中间分隔 + 快捷周期，窄屏自动换行 */
.cy-rng { display: flex; align-items: center; gap: var(--cy-s-2); flex-wrap: wrap; }
.cy-rng > .cy-input { flex: 1 1 130px; min-width: 0; }
.cy-rng-sep { flex: none; color: var(--cy-text-4); font-size: var(--cy-fs-2); padding: 0 2px; }
.cy-rng-sm > .cy-input { height: 30px; font-size: var(--cy-fs-2); }
.cy-rng-field { position: relative; display: flex; align-items: center; flex: 1 1 150px; min-width: 0; }
.cy-rng-field > .cy-input { padding-left: 30px; }
.cy-rng-field > .cy-input-ic { left: var(--cy-s-4); font-size: 12px; }
.cy-rng-quick { display: inline-flex; gap: var(--cy-s-1); flex-wrap: wrap; }
.cy-rng-btn {
    border: 1px solid var(--cy-line); background: var(--cy-surface); color: var(--cy-text-3);
    height: 30px; padding: 0 var(--cy-s-3); border-radius: var(--cy-r-1); font-size: var(--cy-fs-1);
    font-weight: 700; cursor: pointer; white-space: nowrap;
}
.cy-rng-btn:hover { border-color: var(--cy-line-2); color: var(--cy-text); }
.cy-rng-btn.is-on { background: var(--cy-primary-soft); border-color: var(--cy-primary-soft-line); color: var(--cy-primary-ink); }
/* 日期区间（带图标、中间箭头）的紧凑形态，表格工具条常用 */
.cy-rng-pill {
    display: inline-flex; align-items: center; gap: var(--cy-s-2); padding: 0 var(--cy-s-4); height: 34px;
    border: 1px solid var(--cy-line); border-radius: var(--cy-r-full); background: var(--cy-surface); color: var(--cy-text-2);
    font-size: var(--cy-fs-2); font-weight: 600; font-variant-numeric: tabular-nums;
}
.cy-rng-pill > i { color: var(--cy-text-4); font-size: 12px; }
.cy-rng-pill-x { border: 0; background: transparent; color: var(--cy-text-4); cursor: pointer; padding: 2px; }

/* —— 下拉 / 多行 —— */
.cy-select {
    box-sizing: border-box; width: 100%; height: var(--cy-in-h, 38px); padding: 0 32px 0 var(--cy-s-5);
    -webkit-appearance: none; appearance: none;
    border: 1px solid var(--cy-line); border-radius: var(--cy-in-r, var(--cy-r-2));
    background-color: var(--cy-in-bg, var(--cy-surface));
    color: var(--cy-text); font-family: inherit; font-size: var(--cy-fs-3); cursor: pointer;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='3'><path d='M6 9l6 6 6-6'/></svg>");
    background-repeat: no-repeat; background-position: right var(--cy-s-4) center;
}
.cy-select:hover:not(:disabled) { border-color: var(--cy-line-2); }
.cy-select:disabled { background-color: var(--cy-surface-2); color: var(--cy-text-4); cursor: not-allowed; }
.cy-select:focus { outline: none; border-color: var(--cy-primary); box-shadow: 0 0 0 3px var(--cy-focus-ring); }
/* 深色皮肤下把系统画的小箭头也提亮，否则基本看不见 */
[data-cy-skin="dark"] .cy-select { background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='3'><path d='M6 9l6 6 6-6'/></svg>"); }
.cy-select-xs { height: 30px; font-size: var(--cy-fs-2); }
.cy-select-lg { height: 44px; font-size: var(--cy-fs-4); }
.cy-select-plain { border-color: transparent; background-color: transparent; padding-left: 0; background-position: right 0 center; }
.cy-textarea { min-height: 84px; padding: var(--cy-s-4) var(--cy-s-5); line-height: var(--cy-lh); resize: vertical; }
.cy-textarea-auto { resize: none; overflow-y: auto; }
.cy-textarea-sm { min-height: 58px; }
.cy-textarea-lg { min-height: 136px; }
/* 多行输入右下角拖把手在手机上没用，直接关掉 */
@media (max-width: 640px) {
    .cy-textarea { resize: none; }
}

/* —— 勾选 / 单选 / 开关 —— */
.cy-check, .cy-radio {
    display: inline-flex; align-items: center; gap: var(--cy-s-3); cursor: pointer;
    font-size: var(--cy-fs-3); color: var(--cy-text-2); user-select: none;
}
.cy-check input, .cy-radio input { position: absolute; opacity: 0; width: 0; height: 0; }
.cy-check-box {
    flex: none; width: 18px; height: 18px; border: 1.5px solid var(--cy-line-2); border-radius: 5px;
    background: var(--cy-surface); display: inline-flex; align-items: center; justify-content: center;
    color: #fff; font-size: 11px; transition: all var(--cy-dur) var(--cy-ease);
}
.cy-check-box::after { content: "\2713"; opacity: 0; transform: scale(.6); transition: all var(--cy-dur) var(--cy-ease); }
.cy-check input:checked + .cy-check-box { background: var(--cy-primary); border-color: var(--cy-primary); }
.cy-check input:checked + .cy-check-box::after { opacity: 1; transform: scale(1); }
.cy-check input:indeterminate + .cy-check-box { background: var(--cy-primary); border-color: var(--cy-primary); }
.cy-check input:indeterminate + .cy-check-box::after { content: "\2212"; opacity: 1; transform: none; }
.cy-radio-box {
    flex: none; width: 18px; height: 18px; border: 1.5px solid var(--cy-line-2); border-radius: 50%;
    background: var(--cy-surface); display: inline-flex; align-items: center; justify-content: center;
    transition: all var(--cy-dur) var(--cy-ease);
}
.cy-radio-box::after { content: ""; width: 8px; height: 8px; border-radius: 50%; background: #fff; transform: scale(.4); opacity: 0; transition: all var(--cy-dur) var(--cy-ease); }
.cy-radio input:checked + .cy-radio-box { background: var(--cy-primary); border-color: var(--cy-primary); }
.cy-radio input:checked + .cy-radio-box::after { transform: scale(1); opacity: 1; }
.cy-check input:focus-visible + .cy-check-box, .cy-radio input:focus-visible + .cy-radio-box { outline: 2px solid var(--cy-primary); outline-offset: 2px; }
.cy-check[style*='pointer'] , .cy-check.is-block, .cy-radio.is-block { display: flex; width: 100%; padding: var(--cy-s-3) var(--cy-s-4); border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2); box-sizing: border-box; /* 同 .cy-switch-row（1573 行）的坑：本文件不做全局 reset，不补 border-box 时 width:100% + 内距 + 边框会超出父容器（手机上整行勾选冲破卡片） */ }
.cy-check.is-block:has(input:checked), .cy-radio.is-block:has(input:checked) { border-color: var(--cy-primary); background: var(--cy-primary-soft); }
.cy-check-xs .cy-check-box, .cy-radio-xs .cy-radio-box { width: 15px; height: 15px; }
.cy-check-lg .cy-check-box, .cy-radio-lg .cy-radio-box { width: 22px; height: 22px; }

.cy-switch { position: relative; display: inline-flex; align-items: center; gap: var(--cy-s-3); cursor: pointer; user-select: none; flex: none; }
.cy-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.cy-switch-tr {
    flex: none; width: 40px; height: 23px; border-radius: var(--cy-r-full); background: var(--cy-line-2);
    position: relative; transition: background-color var(--cy-dur) var(--cy-ease);
}
.cy-switch-tr::after {
    content: ""; position: absolute; top: 2px; left: 2px; width: 19px; height: 19px; border-radius: 50%;
    background: #fff; box-shadow: var(--cy-e-2); transition: transform var(--cy-dur) var(--cy-ease);
}
.cy-switch input:checked + .cy-switch-tr { background: var(--cy-success); }
.cy-switch input:checked + .cy-switch-tr::after { transform: translateX(17px); }
.cy-switch-primary input:checked + .cy-switch-tr { background: var(--cy-primary); }
.cy-switch-xs .cy-switch-tr { width: 32px; height: 18px; }
.cy-switch-xs .cy-switch-tr::after { width: 14px; height: 14px; }
.cy-switch-xs input:checked + .cy-switch-tr::after { transform: translateX(14px); }
.cy-switch-lg .cy-switch-tr { width: 50px; height: 28px; }
.cy-switch-lg .cy-switch-tr::after { width: 24px; height: 24px; }
.cy-switch-lg input:checked + .cy-switch-tr::after { transform: translateX(22px); }
.cy-switch input:focus-visible + .cy-switch-tr { outline: 2px solid var(--cy-primary); outline-offset: 2px; }

/* —— 滑块 / 步进器 / 评分 / 分段器 —— */
.cy-slider { width: 100%; height: 22px; appearance: none; background: transparent; cursor: pointer; }
.cy-slider::-webkit-slider-runnable-track { height: 4px; border-radius: 2px; background: var(--cy-line); }
.cy-slider::-webkit-slider-thumb {
    appearance: none; width: 16px; height: 16px; margin-top: -6px; border-radius: 50%;
    background: var(--cy-primary); border: 2px solid #fff; box-shadow: var(--cy-e-2);
}
.cy-slider::-moz-range-track { height: 4px; border-radius: 2px; background: var(--cy-line); }
.cy-slider::-moz-range-thumb { width: 14px; height: 14px; border-radius: 50%; background: var(--cy-primary); border: 2px solid #fff; }
.cy-slider-success::-webkit-slider-thumb, .cy-slider-success::-moz-range-thumb { background: var(--cy-success); }
.cy-slider-danger::-webkit-slider-thumb, .cy-slider-danger::-moz-range-thumb { background: var(--cy-danger); }

/* 步进器：不再用 overflow:hidden 裁圆角（Safari 会漏角，而且会把聚焦外环一起切掉），
   改成首尾子元素各自设圆角 + 聚焦环画在容器上；按钮与数字之间补分隔线，否则“− 5 +”糊成一团 */
.cy-stepper {
    display: inline-flex; align-items: stretch; height: var(--cy-in-h, 38px);
    border: 1px solid var(--cy-line); border-radius: var(--cy-in-r, var(--cy-r-2));
    background: var(--cy-surface); overflow: visible;
    transition: border-color var(--cy-dur) var(--cy-ease), box-shadow var(--cy-dur) var(--cy-ease);
}
.cy-stepper:focus-within { border-color: var(--cy-primary); box-shadow: 0 0 0 3px var(--cy-focus-ring); }
.cy-stepper > .cy-input {
    border: 0; border-radius: 0; text-align: center; width: 54px; height: 100%;
    padding: 0; box-shadow: none !important; background: transparent;
    font-variant-numeric: tabular-nums; font-weight: 700;
}
.cy-stepper-btn {
    border: 0; background: transparent; color: var(--cy-text-3); width: 32px; cursor: pointer;
    font-size: 13px; display: flex; align-items: center; justify-content: center;
    transition: background-color var(--cy-dur) var(--cy-ease), color var(--cy-dur) var(--cy-ease);
}
.cy-stepper-btn:first-child { border-right: 1px solid var(--cy-line-3); border-radius: var(--cy-in-r, var(--cy-r-2)) 0 0 var(--cy-in-r, var(--cy-r-2)); }
.cy-stepper-btn:last-child { border-left: 1px solid var(--cy-line-3); border-radius: 0 var(--cy-in-r, var(--cy-r-2)) var(--cy-in-r, var(--cy-r-2)) 0; }
.cy-stepper-btn:hover { background: var(--cy-surface-3); color: var(--cy-primary); }
.cy-stepper-btn:active { background: var(--cy-primary-soft); }
.cy-stepper-btn:disabled { color: var(--cy-text-5); background: transparent; cursor: not-allowed; }
.cy-stepper-unit { display: flex; align-items: center; padding: 0 var(--cy-s-4); border-left: 1px solid var(--cy-line-3); color: var(--cy-text-4); font-size: var(--cy-fs-2); font-weight: 700; }
.cy-stepper-sm { height: 30px; font-size: var(--cy-fs-2); } .cy-stepper-sm .cy-stepper-btn { width: 26px; }
.cy-stepper-lg { height: 44px; } .cy-stepper-lg .cy-stepper-btn { width: 40px; font-size: 15px; }
.cy-stepper-round { border-radius: var(--cy-r-full); }
.cy-stepper-round .cy-stepper-btn:first-child { border-radius: var(--cy-r-full) 0 0 var(--cy-r-full); }
.cy-stepper-round .cy-stepper-btn:last-child { border-radius: 0 var(--cy-r-full) var(--cy-r-full) 0; }
.cy-stepper-tonal { border-color: transparent; background: var(--cy-surface-2); }
.cy-stepper-tonal > .cy-input { background: transparent; }
.cy-stepper-vertical { flex-direction: column; height: auto; width: 54px; }
.cy-stepper-vertical .cy-stepper-btn:first-child { border-right: 0; border-bottom: 1px solid var(--cy-line-3); border-radius: var(--cy-in-r, var(--cy-r-2)) var(--cy-in-r, var(--cy-r-2)) 0 0; }
.cy-stepper-vertical .cy-stepper-btn:last-child { border-left: 0; border-top: 1px solid var(--cy-line-3); border-radius: 0 0 var(--cy-in-r, var(--cy-r-2)) var(--cy-in-r, var(--cy-r-2)); }
.cy-stepper.is-disabled, .cy-stepper[disabled] { background: var(--cy-surface-2); opacity: .7; }

.cy-segmented { display: inline-flex; padding: 3px; gap: 2px; background: var(--cy-surface-3); border-radius: var(--cy-r-2); }
.cy-segmented-item {
    border: 0; background: transparent; color: var(--cy-text-3); border-radius: var(--cy-r-1);
    padding: 0 var(--cy-s-5); height: 28px; font-size: var(--cy-fs-2); font-weight: 700; cursor: pointer;
    display: inline-flex; align-items: center; gap: 5px; transition: all var(--cy-dur) var(--cy-ease);
}
.cy-segmented-item:hover { color: var(--cy-text); }
.cy-segmented-item.is-on { background: var(--cy-surface); color: var(--cy-primary); box-shadow: var(--cy-e-1); }
.cy-segmented-lg { padding: 4px; }
.cy-segmented-lg .cy-segmented-item { height: 34px; font-size: var(--cy-fs-3); }
.cy-segmented-block { display: flex; width: 100%; }
.cy-segmented-block .cy-segmented-item { flex: 1; justify-content: center; }

.cy-rating { display: inline-flex; gap: 2px; color: var(--cy-warning); font-size: 16px; cursor: pointer; }
.cy-rating.is-readonly { cursor: default; }
.cy-rating i { color: var(--cy-line-2); transition: color var(--cy-dur) var(--cy-ease); }
.cy-rating i.on { color: var(--cy-warning); }
.cy-rating-sm { font-size: 13px; }

/* —— 文件拖放区 / 密码可见 / 字数统计 —— */
.cy-dropzone {
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
    min-height: 108px; padding: var(--cy-s-7); border: 1.5px dashed var(--cy-line-2);
    border-radius: var(--cy-r-3); background: var(--cy-surface-2); color: var(--cy-text-3);
    font-size: var(--cy-fs-3); cursor: pointer; text-align: center;
    transition: all var(--cy-dur) var(--cy-ease);
}
.cy-dropzone:hover, .cy-dropzone.is-over { border-color: var(--cy-primary); background: var(--cy-primary-soft); color: var(--cy-primary-ink); }
.cy-dropzone > i { font-size: 22px; color: var(--cy-text-4); }
.cy-dropzone.is-busy { pointer-events: none; opacity: .7; }
.cy-count { font-size: var(--cy-fs-1); color: var(--cy-text-5); font-variant-numeric: tabular-nums; }
.cy-count.is-over { color: var(--cy-danger); }

/* ==========================================================================
   反馈：横幅 / 提示条 / 气泡 / 菜单 / 进度 / 微标
   ========================================================================== */
.cy-alert {
    display: flex; align-items: flex-start; gap: var(--cy-s-4); padding: var(--cy-s-5) var(--cy-s-6);
    border-radius: var(--cy-r-2); background: var(--cy-surface-2); border: 1px solid var(--cy-line-3);
    color: var(--cy-text-2); font-size: var(--cy-fs-3); line-height: var(--cy-lh);
}
.cy-alert > i:first-child { margin-top: 2px; font-size: 14px; color: var(--cy-text-3); }
.cy-alert-body { flex: 1; min-width: 0; }
.cy-alert-t { display: block; font-weight: 700; color: var(--cy-text); margin-bottom: 2px; }
.cy-alert-x { border: 0; background: transparent; color: var(--cy-text-4); cursor: pointer; font-size: 12px; padding: 2px; }
.cy-alert-info { background: var(--cy-info-soft); border-color: var(--cy-info-soft-line); color: var(--cy-info-ink); }
.cy-alert-info > i:first-child { color: var(--cy-info); }
.cy-alert-success { background: var(--cy-success-soft); border-color: var(--cy-success-soft-line); color: var(--cy-success-ink); }
.cy-alert-success > i:first-child { color: var(--cy-success); }
.cy-alert-warning { background: var(--cy-warning-soft); border-color: var(--cy-warning-soft-line); color: var(--cy-warning-ink); }
.cy-alert-warning > i:first-child { color: var(--cy-warning); }
.cy-alert-danger { background: var(--cy-danger-soft); border-color: var(--cy-danger-soft-line); color: var(--cy-danger-ink); }
.cy-alert-danger > i:first-child { color: var(--cy-danger); }
.cy-alert-sm { padding: var(--cy-s-3) var(--cy-s-4); font-size: var(--cy-fs-2); }
.cy-alert-lg { padding: var(--cy-s-6) var(--cy-s-7); font-size: var(--cy-fs-4); }
.cy-alert-elevated { border-color: transparent; box-shadow: var(--cy-e-3); }
.cy-alert-left { border-left: 3px solid currentColor; border-radius: 0 var(--cy-r-2) var(--cy-r-2) 0; }
.cy-alert-inline { border-radius: var(--cy-r-1); }
/* 表单校验/结果用的小提示条（不带图标也可） */
.cy-snack {
    display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px; border-radius: var(--cy-r-full);
    font-size: var(--cy-fs-1); font-weight: 700; background: var(--cy-surface-3); color: var(--cy-text-3);
}
.cy-snack-success { background: var(--cy-success-soft); color: var(--cy-success-ink); }
.cy-snack-warning { background: var(--cy-warning-soft); color: var(--cy-warning-ink); }
.cy-snack-danger { background: var(--cy-danger-soft); color: var(--cy-danger-ink); }
.cy-snack-primary { background: var(--cy-primary-soft); color: var(--cy-primary-ink); }

/* 进度：线性 + 圆形（圆形就是项目里已定的 MD 风格不确定态圆圈） */
.cy-progress { height: 6px; border-radius: var(--cy-r-full); background: var(--cy-surface-3); overflow: hidden; }
.cy-progress-bar { height: 100%; border-radius: var(--cy-r-full); background: var(--cy-primary); transition: width .25s var(--cy-ease); }
.cy-progress-xs { height: 3px; }
.cy-progress-lg { height: 10px; }
.cy-progress-success .cy-progress-bar { background: var(--cy-success); }
.cy-progress-warning .cy-progress-bar { background: var(--cy-warning); }
.cy-progress-danger .cy-progress-bar { background: var(--cy-danger); }
.cy-progress-strip .cy-progress-bar {
    background-image: repeating-linear-gradient(45deg, rgba(255, 255, 255, .22) 0 6px, transparent 6px 12px);
    animation: cy-stripes .8s linear infinite;
}
@keyframes cy-stripes { to { background-position: 17px 0; } }
.cy-spin {
    display: inline-block; width: 16px; height: 16px; border-radius: 50%; flex: none;
    border: 2px solid currentColor; border-top-color: transparent; animation: cy-spin-k .75s linear infinite;
    color: var(--cy-text-4);
}
@keyframes cy-spin-k { to { transform: rotate(360deg); } }
.cy-spin-primary { color: var(--cy-primary); } .cy-spin-light { color: rgba(255, 255, 255, .9); }
.cy-spin-sm { width: 12px; height: 12px; border-width: 2px; }
.cy-spin-lg { width: 26px; height: 26px; border-width: 3px; }
.cy-spin-xl { width: 38px; height: 38px; border-width: 3px; }

/* 气泡提示：纯 CSS，属性驱动（data-cy-tip="文案"），不需要 JS 也能用 */
[data-cy-tip] { position: relative; }
[data-cy-tip]::after {
    content: attr(data-cy-tip); position: absolute; bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%) scale(.96);
    padding: 5px 9px; border-radius: var(--cy-r-1); background: rgba(15, 23, 42, .92); color: #fff;
    font-size: var(--cy-fs-1); font-weight: 600; white-space: nowrap; pointer-events: none; opacity: 0;
    transition: opacity var(--cy-dur) var(--cy-ease), transform var(--cy-dur) var(--cy-ease); z-index: var(--cy-z-toast);
}
[data-cy-tip]:hover::after, [data-cy-tip]:focus-visible::after { opacity: 1; transform: translateX(-50%) scale(1); }
[data-cy-tip=""]::after { display: none; }
/* 逃生口：祖先（如 .cy-dialog、滚动的 .cy-dialog-body）把气泡裁了又不方便改结构时，给那个容器挂上 */
.cy-no-clip { overflow: visible !important; }
.cy-tip-multiline::after { white-space: normal; width: 190px; text-align: center; line-height: 1.4; }
[data-cy-tip-pos="bottom"]::after { bottom: auto; top: calc(100% + 6px); }
[data-cy-tip-pos="left"]::after { bottom: auto; top: 50%; left: auto; right: calc(100% + 6px); transform: translateY(-50%); }
[data-cy-tip-pos="right"]::after { bottom: auto; top: 50%; left: calc(100% + 6px); transform: translateY(-50%); }
/* 边界翻转对齐变体（由 cyui.js 按视口位置写入 data-cy-tip-pos）：top/bottom 不再居中，改贴宿主左/右缘，
   避免顶栏/屏边按钮的气泡被浏览器边界切掉。纯 CSS 无法感知视口，必须 JS 兜底（见 cy.bind 里的 tipFlip）。 */
[data-cy-tip-pos="top-start"]::after,
[data-cy-tip-pos="bottom-start"]::after { left: 0; transform: scale(.96); }
[data-cy-tip-pos="top-end"]::after,
[data-cy-tip-pos="bottom-end"]::after { left: auto; right: 0; transform: scale(.96); }
[data-cy-tip-pos="bottom-start"]::after,
[data-cy-tip-pos="bottom-end"]::after { bottom: auto; top: calc(100% + 6px); }
[data-cy-tip-pos="top-start"]:hover::after,
[data-cy-tip-pos="bottom-start"]:hover::after,
[data-cy-tip-pos="top-end"]:hover::after,
[data-cy-tip-pos="bottom-end"]:hover::after { transform: scale(1); }

/* 浮动菜单 / 下拉面板（JS 只负责定位与开关，样式全在这） */
.cy-menu {
    position: fixed; z-index: var(--cy-z-modal-top); min-width: 168px; padding: var(--cy-s-2);
    background: var(--cy-surface); border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2);
    box-shadow: var(--cy-e-4); opacity: 0; transform: translateY(-4px) scale(.98); pointer-events: none;
    transition: opacity var(--cy-dur) var(--cy-ease), transform var(--cy-dur) var(--cy-ease);
}
.cy-menu.is-open { opacity: 1; transform: none; pointer-events: auto; }
.cy-menu-item {
    box-sizing: border-box;
    display: flex; align-items: center; gap: var(--cy-s-4); width: 100%; padding: 7px var(--cy-s-4);
    border: 0; border-radius: var(--cy-r-1); background: transparent; color: var(--cy-text-2);
    font-size: var(--cy-fs-3); font-weight: 600; cursor: pointer; text-align: left; text-decoration: none;
}
.cy-menu-item > i:first-child { width: 15px; text-align: center; color: var(--cy-text-4); font-size: 12.5px; }
.cy-menu-item:hover { background: var(--cy-surface-2); color: var(--cy-text); }
.cy-menu-item.is-on { background: var(--cy-primary-soft); color: var(--cy-primary-ink); }
.cy-menu-item.is-on > i:first-child { color: var(--cy-primary); }
.cy-menu-item-danger { color: var(--cy-danger); }
.cy-menu-item-danger:hover { background: var(--cy-danger-soft); color: var(--cy-danger-ink); }
.cy-menu-item-danger > i:first-child { color: var(--cy-danger); }
.cy-menu-h { padding: var(--cy-s-3) var(--cy-s-4) var(--cy-s-2); font-size: var(--cy-fs-1); font-weight: 800; color: var(--cy-text-4); letter-spacing: .3px; }
.cy-menu-m { margin-left: auto; padding-left: var(--cy-s-5); font-size: var(--cy-fs-1); color: var(--cy-text-5); font-variant-numeric: tabular-nums; }
.cy-menu-sep { height: 1px; background: var(--cy-line-3); margin: var(--cy-s-2) var(--cy-s-3); }
.cy-menu-wide { min-width: 244px; }

/* 徽标环 / 可移除标签 / 头像组 */
.cy-badge-ring { box-shadow: 0 0 0 2px var(--cy-surface); }
.cy-tag-x { margin-left: 2px; opacity: .65; cursor: pointer; font-size: 9px; }
.cy-tag-x:hover { opacity: 1; }
.cy-avatar {
    display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px;
    border-radius: 50%; background: var(--cy-primary-soft); color: var(--cy-primary-ink);
    font-size: var(--cy-fs-3); font-weight: 800; flex: none; overflow: hidden; user-select: none;
}
.cy-avatar img { width: 100%; height: 100%; object-fit: cover; }
.cy-avatar-xs { width: 22px; height: 22px; font-size: var(--cy-fs-1); }
.cy-avatar-sm { width: 26px; height: 26px; font-size: var(--cy-fs-2); }
.cy-avatar-lg { width: 44px; height: 44px; font-size: var(--cy-fs-5); }
.cy-avatar-xl { width: 62px; height: 62px; font-size: 22px; }
.cy-avatar-square { border-radius: var(--cy-r-2); }
.cy-avatar-success { background: var(--cy-success-soft); color: var(--cy-success-ink); }
.cy-avatar-warning { background: var(--cy-warning-soft); color: var(--cy-warning-ink); }
.cy-avatar-danger { background: var(--cy-danger-soft); color: var(--cy-danger-ink); }
.cy-avatar-group { display: inline-flex; }
.cy-avatar-group .cy-avatar { box-shadow: 0 0 0 2px var(--cy-surface); margin-left: -8px; }
.cy-avatar-group .cy-avatar:first-child { margin-left: 0; }

/* 键盘键帽 / 行内代码 */
.cy-kbd {
    display: inline-flex; align-items: center; min-width: 20px; height: 20px; padding: 0 5px;
    border: 1px solid var(--cy-line); border-bottom-width: 2px; border-radius: var(--cy-r-1);
    background: var(--cy-surface-2); color: var(--cy-text-3);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 10.5px; font-weight: 700;
}
.cy-code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .92em;
    padding: 1px 5px; border-radius: var(--cy-r-1); background: var(--cy-surface-3); color: var(--cy-text-2);
}

/* ==========================================================================
   导航：顶栏 / 页签 / 侧栏 / 分页 / 步骤 / 时间轴 / 底部导航 / 浮动按钮
   ========================================================================== */
.cy-appbar {
    position: sticky; top: 0; z-index: var(--cy-z-sticky); display: flex; align-items: center; gap: var(--cy-s-5);
    height: 56px; padding: 0 var(--cy-s-6); background: var(--cy-surface);
    border-bottom: 1px solid var(--cy-line-3);
}
.cy-appbar-title { font-size: var(--cy-fs-5); font-weight: 800; color: var(--cy-text); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cy-appbar-sub { font-size: var(--cy-fs-1); color: var(--cy-text-4); font-weight: 500; }
.cy-appbar-actions { margin-left: auto; display: inline-flex; align-items: center; gap: var(--cy-s-3); flex: none; }
.cy-appbar-elevated { border-bottom: 0; box-shadow: var(--cy-e-3); }
.cy-appbar-compact { height: 46px; }
.cy-appbar-transparent { background: transparent; border-bottom: 0; }
.cy-appbar-primary { background: var(--cy-primary); border-bottom: 0; color: #fff; }
.cy-appbar-primary .cy-appbar-title, .cy-appbar-primary .cy-appbar-sub { color: #fff; }

.cy-tabs { display: flex; align-items: center; gap: var(--cy-s-6); border-bottom: 1px solid var(--cy-line); position: relative; }
.cy-tab {
    border: 0; background: transparent; padding: 10px 2px; font-size: var(--cy-fs-3); font-weight: 700;
    color: var(--cy-text-3); cursor: pointer; position: relative; white-space: nowrap; display: inline-flex; align-items: center; gap: 5px;
}
.cy-tab:hover { color: var(--cy-text); }
.cy-tab.is-on { color: var(--cy-primary); }
.cy-tab.is-on::after { content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px; border-radius: 2px; background: var(--cy-primary); }
.cy-tab-cnt { font-size: var(--cy-fs-1); color: var(--cy-text-4); font-weight: 700; }
.cy-tabs-pill { gap: var(--cy-s-2); border-bottom: 0; }
.cy-tabs-pill .cy-tab { padding: 7px var(--cy-s-5); border-radius: var(--cy-r-2); }
.cy-tabs-pill .cy-tab.is-on { background: var(--cy-primary); color: #fff; }
.cy-tabs-pill .cy-tab.is-on::after { display: none; }
.cy-tabs-scroll { overflow-x: auto; scrollbar-width: none; }
.cy-tabs-scroll::-webkit-scrollbar { display: none; }
.cy-tabs-center { justify-content: center; }
.cy-tab-panel { display: none; }
.cy-tab-panel.is-on { display: block; }

.cy-nav { display: flex; flex-direction: column; gap: 2px; }
.cy-nav-h { padding: var(--cy-s-5) var(--cy-s-5) var(--cy-s-2); font-size: var(--cy-fs-1); font-weight: 800; color: var(--cy-text-4); letter-spacing: .4px; }
.cy-nav-item {
    display: flex; align-items: center; gap: var(--cy-s-4); padding: 8px var(--cy-s-5); border-radius: var(--cy-r-2);
    font-size: var(--cy-fs-3); font-weight: 600; color: var(--cy-text-2); cursor: pointer; text-decoration: none;
    transition: background-color var(--cy-dur) var(--cy-ease), color var(--cy-dur) var(--cy-ease);
}
.cy-nav-item > i:first-child { width: 17px; text-align: center; color: var(--cy-text-4); font-size: 13px; }
.cy-nav-item:hover { background: var(--cy-surface-2); color: var(--cy-text); }
.cy-nav-item.is-on { background: var(--cy-primary-soft); color: var(--cy-primary-ink); }
.cy-nav-item.is-on > i:first-child { color: var(--cy-primary); }
.cy-nav-item .cy-spacer { min-width: 0; }
.cy-nav-dense .cy-nav-item { padding: 5px var(--cy-s-4); font-size: var(--cy-fs-2); }

.cy-pager { display: inline-flex; align-items: center; gap: var(--cy-s-2); flex-wrap: wrap; }
.cy-pager-btn {
    min-width: 30px; height: 30px; padding: 0 var(--cy-s-3); border: 1px solid var(--cy-line); border-radius: var(--cy-r-1);
    background: var(--cy-surface); color: var(--cy-text-3); font-size: var(--cy-fs-2); font-weight: 700; cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center; font-variant-numeric: tabular-nums;
}
.cy-pager-btn:hover:not(:disabled) { border-color: var(--cy-line-2); color: var(--cy-text); }
.cy-pager-btn.is-on { background: var(--cy-primary); border-color: var(--cy-primary); color: #fff; }
.cy-pager-btn:disabled { opacity: .45; cursor: not-allowed; }
.cy-pager-info { font-size: var(--cy-fs-2); color: var(--cy-text-4); padding: 0 var(--cy-s-2); }

/* 步骤条（水平）：done / 当前 / 未到三态 */
.cy-steps { display: flex; align-items: flex-start; gap: 0; counter-reset: cy-step; }
.cy-step { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 5px; position: relative; text-align: center; }
.cy-step-dot {
    width: 26px; height: 26px; border-radius: 50%; background: var(--cy-surface-3); color: var(--cy-text-4);
    border: 1px solid var(--cy-line); display: flex; align-items: center; justify-content: center;
    font-size: var(--cy-fs-1); font-weight: 800; position: relative; z-index: 1;
}
.cy-step::before, .cy-step::after { content: ""; position: absolute; top: 13px; height: 2px; background: var(--cy-line-3); width: 50%; }
.cy-step::before { left: 0; } .cy-step::after { right: 0; }
.cy-step:first-child::before, .cy-step:last-child::after { display: none; }
.cy-step-t { font-size: var(--cy-fs-2); font-weight: 700; color: var(--cy-text-3); }
.cy-step-s { font-size: var(--cy-fs-1); color: var(--cy-text-5); }
.cy-step.is-done .cy-step-dot { background: var(--cy-success); border-color: var(--cy-success); color: #fff; }
.cy-step.is-done .cy-step-dot::after { content: "\2713"; font-size: 12px; }
.cy-step.is-done .cy-step-dot { font-size: 0; }
.cy-step.is-on .cy-step-dot { background: var(--cy-primary); border-color: var(--cy-primary); color: #fff; }
.cy-step.is-on .cy-step-t { color: var(--cy-primary); }
.cy-step.is-error .cy-step-dot { background: var(--cy-danger-soft); border-color: var(--cy-danger); color: var(--cy-danger); }

/* 时间轴：日志/节点推进类 */
.cy-tl { position: relative; padding-left: 22px; display: flex; flex-direction: column; gap: var(--cy-s-6); }
.cy-tl::before { content: ""; position: absolute; left: 5px; top: 4px; bottom: 4px; width: 2px; background: var(--cy-line-3); }
.cy-tl-item { position: relative; }
.cy-tl-item::before { content: ""; position: absolute; left: -21px; top: 4px; width: 10px; height: 10px; border-radius: 50%; background: var(--cy-surface); border: 2px solid var(--cy-line-2); }
.cy-tl-item.is-on::before { background: var(--cy-primary); border-color: var(--cy-primary); }
.cy-tl-item.is-success::before { background: var(--cy-success); border-color: var(--cy-success); }
.cy-tl-item.is-danger::before { background: var(--cy-danger); border-color: var(--cy-danger); }
.cy-tl-t { font-size: var(--cy-fs-3); font-weight: 700; color: var(--cy-text); }
.cy-tl-d { font-size: var(--cy-fs-1); color: var(--cy-text-4); margin-top: 1px; }
.cy-tl-b { font-size: var(--cy-fs-2); color: var(--cy-text-3); margin-top: 4px; line-height: var(--cy-lh); }

/* 底部导航（移动主场景）+ 浮动按钮 */
.cy-bnav {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--cy-z-drawer); display: flex;
    background: var(--cy-surface); border-top: 1px solid var(--cy-line-3); padding-bottom: env(safe-area-inset-bottom, 0);
}
.cy-bnav-item {
    flex: 1; border: 0; background: transparent; padding: 7px 0 6px; display: flex; flex-direction: column;
    align-items: center; gap: 3px; font-size: 10.5px; font-weight: 700; color: var(--cy-text-4); cursor: pointer; position: relative;
}
.cy-bnav-item > i { font-size: 16px; }
.cy-bnav-item.is-on { color: var(--cy-primary); }
.cy-bnav-item .cy-badge { position: absolute; top: 3px; right: 24%; }
.cy-fab {
    display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: 50px; min-width: 50px;
    padding: 0 var(--cy-s-7); border: 0; border-radius: var(--cy-r-3); background: var(--cy-primary); color: #fff;
    font-size: var(--cy-fs-4); font-weight: 700; cursor: pointer; box-shadow: var(--cy-e-4);
}
.cy-fab:hover { background: var(--cy-primary-hover); }
.cy-fab-sm { height: 40px; min-width: 40px; padding: 0 var(--cy-s-5); font-size: var(--cy-fs-3); }
.cy-fab-circle { width: 50px; padding: 0; border-radius: 50%; }
.cy-fab-danger { background: var(--cy-danger); } .cy-fab-success { background: var(--cy-success); }

/* ==========================================================================
   数据展示：列表 / 表格 / 区块标题 / 工具条 / 设置行
   ========================================================================== */
.cy-list { display: flex; flex-direction: column; background: var(--cy-surface); border-radius: var(--cy-card-r, var(--cy-r-3)); }
/* 行容器不裁剪，否则行内操作钮的气泡出不来；圆角改给首尾行自己 */
.cy-list > :first-child { border-top-left-radius: var(--cy-card-r, var(--cy-r-3)); border-top-right-radius: var(--cy-card-r, var(--cy-r-3)); }
.cy-list > :last-child { border-bottom-left-radius: var(--cy-card-r, var(--cy-r-3)); border-bottom-right-radius: var(--cy-card-r, var(--cy-r-3)); }
.cy-list-outlined { border: 1px solid var(--cy-line-3); }
.cy-list-divided > .cy-li + .cy-li { border-top: 1px solid var(--cy-line-3); }
.cy-li {
    display: flex; align-items: center; gap: var(--cy-s-5); padding: var(--cy-s-5) var(--cy-s-6);
    color: var(--cy-text-2); font-size: var(--cy-fs-3); cursor: default; text-decoration: none;
}
.cy-li > i:first-child { width: 20px; text-align: center; color: var(--cy-text-4); font-size: 15px; flex: none; }
.cy-li-main { flex: 1 1 auto; min-width: 0; }
.cy-li-t { font-size: var(--cy-fs-4); font-weight: 700; color: var(--cy-text); line-height: 1.35; }
.cy-li-d { font-size: var(--cy-fs-2); color: var(--cy-text-4); margin-top: 2px; line-height: 1.4; }
.cy-li-meta { font-size: var(--cy-fs-2); color: var(--cy-text-4); font-weight: 600; flex: none; font-variant-numeric: tabular-nums; text-align: right; }
.cy-li-act { display: inline-flex; align-items: center; gap: var(--cy-s-2); flex: none; }
.cy-li-click { cursor: pointer; }
.cy-li-click:hover { background: var(--cy-surface-2); }
.cy-li.is-on { background: var(--cy-primary-soft); }
.cy-li-danger { color: var(--cy-danger); } .cy-li-danger > i:first-child { color: var(--cy-danger); }
.cy-list-dense .cy-li { padding: var(--cy-s-3) var(--cy-s-5); }
.cy-list-set .cy-li { border-bottom: 1px solid var(--cy-line-3); }
.cy-list-set .cy-li:last-child { border-bottom: 0; }
.cy-li-grid { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; }

.cy-table { width: 100%; border-collapse: collapse; font-size: var(--cy-fs-3); background: var(--cy-surface); }
.cy-table th, .cy-table td { padding: var(--cy-s-4) var(--cy-s-5); text-align: left; border-bottom: 1px solid var(--cy-line-3); color: var(--cy-text-2); }
.cy-table th { font-size: var(--cy-fs-1); font-weight: 800; color: var(--cy-text-4); background: var(--cy-surface-2); white-space: nowrap; }
.cy-table-zebra tbody tr:nth-child(even) { background: var(--cy-surface-2); }
.cy-table-hover tbody tr:hover { background: var(--cy-primary-soft); }
.cy-table-dense th, .cy-table-dense td { padding: var(--cy-s-2) var(--cy-s-4); }
.cy-table-outlined { border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2); }
/* 表格也不裁剪：单元里的操作钮要能冒出水泡；圆角改给表头首末格与末行首末格 */
.cy-table-outlined thead th:first-child { border-top-left-radius: calc(var(--cy-r-2) - 1px); }
.cy-table-outlined thead th:last-child { border-top-right-radius: calc(var(--cy-r-2) - 1px); }
.cy-table-outlined tbody tr:last-child td:first-child { border-bottom-left-radius: calc(var(--cy-r-2) - 1px); }
.cy-table-outlined tbody tr:last-child td:last-child { border-bottom-right-radius: calc(var(--cy-r-2) - 1px); }
.cy-table-num th:not(:first-child), .cy-table-num td:not(:first-child) { text-align: right; font-variant-numeric: tabular-nums; }
.cy-table-nowrap td { white-space: nowrap; }
.cy-table thead.sticky th { position: sticky; top: 0; z-index: 1; }

/* 区块标题 / 工具条 / 设置行 */
.cy-sec { display: flex; align-items: center; gap: var(--cy-s-4); margin: 0 0 var(--cy-s-5); }
.cy-sec-t { font-size: var(--cy-fs-4); font-weight: 800; color: var(--cy-text); }
.cy-sec-s { font-size: var(--cy-fs-2); color: var(--cy-text-4); font-weight: 500; }
.cy-sec-actions { margin-left: auto; display: inline-flex; align-items: center; gap: var(--cy-s-3); flex-wrap: wrap; }
.cy-sec-bar { padding-bottom: var(--cy-s-4); border-bottom: 1px solid var(--cy-line-3); }
.cy-toolbar {
    display: flex; align-items: center; gap: var(--cy-s-4); flex-wrap: wrap; padding: var(--cy-s-5) var(--cy-s-6);
    background: var(--cy-surface); border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-3);
}
.cy-tool-search { flex: 1 1 200px; min-width: 160px; max-width: 340px; }
.cy-kv { display: flex; align-items: baseline; gap: var(--cy-s-4); padding: var(--cy-s-3) 0; border-bottom: 1px dashed var(--cy-line-3); font-size: var(--cy-fs-3); }
.cy-kv:last-child { border-bottom: 0; }
.cy-kv-k { flex: none; width: 88px; color: var(--cy-text-4); font-size: var(--cy-fs-2); font-weight: 600; }
.cy-kv-v { flex: 1; min-width: 0; color: var(--cy-text); font-weight: 600; overflow-wrap: anywhere; }

/* ==========================================================================
   浮层：遮罩 / 弹窗 / 底部面板 / 轻提 / 黑屏级阻塞进度
   （弹窗 DOM 结构由 cyui.js 生成，样式全在这；不用 JS 也能手写这套类）
   ========================================================================== */
/* 弹窗形态约定（重要）：
   默认 = 居中窗，尺寸类 cy-dialog-sm/md/lg/xl/wide 就是【窗户宽度】；
   ≤640px 自动变贴底抽屉（不写额外参数）；
   全屏不是默认值，是一种显式形态：size:'full'（→ .cy-dialog-full + .cy-mask--full），
   用于 3D 预览、网格表、长表单这种真正吃满空间的场景。 */
/* 视口单位三条守则（iOS 26 实测，改这一族前必读）
   现象：刷新后先“一瞬间很沉浸”，接着冒出一个很高的色块，然后突然缩一截，
   底边正好卡在底部工具栏上沿——不是玄学，是浏览器在首帧之后把布局视口改小了。
   实测（440×956 机型，文档诊断行）：innerH 760 ＜ svh 796 ＜ lvh 836，
   即“当前可见高度”比 svh 还小 36px；iOS 首帧按大视口画，工具栏展开后重排，
   dvh 会跟着重算但发生在 settle 之后 → 凡“用视口单位定高”的层都必跳一次。
   ① 遮挡层（.cy-mask / .cy-drawer / .cy-blocker / .cy-fab-mask / .cy-dialog-full）：
      用 `height:100vh; height:100dvh`（跟工具栏收放、底部不留白条），但自身永远
      不带可见背景——颜色一律画在 ::before 上靠 opacity 门控，否则首帧那一下就是满屏色块。
   ② 贴底控件（.cy-fabs / .cy-sticktop / .cy-bulk / .cy-toasts--bottom）：
      一律 `bottom: calc(N + env(safe-area-inset-bottom))` 直接锚底，不要用视口单位撑高
      再 justify-content:flex-end —— svh 是常量、dvh 滞后，视口一变底边就落到可见区之外
      （.cy-fabs 曾经用 100dvh、后用 100svh，两者都被底部工具栏切掉半截，就是这个）。
   ③ 带背景的卡片：移动端别用 `max-height: calc(100dvh - N)` 限高（文档 .tst-toc 就是样本），
      要限高就写定值 px 或交给 overflow；白底+边框+阴影再配视口高度，就是那个“很高的色块”。
   先写 vh 再写 dvh：老内核丢掉第二行，退回第一行而不是整条失效。
   判“真可见高度”只信 window.innerHeight（或 vv.height），不要信 vh 系换算。 */
.cy-mask {
    position: fixed; top: 0; left: 0; right: 0; z-index: var(--cy-z-modal);
    height: 100vh; height: 100dvh;
    display: flex; align-items: center; justify-content: center; padding: var(--cy-s-7);
    opacity: 0; pointer-events: none; transition: opacity .18s var(--cy-ease);
}
/* 遮罩色画在伪元素上（iOS 26 取色规矩见「视口单位三条守则」①与本文件 .cy-fab-mask 处注释）：
   弹窗关闭后的 200ms 摘除窗口里 mask 还在 DOM，background 挂在自身会让地址栏染色残留
   （实测 WebKit bug 306267，颜色上了伪元素就彻底免疫）。
   min-height 不可省：JS 会把 mask 的盒高压到“真可见高度”（visualViewport.height），
   否则工具栏一收起，底下会露出一条没暗下来的带 */
.cy-mask::before { content: ""; position: absolute; inset: 0; min-height: 100dvh; background: rgba(15, 23, 42, .48); }
.cy-mask.is-open { opacity: 1; pointer-events: auto; }
/* 弹窗默认：居中窗（宽度由尺寸类控制，手机 ≤640 自动变贴底抽屉）。
   全屏不是默认值，是一种形态：size:'full' → .cy-dialog-full */
.cy-dialog {
    box-sizing: border-box; width: 100%; max-width: var(--cy-dialog-w, 560px); overflow: hidden;
    position: relative; z-index: 1;            /* 抬到 .cy-mask::before 之上：遮罩色画在 ::before（iOS26 取色规矩），
                                                  ::before 是定位元素会盖在非定位的对话框之上，这里把对话框也定位并抬层 */
    max-height: min(86dvh, calc(100dvh - var(--cy-s-8) * 2));
    display: flex; flex-direction: column; background: var(--cy-surface); color: var(--cy-text);
    border-radius: var(--cy-r-4); box-shadow: var(--cy-e-5);
    transform: translateY(10px) scale(.99); opacity: 0; transition: transform .2s var(--cy-ease), opacity .2s var(--cy-ease);
}
.cy-mask.is-open > .cy-dialog { transform: none; opacity: 1; }
/* 正文列宽：居中小窗不限宽（窗宽已经限了），只在全屏形态下限，避免一行拉 200 字 */
.cy-dialog-in { box-sizing: border-box; width: 100%; max-width: none; margin: 0 auto; }
.cy-dialog-head {
    flex: none; display: flex; align-items: center; gap: var(--cy-s-4); flex-wrap: wrap;
    min-height: 54px; padding: var(--cy-s-4) var(--cy-s-6); border-bottom: 1px solid var(--cy-line-3);
}
.cy-dialog-ic { display: flex; align-items: center; justify-content: center; width: 32px; height: 32px; flex: none; border-radius: var(--cy-r-1); background: var(--cy-primary-soft); color: var(--cy-primary); font-size: 14px; }
.cy-dialog-t { font-size: var(--cy-fs-5); font-weight: 800; line-height: 1.3; min-width: 0; }
.cy-dialog-sub { font-size: var(--cy-fs-2); color: var(--cy-text-4); margin-top: 2px; font-weight: 500; }
.cy-dialog-x { margin-left: auto; flex: none; width: 34px; height: 34px; display: flex; align-items: center; justify-content: center; border: 0; background: transparent; color: var(--cy-text-4); font-size: 15px; cursor: pointer; border-radius: var(--cy-r-1); }
.cy-dialog-x:hover { background: var(--cy-surface-3); color: var(--cy-text); }
.cy-dialog-body {
    flex: 1 1 auto; min-height: 0; overflow: auto; -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;                    /* iOS：正文滚到头不要把背景一起带动 */
    padding: var(--cy-s-6) var(--cy-s-6) var(--cy-s-7); font-size: var(--cy-fs-3); line-height: var(--cy-lh); color: var(--cy-text-2);
}
.cy-dialog-body--pad { padding-top: var(--cy-s-6); }
.cy-dialog-foot {
    flex: none; display: flex; align-items: center; gap: var(--cy-s-3); flex-wrap: wrap;
    padding: var(--cy-s-4) var(--cy-s-6); border-top: 1px solid var(--cy-line-3); background: var(--cy-surface-2);
}
.cy-dialog-foot--end { justify-content: flex-end; }
.cy-dialog-foot--between { justify-content: space-between; }
/* 尺寸类 = 窗户宽度（不是正文列宽） */
.cy-dialog-sm { --cy-dialog-w: 460px; }
.cy-dialog-md { --cy-dialog-w: 680px; }
.cy-dialog-lg { --cy-dialog-w: 900px; }
.cy-dialog-xl { --cy-dialog-w: 1160px; }
.cy-dialog-wide { --cy-dialog-w: 1400px; }     /* 台账表、文件列表这种宽内容 */
/* 全屏形态（显式选择，PC 与手机都真全屏）：适合 3D 预览、长表单、网格表 */
.cy-dialog-full {
    width: 100%; max-width: none; max-height: none;
    height: 100vh; height: 100dvh;                /* 老浏览器先吃 vh，新浏览器 dvh 更准 */
    border-radius: 0; box-shadow: none;
    padding-top: env(safe-area-inset-top, 0px); padding-bottom: env(safe-area-inset-bottom, 0px);
    transform: translateY(12px);                 /* 全屏入场用位移，scale 在大面上很抖 */
}
.cy-mask--full { padding: 0; align-items: stretch; }
.cy-dialog-full .cy-dialog-in { max-width: var(--cy-dialog-page-w, 1560px); }
.cy-dialog-flush .cy-dialog-body { padding-left: 0; padding-right: 0; }
.cy-dialog-plain .cy-dialog-foot { background: transparent; border-top: 0; }
/* 底部面板（移动端主场景，上抛式）
   不吃顶部安全区（那是刘海，面板在底部用不上），但必须吃底部内距，
   否则 home indicator 会压在面板底部按钮上 */
.cy-sheet {
    box-sizing: border-box;
    width: min(var(--cy-sheet-w, 620px), 100%);          /* 桌面上居中限宽，不贴底拉成一条 */
    height: auto; max-width: none; max-height: 88dvh;
    align-self: flex-end;
    border-radius: var(--cy-r-4) var(--cy-r-4) 0 0;
    border-top: 1px solid var(--cy-line-3);              /* 深色皮肤下靠这条线把面板和遮罩分开 */
    box-shadow: 0 -18px 42px -18px rgba(15, 23, 42, .42); /* .cy-dialog 现在是 box-shadow:none，这里要补回来 */
    padding-top: 0;
    padding-bottom: env(safe-area-inset-bottom, 0px);
    transform: translateY(18px);
    /* 切档时高度也要动，不然是瞬变 */
    transition: transform .22s var(--cy-ease), opacity .2s var(--cy-ease),
                max-height .28s var(--cy-ease), min-height .28s var(--cy-ease);
}
/* 拖拽中不要过渡，否则面板跟手会有橡皮筋感 */
.cy-sheet.is-dragging { transition: none; }
/* 抓手：整行是热区（以前只有 38px 小条，手机上根本按不到）：
   点一下在 peek→half→full 循环，往下拉超过阈值直接收起 */
.cy-sheet-grip {
    box-sizing: border-box; display: block; width: 100%; height: 26px; flex: none;
    border: 0; background: transparent; cursor: grab; touch-action: none;
    /* 拖拽时不要选中文字 / 弹出 iOS 长按菜单 */
    -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
}
.cy-sheet-grip::after {
    content: ""; display: block; width: 44px; height: 5px; margin: 10px auto 0;
    border-radius: 3px; background: var(--cy-line-2);
    transition: background-color var(--cy-dur) var(--cy-ease), width var(--cy-dur) var(--cy-ease);
}
.cy-sheet-grip:hover::after { background: var(--cy-primary); width: 58px; }
.cy-sheet-grip:active { cursor: grabbing; }
.cy-sheet.is-dragging .cy-sheet-grip::after { background: var(--cy-primary); width: 68px; }
/* 没标题时的头：只留一个关闭钮，不要空出一条 54px 的空白行 */
.cy-dialog-head--bare { min-height: 0; padding: 0 var(--cy-s-3) 0 var(--cy-s-6); border-bottom: 0; }

/* 轻提容器：六个方位（JS 按 pos 参数分桶），窄屏一律贴底全宽 */
.cy-toasts {
    position: fixed; z-index: var(--cy-z-toast);
    display: flex; flex-direction: column; gap: var(--cy-s-3);
    width: min(92vw, 480px); pointer-events: none;
}
.cy-toasts--top { left: 50%; transform: translateX(-50%); top: calc(20px + env(safe-area-inset-top, 0px)); align-items: center; }
.cy-toasts--bottom { left: 50%; transform: translateX(-50%); bottom: calc(24px + env(safe-area-inset-bottom, 0px)); align-items: center; }
.cy-toasts--top-left { top: calc(20px + env(safe-area-inset-top, 0px)); left: calc(20px + env(safe-area-inset-left, 0px)); align-items: flex-start; }
.cy-toasts--top-right { top: calc(20px + env(safe-area-inset-top, 0px)); right: calc(20px + env(safe-area-inset-right, 0px)); align-items: flex-end; }
.cy-toasts--bottom-left { bottom: calc(24px + env(safe-area-inset-bottom, 0px)); left: calc(20px + env(safe-area-inset-left, 0px)); align-items: flex-start; }
.cy-toasts--bottom-right { bottom: calc(24px + env(safe-area-inset-bottom, 0px)); right: calc(20px + env(safe-area-inset-right, 0px)); align-items: flex-end; }
.cy-toasts--center { left: 50%; top: 50%; transform: translate(-50%, -50%); align-items: center; }
.cy-toast {
    box-sizing: border-box;
    position: relative;                            /* 给 ::before 色板当定位父（颜色不能挂在自身，见下） */
    display: flex; align-items: center; gap: var(--cy-s-4); padding: var(--cy-s-4) var(--cy-s-6);
    min-height: 38px; line-height: 1.4;
    border-radius: var(--cy-toast-r, var(--cy-r-full)); background: transparent; color: #fff;
    font-size: var(--cy-fs-3); font-weight: 600; box-shadow: var(--cy-e-4); pointer-events: auto;
    max-width: 100%;
}
/* 色板上伪元素：toast 容器是贴在视口下边的 fixed 层（z 台阶最高一档），
   background 挂在自身会被 iOS 26 取色器读到 → 弹一条 toast，底部地址栏就被钉成深色块，
   “沉浸”当场丢（守则见文件内「视口单位三条守则」①）。z-index:-1 在 .cy-toasts 上下文内
   垫到文字之下，不会跑到页面背后面去。 */
.cy-toast::before {
    content: ""; position: absolute; inset: 0; z-index: -1;
    border-radius: inherit; background: rgba(15, 23, 42, .92);
}
/* 四套入场动画（默认 slide） */
.cy-toast--slide { animation: cy-toast-in .22s var(--cy-ease); }
.cy-toast--fade { animation: cy-toast-fade .24s var(--cy-ease); }
.cy-toast--zoom { animation: cy-toast-zoom .24s cubic-bezier(.2, .9, .3, 1.3); }
.cy-toast--drop { animation: cy-toast-drop .26s var(--cy-ease); }
.cy-toast.is-out { animation: cy-toast-out .18s var(--cy-ease) forwards; }
@keyframes cy-toast-in { from { opacity: 0; transform: translateY(10px); } }
@keyframes cy-toast-fade { from { opacity: 0; } }
@keyframes cy-toast-zoom { from { opacity: 0; transform: scale(.86); } }
@keyframes cy-toast-drop { from { opacity: 0; transform: translateY(-12px) scale(.98); } }
@keyframes cy-toast-out { to { opacity: 0; transform: translateY(6px); } }
.cy-toast-sq { border-radius: var(--cy-r-2); }
.cy-toast-plain { color: var(--cy-text); box-shadow: var(--cy-e-3); }
.cy-toast-plain::before { background: var(--cy-surface); border: 1px solid var(--cy-line); }
.cy-toast-plain .cy-toast-action { background: var(--cy-surface-3); color: var(--cy-text-2); }
.cy-toast > i:first-child { margin-top: 1px; font-size: 13px; }
.cy-toast-success::before { background: rgba(6, 78, 59, .94); }
.cy-toast-warning::before { background: rgba(124, 45, 18, .94); }
.cy-toast-error::before { background: rgba(127, 29, 29, .94); }
.cy-toast-action { margin-left: var(--cy-s-3); border: 0; background: rgba(255, 255, 255, .16); color: #fff; border-radius: var(--cy-r-full); padding: 3px 10px; font-size: var(--cy-fs-1); font-weight: 800; cursor: pointer; }
.cy-toast-action:hover { background: rgba(255, 255, 255, .28); }
/* 窄屏：一律贴底全宽（1153 行约定的行为，原 CSS 没落地）。
   覆盖六个方位修饰类与 center 的定位，reset 掉 transform 与 top，
   容器铺满左右留 12px 安全边，toast 占满容器宽度。 */
@media (max-width: 640px) {
    .cy-toasts,
    .cy-toasts--top, .cy-toasts--bottom,
    .cy-toasts--top-left, .cy-toasts--top-right,
    .cy-toasts--bottom-left, .cy-toasts--bottom-right,
    .cy-toasts--center {
        top: auto; bottom: calc(16px + env(safe-area-inset-bottom, 0px));
        left: 0; right: 0; transform: none; padding: 0 12px;
    }
    .cy-toast {
        width: 100%;
        padding: 12px var(--cy-s-5);
        font-size: var(--cy-fs-4);
        border-radius: var(--cy-r-3);
    }
}

/* 不可关闭的进度遮罩（NAS 上传/删除那类慢操作，带真实百分比位） */
.cy-blocker { position: fixed; top: 0; left: 0; right: 0; z-index: var(--cy-z-blocker); height: 100vh; height: 100dvh; display: flex; align-items: center; justify-content: center; }
/* 同一族坑：blocker 是满屏 fixed 层，background 挂在自身会染底部地址栏（守则①） */
.cy-blocker::before { content: ""; position: absolute; inset: 0; z-index: -1; min-height: 100dvh; background: rgba(15, 23, 42, .55); }
.cy-blocker-box {
    width: min(88vw, 360px); padding: var(--cy-s-8) var(--cy-s-7); border-radius: var(--cy-r-4);
    background: var(--cy-surface); box-shadow: var(--cy-e-5); text-align: center;
}
.cy-blocker-t { font-size: var(--cy-fs-3); font-weight: 700; color: var(--cy-text); line-height: 1.5; word-break: break-all; }
.cy-blocker-p { margin-top: var(--cy-s-4); height: 4px; border-radius: 2px; background: var(--cy-surface-3); overflow: hidden; }
.cy-blocker-p > i { display: block; height: 100%; width: 0%; background: var(--cy-primary); border-radius: 2px; transition: width .2s linear; }
.cy-blocker-n { margin-top: 5px; font-size: var(--cy-fs-1); color: var(--cy-text-4); font-variant-numeric: tabular-nums; }
.cy-blocker-spin { display: flex; justify-content: center; margin-bottom: var(--cy-s-5); }

/* 点击波纹（Material 风）：包在 [data-cy-ripple] 容器上，JS 只画一个 span */
[data-cy-ripple] { position: relative; overflow: hidden; }
.cy-ripple {
    position: absolute; border-radius: 50%; background: currentColor; opacity: .18; pointer-events: none;
    transform: scale(0); animation: cy-ripple-k .55s var(--cy-ease) forwards;
}
@keyframes cy-ripple-k { to { transform: scale(2.6); opacity: 0; } }

/* ==========================================================================
   ↓↓↓ 以下自 oal 业务页现有设计反推收编（仪表盘 / 检测报告 / 客户列表 /
   人员库 / 签字汇总 / 骨架屏），每个都带全套预设与旋钮 ↓↓↓
   ========================================================================== */

/* ---------- KPI 统计卡（原 .stat-card / .stats-grid / .cd-stat-grid）----------
   图标瓦 + 大数字 + 标签，可挂环比、占比条、补充行 */
.cy-kpi-grid { display: grid; gap: var(--cy-s-5); grid-template-columns: repeat(auto-fit, minmax(var(--cy-kpi-min, 168px), 1fr)); }
.cy-kpi-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.cy-kpi-grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.cy-kpi-grid-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
.cy-kpi {
    box-sizing: border-box; display: flex; align-items: center; gap: var(--cy-s-4);
    padding: var(--cy-kpi-pad, var(--cy-s-6)); border-radius: var(--cy-kpi-r, var(--cy-r-3));
    background: var(--cy-kpi-bg, var(--cy-surface)); border: 1px solid var(--cy-kpi-line, var(--cy-line-3));
    box-shadow: var(--cy-kpi-e, var(--cy-e-1)); min-width: 0;
}
.cy-kpi-ic {
    display: flex; align-items: center; justify-content: center; flex: none;
    width: var(--cy-kpi-ic, 42px); height: var(--cy-kpi-ic, 42px); border-radius: var(--cy-r-2);
    background: var(--cy-surface-3); color: var(--cy-text-3); font-size: 16px;
}
.cy-kpi-b { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.cy-kpi-v {
    font-size: var(--cy-fs-6); font-weight: 800; color: var(--cy-text); line-height: 1.15;
    font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cy-kpi-l { font-size: var(--cy-fs-2); color: var(--cy-text-4); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cy-kpi-x { font-size: var(--cy-fs-1); color: var(--cy-text-5); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cy-kpi-top { display: flex; align-items: center; gap: var(--cy-s-3); }
.cy-kpi-sm { padding: var(--cy-s-4) var(--cy-s-5); gap: var(--cy-s-3); }
.cy-kpi-sm .cy-kpi-v { font-size: var(--cy-fs-5); }
.cy-kpi-lg { padding: var(--cy-s-7) var(--cy-s-8); }
.cy-kpi-lg .cy-kpi-v { font-size: 26px; }
.cy-kpi-col { flex-direction: column; align-items: flex-start; }
.cy-kpi-plain { border-color: transparent; box-shadow: none; background: transparent; padding-left: 0; }
.cy-kpi-soft { background: var(--cy-surface-2); border-color: transparent; box-shadow: none; }
.cy-kpi-bar { border-left: 3px solid var(--cy-primary); border-radius: 0 var(--cy-r-2) var(--cy-r-2) 0; }
.cy-kpi-click { cursor: pointer; transition: all var(--cy-dur) var(--cy-ease); }
.cy-kpi-click:hover { transform: translateY(-1px); box-shadow: var(--cy-e-3); border-color: var(--cy-line-2); }
/* 图标瓦语义色（仪表盘里每个卡一个颜色就靠这个） */
.cy-kpi-primary .cy-kpi-ic { background: var(--cy-primary-soft); color: var(--cy-primary); }
.cy-kpi-success .cy-kpi-ic { background: var(--cy-success-soft); color: var(--cy-success); }
.cy-kpi-warning .cy-kpi-ic { background: var(--cy-warning-soft); color: var(--cy-warning-ink); }
.cy-kpi-danger  .cy-kpi-ic { background: var(--cy-danger-soft); color: var(--cy-danger); }
.cy-kpi-info    .cy-kpi-ic { background: var(--cy-info-soft); color: var(--cy-info); }
.cy-kpi-grad .cy-kpi-ic { color: #fff; background: linear-gradient(135deg, var(--cy-primary), var(--cy-primary-hover)); box-shadow: var(--cy-e-2); }

/* 环比 / 涨跌 */
.cy-delta {
    display: inline-flex; align-items: center; gap: 3px; padding: 1px 6px; border-radius: var(--cy-r-full);
    font-size: var(--cy-fs-1); font-weight: 800; font-variant-numeric: tabular-nums;
    background: var(--cy-success-soft); color: var(--cy-success-ink);
}
.cy-delta-down { background: var(--cy-danger-soft); color: var(--cy-danger-ink); }
.cy-delta-flat { background: var(--cy-surface-3); color: var(--cy-text-4); }
.cy-delta-plain { background: transparent; padding-left: 0; }

/* 卡内迷你占比条（完成度/构成） */
.cy-ratio { display: flex; height: 5px; border-radius: 3px; background: var(--cy-surface-3); overflow: hidden; margin-top: var(--cy-s-2); }
.cy-ratio-i { height: 100%; background: var(--cy-primary); width: var(--cy-v, 0%); }
.cy-ratio-i + .cy-ratio-i { background: var(--cy-success); }
.cy-ratio-i.s3 { background: var(--cy-warning); } .cy-ratio-i.s4 { background: var(--cy-text-5); }
.cy-ratio-thin { height: 3px; }
.cy-ratio-lg { height: 8px; border-radius: 4px; }

/* 环形百分比不做：进度的环、占比的饼、趋势的线全部交给 ECharts。
   cyui 只保留 cy-progress（线性）与 cy-ratio（卡内占比条）这两个“UI 件”，
   不当图表库的轮子重复造。 */

/* 横向条形排行 / 堆叠条 / 日历热力：全部属于图表，交给 ECharts 做，cyui 不再自造 */
.cy-legend { display: flex; align-items: center; gap: var(--cy-s-4); flex-wrap: wrap; font-size: var(--cy-fs-1); color: var(--cy-text-3); }
.cy-legend-i { display: inline-flex; align-items: center; gap: 4px; }
.cy-legend-i > i { width: 8px; height: 8px; border-radius: 2px; background: var(--cy-primary); display: inline-block; }
.cy-legend-i.s2 > i { background: var(--cy-success); } .cy-legend-i.s3 > i { background: var(--cy-warning); }
.cy-legend-i.s4 > i { background: var(--cy-danger); } .cy-legend-i.s5 > i { background: var(--cy-info); }
.cy-legend-b { margin-left: auto; font-weight: 800; color: var(--cy-text-2); font-variant-numeric: tabular-nums; }

/* （日历热力图属于图表，交给 ECharts / 自定义 SVG，cyui 不做） */

/* 功能入口瓦（仪表盘快捷区） */
.cy-tiles { display: grid; gap: var(--cy-s-4); grid-template-columns: repeat(auto-fill, minmax(var(--cy-tile-min, 150px), 1fr)); }
.cy-tile {
    display: flex; flex-direction: column; gap: 4px; padding: var(--cy-s-5); border-radius: var(--cy-r-3);
    border: 1px solid var(--cy-line-3); background: var(--cy-surface); text-decoration: none; color: inherit; cursor: pointer;
    transition: all var(--cy-dur) var(--cy-ease);
}
.cy-tile:hover { border-color: var(--cy-primary-soft-line); box-shadow: var(--cy-e-3); transform: translateY(-1px); }
.cy-tile-t { display: flex; align-items: center; gap: var(--cy-s-3); font-size: var(--cy-fs-3); font-weight: 700; color: var(--cy-text); }
.cy-tile-t > i { width: 26px; height: 26px; display: flex; align-items: center; justify-content: center; border-radius: var(--cy-r-1); background: var(--cy-primary-soft); color: var(--cy-primary); font-size: 12px; flex: none; }
.cy-tile-d { font-size: var(--cy-fs-1); color: var(--cy-text-4); line-height: 1.4; }
.cy-tile-success .cy-tile-t > i { background: var(--cy-success-soft); color: var(--cy-success); }
.cy-tile-warning .cy-tile-t > i { background: var(--cy-warning-soft); color: var(--cy-warning-ink); }
.cy-tile-danger .cy-tile-t > i { background: var(--cy-danger-soft); color: var(--cy-danger); }

/* ---------- 图表面板卡（原 .oa-chart / .oa-chart-head / .oa-chart-canvas）----------
   主标题不被长副标题挤掉：head 开 flex-shrink:0 固定，副标题才折行 */
.cy-panel {
    box-sizing: border-box; background: var(--cy-panel-bg, var(--cy-surface));
    border: 1px solid var(--cy-panel-line, var(--cy-line-3)); border-radius: var(--cy-panel-r, var(--cy-r-3));
    padding: var(--cy-panel-pad, var(--cy-s-6)); box-shadow: var(--cy-panel-e, var(--cy-e-1)); min-width: 0;
}
.cy-panel-head { display: flex; align-items: center; gap: var(--cy-s-4); flex-wrap: wrap; margin-bottom: var(--cy-s-4); flex-shrink: 0; }
.cy-panel-t { font-size: var(--cy-fs-4); font-weight: 800; color: var(--cy-text); flex-shrink: 0; white-space: nowrap; }
.cy-panel-sub { font-size: var(--cy-fs-2); color: var(--cy-text-4); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cy-panel-tools { margin-left: auto; display: inline-flex; align-items: center; gap: var(--cy-s-2); flex: none; }
.cy-panel-canvas { width: 100%; height: var(--cy-panel-h, 230px); position: relative; }
.cy-panel-h150 { --cy-panel-h: 150px; } .cy-panel-h190 { --cy-panel-h: 190px; }
.cy-panel-h230 { --cy-panel-h: 230px; } .cy-panel-h300 { --cy-panel-h: 300px; }
.cy-panel-h360 { --cy-panel-h: 360px; } .cy-panel-h420 { --cy-panel-h: 420px; }
.cy-panel-plain { border-color: transparent; box-shadow: none; padding: 0; }
.cy-panel-dense { --cy-panel-pad: var(--cy-s-4); }
.cy-panel-grid { display: grid; gap: var(--cy-s-5); grid-template-columns: repeat(auto-fit, minmax(var(--cy-min, 300px), 1fr)); }
.cy-panel-foot { margin-top: var(--cy-s-4); padding-top: var(--cy-s-3); border-top: 1px dashed var(--cy-line-3); font-size: var(--cy-fs-1); color: var(--cy-text-4); display: flex; align-items: center; gap: var(--cy-s-4); flex-wrap: wrap; }

/* ---------- 环节进度轨道（三态圆点 + 连接线，原仪表盘“环节三态”那套）---------- */
.cy-track { display: flex; align-items: flex-start; gap: 0; min-width: 0; }
.cy-track-node { position: relative; flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 4px; padding-top: 0; }
.cy-track-node::before, .cy-track-node::after { content: ""; position: absolute; top: 9px; height: 2px; background: var(--cy-line-3); width: 50%; }
.cy-track-node::before { left: 0; } .cy-track-node::after { right: 0; }
.cy-track-node:first-child::before, .cy-track-node:last-child::after { display: none; }
.cy-track-dot {
    position: relative; z-index: 1; width: 20px; height: 20px; border-radius: 50%; flex: none;
    display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 800;
    background: var(--cy-surface); border: 2px solid var(--cy-line-2); color: var(--cy-text-4);
}
.cy-track-lb { font-size: var(--cy-fs-1); color: var(--cy-text-3); font-weight: 600; text-align: center; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cy-track-s { font-size: 9.5px; color: var(--cy-text-5); font-variant-numeric: tabular-nums; }
.cy-track-node.is-done .cy-track-dot { background: var(--cy-success); border-color: var(--cy-success); color: #fff; }
.cy-track-node.is-done .cy-track-dot::before { content: "\2713"; font-size: 11px; }
.cy-track-node.is-done .cy-track-dot { font-size: 0; }
.cy-track-node.is-done::before, .cy-track-node.is-done::after { background: var(--cy-success); }
.cy-track-node.is-on .cy-track-dot { background: var(--cy-primary); border-color: var(--cy-primary); color: #fff; box-shadow: 0 0 0 4px var(--cy-primary-soft); }
.cy-track-node.is-on .cy-track-lb { color: var(--cy-primary); font-weight: 800; }
.cy-track-node.is-warn .cy-track-dot { background: var(--cy-warning-soft); border-color: var(--cy-warning); color: var(--cy-warning-ink); font-size: 10px; }
.cy-track-node.is-warn .cy-track-lb { color: var(--cy-warning-ink); }
.cy-track-node.is-error .cy-track-dot { background: var(--cy-danger-soft); border-color: var(--cy-danger); color: var(--cy-danger); font-size: 10px; }
/* 未完成与已完成之间用虚线：“企业整改中”这类中间态 */
.cy-track-node.is-hold::after, .cy-track-node.is-hold::before { background: repeating-linear-gradient(90deg, var(--cy-warning) 0 4px, transparent 4px 8px); }
.cy-track--v { flex-direction: column; gap: 0; }
.cy-track--v .cy-track-node { flex-direction: row; align-items: flex-start; gap: var(--cy-s-4); padding-bottom: var(--cy-s-5); }
.cy-track--v .cy-track-node::before, .cy-track--v .cy-track-node::after { width: 2px; height: 50%; left: 9px; right: auto; top: 0; }
.cy-track--v .cy-track-node::after { top: auto; bottom: 0; left: 9px; }
.cy-track--v .cy-track-node:first-child::before, .cy-track--v .cy-track-node:last-child::after { display: none; }
.cy-track--v .cy-track-lb { text-align: left; white-space: normal; }
.cy-track-dense .cy-track-dot { width: 14px; height: 14px; border-width: 1.5px; }

/* ---------- 多段状态胶囊（原 .dr-state：正文/Word/PDF+扫描件 各自独立指示）---------- */
.cy-pbs {
    display: inline-flex; align-items: stretch; overflow: hidden; background: var(--cy-surface);
    border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2); font-size: var(--cy-fs-1); font-weight: 700; vertical-align: middle;
}
.cy-pbs-seg { display: inline-flex; align-items: center; gap: 4px; padding: 3px 7px; background: var(--cy-surface-2); color: var(--cy-text-5); white-space: nowrap; }
.cy-pbs-seg + .cy-pbs-seg { border-left: 1px solid var(--cy-line-3); }
.cy-pbs-dot { width: 5px; height: 5px; border-radius: 50%; background: currentColor; flex: none; }
.cy-pbs-ico { font-size: 11.5px; line-height: 1; }
.cy-pbs-num { font-size: 9.5px; opacity: .9; }
.cy-pbs-warn { font-size: 9px; color: var(--cy-warning); }
.cy-pbs-seg.s-primary { background: var(--cy-primary-soft); color: var(--cy-primary-ink); }
.cy-pbs-seg.s-blue { background: #eff6ff; color: #1d4ed8; }
.cy-pbs-seg.s-green { background: #f0fdf4; color: #15803d; }
.cy-pbs-seg.s-red { background: #fef2f2; color: #b91c1c; }
.cy-pbs-seg.s-teal { background: #f0fdfa; color: #0f766e; }
.cy-pbs-seg.s-amber { background: #fffbeb; color: #b45309; }
.cy-pbs-sm .cy-pbs-lb { display: none; }

/* ---------- 行内操作胶囊组（原 .act-pills：独立胶囊 + 语义色 + 限列网格换行）----------
   注意：刻意不挂 .btn，避开换肤层对 .btn 的背景覆盖 */
.cy-pillrow { display: inline-flex; align-items: center; gap: var(--cy-s-2); flex-wrap: wrap; }
.cy-pillrow-grid { display: grid; grid-template-columns: repeat(var(--cy-apc, 3), minmax(0, 1fr)); gap: var(--cy-s-2); justify-content: end; min-width: 0; max-width: 100%; }
/* 列必须可收缩：auto 轨道最小就是内容宽，窄屏下 3 列加起来会顶破卡片（实测手机上按钮冲出背景）；
   minmax(0,1fr) 桌面仍按内容取宽、外观不变，窄屏则等分收缩，按钮文字用省略号兜底 */
.cy-pb {
    box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center; gap: 5px;
    height: var(--cy-pb-h, 28px); padding: 0 var(--cy-s-4); border: 1px solid var(--cy-line); border-radius: var(--cy-r-2);
    background: var(--cy-surface); color: var(--cy-text-3); font-size: var(--cy-fs-2); font-weight: 600; line-height: 1;
    white-space: nowrap; cursor: pointer; text-decoration: none;
    transition: background-color var(--cy-dur) var(--cy-ease), border-color var(--cy-dur) var(--cy-ease), color var(--cy-dur) var(--cy-ease), box-shadow var(--cy-dur) var(--cy-ease);
}
.cy-pillrow-grid .cy-pb { width: 100%; min-width: 0; overflow: hidden; }
.cy-pillrow-grid .cy-pb .cy-btn-lb { overflow: hidden; text-overflow: ellipsis; }
.cy-pb:hover { border-color: var(--cy-line-2); box-shadow: var(--cy-e-1); color: var(--cy-text); }
.cy-pb:active { transform: translateY(1px); box-shadow: none; }
.cy-pb.is-on { background: var(--cy-primary); border-color: var(--cy-primary); color: #fff; }
.cy-pb-p { background: var(--cy-primary-soft); border-color: var(--cy-primary-soft-line); color: var(--cy-primary-ink); }
.cy-pb-s { background: var(--cy-success-soft); border-color: var(--cy-success-soft-line); color: var(--cy-success-ink); }
.cy-pb-w { color: var(--cy-warning-ink); } .cy-pb-w:hover { background: var(--cy-warning-soft); border-color: var(--cy-warning-soft-line); }
.cy-pb-d { color: var(--cy-danger); } .cy-pb-d:hover { background: var(--cy-danger-soft); border-color: var(--cy-danger-soft-line); color: var(--cy-danger-ink); }
.cy-pb-i { color: var(--cy-info); } .cy-pb-i:hover { background: var(--cy-info-soft); border-color: var(--cy-info-soft-line); }
/* 纯图标小钮：宽度跟着高度走（与 .cy-btn-icon 同病同治）——
   窄屏把 .cy-pb 抬到 36px 高时，写死 28px 宽就会变成 28×36 的竖向长方形 */
.cy-pb-icon { padding: 0; width: var(--cy-pb-h, 28px); flex: none; }

/* ---------- 状态徽章（把项目里那套状态词固定下来：进行中/已完成/未开始/逾期/整改中/已拒/已签）---------- */
.cy-status {
    display: inline-flex; align-items: center; gap: 4px; height: 20px; padding: 0 8px; border-radius: var(--cy-r-full);
    font-size: var(--cy-fs-1); font-weight: 800; background: var(--cy-surface-3); color: var(--cy-text-3); white-space: nowrap;
}
.cy-status > i { font-size: 6px; width: 5px; height: 5px; border-radius: 50%; background: currentColor; display: inline-block; }
.cy-status-run { background: var(--cy-primary-soft); color: var(--cy-primary-ink); }
.cy-status-done { background: var(--cy-success-soft); color: var(--cy-success-ink); }
.cy-status-todo { background: var(--cy-surface-3); color: var(--cy-text-4); }
.cy-status-over { background: var(--cy-danger-soft); color: var(--cy-danger-ink); }
.cy-status-rectify { background: var(--cy-warning-soft); color: var(--cy-warning-ink); border: 1px dashed var(--cy-warning-soft-line); }
.cy-status-reject { background: var(--cy-danger-soft); color: var(--cy-danger-ink); }
.cy-status-sign { background: var(--cy-success-soft); color: var(--cy-success-ink); }
.cy-status-unsigned { background: var(--cy-warning-soft); color: var(--cy-warning-ink); }
.cy-status-sm { height: 17px; padding: 0 6px; font-size: 9.5px; }
.cy-status-lg { height: 24px; padding: 0 var(--cy-s-4); font-size: var(--cy-fs-2); }

/* ---------- 桌面多列行↔手机卡片（原 .lt-pc-* 客户列表那一套）----------
   列宽用 --cy-rg-cols 一个变量控；窄屏自动降级，每个单元格拿 data-l 当小标签 */
.cy-rg { --cy-rg-cols: 44px minmax(0, 2.2fr) 92px 76px 64px 96px 210px; }
.cy-rg-head, .cy-rg-row { display: grid; grid-template-columns: var(--cy-rg-cols); align-items: center; gap: var(--cy-s-4); }
.cy-rg-head {
    padding: var(--cy-s-3) var(--cy-s-6); background: var(--cy-surface-2);
    border-bottom: 1px solid var(--cy-line); font-size: var(--cy-fs-1); font-weight: 800; color: var(--cy-text-4);
}
.cy-rg { background: var(--cy-surface); border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-3); }
/* 多列行的操作钮全部带气泡，所以这里也不裁剪，圆角给表头与末行 */
.cy-rg-head { border-top-left-radius: calc(var(--cy-r-3) - 1px); border-top-right-radius: calc(var(--cy-r-3) - 1px); }
.cy-rg-row:last-child { border-bottom-left-radius: calc(var(--cy-r-3) - 1px); border-bottom-right-radius: calc(var(--cy-r-3) - 1px); }
.cy-rg-row { padding: var(--cy-s-4) var(--cy-s-6); border-bottom: 1px solid var(--cy-line-3); font-size: var(--cy-fs-3); color: var(--cy-text-2); }
.cy-rg-row:last-child { border-bottom: 0; }
.cy-rg-row:hover { background: var(--cy-surface-2); }
.cy-rg-row.is-on { background: var(--cy-primary-soft); }
.cy-rg-idx { font-size: var(--cy-fs-2); font-weight: 800; color: var(--cy-text-5); font-variant-numeric: tabular-nums; }
.cy-rg-name { min-width: 0; display: flex; align-items: center; gap: var(--cy-s-3); }
.cy-rg-name > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 700; color: var(--cy-text); }
.cy-rg-badges { display: flex; align-items: center; gap: var(--cy-s-2); flex-wrap: wrap; margin-top: 2px; }
.cy-rg-num { text-align: right; font-variant-numeric: tabular-nums; font-weight: 700; color: var(--cy-text-2); }
.cy-rg-acts { display: flex; align-items: center; gap: var(--cy-s-2); justify-content: flex-end; flex-wrap: wrap; }
.cy-rg-chip {
    display: inline-flex; align-items: center; gap: 3px; height: 19px; padding: 0 6px; border-radius: var(--cy-r-1);
    background: var(--cy-surface-3); color: var(--cy-text-3); font-size: 10px; font-weight: 700; white-space: nowrap;
}
.cy-rg-chip-s { background: var(--cy-success-soft); color: var(--cy-success-ink); }
.cy-rg-chip-w { background: var(--cy-warning-soft); color: var(--cy-warning-ink); }
.cy-rg-more { color: var(--cy-text-4); font-size: 10px; font-weight: 800; }

/* ---------- 人员卡（原 .staff-card：专家库/人员列表那套）---------- */
.cy-person {
    box-sizing: border-box; background: var(--cy-surface); border: 1px solid var(--cy-line-3);
    border-radius: var(--cy-r-3); box-shadow: var(--cy-e-1); padding: var(--cy-s-5); display: flex; flex-direction: column; gap: var(--cy-s-4);
}
.cy-person-hd { display: flex; align-items: center; gap: var(--cy-s-4); min-width: 0; }
.cy-person-nm { font-size: var(--cy-fs-4); font-weight: 800; color: var(--cy-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cy-person-role { font-size: var(--cy-fs-1); color: var(--cy-text-4); margin-top: 1px; }
.cy-person-tags { display: flex; flex-wrap: wrap; gap: var(--cy-s-2); }
.cy-person-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--cy-s-2); text-align: center; }
.cy-person-stat { padding: var(--cy-s-3) var(--cy-s-2); border-radius: var(--cy-r-2); background: var(--cy-surface-2); min-width: 0; }
.cy-person-stat b { display: block; font-size: var(--cy-fs-5); font-weight: 800; color: var(--cy-text); font-variant-numeric: tabular-nums; }
.cy-person-stat span { font-size: 9.5px; color: var(--cy-text-4); }
.cy-person-foot { display: flex; align-items: center; gap: var(--cy-s-2); flex-wrap: wrap; }
.cy-person-compact { flex-direction: row; align-items: center; gap: var(--cy-s-4); padding: var(--cy-s-4) var(--cy-s-5); }
.cy-person-compact .cy-person-stats { margin-left: auto; grid-template-columns: repeat(2, auto); }
.cy-person-flat { border-color: transparent; box-shadow: none; background: var(--cy-surface-2); }
.cy-person-on { border-color: var(--cy-primary-soft-line); box-shadow: 0 0 0 3px var(--cy-primary-soft); }

/* ---------- 记录卡（原 .ss-card 签字汇总：左色条 + 主体 + 底部操作）---------- */
.cy-record {
    box-sizing: border-box; display: flex; background: var(--cy-surface); border: 1px solid var(--cy-line-3);
    border-radius: var(--cy-r-3); box-shadow: var(--cy-e-1); min-width: 0;   /* 不裁剪：卡内按钮气泡要能露出 */
}
.cy-record-bar { width: 4px; flex: none; background: var(--cy-primary); }
/* 色条贴在圆角容器左侧，自己带上左圆角（父级不再裁剪，否则会漏色） */
.cy-record > .cy-record-bar:first-child { border-top-left-radius: calc(var(--cy-r-3) - 1px); border-bottom-left-radius: calc(var(--cy-r-3) - 1px); }
.cy-record-bar.s2 { background: var(--cy-success); } .cy-record-bar.s3 { background: var(--cy-warning); }
.cy-record-bar.s4 { background: var(--cy-info); } .cy-record-bar.s5 { background: var(--cy-danger); } .cy-record-bar.s6 { background: #8b5cf6; }
.cy-record-b { flex: 1 1 auto; min-width: 0; padding: var(--cy-s-5) var(--cy-s-6); display: flex; flex-direction: column; gap: var(--cy-s-4); }
.cy-record-hd { display: flex; align-items: center; gap: var(--cy-s-4); min-width: 0; }
.cy-record-idx {
    display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; flex: none;
    border-radius: var(--cy-r-1); background: var(--cy-surface-3); color: var(--cy-text-3);
    font-size: var(--cy-fs-1); font-weight: 800; font-variant-numeric: tabular-nums;
}
.cy-record-tt { font-size: var(--cy-fs-4); font-weight: 800; color: var(--cy-text); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cy-record-dt { margin-left: auto; flex: none; display: inline-flex; align-items: center; gap: 4px; font-size: var(--cy-fs-2); color: var(--cy-text-4); font-variant-numeric: tabular-nums; }
.cy-record-meta { font-size: var(--cy-fs-2); color: var(--cy-text-4); display: flex; align-items: center; gap: var(--cy-s-3); flex-wrap: wrap; }
.cy-record-eps { display: flex; flex-wrap: wrap; gap: var(--cy-s-2); }
.cy-record-foot { display: flex; align-items: center; gap: var(--cy-s-3); flex-wrap: wrap; padding-top: var(--cy-s-3); border-top: 1px dashed var(--cy-line); }
.cy-record-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--cy-s-4) var(--cy-s-6); }

/* ---------- 骨架族（原 .skel-* / .sk-row / .sk-w1..8，首屏不跳顶）---------- */
.cy-sk, .cy-skeleton { border-radius: var(--cy-r-1); background: var(--cy-surface-3); position: relative; overflow: hidden; }
.cy-sk::after, .cy-skeleton::after {
    content: ""; position: absolute; inset: 0;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .5), transparent);
    transform: translateX(-100%); animation: cy-shimmer 1.3s infinite;
}
/* 夜间下白扫光太刺眼，强度压低 */
[data-cy-skin="dark"] .cy-sk::after, [data-cy-skin="dark"] .cy-skeleton::after { background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .16), transparent); }
.cy-sk-h12 { height: 12px; } .cy-sk-h14 { height: 14px; } .cy-sk-h18 { height: 18px; }
.cy-sk-h24 { height: 24px; } .cy-sk-h32 { height: 32px; } .cy-sk-h42 { height: 42px; }
.cy-sk-w1 { width: 12%; } .cy-sk-w2 { width: 24%; } .cy-sk-w3 { width: 36%; }
.cy-sk-w4 { width: 48%; } .cy-sk-w5 { width: 62%; } .cy-sk-w6 { width: 74%; }
.cy-sk-w7 { width: 86%; } .cy-sk-w8 { width: 100%; }
.cy-sk-circle { border-radius: 50%; }
.cy-sk-pill { border-radius: var(--cy-r-full); }
.cy-sk-rows { display: flex; flex-direction: column; gap: var(--cy-s-3); }
/* 多列骨架：列宽用 --cy-sk-cols 控，跟真表格一致 */
.cy-sk-table { display: grid; grid-template-columns: var(--cy-sk-cols, 1.2fr .8fr 2fr .8fr 1fr); gap: var(--cy-s-4); align-items: center; }
.cy-sk-card { display: flex; align-items: center; gap: var(--cy-s-4); padding: var(--cy-s-5); border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-3); }
.cy-sk-grid { display: grid; gap: var(--cy-s-5); grid-template-columns: repeat(auto-fill, minmax(var(--cy-min, 240px), 1fr)); }
.cy-sk-stack { display: flex; gap: var(--cy-s-2); }

/* ---------- 可折叠分组（原 .completion-block / lt-pc-group-row）---------- */
.cy-group { border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-3); background: var(--cy-surface); }
/* 折叠分组不裁剪：头部右侧计数/操作钮可能带气泡；圆角给首尾段 */
.cy-group > .cy-group-hd:first-child { border-top-left-radius: calc(var(--cy-r-3) - 1px); border-top-right-radius: calc(var(--cy-r-3) - 1px); }
.cy-group > .cy-group-bd:last-child { border-bottom-left-radius: calc(var(--cy-r-3) - 1px); border-bottom-right-radius: calc(var(--cy-r-3) - 1px); }
.cy-group-hd {
    display: flex; align-items: center; gap: var(--cy-s-4); padding: var(--cy-s-4) var(--cy-s-6);
    background: var(--cy-surface-2); cursor: pointer; font-size: var(--cy-fs-3); font-weight: 800; color: var(--cy-text);
}
.cy-group-hd > i:first-child { color: var(--cy-warning); font-size: 12px; }
.cy-group-n { margin-left: auto; flex: none; font-size: var(--cy-fs-2); font-weight: 600; color: var(--cy-text-4); font-variant-numeric: tabular-nums; }
.cy-group-caret { flex: none; font-size: 10px; color: var(--cy-text-4); transition: transform var(--cy-dur) var(--cy-ease); }
.cy-group-caret.is-open { transform: rotate(90deg); }
.cy-group-bd { padding: var(--cy-s-5) var(--cy-s-6); border-top: 1px solid var(--cy-line-3); }
.cy-group-bd.is-hide { display: none; }
.cy-group + .cy-group { margin-top: var(--cy-s-4); }

/* ---------- 开关增强（原 .oal-switch：带文字、整行设置项）---------- */
/* 带文字的开关：基础轨道只有 40px，19px 滑块 + 三段文字挤在一起会把文字端部压在滑块底下，
   看着“显示不全”。这里把轨道加宽到 46px，滑块行程同步加大，文字内距让到滑块另一侧，
   保证 OFF/ON 完整露在滑块旁边（不影响纯图标开关的尺寸） */
.cy-switch--text .cy-switch-tr { width: 46px; }
.cy-switch--text .cy-switch-tr::before {
    content: "OFF"; position: absolute; right: 7px; top: 0; line-height: 23px;
    font-size: 8.5px; font-weight: 800; color: var(--cy-text-4); letter-spacing: .3px;
    pointer-events: none;
}
.cy-switch--text input:checked + .cy-switch-tr::before { content: "ON"; left: 7px; right: auto; color: #fff; }
.cy-switch--text input:checked + .cy-switch-tr::after { transform: translateX(23px); }
.cy-switch-row {
    box-sizing: border-box;          /* 关键：不设 border-box 时 width:100% + 左左内距会多出 24px，
                                       被 .cy-list 的 overflow:hidden 切掉右边，开关看起来“被遮挡” */
    display: flex; align-items: center; gap: var(--cy-s-4); width: 100%;
    padding: var(--cy-s-4) var(--cy-s-5); border-bottom: 1px solid var(--cy-line-3); cursor: pointer;
}
.cy-switch-row:last-child { border-bottom: 0; }
.cy-switch-row .cy-spacer { min-width: 0; }
.cy-switch-row:hover { background: var(--cy-surface-2); }

/* ---------- 弹窗内键值网格（原 .pstat-table / .pstat-loc / .pstat-remark）---------- */
.cy-kvgrid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1px; background: var(--cy-line-3); border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2); overflow: hidden; }
.cy-kvgrid-i { background: var(--cy-surface); padding: var(--cy-s-3) var(--cy-s-4); min-width: 0; }
.cy-kvgrid-i--full { grid-column: 1 / -1; }
.cy-kvgrid-k { font-size: 9.5px; color: var(--cy-text-4); font-weight: 800; letter-spacing: .2px; }
.cy-kvgrid-v { font-size: var(--cy-fs-3); color: var(--cy-text); font-weight: 600; margin-top: 2px; overflow-wrap: anywhere; }

/* ==========================================================================
   与原生 HTML 共存：三条规矩
   ① cyui 不写“裸元素选择器改全局”（不设 *{}、不设 body button{}），
      所以不挂 cy 类的页面与元素完全不受影响；
   ② 要美化原生标签，一律包在 :where() 里（特异性 0,0,0）或限定在 .cy-native 容器内，
      这样只要页面自己写了样式、或浏览器默认更合适，就以那边为准，不需要 !important 去抢；
   ③ 真要强制盖过原生，用下面显式的 .cy-force-* 工具类（带 !important，可审计）。
   ========================================================================== */

/* .cy-native ：可选“原生元素美化”容器。只影响包起来的标签，且全部 :where() 降权 */
.cy-native :where(h1, h2, h3, h4) { line-height: 1.3; color: var(--cy-text); margin: 0 0 .5em; font-weight: 800; }
.cy-native :where(h2) { font-size: var(--cy-fs-6); }
.cy-native :where(h3) { font-size: var(--cy-fs-5); }
.cy-native :where(h4) { font-size: var(--cy-fs-4); }
.cy-native :where(p) { margin: 0 0 .8em; line-height: var(--cy-lh); color: var(--cy-text-2); }
.cy-native :where(a) { color: var(--cy-primary); text-decoration: none; }
.cy-native :where(a:hover) { color: var(--cy-primary-hover); text-decoration: underline; }
.cy-native :where(hr) { border: 0; border-top: 1px solid var(--cy-line-3); margin: var(--cy-s-6) 0; }
.cy-native :where(ul, ol) { padding-left: 1.35em; margin: 0 0 .8em; line-height: 1.7; color: var(--cy-text-2); }
.cy-native :where(li)::marker { color: var(--cy-text-4); }
.cy-native :where(strong, b) { color: var(--cy-text); }
.cy-native :where(small) { font-size: var(--cy-fs-1); color: var(--cy-text-4); }
.cy-native :where(mark) { background: #fef3c7; color: #92400e; padding: 0 3px; border-radius: 3px; }
.cy-native :where(abbr[title]) { text-decoration: underline dotted; cursor: help; }
.cy-native :where(img) { max-width: 100%; height: auto; }
.cy-native :where(table) { width: 100%; border-collapse: collapse; font-size: var(--cy-fs-3); }
.cy-native :where(th, td) { padding: var(--cy-s-3) var(--cy-s-4); border-bottom: 1px solid var(--cy-line-3); text-align: left; }
.cy-native :where(th) { font-size: var(--cy-fs-1); color: var(--cy-text-4); background: var(--cy-surface-2); }
.cy-native :where(code) { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .9em; background: var(--cy-surface-3); padding: 1px 5px; border-radius: var(--cy-r-1); }
.cy-native :where(pre) { background: var(--cy-surface-2); border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2); padding: var(--cy-s-5); overflow: auto; font-size: var(--cy-fs-2); }
.cy-native :where(pre code) { background: transparent; padding: 0; }
.cy-native :where(kbd) { font-family: ui-monospace, monospace; font-size: 10.5px; border: 1px solid var(--cy-line); border-bottom-width: 2px; border-radius: var(--cy-r-1); padding: 1px 5px; background: var(--cy-surface-2); }
.cy-native :where(fieldset) { border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2); padding: var(--cy-s-5); margin: 0 0 var(--cy-s-5); min-width: 0; }
.cy-native :where(legend) { font-size: var(--cy-fs-2); font-weight: 800; color: var(--cy-text-3); padding: 0 var(--cy-s-2); }
.cy-native :where(output) { font-weight: 700; color: var(--cy-primary); font-variant-numeric: tabular-nums; }

/* 原生 progress / meter / range / color / file / select[multiple] —— 只“顺着原生画”，
   不抢 appearance：进度的条、颜色块、文件按钮都交给浏览器，我们只控尺寸与圆角 */
.cy-native :where(progress) { width: 100%; height: 8px; accent-color: var(--cy-primary); border: 0; }
.cy-native :where(meter) { width: 100%; height: 8px; accent-color: var(--cy-success); }
.cy-native :where(input[type=color]) { width: 40px; height: 30px; padding: 2px; border: 1px solid var(--cy-line); border-radius: var(--cy-r-1); background: var(--cy-surface); }
.cy-native :where(input[type=file]) {
    display: block; box-sizing: border-box; width: 100%;
    font-size: var(--cy-fs-3); color: var(--cy-text-2);
    padding: var(--cy-s-2) var(--cy-s-4);
    border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2); background: var(--cy-surface);
}
.cy-native :where(input[type=file]::file-selector-button) {
    margin-right: var(--cy-s-4);
    height: var(--cy-in-h, 38px); padding: 0 var(--cy-s-5);
    background: var(--cy-primary); color: #fff;
    border: 1px solid var(--cy-primary); border-radius: var(--cy-r-2);
    font-size: var(--cy-fs-3); font-weight: 600; cursor: pointer;
    transition: background var(--cy-dur) var(--cy-ease), border-color var(--cy-dur) var(--cy-ease);
}
.cy-native :where(input[type=file]::file-selector-button:hover) { background: var(--cy-primary-hover); border-color: var(--cy-primary-hover); }
.cy-native :where(input[type=file]:disabled) { opacity: .55; cursor: not-allowed; }
.cy-native :where(input[type=file]:disabled::file-selector-button) { cursor: not-allowed; }
.cy-native :where(select[multiple]) { height: auto; padding: var(--cy-s-2); }
.cy-native :where(input[type=search]::-webkit-search-decoration,
                    input[type=search]::-webkit-search-cancel-button) { -webkit-appearance: none; }

/* 原生 <details> 手风琴（零 JS）与原生 <dialog>（:modal 自带遮罩） */
.cy-acc { border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2); background: var(--cy-surface); overflow: hidden; }
.cy-acc > summary {
    display: flex; align-items: center; gap: var(--cy-s-4); padding: var(--cy-s-4) var(--cy-s-5);
    font-size: var(--cy-fs-3); font-weight: 700; color: var(--cy-text); cursor: pointer; list-style: none;
}
.cy-acc > summary::-webkit-details-marker { display: none; }
.cy-acc > summary::before { content: ""; width: 0; height: 0; border: 4px solid transparent; border-left-color: var(--cy-text-4); transition: transform var(--cy-dur) var(--cy-ease); }
.cy-acc[open] > summary::before { transform: rotate(90deg); }
.cy-acc > summary:hover { background: var(--cy-surface-2); }
.cy-acc > .cy-acc-bd { padding: var(--cy-s-5); border-top: 1px solid var(--cy-line-3); font-size: var(--cy-fs-3); color: var(--cy-text-2); }
dialog.cy-dialog-el { border: 0; padding: 0; background: transparent; color: var(--cy-text); max-width: none; width: 100%; height: 100%; }
dialog.cy-dialog-el::backdrop { background: rgba(15, 23, 42, .48); }

/* 真需要压过原生时的逃生口（少用，带 !important 可审计） */
.cy-force-round { border-radius: var(--cy-r, var(--cy-r-2)) !important; }
.cy-force-line { border: var(--cy-force-w, 1px) solid var(--cy-force-c, var(--cy-line)) !important; }
.cy-force-flat { background: transparent !important; border-color: transparent !important; box-shadow: none !important; }

/* ==========================================================================
   业务专用组件族（从实际页面需求里抽出来的）
   ========================================================================== */

/* 图库（现场照片 / 报告扫描页）：自适应列数 + 备注当 caption + 删除角标 + 选中态 */
.cy-gal { display: grid; gap: var(--cy-s-3); grid-template-columns: repeat(auto-fill, minmax(var(--cy-tile, 104px), 1fr)); }
.cy-gal-i { position: relative; border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2); overflow: hidden; background: var(--cy-surface); cursor: pointer; transition: all var(--cy-dur) var(--cy-ease); }
.cy-gal-i:hover { border-color: var(--cy-primary-soft-line); box-shadow: var(--cy-e-3); }
.cy-gal-img { display: block; position: relative; width: 100%; padding-top: 100%; background: var(--cy-surface-3); }
.cy-gal-img img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
/* 悬停盖一层放大镜（不依赖 oal.css 里任何一个类，框架自带） */
.cy-gal-zoom {
    position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
    background: rgba(15, 23, 42, .45); color: #fff; font-size: 13px; opacity: 0; transition: opacity var(--cy-dur) var(--cy-ease);
}
.cy-gal-i:hover .cy-gal-zoom { opacity: 1; }
.cy-gal-cap {
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
    padding: 4px 6px 5px; font-size: 10px; font-weight: 600; color: var(--cy-text-3); line-height: 1.35; word-break: break-all;
}
.cy-gal-x {
    position: absolute; top: 4px; right: 4px; width: 20px; height: 20px; border: 0; border-radius: 50%;
    background: rgba(15, 23, 42, .62); color: #fff; font-size: 9px; cursor: pointer;
    display: flex; align-items: center; justify-content: center; opacity: 0; transition: opacity var(--cy-dur) var(--cy-ease);
}
.cy-gal-i:hover .cy-gal-x { opacity: 1; }
.cy-gal-x:hover { background: var(--cy-danger); }
.cy-gal-add { display: flex; align-items: center; justify-content: center; min-height: var(--cy-tile, 104px); border: 1.5px dashed var(--cy-line-2); color: var(--cy-text-4); font-size: var(--cy-fs-2); font-weight: 700; cursor: pointer; background: transparent; }
.cy-gal-add:hover { border-color: var(--cy-primary); color: var(--cy-primary); background: var(--cy-primary-soft); }
.cy-gal-i.is-on { border-color: var(--cy-primary); box-shadow: 0 0 0 2px var(--cy-primary-soft); }

/* 上传/同步队列（文件名 + 进度 + 状态，失败可重试） */
.cy-upl { display: flex; flex-direction: column; gap: var(--cy-s-2); }
.cy-upl-i { display: grid; grid-template-columns: 24px 1fr auto; align-items: center; gap: var(--cy-s-4); padding: var(--cy-s-2) 0; font-size: var(--cy-fs-2); }
.cy-upl-i > i:first-child { color: var(--cy-text-4); text-align: center; }
.cy-upl-nm { min-width: 0; color: var(--cy-text-2); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cy-upl-bar { grid-column: 2 / 4; height: 3px; border-radius: 2px; background: var(--cy-surface-3); overflow: hidden; }
.cy-upl-bar > i { display: block; height: 100%; width: var(--cy-v, 0%); background: var(--cy-primary); border-radius: 2px; }
.cy-upl-st { flex: none; font-size: 10px; font-weight: 800; color: var(--cy-text-4); font-variant-numeric: tabular-nums; }
.cy-upl-i.is-ok .cy-upl-st { color: var(--cy-success); }
.cy-upl-i.is-err .cy-upl-st { color: var(--cy-danger); }
.cy-upl-i.is-err .cy-upl-bar > i { background: var(--cy-danger); }

/* 看板分栏（未开始 / 进行中 / 已完成） */
.cy-kanban { display: grid; gap: var(--cy-s-4); grid-template-columns: repeat(auto-fit, minmax(var(--cy-min, 220px), 1fr)); align-items: start; }
.cy-kan-col { background: var(--cy-surface-2); border-radius: var(--cy-r-3); padding: var(--cy-s-4); min-width: 0; }
.cy-kan-hd { display: flex; align-items: center; gap: var(--cy-s-3); font-size: var(--cy-fs-2); font-weight: 800; color: var(--cy-text-3); margin-bottom: var(--cy-s-3); }
.cy-kan-hd > i { width: 7px; height: 7px; border-radius: 50%; background: var(--cy-text-5); }
.cy-kan-col.is-run .cy-kan-hd > i { background: var(--cy-primary); } .cy-kan-col.is-run .cy-kan-hd { color: var(--cy-primary-ink); }
.cy-kan-col.is-ok .cy-kan-hd > i { background: var(--cy-success); }
.cy-kan-n { margin-left: auto; font-size: var(--cy-fs-1); color: var(--cy-text-4); }
.cy-kan-card { background: var(--cy-surface); border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2); padding: var(--cy-s-4); box-shadow: var(--cy-e-1); }
.cy-kan-card + .cy-kan-card { margin-top: var(--cy-s-3); }

/* 批量操作浮条（选中后从底部浮出） */
.cy-bulk {
    position: fixed; left: 50%; transform: translateX(-50%); bottom: calc(18px + env(safe-area-inset-bottom, 0px)); z-index: var(--cy-z-drawer);
    display: flex; align-items: center; gap: var(--cy-s-4); padding: var(--cy-s-3) var(--cy-s-5);
    background: var(--cy-text); color: var(--cy-surface); border-radius: var(--cy-r-full); box-shadow: var(--cy-e-5);
    font-size: var(--cy-fs-2); font-weight: 700;
}
.cy-bulk b { font-variant-numeric: tabular-nums; }
.cy-bulk .cy-pb { background: transparent; border-color: rgba(255, 255, 255, .24); color: #fff; }
.cy-bulk .cy-pb:hover { background: rgba(255, 255, 255, .14); border-color: rgba(255, 255, 255, .4); }

/* 提示块 / 引用块 / 带文字分隔线 */
.cy-callout {
    display: flex; gap: var(--cy-s-4); padding: var(--cy-s-4) var(--cy-s-5);
    border-left: 3px solid var(--cy-line-2); border-radius: 0 var(--cy-r-2) var(--cy-r-2) 0;
    background: var(--cy-surface-2); font-size: var(--cy-fs-3); color: var(--cy-text-2); line-height: 1.6;
}
.cy-callout > i { margin-top: 2px; color: var(--cy-text-3); }
.cy-callout b { display: block; margin-bottom: 2px; color: var(--cy-text); }
.cy-callout-primary { border-left-color: var(--cy-primary); background: var(--cy-primary-soft); color: var(--cy-primary-ink); }
.cy-callout-success { border-left-color: var(--cy-success); background: var(--cy-success-soft); color: var(--cy-success-ink); }
.cy-callout-warning { border-left-color: var(--cy-warning); background: var(--cy-warning-soft); color: var(--cy-warning-ink); }
.cy-callout-danger { border-left-color: var(--cy-danger); background: var(--cy-danger-soft); color: var(--cy-danger-ink); }
/* 卡内提示块：卡自己已经有一层边框，里面这层不再描边（否则就是“框套框”两层线）。
   语义照样读得出来 —— 靠软底 + 图标点色，不靠再画一条竖线。 */
:where(.cy-card, .cy-panel, .cy-inset, .cy-drawer-bd, .cy-dialog-body) .cy-callout {
    border-left-width: 0; border-radius: var(--cy-r-2);
}
.cy-callout-primary > i { color: var(--cy-primary); }
.cy-callout-success > i { color: var(--cy-success); }
.cy-callout-warning > i { color: var(--cy-warning); }
.cy-callout-danger > i { color: var(--cy-danger); }
.cy-quote { margin: 0; padding: var(--cy-s-2) var(--cy-s-5); border-left: 3px solid var(--cy-line); color: var(--cy-text-3); font-size: var(--cy-fs-3); font-style: italic; }
.cy-quote > footer { margin-top: 4px; font-size: var(--cy-fs-1); font-style: normal; color: var(--cy-text-4); }
.cy-divider-t { display: flex; align-items: center; gap: var(--cy-s-4); margin: var(--cy-s-6) 0; font-size: var(--cy-fs-1); font-weight: 700; color: var(--cy-text-4); white-space: nowrap; }
.cy-divider-t::before, .cy-divider-t::after { content: ""; height: 1px; background: var(--cy-line-3); flex: 1; }

/* 面包屑 / 锚点目录 / 页头 / 整页状态 */
.cy-crumb { display: flex; align-items: center; gap: var(--cy-s-2); flex-wrap: wrap; font-size: var(--cy-fs-2); color: var(--cy-text-4); }
.cy-crumb a, .cy-crumb button { border: 0; background: transparent; color: var(--cy-primary); font-size: inherit; font-weight: 600; cursor: pointer; padding: 0; }
.cy-crumb a:hover, .cy-crumb button:hover { text-decoration: underline; }
.cy-crumb-i { display: inline-flex; align-items: center; gap: var(--cy-s-2); }
.cy-crumb-i + .cy-crumb-i::before { content: "/"; color: var(--cy-text-5); }
.cy-crumb-now { color: var(--cy-text-2); font-weight: 700; }
.cy-toc { display: flex; flex-direction: column; gap: 1px; position: sticky; top: var(--cy-s-6); font-size: var(--cy-fs-2); }
.cy-toc-a { padding: 5px var(--cy-s-4); border-left: 2px solid transparent; color: var(--cy-text-3); text-decoration: none; }
.cy-toc-a:hover { color: var(--cy-text); background: var(--cy-surface-2); }
.cy-toc-a.is-on { border-left-color: var(--cy-primary); color: var(--cy-primary); background: var(--cy-primary-soft); font-weight: 700; }
.cy-pagehead { display: flex; align-items: flex-end; gap: var(--cy-s-5); flex-wrap: wrap; margin-bottom: var(--cy-s-6); }
.cy-pagehead-t { font-size: var(--cy-fs-6); font-weight: 800; color: var(--cy-text); letter-spacing: -.2px; }
.cy-pagehead-d { font-size: var(--cy-fs-2); color: var(--cy-text-4); margin-top: 3px; max-width: 68ch; }
.cy-pagehead-acts { margin-left: auto; display: inline-flex; align-items: center; gap: var(--cy-s-3); flex-wrap: wrap; }
.cy-hero {
    position: relative; overflow: hidden; padding: var(--cy-s-8); border-radius: var(--cy-r-4);
    background: linear-gradient(135deg, var(--cy-primary), var(--cy-primary-hover)); color: #fff;
}
.cy-hero-t { font-size: 24px; font-weight: 800; line-height: 1.25; }
.cy-hero-d { font-size: var(--cy-fs-3); opacity: .88; margin-top: 6px; max-width: 60ch; line-height: 1.6; }
.cy-hero-acts { display: flex; gap: var(--cy-s-3); margin-top: var(--cy-s-6); flex-wrap: wrap; }
.cy-hero .cy-pb { background: rgba(255, 255, 255, .16); border-color: rgba(255, 255, 255, .3); color: #fff; }
.cy-state { display: flex; flex-direction: column; align-items: center; gap: var(--cy-s-4); padding: 40px 20px; text-align: center; }
.cy-state-ic { display: flex; align-items: center; justify-content: center; width: 62px; height: 62px; border-radius: 50%; background: var(--cy-surface-3); color: var(--cy-text-4); font-size: 24px; }
.cy-state-t { font-size: var(--cy-fs-5); font-weight: 800; color: var(--cy-text); }
.cy-state-d { font-size: var(--cy-fs-3); color: var(--cy-text-4); max-width: 44ch; line-height: 1.6; }
.cy-state-danger .cy-state-ic { background: var(--cy-danger-soft); color: var(--cy-danger); }
.cy-state-primary .cy-state-ic { background: var(--cy-primary-soft); color: var(--cy-primary); }

/* 迷你火花柱也删了：趋势线/柱一律用 ECharts grid + bar 的小尺寸实例 */
.cy-metric { display: flex; align-items: baseline; gap: var(--cy-s-3); flex-wrap: wrap; }
.cy-metric-v { font-size: 26px; font-weight: 800; color: var(--cy-text); line-height: 1; font-variant-numeric: tabular-nums; letter-spacing: -.5px; }
.cy-metric-u { font-size: var(--cy-fs-2); color: var(--cy-text-4); font-weight: 700; }
.cy-metric-l { font-size: var(--cy-fs-2); color: var(--cy-text-3); }

/* 附件行 / 任务行 / 勾选清单 / 动态流 */
.cy-att { display: flex; align-items: center; gap: var(--cy-s-4); padding: var(--cy-s-3) var(--cy-s-4); border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2); background: var(--cy-surface); font-size: var(--cy-fs-2); }
.cy-att + .cy-att { margin-top: var(--cy-s-2); }
.cy-att-ic { display: flex; align-items: center; justify-content: center; width: 30px; height: 30px; flex: none; border-radius: var(--cy-r-1); background: var(--cy-surface-3); color: var(--cy-text-3); font-size: 13px; }
.cy-att-nm { flex: 1 1 auto; min-width: 0; font-weight: 700; color: var(--cy-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cy-att-meta { flex: none; color: var(--cy-text-4); font-variant-numeric: tabular-nums; }
.cy-att.is-doing { border-color: var(--cy-warning-soft-line); background: var(--cy-warning-soft); }
.cy-att.is-doing .cy-att-ic i { animation: cy-spin-k .9s linear infinite; }
.cy-task { display: flex; align-items: center; gap: var(--cy-s-4); padding: var(--cy-s-4) var(--cy-s-5); background: var(--cy-surface); border: 1px solid var(--cy-line-3); border-left: 3px solid var(--cy-line-2); border-radius: var(--cy-r-2); }
.cy-task + .cy-task { margin-top: var(--cy-s-2); }
.cy-task-hi { border-left-color: var(--cy-danger); } .cy-task-mid { border-left-color: var(--cy-warning); } .cy-task-low { border-left-color: var(--cy-line); }
.cy-task-t { flex: 1 1 auto; min-width: 0; font-size: var(--cy-fs-3); font-weight: 700; color: var(--cy-text); }
.cy-task-m { font-size: var(--cy-fs-1); color: var(--cy-text-4); margin-top: 2px; display: flex; gap: var(--cy-s-3); flex-wrap: wrap; }
.cy-checklist { display: flex; flex-direction: column; gap: 2px; }
.cy-checklist-i { display: flex; align-items: center; gap: var(--cy-s-4); padding: var(--cy-s-3) var(--cy-s-4); border-radius: var(--cy-r-1); font-size: var(--cy-fs-3); color: var(--cy-text-2); cursor: pointer; }
.cy-checklist-i:hover { background: var(--cy-surface-2); }
.cy-checklist-i.is-done { color: var(--cy-text-4); text-decoration: line-through; }
.cy-feed { display: flex; flex-direction: column; gap: var(--cy-s-5); }
.cy-feed-i { display: flex; gap: var(--cy-s-4); min-width: 0; }
.cy-feed-b { flex: 1 1 auto; min-width: 0; }
.cy-feed-h { display: flex; align-items: baseline; gap: var(--cy-s-3); font-size: var(--cy-fs-2); }
.cy-feed-n { font-weight: 800; color: var(--cy-text); }
.cy-feed-t { color: var(--cy-text-5); font-size: var(--cy-fs-1); margin-left: auto; flex: none; font-variant-numeric: tabular-nums; }
.cy-feed-x { font-size: var(--cy-fs-3); color: var(--cy-text-2); margin-top: 2px; line-height: var(--cy-lh); }
.cy-feed-ref { margin-top: 6px; padding: var(--cy-s-3) var(--cy-s-4); border-left: 2px solid var(--cy-line); background: var(--cy-surface-2); border-radius: 0 var(--cy-r-1) var(--cy-r-1) 0; font-size: var(--cy-fs-2); color: var(--cy-text-3); }

/* 回执/支取单（现金支取申请单、签字回执那种可打印单据） */
.cy-doc { background: var(--cy-surface); border: 1px solid var(--cy-line); border-radius: var(--cy-r-3); padding: var(--cy-s-8); }
.cy-doc-hd { text-align: center; padding-bottom: var(--cy-s-5); border-bottom: 2px solid var(--cy-text); }
.cy-doc-t { font-size: var(--cy-fs-6); font-weight: 800; letter-spacing: 2px; color: var(--cy-text); }
.cy-doc-sub { font-size: var(--cy-fs-2); color: var(--cy-text-3); margin-top: 4px; letter-spacing: 1px; }
.cy-doc-rows { display: flex; flex-direction: column; }
.cy-doc-row { display: flex; align-items: baseline; gap: var(--cy-s-3); padding: var(--cy-s-3) 0; border-bottom: 1px dashed var(--cy-line); font-size: var(--cy-fs-3); }
.cy-doc-k { flex: none; width: 96px; color: var(--cy-text-3); }
.cy-doc-v { flex: 1; min-width: 0; font-weight: 700; color: var(--cy-text); border-bottom: 1px solid var(--cy-line); }
.cy-doc-total { display: flex; align-items: baseline; justify-content: flex-end; gap: var(--cy-s-4); margin-top: var(--cy-s-5); padding-top: var(--cy-s-4); border-top: 2px solid var(--cy-text); }
.cy-doc-sign { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--cy-s-7); margin-top: 34px; font-size: var(--cy-fs-2); color: var(--cy-text-3); }
.cy-doc-sign > span { border-bottom: 1px solid var(--cy-text-4); padding-bottom: 4px; }

/* 签名区 / 二维码位 / 时间戳块 */
.cy-signpad { height: 96px; border: 1px dashed var(--cy-line-2); border-radius: var(--cy-r-2); background: var(--cy-surface-2) repeating-linear-gradient(0deg, transparent 0 23px, var(--cy-line-3) 23px 24px); display: flex; align-items: center; justify-content: center; color: var(--cy-text-5); font-size: var(--cy-fs-2); }
.cy-qr { width: var(--cy-qr, 120px); height: var(--cy-qr, 120px); border: 1px solid var(--cy-line); border-radius: var(--cy-r-2); background: var(--cy-surface); display: flex; align-items: center; justify-content: center; color: var(--cy-text-5); font-size: var(--cy-fs-1); }

/* 内容可编辑 / 金额展示 / 溢出渐隐 / 滚动提示 */
.cy-editable { border-radius: var(--cy-r-1); padding: 1px 4px; outline: none; transition: background-color var(--cy-dur) var(--cy-ease); }
.cy-editable:hover { background: var(--cy-surface-2); }
.cy-editable:focus { background: var(--cy-surface); box-shadow: 0 0 0 2px var(--cy-primary-soft-line); }
.cy-money { display: inline-flex; align-items: baseline; gap: 1px; font-variant-numeric: tabular-nums; font-weight: 800; color: var(--cy-text); }
.cy-money-cny { font-size: .78em; opacity: .6; margin-right: 1px; }
.cy-money-cent { font-size: .78em; opacity: .65; }
.cy-fade-r { position: relative; max-height: var(--cy-fade, 240px); overflow: auto; }
.cy-fade-r::after { content: ""; position: sticky; bottom: 0; display: block; height: 34px; margin-top: -34px; background: linear-gradient(transparent, var(--cy-surface)); pointer-events: none; }

/* 无障碍与打印、细滚动条、紧凑模式 */
.cy-sr {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}
.cy-skiplink { position: absolute; left: -9999px; z-index: var(--cy-z-toast); padding: 8px 14px; background: var(--cy-primary); color: #fff; border-radius: 0 0 var(--cy-r-2) 0; }
.cy-skiplink:focus { left: 0; top: 0; }
.cy-thin::-webkit-scrollbar { width: 7px; height: 7px; }
.cy-thin::-webkit-scrollbar-thumb { background: var(--cy-line-2); border-radius: 4px; }
.cy-thin::-webkit-scrollbar-track { background: transparent; }
.cy-dense { --cy-s-6: 13px; --cy-s-7: 16px; --cy-panel-pad: 10px; --cy-card-pad-x: 13px; --cy-card-pad-y: 8px; --cy-in-h: 32px; }
.cy-print-only { display: none; }
@media print {
    .cy-print-only { display: block; }
    .cy-no-print { display: none !important; }
    .cy-doc { border: 0; padding: 0; }
    .cy-doc, .cy-doc-row, .cy-record, .cy-panel, .cy-card { break-inside: avoid; }
}

/* ==========================================================================
   12 栏轻量栅格（只需要跨列与响应，不做完整 Tailwind）
   ========================================================================== */
.cy-cols { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--cy-gap, var(--cy-s-5)); }
.cy-col-2 { grid-column: span 2; } .cy-col-3 { grid-column: span 3; }
.cy-col-4 { grid-column: span 4; } .cy-col-5 { grid-column: span 5; }
.cy-col-6 { grid-column: span 6; } .cy-col-7 { grid-column: span 7; }
.cy-col-8 { grid-column: span 8; } .cy-col-9 { grid-column: span 9; }
.cy-col-10 { grid-column: span 10; } .cy-col-12 { grid-column: span 12; }
.cy-rowline { display: flex; flex-wrap: wrap; gap: var(--cy-gap, var(--cy-s-5)); }

/* ==========================================================================
   浮动按钮族：FAB 开花（speed-dial）、地图控件竖列
   用法：<div class="cy-fabs"><div class="cy-fab-group" data-cy-fab>
            <div class="cy-fab-mask" data-cy-fab-mask></div>
            <div class="cy-fab-menu"><div class="cy-fab-item"><span class="cy-fab-lb">拍照</span><button class="cy-fab-mini">…</button></div>…</div>
            <button class="cy-fab cy-fab-main"><i class="fa-solid fa-plus"></i></button>
          </div></div>
   开关动作在 cyui.js 的 [data-cy-fab] 委托里，键盘 Esc 可收。
   ========================================================================== */
/* 直接锚底边，不拿任何视口单位撑高：实测 iOS 26 顶端静止态 innerH 760 而 svh 796、lvh 836，
   可见高度比 svh 还小 36px —— 用“整屏高 + justify-content:flex-end”算出来的底边必然落在
   可见区之外，FAB 被底部工具栏切掉半截（100dvh / 100svh 都会，只是差多少的区别）。
   本容器不是遮挡层（pointer-events:none，不需要盖住全屏），所以不适用“整屏 fixed 层用 dvh”
   那条规矩；菜单项在 DOM 里排在主按钮之前，锚底后自然往上长。 */
.cy-fabs {
    position: fixed; right: calc(18px + env(safe-area-inset-right, 0px));
    bottom: calc(18px + env(safe-area-inset-bottom, 0px));
    z-index: var(--cy-z-drawer);
    display: flex; flex-direction: column; align-items: flex-end;
    pointer-events: none;                       /* 不能吃掉页面点击 */
}
.cy-fabs .cy-fab-main, .cy-fabs .cy-fab-stack { pointer-events: auto; }
.cy-fab-group { position: relative; display: flex; flex-direction: column; align-items: flex-end; gap: var(--cy-s-3); }
/* iOS 26 取色规矩（全遮罩族通用，改前必读）：
   Safari 26 的 Liquid Glass 会扫描视口边缘附近的 fixed/sticky 元素，读它自身的
   background-color / backdrop-filter 染进地址栏和状态栏——opacity:0 藏不住，
   元素只要还在 DOM 里就持续被采样。fab-mask 在演示页是常驻 DOM 的，它一挂
   background，地址栏就被钉成一块深色，整个页面永远进不了沉浸态。
   解法：颜色一律画在 ::before（或 absolute 子元素）上，取色器不采样这两类，
   渐隐动画照旧。 */
.cy-fab-mask {
    position: fixed; top: 0; left: 0; right: 0; z-index: -1;
    height: 100vh; height: 100dvh;              /* 同 .cy-mask：跟工具栏收放，底部不留白条 */
    opacity: 0; pointer-events: none; transition: opacity .18s var(--cy-ease);
}
.cy-fab-mask::before {
    content: ""; position: absolute; inset: 0; min-height: 100dvh; background: rgba(15, 23, 42, .34);
}
.cy-fab-group.is-open .cy-fab-mask { opacity: 1; pointer-events: auto; }
.cy-fab-menu { display: flex; flex-direction: column; align-items: flex-end; gap: var(--cy-s-3); }
.cy-fab-menu > * {
    opacity: 0; transform: translateY(12px) scale(.84); pointer-events: none;
    transition: opacity .16s var(--cy-ease), transform .22s cubic-bezier(.2, .9, .3, 1.25);
}
.cy-fab-group.is-open .cy-fab-menu > * { opacity: 1; transform: none; pointer-events: auto; }
/* 开花错开时间：从上往下依次弹出（最多照 6 个） */
.cy-fab-group.is-open .cy-fab-menu > :nth-child(1) { transition-delay: .15s; }
.cy-fab-group.is-open .cy-fab-menu > :nth-child(2) { transition-delay: .11s; }
.cy-fab-group.is-open .cy-fab-menu > :nth-child(3) { transition-delay: .07s; }
.cy-fab-group.is-open .cy-fab-menu > :nth-child(4) { transition-delay: .04s; }
.cy-fab-group.is-open .cy-fab-menu > :nth-child(5) { transition-delay: .02s; }
.cy-fab-item { display: inline-flex; align-items: center; gap: var(--cy-s-3); }
.cy-fab-lb {
    padding: 4px 10px; border-radius: var(--cy-r-full); background: var(--cy-text); color: var(--cy-surface);
    font-size: var(--cy-fs-2); font-weight: 700; white-space: nowrap; box-shadow: var(--cy-e-2);
}
.cy-fab-mini {
    box-sizing: border-box; width: 40px; height: 40px; border: 0; border-radius: 50%;
    display: flex; align-items: center; justify-content: center; flex: none;
    background: var(--cy-surface); color: var(--cy-text-2); font-size: 14px; cursor: pointer; box-shadow: var(--cy-e-3);
}
.cy-fab-mini:hover { background: var(--cy-surface-2); color: var(--cy-primary); }
.cy-fab-mini-primary { background: var(--cy-primary); color: #fff; } .cy-fab-mini-primary:hover { background: var(--cy-primary-hover); color: #fff; }
.cy-fab-mini-success { background: var(--cy-success); color: #fff; } .cy-fab-mini-danger { background: var(--cy-danger); color: #fff; }
.cy-fab-mini-sm { width: 32px; height: 32px; font-size: 12px; }
.cy-fab-main { transition: box-shadow var(--cy-dur) var(--cy-ease), background-color var(--cy-dur) var(--cy-ease); }
.cy-fab-main > i { transition: transform .24s cubic-bezier(.2, .9, .3, 1.3); font-size: 17px; }
.cy-fab-group.is-open .cy-fab-main { background: var(--cy-primary-hover); }
/* 主钮的 ＋ 开花时旋成 ×，比另外画一个图标更稳 */
.cy-fab-group.is-open .cy-fab-main > i { transform: rotate(135deg); }
/* 地图右下角那种控件竖列（缩放/定位/全屏） */
/* 地图控件竖列：不能用 overflow:hidden 裁圆角，否则内部按钮的 data-cy-tip 气泡会被切掉
   （这类控件永远贴屏边，所以气泡默认朝左，不用手写 data-cy-tip-pos） */
.cy-fab-stack { display: inline-flex; flex-direction: column; border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2); background: var(--cy-surface); box-shadow: var(--cy-e-3); }
.cy-fs-btn:first-child { border-radius: calc(var(--cy-r-2) - 1px) calc(var(--cy-r-2) - 1px) 0 0; }
.cy-fs-btn:last-child { border-radius: 0 0 calc(var(--cy-r-2) - 1px) calc(var(--cy-r-2) - 1px); }
.cy-fs-btn:only-child { border-radius: calc(var(--cy-r-2) - 1px); }
.cy-fs-btn[data-cy-tip]::after { bottom: auto; top: 50%; left: auto; right: calc(100% + 6px); transform: translateY(-50%); }
.cy-fs-btn[data-cy-tip-pos="top"]::after { bottom: calc(100% + 6px); top: auto; left: 50%; right: auto; transform: translateX(-50%); }
.cy-fs-btn {
    box-sizing: border-box; width: 36px; height: 36px; border: 0; background: transparent;
    color: var(--cy-text-2); font-size: 13px; cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.cy-fs-btn + .cy-fs-btn { border-top: 1px solid var(--cy-line-3); }
.cy-fs-btn:hover { background: var(--cy-surface-2); color: var(--cy-primary); }

/* ---------- 底部面板三档 + 移动侧滑抽屉（收编 _mm-mobile 的 mm-side 那套）---------- */
.cy-mask--sheet { align-items: flex-end; padding: 0; }
.cy-sheet .cy-dialog-body { flex: 1 1 auto; min-height: 0; }
/* 三档高度。peek 得给够：grip 26 + 标题 48 + 按钮区 54 ≈ 128，
   再低正文就看不见了（这就是之前“peek 档看着像坏了”的原因）；
   每档再给一个 min-height，内容很少时三档看着也是三档，不会都缩成一样高 */
.cy-sheet--peek { max-height: min(252px, 38dvh); min-height: 148px; }
.cy-sheet--peek .cy-dialog-sub { display: none; }          /* 摘要档只留标题 */
.cy-sheet--peek .cy-dialog-head { min-height: 44px; }
.cy-sheet--half { max-height: 58dvh; min-height: 40dvh; }
.cy-sheet--full { max-height: 94dvh; min-height: 76dvh; }
.cy-sheet .cy-dialog-foot { flex: none; }
/* 没选档时面板也不应该吃掉整个屏：默认正文自己滚 */
.cy-sheet .cy-dialog-in { max-width: none; }
.cy-drawer {
    position: fixed; top: 0; left: 0; z-index: var(--cy-z-modal-top); width: min(84vw, 330px);
    height: 100vh; height: 100dvh;              /* 不用 bottom:0：那按小视口定位，工具栏一折叠抽屉就短一截 */
    display: flex; flex-direction: column; background: var(--cy-surface); box-shadow: var(--cy-e-5);
    padding-top: env(safe-area-inset-top, 0); transform: translateX(-100%); transition: transform .24s var(--cy-ease);
}
.cy-drawer.is-open { transform: none; }
.cy-drawer-r { left: auto; right: 0; transform: translateX(100%); }
.cy-drawer-hd { display: flex; align-items: center; gap: var(--cy-s-4); padding: var(--cy-s-5) var(--cy-s-6); border-bottom: 1px solid var(--cy-line-3); flex: none; }
.cy-drawer-bd { flex: 1 1 auto; min-width: 0; overflow: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; padding: var(--cy-s-5) var(--cy-s-6); }
.cy-drawer-ft { flex: none; padding: var(--cy-s-4) var(--cy-s-6); border-top: 1px solid var(--cy-line-3); background: var(--cy-surface-2); padding-bottom: calc(var(--cy-s-4) + env(safe-area-inset-bottom, 0px)); }
.cy-drawer-ov { position: fixed; top: 0; left: 0; right: 0; z-index: var(--cy-z-modal); height: 100vh; height: 100dvh; opacity: 0; pointer-events: none; transition: opacity .2s var(--cy-ease); }
/* 颜色画在伪元素上：iOS 26 取色器不采样伪元素，抽屉关掉后地址栏不会残留一层灰 */
.cy-drawer-ov::before { content: ""; position: absolute; inset: 0; background: rgba(15, 23, 42, .42); }
.cy-drawer-ov.is-open { opacity: 1; pointer-events: auto; }

/* ---------- 风格预设：只改令牌与一个 backdrop 钩子，不覆写任何组件规则 ----------
   收编自 oal-structures.css 的 oa-st-glass / brutal / neon / compact / gradient */
.cy-s-glass { --cy-surface: rgba(255, 255, 255, .68); --cy-card-blur: blur(14px) saturate(165%); --cy-r-base: 16px; --cy-e-1: 0 12px 30px -20px rgba(15, 23, 42, .42); }
.cy-s-brutal { --cy-r-base: 0px; --cy-line: #0f172a; --cy-line-2: #0f172a; --cy-line-3: #0f172a; --cy-e-1: 4px 4px 0 0 rgba(15, 23, 42, .9); --cy-e-2: 5px 5px 0 0 rgba(15, 23, 42, .9); --cy-e-3: 7px 7px 0 0 rgba(15, 23, 42, .9); --cy-e-4: 9px 9px 0 0 rgba(15, 23, 42, .9); --cy-e-5: 12px 12px 0 0 rgba(15, 23, 42, .9); }
.cy-s-neon { --cy-primary: #22d3ee; --cy-primary-hover: #67e8f9; --cy-primary-ink: #0e7490; --cy-e-1: 0 0 0 1px rgba(34, 211, 238, .42), 0 0 18px -4px rgba(34, 211, 238, .5); --cy-e-2: 0 0 0 1px rgba(34, 211, 238, .5), 0 0 24px -4px rgba(34, 211, 238, .55); }
.cy-s-compact { --cy-r-base: 6px; --cy-s-6: 12px; --cy-s-7: 14px; --cy-s-8: 18px; --cy-in-h: 32px; --cy-fs-4: 13px; --cy-fs-6: 17px; }
.cy-s-gradient { --cy-primary: #6366f1; --cy-primary-hover: #4338ca; --cy-success: #10b981; --cy-warning: #f59e0b; --cy-r-base: 14px; --cy-e-1: 0 4px 14px -6px rgba(99, 102, 241, .4); --cy-e-2: 0 8px 22px -10px rgba(99, 102, 241, .45); }
/* backdrop-filter 只能写在元素上，所以用 :is() 集中挂一个钩子（变量没设就是 none） */
[class*=cy-s-] :is(.cy-card, .cy-panel, .cy-kpi, .cy-list, .cy-menu, .cy-person, .cy-record, .cy-drawer) {
    -webkit-backdrop-filter: var(--cy-card-blur, none); backdrop-filter: var(--cy-card-blur, none);
}
.cy-s-glass .cy-card, .cy-s-glass .cy-panel, .cy-s-glass .cy-kpi, .cy-s-glass .cy-list { border-color: rgba(255, 255, 255, .7); }

/* ---------- 其他零碎 ---------- */
.cy-search-x { position: absolute; right: var(--cy-s-3); width: 24px; height: 24px; border: 0; border-radius: 50%; background: var(--cy-surface-3); color: var(--cy-text-3); font-size: 10px; cursor: pointer; display: flex; align-items: center; justify-content: center; }
.cy-search-x:hover { background: var(--cy-line-2); color: var(--cy-text); }
.cy-hair { height: 1px; background: var(--cy-hair, var(--cy-line-3)); transform: scaleY(.5); transform-origin: 0 100%; }
.cy-safe-b { padding-bottom: calc(var(--cy-s-5) + env(safe-area-inset-bottom, 0px)); }
/* 沉浸式配套：页面铺满整屏，贴边的容器/浮层用这几个类把自己推开安全区（而不是把页面缩进去） */
.cy-safe-t { padding-top: calc(var(--cy-s-5) + env(safe-area-inset-top, 0px)); }
.cy-safe-x { padding-left: env(safe-area-inset-left, 0px); padding-right: env(safe-area-inset-right, 0px); }
.cy-safe-full {
    padding-top: env(safe-area-inset-top, 0px); padding-bottom: env(safe-area-inset-bottom, 0px);
    padding-left: env(safe-area-inset-left, 0px); padding-right: env(safe-area-inset-right, 0px);
}
.cy-linkbar { display: flex; align-items: center; gap: var(--cy-s-4); flex-wrap: wrap; font-size: var(--cy-fs-2); }
.cy-linkbar a { color: var(--cy-primary); text-decoration: none; font-weight: 600; }
.cy-linkbar a + a::before { content: ""; width: 1px; height: 11px; background: var(--cy-line); margin-right: var(--cy-s-4); vertical-align: -1px; }
.cy-avatar-st { position: absolute; right: -1px; bottom: -1px; width: 10px; height: 10px; border-radius: 50%; border: 2px solid var(--cy-surface); background: var(--cy-success); }
.cy-avatar { position: relative; }

/* ==========================================================================
   导航与结构族
   ========================================================================== */

/* 底部导航（移动端主导航，自动吃安全区） */
.cy-tabbar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--cy-z-nav);
    display: flex; align-items: stretch; background: var(--cy-surface);
    border-top: 1px solid var(--cy-line-3);
    padding-bottom: env(safe-area-inset-bottom, 0px);
    box-shadow: 0 -2px 12px -6px rgba(15, 23, 42, .28);
}
.cy-tabbar > * { flex: 1 1 0; min-width: 0; }
.cy-tabbar-i {
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
    padding: 7px 2px 6px; border: 0; background: transparent; color: var(--cy-text-4);
    font-size: 10.5px; font-weight: 700; cursor: pointer; text-decoration: none; position: relative;
}
.cy-tabbar-i > i { font-size: 17px; line-height: 1; }
.cy-tabbar-i.is-on { color: var(--cy-primary); }
.cy-tabbar-i.is-on::before { content: ""; position: absolute; top: 0; left: 50%; transform: translateX(-50%); width: 22px; height: 3px; border-radius: 0 0 3px 3px; background: var(--cy-primary); }
.cy-tabbar-wrap { padding-bottom: calc(64px + env(safe-area-inset-bottom, 0px)); }
/* static 变体：嵌在页面/测试台里用，不固定到屏底 */
.cy-tabbar--static { position: static; box-shadow: none; padding-bottom: 0; }
.cy-tabbar-top { bottom: auto; top: 0; border-top: 0; border-bottom: 1px solid var(--cy-line-3); padding-top: env(safe-area-inset-top, 0px); padding-bottom: 0; }
.cy-tabbar-dots .cy-tabbar-i > i { font-size: 8px; width: 8px; height: 8px; border-radius: 50%; background: currentColor; }

/* 导航轨（桌面左侧窄条，Material navigation rail） */
.cy-rail {
    display: flex; flex-direction: column; align-items: center; gap: var(--cy-s-2);
    width: 78px; padding: var(--cy-s-5) var(--cy-s-2); background: var(--cy-surface);
    border-right: 1px solid var(--cy-line-3);
}
.cy-rail-i {
    display: flex; flex-direction: column; align-items: center; gap: 3px; width: 100%; padding: 7px 2px;
    border: 0; border-radius: var(--cy-r-full); background: transparent; color: var(--cy-text-4);
    font-size: 10.5px; font-weight: 700; cursor: pointer;
}
.cy-rail-i > i { font-size: 16px; }
.cy-rail-i:hover { background: var(--cy-surface-3); color: var(--cy-text-2); }
.cy-rail-i.is-on { background: var(--cy-primary-soft); color: var(--cy-primary-ink); }
.cy-rail-hr { width: 34px; height: 1px; background: var(--cy-line-3); margin: var(--cy-s-3) 0; }

/* 侧栏导航上的计数/待办红点（收编 .nav-cnt / .nav-om-due） */
.cy-nav-cnt {
    margin-left: auto; flex: none; min-width: 19px; height: 18px; padding: 0 5px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: var(--cy-r-full); background: var(--cy-surface-3); color: var(--cy-text-3);
    font-size: 10.5px; font-weight: 800; font-variant-numeric: tabular-nums;
}
.cy-nav-cnt.is-alert { background: var(--cy-danger); color: #fff; }
.cy-nav-cnt.is-dot { width: 8px; min-width: 8px; height: 8px; padding: 0; background: var(--cy-warning); }

/* 树形（用原生 details/summary，零 JS） */
.cy-tree { font-size: var(--cy-fs-3); }
.cy-tree, .cy-tree dd { margin: 0; padding: 0; }
.cy-tree ul { list-style: none; margin: 0; padding-left: 18px; position: relative; }
.cy-tree ul::before { content: ""; position: absolute; left: 7px; top: 2px; bottom: 2px; width: 1px; background: var(--cy-line-3); }
.cy-tree-li { display: flex; align-items: center; gap: var(--cy-s-3); padding: 4px var(--cy-s-2); border-radius: var(--cy-r-1); cursor: pointer; }
.cy-tree-li:hover { background: var(--cy-surface-2); }
.cy-tree-li.is-on { background: var(--cy-primary-soft); color: var(--cy-primary-ink); font-weight: 700; }
.cy-tree-t { display: inline-flex; align-items: center; gap: var(--cy-s-2); min-width: 0; }
.cy-tree-t > i:first-child { width: 13px; flex: none; font-size: 9px; color: var(--cy-text-4); transition: transform var(--cy-dur) var(--cy-ease); }
.cy-tree details[open] > .cy-tree-t > i:first-child { transform: rotate(90deg); }
.cy-tree details > summary { list-style: none; }
.cy-tree details > summary::-webkit-details-marker { display: none; }
.cy-tree-n { color: var(--cy-text-4); font-size: 10px; font-weight: 800; }

/* 描述列表（dt/dd 网格，报告正文、设备参数那种） */
.cy-dl { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--cy-s-2) var(--cy-s-6); font-size: var(--cy-fs-3); }
.cy-dl-1 { grid-template-columns: 1fr; }
.cy-dl-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.cy-dl-row { display: flex; gap: var(--cy-s-3); padding: 5px 0; border-bottom: 1px dashed var(--cy-line-3); min-width: 0; }
.cy-dl-row > dt { flex: none; width: 92px; color: var(--cy-text-4); font-size: var(--cy-fs-2); font-weight: 700; }
.cy-dl-row > dd { flex: 1 1 auto; min-width: 0; margin: 0; color: var(--cy-text); font-weight: 600; overflow-wrap: anywhere; }

/* 便当盒网格（仪表盘不等分卡布局） */
.cy-bento { display: grid; gap: var(--cy-s-4); grid-template-columns: repeat(auto-fit, minmax(var(--cy-min, 200px), 1fr)); grid-auto-rows: minmax(var(--cy-row-h, 96px), auto); }
.cy-bento-w2 { grid-column: span 2; } .cy-bento-w3 { grid-column: span 3; }
.cy-bento-h2 { grid-row: span 2; }

/* 左右分栏（带把手，只给视觉，拖拽自己接） */
.cy-split { display: grid; grid-template-columns: var(--cy-split-a, 1fr) var(--cy-split-b, 300px); gap: 0; min-width: 0; }
.cy-split-bd { position: relative; min-width: 0; }
.cy-split-gut { width: 12px; cursor: col-resize; background: var(--cy-surface-2); border-left: 1px solid var(--cy-line-3); border-right: 1px solid var(--cy-line-3); }
.cy-split-gut::after { content: ""; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 2px; height: 26px; border-radius: 2px; background: var(--cy-line-2); }

/* 粘顶小节头 + 回到顶部 */
.cy-stickyhd { position: sticky; top: 0; z-index: var(--cy-z-sticky); background: var(--cy-surface); border-bottom: 1px solid var(--cy-line-3); padding: var(--cy-s-3) var(--cy-s-5); font-size: var(--cy-fs-2); font-weight: 800; color: var(--cy-text-3); }
.cy-sticktop { position: fixed; right: calc(18px + env(safe-area-inset-right, 0px)); bottom: calc(84px + env(safe-area-inset-bottom, 0px)); width: 36px; height: 36px; border: 1px solid var(--cy-line-3); border-radius: 50%; background: var(--cy-surface); color: var(--cy-text-3); box-shadow: var(--cy-e-3); cursor: pointer; display: flex; align-items: center; justify-content: center; }
.cy-loadmore { display: flex; align-items: center; justify-content: center; gap: var(--cy-s-3); width: 100%; padding: var(--cy-s-4); border: 1px dashed var(--cy-line-2); border-radius: var(--cy-r-2); background: transparent; color: var(--cy-text-3); font-size: var(--cy-fs-2); font-weight: 700; cursor: pointer; }
.cy-loadmore:hover { border-color: var(--cy-primary); color: var(--cy-primary); background: var(--cy-primary-soft); }

/* ==========================================================================
   输入增强族
   ========================================================================== */

/* 标签输入（chip 里带 ×，末尾是 input） */
.cy-tags {
    box-sizing: border-box; display: flex; flex-wrap: wrap; align-items: center; gap: var(--cy-s-2);
    min-height: var(--cy-in-h, 38px); padding: 5px var(--cy-s-4); border: 1px solid var(--cy-line);
    border-radius: var(--cy-in-r, var(--cy-r-2)); background: var(--cy-in-bg, var(--cy-surface)); cursor: text;
}
.cy-tags:focus-within { border-color: var(--cy-primary); box-shadow: 0 0 0 3px var(--cy-focus-ring); }
.cy-tags-i { display: inline-flex; align-items: center; gap: 3px; height: 22px; padding: 0 4px 0 7px; border-radius: var(--cy-r-1); background: var(--cy-primary-soft); color: var(--cy-primary-ink); font-size: var(--cy-fs-1); font-weight: 700; }
.cy-tags-x { border: 0; background: transparent; color: inherit; opacity: .6; cursor: pointer; font-size: 10px; padding: 2px; }
.cy-tags-x:hover { opacity: 1; color: var(--cy-danger); }
.cy-tags > input { flex: 1 1 90px; min-width: 90px; border: 0; outline: 0; background: transparent; color: var(--cy-text); font: inherit; font-size: var(--cy-fs-3); }

/* 自动补全建议列（挂在输入框下方，高亮项走 .is-on） */
.cy-suggest {
    position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: var(--cy-z-popover);
    box-sizing: border-box; max-height: 264px; overflow: auto; padding: var(--cy-s-1);
    border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2); background: var(--cy-surface); box-shadow: var(--cy-e-4);
}
.cy-suggest-i { box-sizing: border-box; display: flex; align-items: center; gap: var(--cy-s-3); width: 100%; padding: 6px var(--cy-s-3); border: 0; border-radius: var(--cy-r-1); background: transparent; color: var(--cy-text-2); font-size: var(--cy-fs-3); text-align: left; cursor: pointer; }
.cy-suggest-i.is-on { background: var(--cy-primary-soft); color: var(--cy-primary-ink); }
.cy-suggest-k { color: var(--cy-primary); font-weight: 800; }
.cy-suggest-m { margin-left: auto; flex: none; font-size: var(--cy-fs-1); color: var(--cy-text-4); }
.cy-suggest-empty { padding: var(--cy-s-5); text-align: center; color: var(--cy-text-4); font-size: var(--cy-fs-2); }
/* 嵌在表单里直接展开（不弹浮层）的场景 */
.cy-suggest--static { position: static; max-height: none; box-shadow: none; margin-top: var(--cy-s-2); }

/* 命令面板（cy.cmdk 用，键盘 ↑↓ + 回车） */
.cy-cmd-input { box-sizing: border-box; width: 100%; height: 46px; padding: 0 var(--cy-s-6) 0 40px; border: 0; border-bottom: 1px solid var(--cy-line-3); background: transparent; color: var(--cy-text); font-size: var(--cy-fs-4); outline: 0; }
.cy-cmd-ic { position: absolute; left: var(--cy-s-6); top: 15px; color: var(--cy-text-4); }
.cy-cmd-grp { padding: var(--cy-s-3) var(--cy-s-4) 4px; font-size: 10px; font-weight: 800; letter-spacing: .4px; color: var(--cy-text-4); text-transform: uppercase; }
.cy-cmd-list { max-height: 340px; overflow: auto; -webkit-overflow-scrolling: touch; padding: 0 var(--cy-s-2) var(--cy-s-3); }

/* 滑块：保留原生 appearance（体验最顺），只控颜色与刻度行 */
.cy-range { width: 100%; accent-color: var(--cy-primary); }
.cy-range-lg { height: 30px; }
.cy-range-row { display: flex; align-items: center; gap: var(--cy-s-4); }
.cy-range-row > output { flex: none; min-width: 46px; text-align: right; font-weight: 800; color: var(--cy-primary); font-variant-numeric: tabular-nums; }
.cy-range-ticks { display: flex; justify-content: space-between; margin-top: 2px; font-size: var(--cy-fs-1); color: var(--cy-text-4); font-variant-numeric: tabular-nums; }

/* 表单分组与响应式列 */
.cy-fieldset { box-sizing: border-box; border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-3); padding: var(--cy-s-6); background: var(--cy-surface); min-width: 0; }
.cy-legend { display: inline-flex; align-items: center; gap: var(--cy-s-3); font-size: var(--cy-fs-2); font-weight: 800; color: var(--cy-text-3); padding: 0 var(--cy-s-3); background: var(--cy-surface); }
.cy-formgrid { display: grid; gap: var(--cy-s-5); grid-template-columns: repeat(auto-fit, minmax(var(--cy-min, 220px), 1fr)); }
.cy-formgrid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.cy-formspan2 { grid-column: 1 / -1; }

/* 筛选条（已选条件 + 清除） */
.cy-filterbar { display: flex; align-items: center; gap: var(--cy-s-3); flex-wrap: wrap; padding: var(--cy-s-4) var(--cy-s-5); border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2); background: var(--cy-surface-2); font-size: var(--cy-fs-2); }
.cy-filterbar-k { color: var(--cy-text-4); font-weight: 700; }
.cy-filterbar-x { margin-left: auto; border: 0; background: transparent; color: var(--cy-primary); font-size: var(--cy-fs-2); font-weight: 700; cursor: pointer; }

/* ==========================================================================
   业务输出族（任务卡 / 地图 / 结果页 / 引导 / 代码块 / 水印 / 印章）
   ========================================================================== */

/* 任务卡（收编 .detect-task-card / .wf-project-card：状态 + 环节轨道 + 人员 + 截止 + 操作） */
.cy-tcard {
    box-sizing: border-box; display: flex; flex-direction: column; gap: var(--cy-s-4);
    padding: var(--cy-s-5) var(--cy-s-6); border: 1px solid var(--cy-line-3); border-left: 3px solid var(--cy-primary);
    border-radius: var(--cy-r-3); background: var(--cy-surface); box-shadow: var(--cy-e-1); min-width: 0;
}
.cy-tcard-s { border-left-color: var(--cy-success); } .cy-tcard-w { border-left-color: var(--cy-warning); }
.cy-tcard-d { border-left-color: var(--cy-line-2); } .cy-tcard-e { border-left-color: var(--cy-danger); }
.cy-tcard-hd { display: flex; align-items: flex-start; gap: var(--cy-s-4); flex-wrap: wrap; }
.cy-tcard-t { font-size: var(--cy-fs-4); font-weight: 800; color: var(--cy-text); min-width: 0; }
.cy-tcard-m { font-size: var(--cy-fs-2); color: var(--cy-text-4); margin-top: 2px; }
.cy-tcard-dead { margin-left: auto; flex: none; display: inline-flex; align-items: center; gap: 4px; font-size: var(--cy-fs-2); font-weight: 700; color: var(--cy-text-3); font-variant-numeric: tabular-nums; }
.cy-tcard-dead.is-over { color: var(--cy-danger); }
.cy-tcard-people { display: flex; align-items: center; gap: var(--cy-s-2); flex-wrap: wrap; font-size: var(--cy-fs-1); color: var(--cy-text-3); }
.cy-tcard-acts { display: flex; align-items: center; gap: var(--cy-s-2); flex-wrap: wrap; padding-top: var(--cy-s-3); border-top: 1px dashed var(--cy-line); }
/* 头像堆叠（+N） */
.cy-avatars { display: inline-flex; align-items: center; }
.cy-avatars > .cy-avatar { margin-left: -7px; border: 2px solid var(--cy-surface); }
.cy-avatars > .cy-avatar:first-child { margin-left: 0; }
.cy-avatars-n { margin-left: 4px; font-size: var(--cy-fs-1); font-weight: 800; color: var(--cy-text-4); }

/* 地图 popup 卡 / 图层开关 / 坐标行（收编 _mm-mobile 的 mm-popup 等） */
.cy-mappop {
    box-sizing: border-box; width: 258px; padding: var(--cy-s-4) var(--cy-s-5);
    border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2); background: var(--cy-surface); box-shadow: var(--cy-e-4); font-size: var(--cy-fs-2);
}
.cy-mappop-t { display: flex; align-items: center; gap: var(--cy-s-3); font-size: var(--cy-fs-3); font-weight: 800; color: var(--cy-text); }
.cy-mappop-x { margin-left: auto; border: 0; background: transparent; color: var(--cy-text-4); cursor: pointer; }
.cy-mappop-d { color: var(--cy-text-3); margin-top: 4px; line-height: 1.5; }
.cy-mappop-acts { display: flex; gap: var(--cy-s-2); margin-top: var(--cy-s-4); flex-wrap: wrap; }
.cy-layer { display: flex; flex-direction: column; }
.cy-layer-i { display: flex; align-items: center; gap: var(--cy-s-4); padding: var(--cy-s-3) var(--cy-s-4); font-size: var(--cy-fs-3); color: var(--cy-text-2); cursor: pointer; }
.cy-layer-i + .cy-layer-i { border-top: 1px solid var(--cy-line-3); }
.cy-layer-i:hover { background: var(--cy-surface-2); }
.cy-layer-sw { width: 12px; height: 12px; border-radius: 3px; flex: none; border: 1px solid var(--cy-line-2); background: var(--cy-surface); }
.cy-layer-n { margin-left: auto; font-size: var(--cy-fs-1); color: var(--cy-text-4); font-variant-numeric: tabular-nums; }
.cy-coord { display: flex; align-items: center; gap: var(--cy-s-3); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--cy-fs-2); color: var(--cy-text-2); font-variant-numeric: tabular-nums; }
.cy-coord-k { color: var(--cy-text-4); font-weight: 800; }

/* 结果页（提交/审批/导入完成那种整屏反馈） */
.cy-result { display: flex; flex-direction: column; align-items: center; gap: var(--cy-s-5); padding: 34px 20px 30px; text-align: center; }
.cy-result-ic { display: flex; align-items: center; justify-content: center; width: 72px; height: 72px; border-radius: 50%; font-size: 30px; background: var(--cy-success-soft); color: var(--cy-success); }
.cy-result-danger .cy-result-ic { background: var(--cy-danger-soft); color: var(--cy-danger); }
.cy-result-warning .cy-result-ic { background: var(--cy-warning-soft); color: var(--cy-warning-ink); }
.cy-result-info .cy-result-ic { background: var(--cy-primary-soft); color: var(--cy-primary); }
.cy-result-t { font-size: var(--cy-fs-6); font-weight: 800; color: var(--cy-text); }
.cy-result-d { font-size: var(--cy-fs-3); color: var(--cy-text-3); max-width: 52ch; line-height: var(--cy-lh); }
.cy-result-acts { display: flex; gap: var(--cy-s-4); flex-wrap: wrap; justify-content: center; }
.cy-result-meta { display: flex; flex-direction: column; gap: 2px; margin-top: var(--cy-s-2); font-size: var(--cy-fs-2); color: var(--cy-text-4); }

/* 分步引导（高亮罩 + 气泡 + 步骤点） */
.cy-tour {
    position: fixed; z-index: var(--cy-z-toast); width: min(88vw, 320px); padding: var(--cy-s-5) var(--cy-s-6);
    border-radius: var(--cy-r-3); background: var(--cy-text); color: var(--cy-surface); box-shadow: var(--cy-e-5);
}
.cy-tour-t { font-size: var(--cy-fs-4); font-weight: 800; }
.cy-tour-d { font-size: var(--cy-fs-2); line-height: 1.6; opacity: .86; margin-top: 4px; }
.cy-tour-dots { display: flex; gap: 5px; margin-top: var(--cy-s-4); }
.cy-tour-dot { width: 6px; height: 6px; border-radius: 50%; background: rgba(255, 255, 255, .3); }
.cy-tour-dot.is-on { background: #fff; width: 16px; border-radius: 3px; }
.cy-tour-acts { display: flex; align-items: center; gap: var(--cy-s-3); margin-top: var(--cy-s-4); }
.cy-tour-acts .cy-pb { background: transparent; border-color: rgba(255, 255, 255, .26); color: #fff; }
.cy-tour-acts .cy-pb:hover { background: rgba(255, 255, 255, .14); }
.cy-tour-arrow { position: absolute; width: 12px; height: 12px; background: var(--cy-text); transform: rotate(45deg); }
.cy-tour--static { position: static; width: auto; }

/* 代码块（带语言标 + 复制钮） */
.cy-codeblock { position: relative; box-sizing: border-box; margin: 0; padding: var(--cy-s-5) var(--cy-s-6) var(--cy-s-5) var(--cy-s-5); border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2); background: var(--cy-surface-2); overflow: auto; }
.cy-codeblock code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--cy-fs-2); line-height: 1.65; color: var(--cy-text-2); display: block; }
.cy-codeblock-lang { position: absolute; top: 5px; right: 46px; font-size: 9.5px; font-weight: 800; letter-spacing: .4px; color: var(--cy-text-5); text-transform: uppercase; }
.cy-codeblock-copy { position: absolute; top: 5px; right: 6px; border: 1px solid var(--cy-line); border-radius: var(--cy-r-1); background: var(--cy-surface); color: var(--cy-text-3); font-size: 10px; font-weight: 700; padding: 2px 6px; cursor: pointer; }
.cy-codeblock-copy:hover { color: var(--cy-primary); border-color: var(--cy-primary-soft-line); }

/* 印章与水印（报告预览/已审核标记） */
.cy-stamp {
    display: inline-flex; align-items: center; justify-content: center; padding: 4px 12px;
    border: 2px solid currentColor; border-radius: var(--cy-r-1); color: var(--cy-danger);
    font-size: var(--cy-fs-4); font-weight: 800; letter-spacing: 2px; transform: rotate(-8deg); opacity: .88;
}
.cy-stamp-ok { color: var(--cy-success); } .cy-stamp-void { color: var(--cy-text-4); }
.cy-stamp-circle { width: 84px; height: 84px; border-radius: 50%; font-size: var(--cy-fs-2); line-height: 1.3; text-align: center; }
.cy-wmk { position: relative; overflow: hidden; }
.cy-wmk::before {
    content: attr(data-cy-wmk); position: absolute; inset: 0; pointer-events: none; z-index: 1;
    display: flex; align-items: center; justify-content: center;
    font-size: 42px; font-weight: 800; letter-spacing: 6px; color: rgba(148, 163, 184, .18);
    transform: rotate(-28deg); white-space: nowrap;
}

/* 待办盒子行（未读点 + 左色标） */
.cy-inbox { display: flex; flex-direction: column; }
.cy-inbox-row { display: flex; align-items: center; gap: var(--cy-s-4); padding: var(--cy-s-4) var(--cy-s-5); border-bottom: 1px solid var(--cy-line-3); cursor: pointer; min-width: 0; }
.cy-inbox-row:hover { background: var(--cy-surface-2); }
.cy-inbox-row.is-unread { background: var(--cy-primary-soft); }
.cy-inbox-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--cy-line-2); }
.cy-inbox-row.is-unread .cy-inbox-dot { background: var(--cy-primary); }
.cy-inbox-t { flex: 1 1 auto; min-width: 0; font-size: var(--cy-fs-3); font-weight: 700; color: var(--cy-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cy-inbox-m { flex: none; font-size: var(--cy-fs-1); color: var(--cy-text-4); font-variant-numeric: tabular-nums; }

/* 迷你月历（排期/到期提醒，不是图表，纯日历格） */
.cy-cal { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 3px; font-size: var(--cy-fs-1); }
.cy-cal-h { text-align: center; color: var(--cy-text-4); font-weight: 800; padding: 2px 0; }
.cy-cal-d { position: relative; box-sizing: border-box; aspect-ratio: 1 / 1; display: flex; align-items: center; justify-content: center; border-radius: var(--cy-r-1); background: var(--cy-surface-2); color: var(--cy-text-2); font-variant-numeric: tabular-nums; cursor: pointer; }
.cy-cal-d:hover { background: var(--cy-surface-3); }
.cy-cal-d.is-out { color: var(--cy-text-5); background: transparent; pointer-events: none; }
.cy-cal-d.is-today { box-shadow: inset 0 0 0 1.5px var(--cy-primary); font-weight: 800; color: var(--cy-primary); }
.cy-cal-d.is-on { background: var(--cy-primary); color: #fff; font-weight: 800; }
.cy-cal-d.is-range { background: var(--cy-primary-soft); color: var(--cy-primary-ink); }
.cy-cal-d > i { position: absolute; bottom: 3px; left: 50%; transform: translateX(-50%); width: 4px; height: 4px; border-radius: 50%; background: var(--cy-warning); }

/* ==========================================================================
   下拉框家族
   ① cy-select：原生 select（能用就用，移动端体验最好）
   ② cy-dd：自定义下拉（多选 / 搜索 / 分组 / 已选 chips），cy.dd() 接键盘与外点关闭
   ========================================================================== */
.cy-dd { position: relative; display: inline-block; min-width: 0; }
.cy-dd-btn {
    box-sizing: border-box; display: flex; align-items: center; gap: var(--cy-s-3); width: 100%;
    min-height: var(--cy-in-h, 38px); padding: 4px 30px 4px var(--cy-s-5);
    -webkit-appearance: none; appearance: none;
    border: 1px solid var(--cy-line); border-radius: var(--cy-in-r, var(--cy-r-2));
    background: var(--cy-in-bg, var(--cy-surface)); color: var(--cy-text); font-family: inherit;
    font-size: var(--cy-fs-3); text-align: left; cursor: pointer; position: relative;
    transition: border-color var(--cy-dur) var(--cy-ease), box-shadow var(--cy-dur) var(--cy-ease);
}
.cy-dd-btn:hover { border-color: var(--cy-line-2); }
.cy-dd-btn.is-on { border-color: var(--cy-primary); box-shadow: 0 0 0 3px var(--cy-focus-ring); }
.cy-dd-btn::after {
    content: ""; position: absolute; right: var(--cy-s-5); top: 50%; width: 8px; height: 8px;
    border: 1.5px solid var(--cy-text-4); border-top: 0; border-left: 0;
    transform: translateY(-70%) rotate(45deg); transition: transform var(--cy-dur) var(--cy-ease);
}
.cy-dd-btn.is-on::after { transform: translateY(-30%) rotate(-135deg); }
.cy-dd-btn:disabled { background: var(--cy-surface-2); color: var(--cy-text-4); cursor: not-allowed; }
.cy-dd-ph { color: var(--cy-ph); }        /* 未选时的占位文案 */
.cy-dd-lb { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cy-dd-cnt {
    flex: none; min-width: 18px; height: 18px; padding: 0 5px; border-radius: var(--cy-r-full);
    background: var(--cy-primary-soft); color: var(--cy-primary-ink);
    font-size: 10px; font-weight: 800; display: inline-flex; align-items: center; justify-content: center;
}
.cy-dd-x { flex: none; border: 0; background: transparent; color: var(--cy-text-4); cursor: pointer; font-size: 10px; padding: 3px; }
.cy-dd-x:hover { color: var(--cy-danger); }
.cy-dd-panel {
    position: absolute; top: calc(100% + 4px); left: 0; z-index: var(--cy-z-popover);
    box-sizing: border-box; min-width: 100%; max-width: min(92vw, 420px); max-height: 268px;
    display: flex; flex-direction: column; overflow: hidden;
    border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2); background: var(--cy-surface); box-shadow: var(--cy-e-4);
    opacity: 0; transform: translateY(-4px); pointer-events: none; transition: opacity .14s var(--cy-ease), transform .14s var(--cy-ease);
}
.cy-dd-panel.is-open { opacity: 1; transform: none; pointer-events: auto; }
.cy-dd-panel--up { top: auto; bottom: calc(100% + 4px); transform: translateY(4px); }
.cy-dd-panel--up.is-open { transform: none; }
/* 刻意不做 cy-dd-panel--static：cy-dd 有自己的触发器，文档必须演真实交互（点开才弹、选中/Esc/点外部收）。
   面板展开时压在下方内容之上是浮层的正常行为（z 台阶 950 就是为压过 sticky 顶栏 900 而定的），
   不是遮挡 bug；若为“常驻可见”改成 position:static，open() 只切 is-open，面板将永远收不起来。 */
.cy-dd-search { flex: none; padding: var(--cy-s-3); border-bottom: 1px solid var(--cy-line-3); }
.cy-dd-list { flex: 1 1 auto; min-height: 0; overflow: auto; -webkit-overflow-scrolling: touch; padding: var(--cy-s-1); }
.cy-dd-grp { position: sticky; top: 0; padding: 6px var(--cy-s-3) 3px; background: var(--cy-surface); font-size: 10px; font-weight: 800; letter-spacing: .3px; color: var(--cy-text-4); text-transform: uppercase; }
.cy-dd-opt {
    box-sizing: border-box; display: flex; align-items: center; gap: var(--cy-s-3); width: 100%;
    padding: 7px var(--cy-s-3); border: 0; border-radius: var(--cy-r-1); background: transparent;
    color: var(--cy-text-2); font-size: var(--cy-fs-3); text-align: left; cursor: pointer; min-width: 0;
}
.cy-dd-opt:hover { background: var(--cy-surface-2); }
.cy-dd-opt.is-on { background: var(--cy-primary-soft); color: var(--cy-primary-ink); }
.cy-dd-opt.is-sel { color: var(--cy-primary-ink); font-weight: 700; }
.cy-dd-opt-tick { flex: none; width: 15px; text-align: center; color: var(--cy-primary); font-size: 11px; opacity: 0; }
.cy-dd-opt.is-sel .cy-dd-opt-tick { opacity: 1; }
.cy-dd-opt-b { min-width: 0; flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cy-dd-opt-m { flex: none; margin-left: auto; font-size: var(--cy-fs-1); color: var(--cy-text-4); }
.cy-dd-foot { flex: none; display: flex; align-items: center; gap: var(--cy-s-3); padding: var(--cy-s-3); border-top: 1px solid var(--cy-line-3); background: var(--cy-surface-2); }
.cy-dd-empty { padding: var(--cy-s-6); text-align: center; color: var(--cy-text-4); font-size: var(--cy-fs-2); }
.cy-dd-chips { display: flex; flex-wrap: wrap; gap: var(--cy-s-2); padding: var(--cy-s-3); border: 1px solid var(--cy-line); border-radius: var(--cy-in-r, var(--cy-r-2)); min-height: var(--cy-in-h, 38px); align-items: center; cursor: text; }
.cy-dd-sm > .cy-dd-btn { min-height: 30px; font-size: var(--cy-fs-2); }
/* 原生多选与分组 */
.cy-select[multiple] { background-image: none; padding: var(--cy-s-2); height: auto; min-height: 92px; }
.cy-select optgroup { font-size: var(--cy-fs-1); font-weight: 800; color: var(--cy-text-4); background: var(--cy-surface-2); font-style: normal; }

/* ==========================================================================
   单选 / 多选组（choice tile）
   卡面样式挂在 .cy-choice-bd 上，用相邻兄弟选择器生效 → 不依赖 :has()，老浏览器也正常
   ========================================================================== */
.cy-choices { display: grid; gap: var(--cy-s-3); grid-template-columns: repeat(auto-fit, minmax(var(--cy-min, 150px), 1fr)); }
.cy-choices-row { display: flex; flex-wrap: wrap; gap: var(--cy-s-3); }
.cy-choice { display: block; position: relative; min-width: 0; }
.cy-choice > input { position: absolute; opacity: 0; width: 0; height: 0; }
.cy-choice-bd {
    box-sizing: border-box; display: flex; align-items: flex-start; gap: var(--cy-s-3); width: 100%;
    min-height: 100%; padding: var(--cy-s-4) var(--cy-s-5); border: 1px solid var(--cy-line);
    border-radius: var(--cy-r-2); background: var(--cy-surface); cursor: pointer;
    transition: border-color var(--cy-dur) var(--cy-ease), background-color var(--cy-dur) var(--cy-ease), box-shadow var(--cy-dur) var(--cy-ease);
}
.cy-choice:hover .cy-choice-bd { border-color: var(--cy-line-2); background: var(--cy-surface-2); }
.cy-choice > input:checked + .cy-choice-bd { border-color: var(--cy-primary); background: var(--cy-primary-soft); box-shadow: inset 0 0 0 1px var(--cy-primary); }
.cy-choice > input:focus-visible + .cy-choice-bd { box-shadow: 0 0 0 3px var(--cy-focus-ring); }
.cy-choice > input:disabled + .cy-choice-bd { opacity: .55; cursor: not-allowed; }
.cy-choice-t { display: block; font-size: var(--cy-fs-3); font-weight: 700; color: var(--cy-text); min-width: 0; }
.cy-choice > input:checked + .cy-choice-bd .cy-choice-t { color: var(--cy-primary-ink); }
.cy-choice-d { display: block; font-size: var(--cy-fs-1); color: var(--cy-text-4); margin-top: 2px; line-height: 1.45; }
.cy-choice-ic { flex: none; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; border-radius: var(--cy-r-1); background: var(--cy-surface-3); color: var(--cy-text-3); font-size: 12px; }
.cy-choice-mark { position: absolute; top: 7px; right: 8px; font-size: 11px; color: var(--cy-primary); opacity: 0; pointer-events: none; }
.cy-choice > input:checked ~ .cy-choice-mark { opacity: 1; }
/* tile 形态：图标居中大字，适合“模态/分类”选择 */
.cy-choice--tile .cy-choice-bd { flex-direction: column; align-items: center; text-align: center; gap: var(--cy-s-2); padding: var(--cy-s-5) var(--cy-s-4); }
.cy-choice--tile .cy-choice-ic { width: 36px; height: 36px; font-size: 15px; }
.cy-choice--sm .cy-choice-bd { padding: var(--cy-s-3) var(--cy-s-4); }
.cy-choice--wide .cy-choice-bd { align-items: center; }
/* 带边框的勾选/单选集（比裸列一排整清） */
.cy-optset { display: flex; flex-direction: column; gap: 2px; padding: var(--cy-s-3); border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2); background: var(--cy-surface); }
.cy-optset-row { flex-direction: row; flex-wrap: wrap; gap: var(--cy-s-3) var(--cy-s-6); align-items: center; }
.cy-optset-t { font-size: var(--cy-fs-1); font-weight: 800; color: var(--cy-text-4); padding: 0 var(--cy-s-2) var(--cy-s-2); }
.cy-optset .cy-check, .cy-optset .cy-radio { padding: 5px var(--cy-s-2); border-radius: var(--cy-r-1); margin: 0; }
.cy-optset .cy-check:hover, .cy-optset .cy-radio:hover { background: var(--cy-surface-2); }

/* ==========================================================================
   排版族：链接 / Markdown 渲染（配合 cy.md()）
   ========================================================================== */
.cy-a { color: var(--cy-primary); text-decoration: none; font-weight: 600; cursor: pointer; word-break: break-word; }
.cy-a:hover { color: var(--cy-primary-hover); text-decoration: underline; }
.cy-a-muted { color: var(--cy-text-3); } .cy-a-muted:hover { color: var(--cy-primary); }
.cy-a-under { text-decoration: underline; text-underline-offset: 2px; }
.cy-a-dashed { text-decoration: underline dotted; text-underline-offset: 3px; cursor: help; }
.cy-a-danger { color: var(--cy-danger); } .cy-a-danger:hover { color: var(--cy-danger-ink); }
.cy-a-ext::after { content: ""; display: inline-block; width: 8px; height: 8px; margin-left: 3px; vertical-align: 1px; background: currentColor; -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3'><path d='M7 17L17 7M9 7h8v8'/></svg>") center / contain no-repeat; mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3'><path d='M7 17L17 7M9 7h8v8'/></svg>") center / contain no-repeat; }
.cy-a-x { border: 0; background: transparent; color: var(--cy-text-4); cursor: pointer; font-size: 10px; padding: 2px; }

.cy-md { font-size: var(--cy-fs-3); line-height: 1.75; color: var(--cy-text-2); word-break: break-word; }
.cy-md > :first-child { margin-top: 0; }
.cy-md > :last-child { margin-bottom: 0; }
.cy-md h1, .cy-md h2, .cy-md h3, .cy-md h4 { color: var(--cy-text); font-weight: 800; line-height: 1.35; margin: 1.3em 0 .55em; }
.cy-md h1 { font-size: 21px; padding-bottom: .3em; border-bottom: 1px solid var(--cy-line-3); }
.cy-md h2 { font-size: var(--cy-fs-6); padding-bottom: .25em; border-bottom: 1px solid var(--cy-line-3); }
.cy-md h3 { font-size: var(--cy-fs-5); }
.cy-md h4 { font-size: var(--cy-fs-4); }
.cy-md p { margin: 0 0 .85em; }
.cy-md ul, .cy-md ol { margin: 0 0 .85em; padding-left: 1.5em; }
.cy-md li { margin: .2em 0; }
.cy-md li::marker { color: var(--cy-text-4); }
.cy-md li + li { margin-top: .3em; }
/* 任务列表（- [ ] / - [x]） */
.cy-md li.cy-md-done { list-style: none; margin-left: -1.5em; color: var(--cy-text-4); text-decoration: line-through; }
.cy-md li.cy-md-todo { list-style: none; margin-left: -1.5em; }
.cy-md li.cy-md-done::before, .cy-md li.cy-md-todo::before { content: "☐"; margin-right: .45em; color: var(--cy-text-4); }
.cy-md li.cy-md-done::before { content: "☑"; color: var(--cy-success); }
.cy-md blockquote { margin: 0 0 .85em; padding: var(--cy-s-2) var(--cy-s-5); border-left: 3px solid var(--cy-line); background: var(--cy-surface-2); color: var(--cy-text-3); border-radius: 0 var(--cy-r-1) var(--cy-r-1) 0; }
.cy-md pre { margin: 0 0 .85em; padding: var(--cy-s-5); border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2); background: var(--cy-surface-2); overflow: auto; }
.cy-md pre code { background: transparent; padding: 0; font-size: var(--cy-fs-2); line-height: 1.65; color: var(--cy-text-2); }
.cy-md code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .88em; background: var(--cy-surface-3); color: var(--cy-primary-ink); padding: .12em .4em; border-radius: var(--cy-r-1); }
.cy-md hr { border: 0; border-top: 1px solid var(--cy-line-3); margin: 1.3em 0; }
.cy-md table { width: 100%; border-collapse: collapse; margin: 0 0 .9em; font-size: var(--cy-fs-2); }
.cy-md th, .cy-md td { border: 1px solid var(--cy-line-3); padding: 6px var(--cy-s-3); text-align: left; vertical-align: top; }
.cy-md th { background: var(--cy-surface-2); font-weight: 800; color: var(--cy-text-3); white-space: nowrap; }
.cy-md tbody tr:nth-child(even) td { background: var(--cy-surface-2); }
.cy-md img { max-width: 100%; height: auto; border-radius: var(--cy-r-2); border: 1px solid var(--cy-line-3); }
.cy-md del { color: var(--cy-text-4); }
.cy-md mark { background: #fef3c7; color: #92400e; padding: 0 3px; border-radius: 3px; }
.cy-md sup a { font-weight: 800; }
.cy-md strong { color: var(--cy-text); }
.cy-md--tight { line-height: 1.6; font-size: var(--cy-fs-2); }
.cy-md--tight h1, .cy-md--tight h2, .cy-md--tight h3 { margin-top: .9em; }
.cy-md--center { text-align: center; }

/* 排版工具三件 */
.cy-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.cy-oh { overflow: hidden; }
.cy-clip { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* 表格↔卡片：窄屏下把行变卡（收编 oal 的 .mt-table 做法：隐 thead，td 拿 data-l 当小标签）
   用法：<table class="cy-table cy-table-cards"><td data-l="任务数">6</td>… */
@media (max-width: 768px) {
    .cy-table-cards thead { display: none; }
    .cy-table-cards, .cy-table-cards tbody, .cy-table-cards tr, .cy-table-cards td { display: block; width: 100%; }
    .cy-table-cards tr {
        box-sizing: border-box; border: 1px solid var(--cy-line-3); border-radius: var(--cy-r-2);
        padding: var(--cy-s-3) var(--cy-s-4); margin-bottom: var(--cy-s-3); background: var(--cy-surface);
    }
    .cy-table-cards td {
        display: flex; gap: var(--cy-s-4); align-items: baseline; justify-content: space-between;
        border: 0; padding: 4px 0; text-align: right;
    }
    .cy-table-cards td::before { content: attr(data-l); flex: none; text-align: left; color: var(--cy-text-4); font-size: 11.5px; font-weight: 700; }
    .cy-table-cards td:not([data-l])::before, .cy-table-cards td[data-l=""]::before { display: none; }
}

/* ==========================================================================
   动画预设库
   命名：cy-in-* 入场 / cy-out-* 退场 / cy-loop-* 循环 / cy-act-* 强调（一次性）
          cy-collapse 高度展开 / cy-flip 翻转 / cy-morph 形变 / cy-stagger 交错
   控制：cy-d-* 时长、cy-delay-1..10 延迟、cy-ease-* 曲线、cy-forever 循环无限
   规则：预设只写 animation，不写 animation-fill-mode 以外的布局属性，
          所以能直接往任何组件上叠；prefers-reduced-motion 里统一关掉。
   ========================================================================== */
.cy-anim { animation-duration: var(--cy-dur-anim, .32s); animation-timing-function: var(--cy-ease); animation-fill-mode: both; }

/* —— 入场 —— */
.cy-in-fade    { animation: cy-k-fade var(--cy-dur-anim, .32s) var(--cy-ease) both; }
.cy-in-up      { animation: cy-k-up var(--cy-dur-anim, .32s) var(--cy-ease-out, cubic-bezier(.16, 1, .3, 1)) both; }
.cy-in-down    { animation: cy-k-down var(--cy-dur-anim, .32s) var(--cy-ease-out, cubic-bezier(.16, 1, .3, 1)) both; }
.cy-in-left    { animation: cy-k-left var(--cy-dur-anim, .32s) var(--cy-ease-out, cubic-bezier(.16, 1, .3, 1)) both; }
.cy-in-right   { animation: cy-k-right var(--cy-dur-anim, .32s) var(--cy-ease-out, cubic-bezier(.16, 1, .3, 1)) both; }
.cy-in-zoom    { animation: cy-k-zoom var(--cy-dur-anim, .32s) cubic-bezier(.2, .9, .3, 1.25) both; }
.cy-in-zoom-out{ animation: cy-k-zoom-out var(--cy-dur-anim, .32s) var(--cy-ease) both; }
.cy-in-pop     { animation: cy-k-pop .38s cubic-bezier(.2, 1.4, .4, 1) both; }
.cy-in-blur    { animation: cy-k-blur .4s var(--cy-ease) both; }
.cy-in-flip-x  { animation: cy-k-flip-x .5s var(--cy-ease) both; transform-origin: top center; }
.cy-in-flip-y  { animation: cy-k-flip-y .5s var(--cy-ease) both; transform-origin: left center; }
.cy-in-rotate  { animation: cy-k-rotate .42s var(--cy-ease) both; }
.cy-in-bounce  { animation: cy-k-bounce .6s cubic-bezier(.2, .9, .3, 1.2) both; }
.cy-in-drop    { animation: cy-k-drop .36s cubic-bezier(.2, 1.2, .4, 1) both; }
.cy-in-swing   { animation: cy-k-swing .6s ease-out both; transform-origin: top center; }
.cy-in-roll    { animation: cy-k-roll .5s var(--cy-ease) both; }
.cy-in-skew    { animation: cy-k-skew .4s var(--cy-ease) both; }
.cy-in-stretch { animation: cy-k-stretch .42s var(--cy-ease) both; transform-origin: center bottom; }
.cy-in-fold    { animation: cy-k-fold .4s var(--cy-ease) both; transform-origin: top left; }

/* —— 退场（与入场成对，JS 里等 animationend 再真删节点）—— */
.cy-out-fade    { animation: cy-k-fade .22s var(--cy-ease) reverse both; }
.cy-out-up      { animation: cy-k-up .24s var(--cy-ease) reverse both; }
.cy-out-down    { animation: cy-k-down .24s var(--cy-ease) reverse both; }
.cy-out-zoom    { animation: cy-k-zoom .24s var(--cy-ease) reverse both; }
.cy-out-shrink  { animation: cy-k-shrink .22s var(--cy-ease) both; }
.cy-out-collapse{ animation: cy-k-collapse .26s var(--cy-ease) both; transform-origin: top center; }
.cy-out-blur    { animation: cy-k-blur .26s var(--cy-ease) reverse both; }
.cy-out-spin    { animation: cy-k-spin-out .3s var(--cy-ease) both; }

/* —— 循环（cy-forever 无限，否则跑一轮）—— */
.cy-loop-spin      { animation: cy-k-spin-forever 1s linear infinite; }
.cy-loop-spin-rev  { animation: cy-k-spin-forever 1s linear infinite reverse; }
.cy-loop-spin-slow { animation: cy-k-spin-forever 6s linear infinite; }
.cy-loop-pulse     { animation: cy-k-pulse 1.6s var(--cy-ease) infinite; }
.cy-loop-blink     { animation: cy-k-blink 1.2s steps(2, start) infinite; }
.cy-loop-ping      { animation: cy-k-ping 1.4s cubic-bezier(0, 0, .2, 1) infinite; }
.cy-loop-breathe   { animation: cy-k-breathe 3.2s ease-in-out infinite; }
.cy-loop-float     { animation: cy-k-float 3s ease-in-out infinite; }
.cy-loop-bob       { animation: cy-k-bob 1.4s ease-in-out infinite; }
.cy-loop-swing     { animation: cy-k-swing-loop 1.6s ease-in-out infinite; transform-origin: top center; }
.cy-loop-bounce    { animation: cy-k-bounce-loop 1s cubic-bezier(.28, .84, .42, 1) infinite; }
.cy-loop-wave      { animation: cy-k-wave 1.4s ease-in-out infinite; }
.cy-loop-heartbeat { animation: cy-k-heartbeat 1.3s ease-in-out infinite; }
.cy-loop-orbit     { animation: cy-k-orbit 4s linear infinite; }
.cy-loop-shimmer   { animation: cy-shimmer 1.3s infinite; }
.cy-loop-marquee   { animation: cy-k-marquee 12s linear infinite; }
.cy-loop-caret     { animation: cy-k-caret 1s steps(2, start) infinite; }
.cy-loop-drift     { animation: cy-k-drift 18s ease-in-out infinite alternate; }   /* 背景光斑慢漂 */

/* —— 强调（一次性，配合 cy.animate(el,'shake') 用）—— */
.cy-act-shake     { animation: cy-k-shake .5s var(--cy-ease) both; }
.cy-act-tada      { animation: cy-k-tada .9s var(--cy-ease) both; }
.cy-act-flash     { animation: cy-k-flash .5s var(--cy-ease) both; }
.cy-act-highlight { animation: cy-k-highlight 1.2s var(--cy-ease) both; }
.cy-act-bump      { animation: cy-k-bump .3s cubic-bezier(.2, 1.4, .4, 1) both; }
.cy-act-jiggle    { animation: cy-k-jiggle .6s ease-in-out both; }
.cy-act-wobble    { animation: cy-k-wobble .8s ease-in-out both; }
.cy-act-glow      { animation: cy-k-glow 1.1s var(--cy-ease) both; }
.cy-act-ring      { animation: cy-k-ring 1s cubic-bezier(0, 0, .2, 1) both; }

/* —— 显隐与形变（零 JS，只切一个类）—— */
/* 高度自适应展开：grid-template-rows 0fr → 1fr，比 max-height 拟真得多 */
.cy-collapse { display: grid; grid-template-rows: 0fr; opacity: 0; transition: grid-template-rows .28s var(--cy-ease), opacity .2s var(--cy-ease); }
.cy-collapse > * { overflow: hidden; min-height: 0; }
.cy-collapse.is-open { grid-template-rows: 1fr; opacity: 1; }
/* 3D 翻转卡：.cy-flip.is-on 翻到背面 */
.cy-flip { position: relative; display: block; perspective: 900px; background: transparent; }
.cy-flip-in { position: relative; width: 100%; height: 100%; transform-style: preserve-3d; transition: transform .55s var(--cy-ease); }
.cy-flip.is-on .cy-flip-in { transform: rotateY(180deg); }
.cy-flip-f, .cy-flip-b { position: absolute; inset: 0; backface-visibility: hidden; -webkit-backface-visibility: hidden; }
.cy-flip-b { transform: rotateY(180deg); }
/* 汤象形变（blob）：圆角持续变化，做占位图/空态背板 */
.cy-morph { animation: cy-k-morph 9s ease-in-out infinite; }
/* 微领斜：hover 拾起 + 轻微旋转 */
.cy-tilt { transition: transform .24s var(--cy-ease), box-shadow .24s var(--cy-ease); }
.cy-tilt:hover { transform: translateY(-3px) rotate(-.6deg); box-shadow: var(--cy-e-3); }
/* 图标开关：＋变×、下变上这类“两个状态一个元素” */
.cy-rot { transition: transform .22s var(--cy-ease); }
.cy-rot.is-on { transform: rotate(135deg); }
.cy-rot-45.is-on { transform: rotate(45deg); }
.cy-rot-90.is-on { transform: rotate(90deg); }
.cy-rot-180.is-on { transform: rotate(180deg); }

/* 交错入场：父容器标 cy-stagger，子项延迟 = calc(--cy-stagger × 序号)。
   序号两个来源：① 元素自带的 --cy-i（内联 style="--cy-i:23" 即可给任意长列表编号，优先级最高）；
   ② 没给就用 nth-child 兜到第 20 项，20 项之后统一排在最后一档。
   旧写法只列到 :nth-child(10)，第 11 个开始没有延迟规则 → 全部挤在 0ms，
   看着像“动画只给前 10 个，第 11 个直接出现”。 */
.cy-stagger > * { animation-fill-mode: both; animation-delay: calc(var(--cy-stagger, 60ms) * var(--cy-i, 0)); }
.cy-stagger > :nth-child(1) { --cy-i: 0; }
.cy-stagger > :nth-child(2) { --cy-i: 1; }
.cy-stagger > :nth-child(3) { --cy-i: 2; }
.cy-stagger > :nth-child(4) { --cy-i: 3; }
.cy-stagger > :nth-child(5) { --cy-i: 4; }
.cy-stagger > :nth-child(6) { --cy-i: 5; }
.cy-stagger > :nth-child(7) { --cy-i: 6; }
.cy-stagger > :nth-child(8) { --cy-i: 7; }
.cy-stagger > :nth-child(9) { --cy-i: 8; }
.cy-stagger > :nth-child(10) { --cy-i: 9; }
.cy-stagger > :nth-child(11) { --cy-i: 10; }
.cy-stagger > :nth-child(12) { --cy-i: 11; }
.cy-stagger > :nth-child(13) { --cy-i: 12; }
.cy-stagger > :nth-child(14) { --cy-i: 13; }
.cy-stagger > :nth-child(15) { --cy-i: 14; }
.cy-stagger > :nth-child(16) { --cy-i: 15; }
.cy-stagger > :nth-child(17) { --cy-i: 16; }
.cy-stagger > :nth-child(18) { --cy-i: 17; }
.cy-stagger > :nth-child(19) { --cy-i: 18; }
.cy-stagger > :nth-child(20) { --cy-i: 19; }
/* 21 项以后：同一条特异度，靠源码顺序兜住，不再“没规则 = 0ms” */
.cy-stagger > :nth-child(n+21) { --cy-i: 19; }

/* 滚动进场钩子：先隐藏，cy.reveal() 给 .is-in 后播入场 */
.cy-reveal { opacity: 0; }
.cy-reveal.is-in { animation: cy-k-up var(--cy-dur-anim, .5s) var(--cy-ease-out, cubic-bezier(.16, 1, .3, 1)) both; }
.cy-reveal-fade.is-in { animation-name: cy-k-fade; }
.cy-reveal-zoom.is-in { animation-name: cy-k-zoom; }
/* 无 JS / 不支持 IntersectionObserver 时不能把内容永远隐掉（scripting 介质特性不支持时本条不生效，
   所以 cyui.js 里还有一道“没 IO 就直接放出来”的兜底） */
@media (scripting: none) { .cy-reveal { opacity: 1; } }

/* —— 控制器：时长 / 延迟 / 曲线 / 循环次数 —— */
.cy-d-75 { animation-duration: 75ms; } .cy-d-150 { animation-duration: 150ms; }
.cy-d-300 { animation-duration: 300ms; } .cy-d-500 { animation-duration: .5s; }
.cy-d-800 { animation-duration: .8s; } .cy-d-1200 { animation-duration: 1.2s; }
.cy-d-2000 { animation-duration: 2s; }
.cy-delay-1 { animation-delay: 60ms; } .cy-delay-2 { animation-delay: 120ms; }
.cy-delay-3 { animation-delay: 180ms; } .cy-delay-4 { animation-delay: 260ms; }
.cy-delay-5 { animation-delay: 340ms; } .cy-delay-6 { animation-delay: 440ms; }
.cy-delay-7 { animation-delay: 560ms; } .cy-delay-8 { animation-delay: 700ms; }
.cy-ease-linear { animation-timing-function: linear; }
.cy-ease-in { animation-timing-function: cubic-bezier(.4, 0, 1, 1); }
.cy-ease-out { animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
.cy-ease-spring { animation-timing-function: cubic-bezier(.2, 1.4, .4, 1); }
.cy-ease-bounce { animation-timing-function: cubic-bezier(.28, 1.6, .42, 1); }
.cy-forever { animation-iteration-count: infinite; }
.cy-paused { animation-play-state: paused; }

/* 下面七个必须显式写 to 帧，不能只留 from：
   .cy-reveal 把元素自身的 opacity 压成了 0，而“只写 from”的 keyframes 会拿
   元素自身值当隐式 100% 帧 → 动画从 0 演到 0，再被 .cy-reveal.is-in 的 both 钉住，
   内容就永久不可见（卡片占位、布局正常、计算值全对，就是看不见 —— 极难查）。
   给 .cy-in-* 用也不受影响：那些元素自身 opacity 本来就是 1，to 与隐式终值同值。 */
@keyframes cy-k-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes cy-k-up { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
@keyframes cy-k-down { from { opacity: 0; transform: translateY(-14px); } to { opacity: 1; transform: none; } }
@keyframes cy-k-left { from { opacity: 0; transform: translateX(-16px); } to { opacity: 1; transform: none; } }
@keyframes cy-k-right { from { opacity: 0; transform: translateX(16px); } to { opacity: 1; transform: none; } }
@keyframes cy-k-zoom { from { opacity: 0; transform: scale(.86); } to { opacity: 1; transform: none; } }
@keyframes cy-k-zoom-out { from { opacity: 0; transform: scale(1.12); } to { opacity: 1; transform: none; } }
@keyframes cy-k-pop { 0% { opacity: 0; transform: scale(.6); } 70% { transform: scale(1.06); } 100% { opacity: 1; transform: scale(1); } }
@keyframes cy-k-blur { from { opacity: 0; filter: blur(8px); transform: scale(1.02); } to { opacity: 1; filter: blur(0); transform: none; } }
@keyframes cy-k-flip-x { from { opacity: 0; transform: perspective(700px) rotateX(-88deg); } to { opacity: 1; transform: perspective(700px) rotateX(0); } }
@keyframes cy-k-flip-y { from { opacity: 0; transform: perspective(700px) rotateY(-88deg); } to { opacity: 1; transform: perspective(700px) rotateY(0); } }
@keyframes cy-k-rotate { from { opacity: 0; transform: rotate(-90deg) scale(.8); } to { opacity: 1; transform: rotate(0) scale(1); } }
@keyframes cy-k-bounce { 0% { opacity: 0; transform: translateY(-30px); } 60% { opacity: 1; transform: translateY(6px); } 80% { transform: translateY(-3px); } 100% { opacity: 1; transform: translateY(0); } }
@keyframes cy-k-drop { from { opacity: 0; transform: translateY(-60%) scale(.9); } 60% { transform: translateY(6%) scale(1.02); } to { opacity: 1; transform: none; } }
@keyframes cy-k-swing { 0% { transform: rotate(0); } 20% { transform: rotate(12deg); } 45% { transform: rotate(-8deg); } 70% { transform: rotate(4deg); } 100% { transform: rotate(0); } }
@keyframes cy-k-roll { from { opacity: 0; transform: translateX(-24px) rotate(-120deg); } to { opacity: 1; transform: none; } }
@keyframes cy-k-skew { from { opacity: 0; transform: skewX(-12deg) translateX(-18px); } to { opacity: 1; transform: none; } }
@keyframes cy-k-stretch { 0% { opacity: 0; transform: scale(.6, .3); } 55% { opacity: 1; transform: scale(1, 1.12); } 100% { opacity: 1; transform: scale(1); } }
@keyframes cy-k-fold { from { opacity: 0; transform: perspective(600px) rotate3d(1, 1, 0, 60deg); } to { opacity: 1; transform: none; } }
@keyframes cy-k-shrink { to { opacity: 0; transform: scale(.9); } }
@keyframes cy-k-collapse { to { opacity: 0; transform: scaleY(.4); } }
@keyframes cy-k-spin-out { to { opacity: 0; transform: rotate(120deg) scale(.7); } }
@keyframes cy-k-spin-forever { to { transform: rotate(360deg); } }
@keyframes cy-k-pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .55; transform: scale(1.04); } }
@keyframes cy-k-blink { 50% { opacity: .25; } }
@keyframes cy-k-ping { 0% { transform: scale(1); opacity: .7; } 80%, 100% { transform: scale(2); opacity: 0; } }
@keyframes cy-k-breathe { 0%, 100% { opacity: .55; transform: scale(.97); } 50% { opacity: 1; transform: scale(1.03); } }
@keyframes cy-k-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-7px); } }
@keyframes cy-k-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(4px); } }
@keyframes cy-k-swing-loop { 0%, 100% { transform: rotate(0); } 25% { transform: rotate(8deg); } 75% { transform: rotate(-8deg); } }
@keyframes cy-k-bounce-loop { 0%, 100% { transform: translateY(0); } 40% { transform: translateY(-12px); } 70% { transform: translateY(0); } }
@keyframes cy-k-wave { 0%, 100% { transform: translateY(0) rotate(0); } 50% { transform: translateY(-4px) rotate(2deg); } }
@keyframes cy-k-heartbeat { 0%, 100% { transform: scale(1); } 14% { transform: scale(1.14); } 28% { transform: scale(1); } 42% { transform: scale(1.1); } 56% { transform: scale(1); } }
@keyframes cy-k-orbit { to { transform: rotate(360deg) translateY(10px) rotate(-360deg); } }
@keyframes cy-k-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@keyframes cy-k-caret { 50% { opacity: 0; } }
@keyframes cy-k-drift { 0% { transform: translate(0, 0) scale(1); } 100% { transform: translate(6%, -5%) scale(1.12); } }
@keyframes cy-k-shake { 10%, 90% { transform: translateX(-2px); } 20%, 80% { transform: translateX(4px); } 30%, 50%, 70% { transform: translateX(-7px); } 40%, 60% { transform: translateX(7px); } }
@keyframes cy-k-tada { 0% { transform: scale(1); } 10%, 20% { transform: scale(.9) rotate(-4deg); } 30%, 50%, 70%, 90% { transform: scale(1.1) rotate(4deg); } 40%, 60%, 80% { transform: scale(1.1) rotate(-4deg); } 100% { transform: scale(1); } }
@keyframes cy-k-flash { 0%, 50%, 100% { opacity: 1; } 25%, 75% { opacity: .2; } }
@keyframes cy-k-highlight { 0% { background: var(--cy-warning-soft); box-shadow: inset 0 0 0 2px var(--cy-warning); } 100% { background: transparent; box-shadow: inset 0 0 0 2px transparent; } }
@keyframes cy-k-bump { 40% { transform: scale(1.12); } }
@keyframes cy-k-jiggle { 0%, 100% { transform: translateX(0) rotate(0); } 25% { transform: translateX(-2px) rotate(-1deg); } 75% { transform: translateX(2px) rotate(1deg); } }
@keyframes cy-k-wobble { 0%, 100% { transform: translateX(0); } 15% { transform: translateX(-12px) rotate(-3deg); } 30% { transform: translateX(9px) rotate(2deg); } 45% { transform: translateX(-6px) rotate(-1deg); } 60% { transform: translateX(4px) rotate(1deg); } 75% { transform: translateX(-2px); } }
@keyframes cy-k-glow { 0%, 100% { box-shadow: 0 0 0 0 transparent; } 50% { box-shadow: 0 0 0 6px var(--cy-primary-soft), 0 0 18px -4px var(--cy-primary); } }
@keyframes cy-k-ring { 0% { box-shadow: 0 0 0 0 var(--cy-primary-soft); } 100% { box-shadow: 0 0 0 14px transparent; } }
@keyframes cy-k-morph { 0%, 100% { border-radius: 42% 58% 63% 37% / 41% 44% 56% 59%; } 33% { border-radius: 60% 40% 35% 65% / 55% 62% 38% 45%; } 66% { border-radius: 35% 65% 55% 45% / 62% 38% 62% 38%; } }

/* grid 子项默认 min-width:auto —— 一个 iOS date input / 长单词就能把同一行其它列压成“一个字宽”，
   手机上标题、提示竖排成单字就是这么来的。给容器子项统一 min-width:0（只给容器，
   不给按钮/头像这类靠内容定宽的元素，否则会被压瘪） */
.cy-grid > *, .cy-grid-2 > *, .cy-grid-3 > *, .cy-grid-4 > *, .cy-grid-auto > *,
.cy-formgrid > *, .cy-cols > *, .cy-bento > *, .cy-kpi-grid > *, .cy-panel-grid > *,
.cy-choices > *, .cy-kanban > *, .cy-field, .cy-dialog-in, .cy-rng-field { min-width: 0; }

/* ==========================================================================
   布局容器 + 原子工具类（刻意只留这些，避免变成 Tailwind）
   ========================================================================== */
.cy-stack { display: flex; flex-direction: column; gap: var(--cy-s-5); }
.cy-stack-2 { gap: var(--cy-s-2); }
.cy-stack-3 { gap: var(--cy-s-3); }
.cy-stack-4 { gap: var(--cy-s-4); }
.cy-stack-6 { gap: var(--cy-s-6); }
.cy-row { display: flex; align-items: center; gap: var(--cy-s-4); flex-wrap: wrap; }
/* .cy-row 里直接放的输入要能收缩：否则 24 位只读值之类会按内容撑宽、顶破卡片背景 */
.cy-row > .cy-input, .cy-row > .cy-select, .cy-row > .cy-textarea { flex: 1 1 auto; min-width: 0; }
.cy-row--between { justify-content: space-between; }
.cy-row--end { justify-content: flex-end; }
.cy-row--nowrap { flex-wrap: nowrap; }
.cy-grid { display: grid; gap: var(--cy-s-5); }
.cy-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.cy-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.cy-grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
/* 列数自适应：单卡最小宽用 --cy-min 旋钮调，不写死。
   min(…, 100%) 是兜底：容器比 --cy-min 还窄时（手机 + 420px 的单卡最小宽），
   轨道宽会被压到容器宽，而不是撑出横向滚动。 */
.cy-grid-auto { grid-template-columns: repeat(auto-fill, minmax(min(var(--cy-min, 280px), 100%), 1fr)); }
.cy-spacer { flex: 1 1 auto; min-width: 0; }

.cy-t-1 { font-size: var(--cy-fs-1); } .cy-t-2 { font-size: var(--cy-fs-2); } .cy-t-3 { font-size: var(--cy-fs-3); }
.cy-t-5 { font-size: var(--cy-fs-5); } .cy-t-6 { font-size: var(--cy-fs-6); }
.cy-strong { font-weight: 800; } .cy-num { font-variant-numeric: tabular-nums; }
.cy-muted { color: var(--cy-text-4); } .cy-dim { color: var(--cy-text-3); } .cy-ink { color: var(--cy-text); }
.cy-primary { color: var(--cy-primary); } .cy-success { color: var(--cy-success); }
.cy-warning { color: var(--cy-warning-ink); } .cy-danger { color: var(--cy-danger); }
.cy-del { text-decoration: line-through; opacity: .6; }
.cy-center { text-align: center; } .cy-right { text-align: right; }
.cy-ep { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cy-ep2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; word-break: break-all; }
.cy-break { overflow-wrap: anywhere; }
.cy-r1 { border-radius: var(--cy-r-1); } .cy-r2 { border-radius: var(--cy-r-2); }
.cy-r3 { border-radius: var(--cy-r-3); } .cy-r4 { border-radius: var(--cy-r-4); } .cy-rp { border-radius: var(--cy-r-full); }
.cy-e1 { box-shadow: var(--cy-e-1); } .cy-e2 { box-shadow: var(--cy-e-2); }
.cy-e3 { box-shadow: var(--cy-e-3); } .cy-e4 { box-shadow: var(--cy-e-4); } .cy-e5 { box-shadow: var(--cy-e-5); }
.cy-bg { background: var(--cy-surface); } .cy-bg2 { background: var(--cy-surface-2); }
.cy-hide { display: none !important; } .cy-grow { flex: 1 1 auto; min-width: 0; } .cy-noshrink { flex: none; }
.cy-w-full { width: 100%; } .cy-w-auto { width: auto; }
/* [hidden] 必须能压住组件自带的 display：UA 样式表的 [hidden]{display:none} 优先级低于任何作者规则，
   而 .cy-kbd / .cy-tag / .cy-chip / .cy-sticktop / .cy-li 这些都自带 display → 业务页拿 hidden 控显隐会“关不掉”。
   这里只给“类名以 cy- 开头”的元件兜底（不用裸 [hidden]，避开全局规则与 oal.css 冲突），
   两个选择器分别覆盖“首个类”与“非首个类”两种写法。 */
[class^="cy-"][hidden], [class*=" cy-"][hidden] { display: none !important; }
.cy-scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.cy-pad-0 { padding: 0; } .cy-pad-5 { padding: var(--cy-s-5); } .cy-pad-6 { padding: var(--cy-s-6); } .cy-pad-7 { padding: var(--cy-s-7); }
.cy-gap-2 { gap: var(--cy-s-2); } .cy-gap-3 { gap: var(--cy-s-3); }
.cy-gap-5 { gap: var(--cy-s-5); } .cy-gap-6 { gap: var(--cy-s-6); } .cy-gap-8 { gap: var(--cy-s-8); }
.cy-mt-4 { margin-top: var(--cy-s-4); } .cy-mt-6 { margin-top: var(--cy-s-6); } .cy-mt-8 { margin-top: var(--cy-s-8); }

/* ==========================================================================
   【自定义入口】三类拓展点，都不需要改框架本体：
   1) 全局换肤：只覆盖 :root 的 --cy-* 令牌（或挂 [data-cy-skin="x"]）
   2) 局部旋钮：每个组件暴露 3–5 个局部变量，写在 style 或自己的类里即可
      cy-card： --cy-card-bg / --cy-card-line / --cy-card-r / --cy-card-e
      cy-btn ： --cy-btn-h / --cy-btn-r / --cy-btn-pad / --cy-btn-gap
      cy-list： --cy-li-pad / --cy-li-r
      cy-dialog： --cy-dialog-w（宽度）
      cy-grid-auto： --cy-min（单卡最小宽）
   3) 结构拓展：新增语义色只需仿下面三行（soft / soft-line / ink + 主色）
   ========================================================================== */
/* cy-btn 的旋钮（--cy-btn-h / -pad / -r / -gap）已改到组件本体那条 .cy-btn 里，
   不要再在这里重声明：放在文件末尾会因“同特异度靠后胜出”压掉后面的尺寸与形状变体 */
.cy-li { padding: var(--cy-li-pad, var(--cy-s-5) var(--cy-s-6)); }
.cy-list { border-radius: var(--cy-li-r, var(--cy-r-3)); }

/* ==========================================================================
   窄屏行为：文字标签收掉只留图标、按钮抬高到 38px（点击区优先，别靠 hover）
   ========================================================================== */
@media (max-width: 640px) {
    .cy-appbar { padding: 0 var(--cy-s-5); height: 52px; }
    /* 多列行在窄屏降级成卡：列隐藏表头，每个单元自己拿 data-l 当小标签 */
    .cy-rg-head { display: none; }
    .cy-rg-row { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--cy-s-3) var(--cy-s-4); padding: var(--cy-s-4) var(--cy-s-5); }
    .cy-rg-c::before { content: attr(data-l); display: block; font-size: 9.5px; color: var(--cy-text-4); font-weight: 700; margin-bottom: 1px; }
    .cy-rg-name, .cy-rg-acts { grid-column: 1 / -1; }
    .cy-rg-acts { justify-content: flex-start; }
    /* 手机上默认弹窗改成贴底抽屉（拇指好操作、与系统应用语义一致）；
       而 size:'full' 仍然是真全屏，两种形态各有用表 */
    .cy-mask { padding: 0; align-items: flex-end; }
    /* max-height 用 % 而不是 92dvh：cyui.js 已把 mask 盒高压成“真可见高度”，
       而 dvh 在 iOS 上比可见区大 36~76px —— 写 92dvh 时贴底抽屉会比 mask 高，
       align-items:flex-end 下多出来的部分会从顶部探出去。% 跟着 mask 走，JS 没跑时退到 92% of 100dvh，与旧行为一致 */
    .cy-dialog { width: 100%; max-width: none; align-self: flex-end; max-height: 92%; border-radius: var(--cy-r-4) var(--cy-r-4) 0 0; padding-bottom: env(safe-area-inset-bottom, 0px); }
    .cy-mask--full { align-items: stretch; }
    .cy-dialog-full { max-height: none; align-self: stretch; border-radius: 0; padding-top: env(safe-area-inset-top, 0px); }
    .cy-sheet { --cy-sheet-w: 100%; }
    /* 轻提窄屏占满左右宽度，但不能再钉 bottom：那会把 --top 容器拉成一整屏高 */
    .cy-toasts { width: auto; }
    .cy-toasts--top, .cy-toasts--bottom, .cy-toasts--top-left, .cy-toasts--top-right,
    .cy-toasts--bottom-left, .cy-toasts--bottom-right { left: 12px; right: 12px; transform: none; align-items: stretch; }
    .cy-toasts--top, .cy-toasts--top-left, .cy-toasts--top-right { top: calc(12px + env(safe-area-inset-top, 0px)); }
    .cy-toasts--bottom, .cy-toasts--bottom-left, .cy-toasts--bottom-right { bottom: calc(12px + env(safe-area-inset-bottom, 0px)); }
    .cy-toast { border-radius: var(--cy-r-3); width: 100%; }
    .cy-steps { font-size: var(--cy-fs-1); }
    .cy-kv-k { width: 68px; }
    .cy-hide-sm { display: none !important; }
    .cy-field--row { flex-direction: column; align-items: stretch; }
    .cy-field--row > .cy-field-label { width: auto; }
    .cy-li { padding-left: var(--cy-s-5); padding-right: var(--cy-s-5); }
    /* iOS 防自动放大：字号给到 16px，否则聚焦时整页被 zoom，刚改好的排版立刻花。
       xs 也不例外 —— 低于 16px 一样会触发 zoom，只能靠加高度（38px）吃下 16px 字 */
    .cy-input, .cy-select, .cy-textarea { font-size: 16px; }
    .cy-input, .cy-select { height: 42px; }
    .cy-input-xs, .cy-select-xs { height: 38px; }
    .cy-rng > .cy-input { flex: 1 1 45%; }
    .cy-rng-sep { display: none; }
    .cy-field-hint, .cy-field-err { font-size: 11.5px; }
}

/* ==========================================================================
   窄屏（手机）行为：
   ★ 不再隐藏按钮文字——之前写成 .cy-btn .cy-btn-lb{display:none}，
     结果手机上所有“详情/删除/重传”全部只剩图标，用户直接“看不到文字”。
     要纯图标按钮请显式用 cy-btn-icon，靠类名控制，不靠媒体查询抹文字。
   ★ 全站字号底线 11.5px：iOS Safari 不会强制最小字号，9.5px 真的就是 9.5px。
   ========================================================================== */
@media (max-width: 900px) {
    /* 中等宽度（半屏窗口 / 小平板）先把多列卡降一档，不挤到 640 才变 */
    .cy-grid-3, .cy-grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .cy-kpi-grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .cy-kpi-grid-6 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
    .cy-btn { height: 40px; padding: 0 var(--cy-s-5); }
    .cy-btn-xs { height: 34px; padding: 0 var(--cy-s-4); }
    /* 窄屏把高度抬到 40 后，方块/图标钮的宽度必须跟着，否则 34×40 变竖向长方形 */
    .cy-btn-icon, .cy-btn-square { width: 40px; }
    .cy-btn-icon.cy-btn-xs, .cy-btn-square.cy-btn-xs { width: 34px; }
    .cy-pb { height: 36px; }
    .cy-pb-icon { width: 36px; }
    .cy-fab-mini { width: 44px; height: 44px; }
    .cy-chip, .cy-segmented-i, .cy-rng-btn, .cy-menu-item { min-height: 36px; }
    /* 字号底线：把全站 9.5 / 10 / 11.5 的小字统一抬到可读 */
    .cy-t-1, .cy-field-hint, .cy-field-err, .cy-btn-xs, .cy-chip, .cy-segmented-i,
    .cy-legend, .cy-rng-btn { font-size: 12px; }
    .cy-gal-cap, .cy-upl-st, .cy-status-sm, .cy-pbs, .cy-pbs-num, .cy-rg-c::before,
    .cy-kvgrid-k, .cy-person-stat span, .cy-track-s, .cy-rg-chip, .cy-rg-more,
    .cy-dialog-sub, .cy-card-sub, .cy-metric-u, .cy-metric-l, .cy-fab-lb,
    .cy-cmd-grp, .cy-layer-n, .cy-tree-n, .cy-avatars-n, .cy-inbox-m,
    .cy-suggest-m, .cy-codeblock-lang, .cy-tabbar-i { font-size: 11.5px; }
    .cy-pbs { font-size: 11.5px; }
    .cy-pbs-ico { font-size: 12.5px; }
    .cy-grid-2, .cy-grid-3, .cy-grid-4 { grid-template-columns: 1fr; }
    /* 单列化必须同时收掉跨列，否则就是那一类“删了某段 CSS 突然就好了”的鬼：
       grid-template-columns:1fr 下若还有子项 grid-column:span 2，Grid 会补出一条 auto 隐式列，
       把几乎全部宽度都给隐式列，显式那条 1fr 被压成 min-content（中文 = 一个字宽），
       于是一半字段竖排、原生 date/month 控件被挤成只剩一个数字的小方块。
       跨列在单列下本就无意义，一律归 auto。（.cy-cols 自己另有 4 列方案，不在射程内）*/
    .cy-grid > *, .cy-grid-2 > *, .cy-grid-3 > *, .cy-grid-4 > *, .cy-grid-auto > * { grid-column: auto; }
    .cy-kpi-grid-3, .cy-kpi-grid-4, .cy-kpi-grid-6 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .cy-desc { grid-template-columns: 1fr; }
    /* 起止区间 cy-rng：手机上竖排——两输入各满一行、隐掉"至"、快捷周期整行折行。
       文档文案早写"窄屏自动折行并隐掉至"，但 CSS 一直没落地，控件在手机上就堆成一团。 */
    .cy-rng { flex-direction: column; align-items: stretch; }
    .cy-rng > .cy-input, .cy-rng-field { flex: 0 0 auto; }
    .cy-rng-sep { display: none; }
    .cy-rng-quick { width: 100%; }
    .cy-rng > .cy-pb, .cy-rng > button:not(.cy-rng-btn) { align-self: flex-start; }
    .cy-card-head, .cy-card-body, .cy-card-foot { padding-left: var(--cy-s-5); padding-right: var(--cy-s-5); }
    /* 选项集窄屏收一档横向间距：桌面 24px 列距是“一行放得下”的奢侈，手机上会把尾项挤到第二行 */
    .cy-optset-row { gap: var(--cy-s-3) var(--cy-s-4); }
    .cy-gal { gap: var(--cy-s-2); }
    .cy-doc { padding: var(--cy-s-5); }
    .cy-doc-sign { grid-template-columns: 1fr; gap: var(--cy-s-6); }
    .cy-doc-k { width: 78px; }
    .cy-doc-row { flex-wrap: wrap; }
    .cy-cols { grid-template-columns: repeat(4, minmax(0, 1fr)); }
    .cy-cols > [class*="cy-col-"] { grid-column: span 4; }
    /* 全屏弹窗在手机上：顶栏变矮、正文内距收窄、关闭钮移到左边（拇指能够到） */
    .cy-dialog-head { min-height: 48px; padding: var(--cy-s-3) var(--cy-s-5); }
    .cy-dialog-x { order: -1; margin-left: 0; }
    .cy-dialog-body { padding: var(--cy-s-5) var(--cy-s-5) var(--cy-s-6); }
    .cy-dialog-foot { padding: var(--cy-s-3) var(--cy-s-5); }
    /* 手机上动作钮平分整行（拇指好按） */
    .cy-dialog-foot .cy-btn { flex: 1 1 auto; justify-content: center; }
    /* 批量条改为贴底全宽（居中胶囊在手机上会被内容撑出屏） */
    .cy-bulk { left: 10px; right: 10px; bottom: calc(10px + env(safe-area-inset-bottom, 0px)); transform: none; width: auto; justify-content: center; border-radius: var(--cy-r-3); }
    .cy-toc { position: static; }
    .cy-att-meta, .cy-upl-st { font-size: 11.5px; }
    .cy-att-nm { white-space: normal; }
    .cy-task { flex-wrap: wrap; }
    /* 本次新增族在窄屏的降级：跨格不跨、分栏堆叠、多列收两列 */
    .cy-bento-w2, .cy-bento-w3 { grid-column: auto; }
    .cy-bento { grid-auto-rows: minmax(84px, auto); }
    .cy-split { grid-template-columns: 1fr; }
    .cy-split-gut { display: none; }
    .cy-dl-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .cy-formgrid-2 { grid-template-columns: 1fr; }
    /* 标签栏：4~5 个 pill 在 360px 下必然超宽（封号中心 4 个、签到 5 个）。
       以前超出的部分被页面 overflow-x:clip 直接裁掉，最后一个 tab 永远点不到；
       改成标签栏自己横滑（滚动条隐藏），所有 tab 都能划到。
       overflow-y 会连带裁掉 is-on 的下划线，所以窄屏把它从 -1px 提到 0。 */
    .cy-tabs {
        overflow-x: auto; overflow-y: hidden;
        -webkit-overflow-scrolling: touch;
        overscroll-behavior-x: contain;
        scrollbar-width: none;
    }
    .cy-tabs::-webkit-scrollbar { display: none; }
    .cy-tabs > * { flex: 0 0 auto; }
    .cy-tab.is-on::after { bottom: 0; }
    .cy-tabbar-i { min-height: 52px; }
    .cy-mappop { width: 100%; }
    .cy-sticktop { bottom: calc(82px + env(safe-area-inset-bottom, 0px)); }
    .cy-tree ul { padding-left: 15px; }
    /* 下拉在手机上占满整列，面板不再限 420px（否则与相邻列重叠看着像坏了） */
    .cy-dd { display: block; width: 100%; }
    .cy-dd-panel { max-width: none; }
    .cy-range-ticks, .cy-cal { font-size: 11.5px; }
    .cy-stamp { letter-spacing: 1px; }
}

@media (prefers-reduced-motion: reduce) {
    .cy-btn, .cy-chip, .cy-card-hoverable, .cy-nav-item, .cy-input, .cy-select { transition: none; }
    .cy-skeleton::after, .cy-sk::after { animation: none; }
    .cy-fab-menu > *, .cy-fab-main > i, .cy-gal-zoom, .cy-group-caret { transition: none; }
    .cy-toast { animation: none; }
    .cy-progress-strip .cy-progress-bar { animation: none; }
    .cy-mask, .cy-dialog { transition: none; }
    /* 动画预设统一关掉：只消动画，不改颜面（不要在这里重定义布局） */
    .cy-anim, [class*="cy-in-"], [class*="cy-out-"], [class*="cy-loop-"],
    [class*="cy-act-"], .cy-morph, .cy-reveal.is-in, .cy-flip.is-on .cy-flip-in { animation: none !important; }
    .cy-collapse, .cy-flip-in, .cy-rot, .cy-tilt, .cy-toast, .cy-dd-panel { transition-duration: .01ms !important; }
    .cy-reveal { opacity: 1; }
    .cy-tilt:hover { transform: none; }
}

/* 打印：浮层与顶栏不参与打印，卡片不拆断 */
@media print {
    .cy-appbar, .cy-mask, .cy-toasts, .cy-blocker, .cy-fab, .cy-bnav, .cy-act, .cy-btn { box-shadow: none !important; }
    .cy-mask, .cy-toasts, .cy-blocker, .cy-fab, .cy-bnav { display: none !important; }
    .cy-card, .cy-li, .cy-tl-item, .cy-step { break-inside: avoid; }
    .cy-table { font-size: 11px; }
    .cy-appbar { position: static; }
}

/* ==========================================================================
   触屏手感（iOS 为主）：专治“按钮要点两次才生效”
   --------------------------------------------------------------------------
   成因两个，缺一个都还会复现：
   ① hover 揭示：iOS 把第一次点击当成 hover（气泡/浮层就是这时候冒出来的），
      真正的 click 要等第二次 —— 触屏本来就没有 hover，这类揭示在触屏上一律
      关掉（气泡）或常显（图库角标），别让它吃掉第一次点击；
   ② 双击缩放：iOS 10 起已无视 user-scalable=no，Safari 每次点击都要留 300ms
      看有没有第二下 —— touch-action:manipulation 只关掉双击缩放，
      滚动和捏合缩放照旧。
   ③ -webkit-tap-highlight-color：给点击一个即时反馈，免得用户以为没点上又补一下。
   ========================================================================== */
@media (hover: none) {
    [data-cy-tip]::after, [data-cy-tip]::before { display: none !important; }
    .cy-gal-zoom, .cy-gal-x { opacity: 1; }
    /* iOS 遇聚焦控件字号 <16px 会自动放大整页（越看越丑）：触屏下统一抬到 16px。
       落实 .cy-input 处既定规矩；用类选择器而非元素选择器，才能压过 .cy-input / .cy-input-xs / .cy-input-lg 的字号声明 */
    .cy-input, .cy-textarea, .cy-select, input, textarea, select { font-size: 16px; }
}
/* 边界盒统一：文件头刻意不做全局 *{box-sizing}（见第 10 行注释），但若组件 width:100% 同时带 padding/border，
   缺 border-box 会算出 100%+内距+边框 而冲破父容器（手机上整行勾选/按钮/分段等溢出卡片的典型坑，已零星修过数处）。
   这里只作用于框架自身的 .cy-* 类（不碰用户内容），一次性兜底并防未来新增组件重犯。全文件 box-sizing 仅出现过 border-box，无 content-box 依赖，零风险。 */
[class*="cy-"] { box-sizing: border-box; }
.cy-btn, .cy-pb, .cy-rng-btn, .cy-chip, .cy-tab, .cy-li-click, .cy-li, .cy-tag-x, .cy-tags-x,
.cy-fab-main, .cy-fab-mini, .cy-fs-btn, .cy-stepper-btn, .cy-dd-opt, .cy-pbs-seg, .cy-dialog-x,
.cy-pg-btn, .cy-sheet-grip, .cy-gal-i, .cy-gal-add, .cy-nav-item, .cy-bnav-i, .cy-act-i, .cy-pg-i {
    touch-action: manipulation;
    -webkit-tap-highlight-color: rgba(15, 23, 42, .1);
}
/* 抓手要吃拖拽手势，不能被 manipulation 影响（none 对自身生效，优先级高于祖先） */
.cy-sheet-grip { touch-action: none; }
