/* =====================================================================
   童话主题底座（跨目录共享）· comm/disney-kit.css
   ---------------------------------------------------------------------
   谱系：与 reading/index.html、test/choice-disney.css、test/ctx-disney.css
         同一套材质语言（夜空外壳 / 亮面象牙故事书页 / 挤塑玩具控件）。
   定位：**组件库**。页面通过「加 dk-* 类名」主动选用，页面自己的样式表
         （games.css / spell.css / 36spell.css）一行都不用改，各页的适配表
         只负责「把旧规则压掉 + 调尺寸间距」。
   用法：
     <link rel="stylesheet" href="/comm/disney-kit.css">   <!-- 底座 -->
     <link rel="stylesheet" href="/xxx/xxx-disney.css">     <!-- 页面适配（可选） -->
   回滚：删掉上面这两行 <link> 即可，本文件可整份删除。
   ---------------------------------------------------------------------
   本轮口味（2026-09-14 用户要求）：「根据 choice.html 风格，但颜色别太深」。
   所以这是同一套材质的**浅色版 · 晨光童话**：
     · 外壳换成晨雾紫的浅色天空（极浅的紫罗兰，不是深靛蓝夜空）；
     · 故事书页、挤塑玩具、魔法光晕三条材质语言与 choice.html 完全一致；
     · 状态语义色继续用全站谱系（正确=深翠绿 / 错误=玫红），
       并且沿用 choice.html 那轮**已被对比度审计压过**的取值——
       白字压底必须 ≥4.5:1，底色相对亮度 ≤0.1833。
   ---------------------------------------------------------------------
   纪律
   · 本文件**不接管站点 chrome**（.topbar / .sidebar 由 nav.css 负责，
     保持全站统一，不随本主题变浅或变深）。
   · 装饰一律 SVG/字符，**不用 emoji**（emoji 是平台位图，跟不上字号与配色）；
     JS 运行时写进页面的 emoji 由 comm/disney-icons.js 就地换成 .dk-i 图标。
   · 所有承载文字的配色都过了 WCAG AA，实算表见文件末尾。
   ===================================================================== */

/* ============ 1. 设计令牌 ============ */
:root{
  /* ---- 外壳 · 晨光童话（浅色）---- */
  --dk-sky-1:#faf8ff;   /* 顶部最亮 */
  --dk-sky-2:#f3eeff;
  --dk-sky-3:#eae3fd;
  --dk-sky-4:#ded4f8;   /* 底部稍深，给书页一个"坐落感" */
  --dk-sky-5:#d2c6f4;   /* 页脚 */

  /* ---- 柔和极光斑（浅色版：粉彩，低透明）---- */
  --dk-aurora-mint:#7fe6cf;
  --dk-aurora-lilac:#b9a4ff;
  --dk-aurora-peach:#ffc2a6;
  --dk-aurora-gold:#ffdf8e;

  /* ---- 外壳上的墨色（深墨压极浅底，实测最坏 7.06:1）---- */
  --dk-ink-on-sky:#3b2f77;
  --dk-ink-on-sky-soft:#53468e;            /* 压最暗的天空停靠点 4.98:1（#5a4f95 只有 4.39，不够）*/

  /* ---- 内容 · 亮面象牙「故事书页」---- */
  --dk-paper-a:#fffdf7; --dk-paper-b:#fdf9ef; --dk-paper-c:#f7f0dd;
  --dk-lip:rgba(96,66,190,.16);            /* 底部挤塑边 */
  --dk-cast:0 16px 30px -16px rgba(78,54,155,.34); /* 落地影（浅色版比夜空版淡）*/
  --dk-ring:inset 0 0 0 1px rgba(122,94,226,.16);

  /* ---- 纸上的墨色 ---- */
  --dk-ink:#2f2a5c;
  --dk-ink-strong:#4a2a9e;
  --dk-ink-soft:#5b4f9e;                   /* 压象牙纸 6.75:1 */
  --dk-ink-mute:#6b5fa8;                   /* 压象牙纸 4.87:1 —— 小字下限 */

  /* ---- 仙紫（主色）---- */
  --dk-vio-hi:#7a55f0; --dk-vio:#6a44ec; --dk-vio-deep:#4c2ad0; --dk-vio-lip:#33209b;

  /* ---- 烫金 ---- */
  --dk-gold:#ffd76b; --dk-gold-2:#ffb84d;
  --dk-gold-ink:#6a4004;                   /* 金字压金底：暗端 #ffb84d 5.20:1、亮端 #ffd76b 7.4:1。
                                              ⚠️ 原 #7a4a06 在暗端只有 4.35（够大字、不够小字）；
                                                 #8a6300 更差（3.93）。渐变按钮的墨色必须按**暗端**校。 */
  --dk-gold-lip:#c08c2e;

  /* ---- 状态：正确 / 错误 / 提醒（白字底全部压到 AA 以内）---- */
  --dk-ok-hi:#0a8060; --dk-ok:#076b4e; --dk-ok-deep:#04402e; --dk-ok-lip:#022f22;
  --dk-no-hi:#c02246; --dk-no:#a3152f; --dk-no-deep:#7d0f24; --dk-no-lip:#5e0a1c;
  --dk-warn-hi:#a46000; --dk-warn:#8a5200; --dk-warn-deep:#6b3f00; --dk-warn-lip:#4d2d00;

  /* ---- 圆角与标尺 ---- */
  --dk-r-page:26px; --dk-r-plate:22px; --dk-r-ctl:16px;
  --dk-r-chip:14px; --dk-r-tab:14px; --dk-r-tile:16px;

  /* ---- 字体 ---- */
  --dk-font-cn:'Noto Sans SC','PingFang SC','Microsoft YaHei',sans-serif;
  --dk-font-en:'Baloo 2','Noto Sans SC','PingFang SC','Microsoft YaHei',sans-serif;

  /* ============ 2. 材质配方 ============ */
  /* 把 box-shadow / 渐变这类"配方"集中成变量：页面适配表一行引用，
     改配方只改这里一处。项目此前吃过「同一条渐变在本文件里有 4~5 份
     字面副本，改色只改了正在看的那一份」的亏，所以这里刻意收口。 */

  /* 故事书页 */
  --dk-page-bg:linear-gradient(180deg,var(--dk-paper-a) 0%,var(--dk-paper-b) 56%,var(--dk-paper-c) 100%);
  --dk-page-shadow:var(--dk-ring),
                   inset 0 2px 0 #fff,
                   inset 0 -4px 0 var(--dk-lip),
                   var(--dk-cast);

  /* 挤塑玩具：中性（象牙塑料）*/
  --dk-plastic-bg:linear-gradient(180deg,#ffffff 0%,#f7f3ff 100%);
  --dk-plastic-bg-hover:linear-gradient(180deg,#fdfbff 0%,#efe8ff 100%);
  --dk-plastic-shadow:inset 0 2px 0 #fff,
                      inset 0 -3px 0 rgba(96,66,190,.18),
                      0 3px 0 #d9cdf7,
                      0 8px 14px -9px rgba(78,54,155,.45);
  --dk-plastic-shadow-press:inset 0 2px 0 rgba(255,255,255,.55),
                            inset 0 -1px 0 rgba(96,66,190,.18),
                            0 0 0 0 #d9cdf7,
                            0 2px 6px -4px rgba(78,54,155,.35);

  /* 挤塑玩具：彩色（白字压上面全部 ≥4.5:1，见末尾验收表）*/
  --dk-vio-plastic:linear-gradient(180deg,var(--dk-vio-hi) 0%,var(--dk-vio) 54%,var(--dk-vio-deep) 100%);
  --dk-vio-plastic-shadow:inset 0 2px 0 rgba(255,255,255,.42),
                          inset 0 -3px 0 rgba(24,8,80,.34),
                          0 3px 0 var(--dk-vio-lip),
                          0 10px 18px -9px rgba(106,68,236,.55);
  --dk-ok-plastic:linear-gradient(180deg,var(--dk-ok-hi) 0%,var(--dk-ok) 58%,var(--dk-ok-deep) 100%);
  --dk-ok-plastic-shadow:inset 0 2px 0 rgba(255,255,255,.38),
                         inset 0 -3px 0 rgba(2,30,22,.36),
                         0 3px 0 var(--dk-ok-lip),
                         0 10px 18px -9px rgba(7,107,78,.55);
  --dk-no-plastic:linear-gradient(180deg,var(--dk-no-hi) 0%,var(--dk-no) 58%,var(--dk-no-deep) 100%);
  --dk-no-plastic-shadow:inset 0 2px 0 rgba(255,255,255,.38),
                         inset 0 -3px 0 rgba(50,6,16,.36),
                         0 3px 0 var(--dk-no-lip),
                         0 10px 18px -9px rgba(163,21,47,.5);
  --dk-warn-plastic:linear-gradient(180deg,var(--dk-warn-hi) 0%,var(--dk-warn) 58%,var(--dk-warn-deep) 100%);
  --dk-warn-plastic-shadow:inset 0 2px 0 rgba(255,255,255,.34),
                           inset 0 -3px 0 rgba(50,30,0,.36),
                           0 3px 0 var(--dk-warn-lip),
                           0 10px 18px -9px rgba(138,82,0,.5);
  --dk-gold-plastic:linear-gradient(180deg,#ffefc4 0%,var(--dk-gold) 46%,var(--dk-gold-2) 100%);
  --dk-gold-plastic-shadow:inset 0 2px 0 rgba(255,255,255,.8),
                           inset 0 -3px 0 rgba(150,92,10,.32),
                           0 3px 0 #d9a13a,
                           0 10px 18px -9px rgba(255,190,80,.6);

  /* 魔法光晕：只给「可点 / 已选中」元素，是可操作性提示，不是装饰 */
  --dk-halo:0 0 18px rgba(150,110,255,.45);
  --dk-halo-strong:0 0 0 4px rgba(150,110,255,.16), 0 0 22px rgba(150,110,255,.5);
}

/* ============ 3. 盒模型清单 ============ */
/* ⚠️ 本项目**没有全局 box-sizing**（默认 content-box），只有 button/input
   被 UA 表改成 border-box。底座里凡是 width:100% + padding 的容器都必须
   显式声明，否则会横向顶出视口；而且**左右对称溢出不会让 scrollWidth 变大**
   （实测某页 .card 宽 394、x=-2，scrollWidth 依然等于 innerWidth），
   只看 scrollWidth 会整类漏判。
   body 也要带上：原表 body{min-height:100vh;padding:20px} 在 content-box 下
   会让文档恒定多出「上下内边距」高的空白滚动。 */
.dk-sky,
.dk-page, .dk-result, .dk-report, .dk-slot, .dk-pool, .dk-tile,
.dk-seg, .dk-seg-item, .dk-btn, .dk-chip, .dk-badge, .dk-rail, .dk-rail-fill,
.dk-feedback, .dk-question, .dk-hud, .dk-keyboard, .dk-key, .dk-iconbtn,
.dk-title, .dk-sub, .dk-word, .dk-label{
  box-sizing:border-box;
}

/* ⚠️ flex 列容器里的「隐形缩水」（实测踩过，很隐蔽）
   有的页面把 body 做成 flex 列容器（test/games.css 就是：
   body{display:flex;flex-direction:column;align-items:center}）。
   flex 在**主轴方向**的 flex-shrink 默认是 1 —— 内容一旦超过视口高度，
   所有子项会被按比例压缩：一个 height:10px 的进度条被压成 **0px**，
   而且文档高度还会"正好等于视口高"，于是溢出探针报"不需要滚动"，
   把「东西被压扁了」伪装成「布局很紧凑」。主题自己的组件不参与收缩。 */
.dk-sky, .dk-page, .dk-result, .dk-report, .dk-slot, .dk-pool,
.dk-seg, .dk-hud, .dk-chip, .dk-rail, .dk-feedback, .dk-keyboard,
.dk-question, .dk-title{
  flex-shrink:0;
}

/* ============ 4. 外壳 · 晨光童话 ============ */
/* body 背景会被传播到画布（html 无背景或只作兜底），于是 z-index:-1 的
   .dk-sky 正好压在天空之上、所有内容之下 —— reading/choice 两页已验证的同一手法。 */
html{ background:var(--dk-sky-4); }

body{
  background-color:var(--dk-sky-2);
  background-image:
    radial-gradient(56% 38% at 88% -6%, rgba(185,164,255,.40), rgba(185,164,255,0) 72%),
    radial-gradient(46% 34% at -10% 20%, rgba(127,230,207,.34), rgba(127,230,207,0) 72%),
    radial-gradient(44% 30% at 108% 66%, rgba(255,194,166,.34), rgba(255,194,166,0) 74%),
    radial-gradient(48% 34% at 2% 104%, rgba(255,223,142,.36), rgba(255,223,142,0) 74%),
    linear-gradient(180deg,var(--dk-sky-1) 0%,var(--dk-sky-2) 32%,var(--dk-sky-3) 66%,var(--dk-sky-4) 100%);
  background-attachment:fixed;
  color:var(--dk-ink-on-sky);
  font-family:var(--dk-font-cn);
  -webkit-font-smoothing:antialiased;
  -webkit-tap-highlight-color:transparent;
}

/* 装饰层：真实元素而不是 body::before/::after。
   原因——有的页面（test/games.css）已经占用了 body 的两个伪元素做浮动光球，
   若底座也用伪元素，两边属性会互相渗透（残留的 filter:blur(48px)、
   width:280px 之类），且顺序一变结论就变。用独立元素 + 自己的伪元素最稳。 */
.dk-sky{ position:fixed; inset:0; z-index:-1; pointer-events:none; overflow:hidden; }

/* 光点 / 星尘：峰值透明度压在 ≤.5 —— 光点恰好落在文字下方时也算「真实背景」，
   太亮会把环境层文字的对比度拖下来。浅色底上这些小点是白的，几乎无风险，
   但仍保留上限以免将来调色时失控。 */
.dk-sky::before{
  content:""; position:absolute; inset:0;
  background-image:
    radial-gradient(1.8px 1.8px at 8% 13%,  rgba(255,255,255,.95), rgba(255,255,255,0) 100%),
    radial-gradient(1.4px 1.4px at 23% 31%, rgba(255,255,255,.80), rgba(255,255,255,0) 100%),
    radial-gradient(2.0px 2.0px at 40% 8%,  rgba(255,230,160,.85), rgba(255,230,160,0) 100%),
    radial-gradient(1.3px 1.3px at 57% 25%, rgba(255,255,255,.72), rgba(255,255,255,0) 100%),
    radial-gradient(1.8px 1.8px at 75% 16%, rgba(255,255,255,.85), rgba(255,255,255,0) 100%),
    radial-gradient(1.3px 1.3px at 90% 40%, rgba(255,255,255,.68), rgba(255,255,255,0) 100%),
    radial-gradient(1.5px 1.5px at 6%  61%, rgba(255,255,255,.70), rgba(255,255,255,0) 100%),
    radial-gradient(1.8px 1.8px at 67% 73%, rgba(255,230,160,.70), rgba(255,230,160,0) 100%),
    radial-gradient(1.3px 1.3px at 33% 55%, rgba(255,255,255,.62), rgba(255,255,255,0) 100%),
    radial-gradient(1.6px 1.6px at 51% 87%, rgba(255,255,255,.72), rgba(255,255,255,0) 100%),
    radial-gradient(1.4px 1.4px at 85% 91%, rgba(255,255,255,.62), rgba(255,255,255,0) 100%);
  animation:dkTwinkle 5.5s ease-in-out infinite alternate;
}
@keyframes dkTwinkle{ from{opacity:.6;} to{opacity:1;} }

/* 柔光太阳 + 远景城堡剪影（纯装饰，低透明，不参与对比度） */
.dk-sky::after{
  content:""; position:absolute; inset:0;
  background:
    radial-gradient(14% 10% at 93% 22%, rgba(255,250,232,.95), rgba(255,250,232,0) 74%),
    radial-gradient(32% 24% at 93% 22%, rgba(255,246,214,.62), rgba(255,246,214,0) 72%),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 120' preserveAspectRatio='none'><path fill='%237a5fd0' fill-opacity='.13' d='M0 120V86H20V70L30 52L40 70V86H62V58L74 34L86 58V86H104V44L118 16L132 44V86H152V60L162 42L172 60V86H190V70L200 52L210 70V86H232V58L244 36L256 58V86H280V70L290 54L300 70V86H320V120Z'/></svg>") bottom center/min(900px,132%) auto no-repeat;
  animation:dkSun 9s ease-in-out infinite alternate;
}
@keyframes dkSun{ from{opacity:.80;} to{opacity:1;} }
/* 矮屏（横屏手机等）藏掉城堡，避免装饰挤占内容 */
@media (max-height:560px){ .dk-sky::after{ background-image:none; } }

/* ============ 5. 故事书页 ============ */
.dk-page{
  position:relative;
  background:var(--dk-page-bg);
  border-radius:var(--dk-r-page);
  box-shadow:var(--dk-page-shadow);
  color:var(--dk-ink);
}
/* 顶部烫金书脊 */
.dk-page::before{
  content:""; position:absolute; left:22px; right:22px; top:0; height:3px;
  border-radius:0 0 3px 3px;
  background:linear-gradient(90deg, rgba(197,144,32,0), #e6b64a 18%, #ffe9a8 50%, #e6b64a 82%, rgba(197,144,32,0));
  opacity:.95;
  pointer-events:none;
}
/* 右上角极薄的书页高光，做出「亮面」质感 */
.dk-page::after{
  content:""; position:absolute; inset:0; border-radius:inherit; pointer-events:none;
  background:radial-gradient(120% 74% at 100% 0%, rgba(255,255,255,.6), rgba(255,255,255,0) 58%);
}

/* ============ 6. 挤塑玩具按钮 ============ */
.dk-btn{
  display:inline-flex; align-items:center; justify-content:center; gap:7px;
  min-height:44px; padding:0 18px;
  border:none; cursor:pointer;
  border-radius:var(--dk-r-ctl);
  font-family:inherit; font-size:15px; font-weight:800; letter-spacing:.3px;
  color:var(--dk-ink-strong);
  background:var(--dk-plastic-bg);
  box-shadow:var(--dk-plastic-shadow);
  transition:transform .14s cubic-bezier(.22,1,.36,1), box-shadow .14s, background .2s, color .2s;
  -webkit-tap-highlight-color:transparent;
  touch-action:manipulation;
}
.dk-btn:hover{ background:var(--dk-plastic-bg-hover); }
.dk-btn:active{ transform:translateY(3px); box-shadow:var(--dk-plastic-shadow-press); }

.dk-btn--vio{ color:#fff; background:var(--dk-vio-plastic); box-shadow:var(--dk-vio-plastic-shadow); }
.dk-btn--vio:hover{ background:var(--dk-vio-plastic); filter:brightness(1.06); box-shadow:var(--dk-vio-plastic-shadow), var(--dk-halo); }
.dk-btn--ok{ color:#fff; background:var(--dk-ok-plastic); box-shadow:var(--dk-ok-plastic-shadow); }
.dk-btn--ok:hover{ filter:brightness(1.05); }
.dk-btn--no{ color:#fff; background:var(--dk-no-plastic); box-shadow:var(--dk-no-plastic-shadow); }
.dk-btn--no:hover{ filter:brightness(1.05); }
.dk-btn--warn{ color:#fff; background:var(--dk-warn-plastic); box-shadow:var(--dk-warn-plastic-shadow); }
.dk-btn--warn:hover{ filter:brightness(1.05); }
.dk-btn--gold{ color:var(--dk-gold-ink); background:var(--dk-gold-plastic); box-shadow:var(--dk-gold-plastic-shadow); }
.dk-btn--gold:hover{ filter:brightness(1.02); }
.dk-btn--press{ transform:translateY(3px); box-shadow:var(--dk-plastic-shadow-press); }

/* 圆形图标按钮（喇叭等） */
.dk-iconbtn{
  display:inline-flex; align-items:center; justify-content:center;
  width:44px; height:44px; padding:0;
  border:none; cursor:pointer; border-radius:50%;
  color:#fff; background:var(--dk-vio-plastic); box-shadow:var(--dk-vio-plastic-shadow);
  transition:transform .14s cubic-bezier(.22,1,.36,1), box-shadow .14s, filter .2s;
  -webkit-tap-highlight-color:transparent; touch-action:manipulation;
}
.dk-iconbtn:hover{ filter:brightness(1.06); box-shadow:var(--dk-vio-plastic-shadow), var(--dk-halo); }
.dk-iconbtn:active{ transform:translateY(3px); box-shadow:var(--dk-plastic-shadow-press); }

/* ============ 7. 分段控件（模式切换） ============ */
.dk-seg{
  display:flex; flex-wrap:nowrap; gap:6px; justify-content:stretch;
  padding:6px; border-radius:var(--dk-r-page);
  background:linear-gradient(180deg, rgba(255,255,255,.74), rgba(238,231,255,.74));
  border:1px solid rgba(122,94,226,.16);
  box-shadow:inset 0 1px 0 #fff,
             inset 0 -2px 0 rgba(122,94,226,.12),
             0 10px 20px -14px rgba(78,54,155,.5);
}
.dk-seg-item{
  flex:1 1 0; min-width:0; min-height:46px;
  display:inline-flex; align-items:center; justify-content:center; gap:6px;
  padding:6px 8px;
  border:none; cursor:pointer; border-radius:var(--dk-r-tab);
  font-family:inherit; font-size:clamp(13px,3.5vw,15px); font-weight:700; line-height:1.15;
  white-space:nowrap; overflow:hidden;
  color:var(--dk-ink-soft);
  background:transparent;
  transition:transform .16s cubic-bezier(.22,1,.36,1), background .22s, color .22s, box-shadow .18s;
  -webkit-tap-highlight-color:transparent;
}
.dk-seg-item:hover:not(.active){ color:var(--dk-ink-strong); background:rgba(122,94,226,.09); }
.dk-seg-item.active{
  color:#fff;
  background:var(--dk-vio-plastic);
  box-shadow:var(--dk-vio-plastic-shadow);
}
/* 选中段的魔法光环（呼吸）——挂在伪元素上，避免动画覆盖 box-shadow */
.dk-seg-item{ position:relative; }
.dk-seg-item.active::after{
  content:""; position:absolute; inset:0; border-radius:inherit; pointer-events:none;
  animation:dkRing 2.6s ease-out infinite;
}
@keyframes dkRing{
  0%   { box-shadow:0 0 0 0 rgba(150,110,255,.5), inset 0 0 0 1px rgba(255,233,168,.7); }
  70%  { box-shadow:0 0 0 9px rgba(150,110,255,0), inset 0 0 0 1px rgba(255,233,168,.26); }
  100% { box-shadow:0 0 0 0 rgba(150,110,255,0), inset 0 0 0 1px rgba(255,233,168,.26); }
}

/* ============ 8. 状态芯片 / HUD ============ */
.dk-hud{ display:flex; flex-wrap:wrap; gap:9px; justify-content:center; align-items:stretch; }
.dk-chip{
  display:inline-flex; align-items:center; gap:7px; min-width:0;
  padding:8px 13px; border-radius:var(--dk-r-chip);
  font-size:13.5px; font-weight:700; line-height:1.2;
  color:var(--dk-ink-soft);
  background:linear-gradient(180deg,#fff,#f6f1ff);
  box-shadow:inset 0 2px 0 #fff,
             inset 0 -2px 0 rgba(122,94,226,.13),
             0 0 0 1px rgba(122,94,226,.15),
             0 8px 14px -10px rgba(78,54,155,.4);
}
.dk-chip b, .dk-chip strong, .dk-chip .dk-chip-val{
  font-weight:900; font-size:1.14em; font-variant-numeric:tabular-nums;
  color:var(--dk-ink-strong);
}
.dk-chip--vio b, .dk-chip--vio .dk-chip-val{ color:var(--dk-vio-deep); }
.dk-chip--ok b,  .dk-chip--ok  .dk-chip-val{ color:var(--dk-ok); }
.dk-chip--no b,  .dk-chip--no  .dk-chip-val{ color:var(--dk-no); }
.dk-chip--god b, .dk-chip--god .dk-chip-val{ color:var(--dk-warn); }
.dk-label{ font-size:12.5px; font-weight:700; letter-spacing:.3px; color:var(--dk-ink-mute); }

/* 小徽章（强化复习 / 正常测试 之类） */
.dk-badge{
  display:inline-flex; align-items:center; gap:6px;
  padding:6px 14px; border-radius:999px;
  font-size:13.5px; font-weight:800; letter-spacing:.3px;
  color:#fff; background:var(--dk-vio-plastic);
  box-shadow:var(--dk-vio-plastic-shadow);
}
.dk-badge--warn{ background:var(--dk-warn-plastic); box-shadow:var(--dk-warn-plastic-shadow); }
.dk-badge--ok{ background:var(--dk-ok-plastic); box-shadow:var(--dk-ok-plastic-shadow); }

/* ============ 9. 进度星轨 ============ */
.dk-rail{
  position:relative; height:10px; border-radius:999px; overflow:visible;
  background:linear-gradient(180deg, rgba(122,94,226,.14), rgba(122,94,226,.08));
  box-shadow:inset 0 2px 4px rgba(78,54,155,.16), 0 1px 0 #fff;
}
.dk-rail-fill{
  position:relative; display:block; height:100%; width:0;
  border-radius:999px;
  background:linear-gradient(90deg,var(--dk-vio) 0%,#9a6bff 52%,var(--dk-gold) 100%);
  box-shadow:0 0 12px rgba(150,110,255,.55);
  transition:width .5s cubic-bezier(.34,1.4,.64,1);
}
/* 轨道末端那颗"星球" */
.dk-rail-fill::after{
  content:""; position:absolute; right:-6px; top:50%; width:16px; height:16px;
  transform:translateY(-50%); border-radius:50%;
  background:radial-gradient(circle at 34% 30%, #fff6d2 0%, var(--dk-gold) 46%, var(--dk-gold-2) 100%);
  box-shadow:0 0 12px rgba(255,190,80,.9), inset 0 -2px 3px rgba(150,92,10,.35);
  transition:opacity .3s;
}
/* 进度为 0 时不显示末端星球（否则它会吊在轨道最左边像个空装饰）。
   JS 写的是 `style.width = pct + '%'`，浏览器序列化成 `width: 0%`（冒号后**有空格**），
   所以两种写法都要覆盖 —— 只写 `[style*="width:0%"]` 是匹配不到的，
   这种"属性选择器少写一个空格就静默失效"的坑很难靠肉眼发现。 */
.dk-rail-fill[style*="width:0%"]::after,
.dk-rail-fill[style*="width: 0%"]::after,
.dk-rail-fill[style*="width:0;"]::after{ opacity:0; }

/* ============ 10. 反馈条 ============ */
.dk-feedback{
  border-radius:var(--dk-r-plate);
  padding:14px 18px;
  font-size:16px; font-weight:800; line-height:1.4; text-align:center;
  color:var(--dk-ink);
  background:linear-gradient(180deg,#fff,#f7f4ff);
  box-shadow:var(--dk-ring),
             inset 0 2px 0 #fff,
             inset 0 -3px 0 var(--dk-lip),
             0 12px 22px -16px rgba(78,54,155,.5);
}
.dk-feedback--ok{
  color:#fff;
  background:var(--dk-ok-plastic);
  box-shadow:inset 0 2px 0 rgba(255,255,255,.34),
             inset 0 -3px 0 var(--dk-ok-lip),
             0 12px 24px -14px rgba(7,107,78,.6);
}
.dk-feedback--no{
  color:#fff;
  background:var(--dk-no-plastic);
  box-shadow:inset 0 2px 0 rgba(255,255,255,.34),
             inset 0 -3px 0 var(--dk-no-lip),
             0 12px 24px -14px rgba(163,21,47,.55);
}
.dk-feedback--warn{
  color:#fff;
  background:var(--dk-warn-plastic);
  box-shadow:inset 0 2px 0 rgba(255,255,255,.3),
             inset 0 -3px 0 var(--dk-warn-lip),
             0 12px 24px -14px rgba(138,82,0,.55);
}

/* ============ 11. 题面 / 槽位 / 字母池 ============ */
.dk-question{
  border-radius:var(--dk-r-plate);
  padding:16px 20px;
  font-size:clamp(20px,5.4vw,28px); font-weight:800; line-height:1.3;
  color:var(--dk-ink-strong);
  background:linear-gradient(180deg,#fff,#f6f1ff);
  box-shadow:var(--dk-ring), inset 0 2px 0 #fff, inset 0 -3px 0 var(--dk-lip);
  text-align:center;
}
.dk-word{
  font-family:var(--dk-font-en);
  font-size:clamp(28px,8vw,44px); font-weight:800; letter-spacing:.5px;
  color:var(--dk-ink-strong);
  text-shadow:0 2px 0 rgba(255,255,255,.9);
}
.dk-sub{ font-size:14px; font-weight:700; color:var(--dk-ink-soft); }

/* 答案槽：待填的空位，虚线 + 内凹 */
.dk-slot{
  border-radius:var(--dk-r-plate);
  padding:18px;
  background:linear-gradient(180deg,#fdfbff,#f4efff);
  box-shadow:inset 0 3px 8px rgba(78,54,155,.14), 0 0 0 1px rgba(122,94,226,.16);
  border:2px dashed rgba(122,94,226,.34);
}
.dk-slot.is-full{ border-style:solid; border-color:rgba(122,94,226,.4); }

/* 字母池 */
.dk-pool{ display:flex; flex-wrap:wrap; justify-content:center; gap:9px; }
.dk-tile{
  display:inline-flex; align-items:center; justify-content:center;
  width:46px; height:46px; border-radius:var(--dk-r-tile);
  font-family:var(--dk-font-en); font-size:22px; font-weight:800;
  color:var(--dk-ink-strong);
  background:var(--dk-plastic-bg);
  box-shadow:var(--dk-plastic-shadow);
  cursor:pointer; user-select:none;
  border:none;
  transition:transform .14s cubic-bezier(.22,1,.36,1), box-shadow .14s, background .2s, color .2s;
  -webkit-tap-highlight-color:transparent; touch-action:manipulation;
}
.dk-tile:hover{ background:var(--dk-plastic-bg-hover); }
.dk-tile:active, .dk-tile.active{ transform:translateY(3px); box-shadow:var(--dk-plastic-shadow-press); }
/* 已被用掉的字母：不删元素（JS 可能还要还原），只做"凹陷空位" */
.dk-tile.is-used{
  color:transparent;
  background:rgba(122,94,226,.07);
  box-shadow:inset 0 2px 5px rgba(78,54,155,.18), 0 0 0 1px rgba(122,94,226,.12);
}

/* ============ 12. 结算卡 / 表格 ============ */
.dk-result{ text-align:center; }
.dk-result h2, .dk-result .dk-result-title{
  margin:0 0 10px;
  font-size:clamp(20px,5.6vw,26px); font-weight:900;
  color:var(--dk-ink-strong);
}
.dk-table{ width:100%; border-collapse:separate; border-spacing:0 7px; font-size:14px; }
.dk-table th{
  font-size:12.5px; font-weight:800; letter-spacing:.3px;
  color:var(--dk-ink-mute); text-align:left; padding:0 10px 2px;
}
.dk-table td{
  padding:10px 12px; background:#fff; color:var(--dk-ink);
  box-shadow:inset 0 2px 0 #fff, 0 0 0 1px rgba(122,94,226,.13);
}
.dk-table tr td:first-child{ border-radius:12px 0 0 12px; }
.dk-table tr td:last-child{ border-radius:0 12px 12px 0; }
/* 业务 JS 会往单元格里写**内联色**（init_spell.js 的 showErrorReport 生成
   `style="color:red"` / `style="color:green"`）。内联声明只能用 !important 压，
   少了它规则命中但颜色不生效 —— 实测就是「font-weight 生效了、color 没生效」
   （红 #ff0000 压白底只有 4.00:1，差一点点就是不达标）。
   注意 *.dk-table 内部的 <td style=...> 一律按语义色接管，别只处理 red。 */
.dk-table tr td[style*="red"], .dk-table td.is-no{ color:var(--dk-no) !important; font-weight:800; }
.dk-table tr td[style*="green"], .dk-table td.is-ok{ color:var(--dk-ok) !important; font-weight:800; }

/* 结算/总结面板里的 <strong> 有的是业务 JS 用**内联浅色**写的
   （games.js 的 endGame 写 `style="color:#4CAF50"`，压象牙页只有 2.73:1）。
   内联声明只能靠 !important 压。
   ⚠️ 这里**只点名那条内联色**，不能写成 `.dk-result strong{color:...}` 一刀切：
   36spell 的「错误单词列表」同样用 <strong style="color:#333">，而 #333 压
   #f9f9f9 约 12:1 是合格的深灰；一刀切会把「错误单词」染成表示正确的翠绿，语义反了。 */
.dk-result strong[style*="4caf50" i],
.dk-report strong[style*="4caf50" i]{ color:var(--dk-ok) !important; }

/* ============ 13. 图标（替换 emoji） ============ */
/* emoji 是平台位图：不跟随字号/配色，小尺寸下糊成色块，各系统还不一样。
   这里一律用 24×24 描边/实心 SVG 的 data-URI，尺寸跟着字走。
   ⚠️ 描边色是**写死**在 data-URI 里的，所以每个图标必须按「它将要落上的底色」选色。
   金色系原本用 #c58a12，压在象牙页（#f7f0dd）只有 **2.63:1** —— 低于非文字图形的
   3:1 下限。改成同族的 #a4611a（本文件里 .dk-i-star 一直在用的描边色）→ 4.36:1。
   改图标色时记住：每个 `stroke='%23xxxxxx'` 都是一份独立副本，没有变量可改，
   改完要 grep 确认残留为 0（本项目就有「同一色值 4~5 份字面副本」的历史）。 */
.dk-i{
  display:inline-block; width:1.18em; height:1.18em; flex:0 0 auto;
  vertical-align:-.2em;
  background-position:center; background-repeat:no-repeat; background-size:contain;
}
.dk-i-party  { background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230a7f5f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M3.2 20.8 8.6 8.4l7 7-12.4 5.4z'/><path d='M13.4 5.6c.6-1.4 2-2 3.4-1.6M19.4 9.6c1.4-.6 2-2 1.6-3.4M17 3.2l.9 2.1 2.1.9-2.1.9-.9 2.1-.9-2.1-2.1-.9 2.1-.9z'/></svg>"); }
.dk-i-trophy { background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a4611a' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'><path d='M7 4h10v5.2a5 5 0 0 1-10 0z'/><path d='M7 5.4H4.4v1.6a3.6 3.6 0 0 0 3.2 3.6M17 5.4h2.6v1.6a3.6 3.6 0 0 1-3.2 3.6'/><path d='M12 14.4V18M8.4 20.4h7.2'/></svg>"); }
.dk-i-rocket  { background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236a44ec' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'><path d='M12 2.6c3.3 2 5 5.2 5 8.9l2.2 2.2-2.6.9-1.4 3.4-3.2-2.6-3.2 2.6-1.4-3.4-2.6-.9L7 11.5c0-3.7 1.7-6.9 5-8.9z'/><circle cx='12' cy='10' r='1.9'/></svg>"); }
.dk-i-muscle  { background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a4611a' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'><path d='M4 8.4h6.4a3.6 3.6 0 0 1 3.6 3.6v1.6a4.4 4.4 0 0 0 4.4 4.4h1.4'/><path d='M4 8.4v4.2a2.6 2.6 0 0 0 2.6 2.6H10'/></svg>"); }
.dk-i-spark   { background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%236a44ec'><path d='M12 2l1.9 5.6L19.5 9.5 13.9 11.4 12 17l-1.9-5.6L4.5 9.5l5.6-1.9z'/><path d='M19 15l.9 2.6 2.6.9-2.6.9-.9 2.6-.9-2.6-2.6-.9 2.6-.9z'/></svg>"); }
.dk-i-bulb    { background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23b06a00' stroke-width='2' stroke-linecap='round'><path d='M9.2 17.5h5.6M10 21h4'/><path d='M12 2.6a6.4 6.4 0 0 0-3.6 11.7v3.2h7.2v-3.2A6.4 6.4 0 0 0 12 2.6z'/></svg>"); }
.dk-i-check   { background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230a7f5f' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='9'/><path d='M7.6 12.4l3.1 3.1 5.7-6.6'/></svg>"); }
.dk-i-check-w{ background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='9'/><path d='M7.6 12.4l3.1 3.1 5.7-6.6'/></svg>"); }
.dk-i-x       { background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23b3203a' stroke-width='2.4' stroke-linecap='round'><circle cx='12' cy='12' r='9'/><path d='M8.6 8.6l6.8 6.8M15.4 8.6l-6.8 6.8'/></svg>"); }
.dk-i-x-w     { background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2.4' stroke-linecap='round'><circle cx='12' cy='12' r='9'/><path d='M8.6 8.6l6.8 6.8M15.4 8.6l-6.8 6.8'/></svg>"); }
.dk-i-warn    { background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23b06a00' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M12 3.6 21 19.6H3z'/><path d='M12 9.6v4.4M12 17h.01'/></svg>"); }
.dk-i-speaker { background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M4.4 9.4h3.4L12.6 5v14l-4.8-4.4H4.4z'/><path d='M16.2 9.2a4 4 0 0 1 0 5.6M19 6.6a7.6 7.6 0 0 1 0 10.8'/></svg>"); }
.dk-i-retry   { background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234c2ad0' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'><path d='M20 12a8 8 0 1 1-2.6-5.9'/><path d='M20 4v4.6h-4.6'/></svg>"); }
.dk-i-loop    { background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='M4.6 11.4a7.4 7.4 0 0 1 12.6-4.8M19.4 12.6a7.4 7.4 0 0 1-12.6 4.8'/><path d='M17.6 3.4v3.6H14M6.4 20.6V17H10'/></svg>"); }
.dk-i-eye     { background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234c2ad0' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'><path d='M2.4 12S5.8 5.6 12 5.6 21.6 12 21.6 12 18.2 18.4 12 18.4 2.4 12 2.4 12z'/><circle cx='12' cy='12' r='2.9'/></svg>"); }
.dk-i-clock   { background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235b4f9e' stroke-width='1.9' stroke-linecap='round'><circle cx='12' cy='12' r='8.6'/><path d='M12 7.2V12l3.4 2.1'/></svg>"); }
.dk-i-point   { background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236a44ec' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M9.6 11.4V4.8a1.6 1.6 0 0 1 3.2 0v5.8'/><path d='M12.8 10.6a1.5 1.5 0 0 1 3 .3v1.3M15.8 13.4a1.5 1.5 0 0 1 3 .5v3.3a4.6 4.6 0 0 1-4.6 4.6h-2.4a4.6 4.6 0 0 1-3.6-1.8l-3-4a1.6 1.6 0 0 1 2.4-2.1l1.8 1.6'/></svg>"); }
.dk-i-star    { background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23e0a12a' stroke='%23a4611a' stroke-width='.8'><path d='M12 2.6l2.95 5.98 6.6.96-4.78 4.66 1.13 6.58L12 17.72l-5.9 3.06 1.13-6.58-4.78-4.66 6.6-.96z'/></svg>"); }
/* ---- 深色承载面上的图标一律反白 ----
   ⚠️ 这一条是**真实缺陷修来的**，别删。
   .dk-i-* 的 stroke 是**写死**进 data-URI 的（为浅色底设计的深色描边），
   一旦图标落进**同色系深色容器**，就变成「同色压同色」。CDP 实测：
     .dk-i-x     #b3203a 压深红反馈条 (#c02246)  = 1.12:1
     .dk-i-retry #4c2ad0 压紫色主按钮 (#4c2ad0)  = 1.00:1
     .dk-i-check #0a7f5f 压深绿反馈条           = 同类问题
   都等于肉眼看不见。而**文字**侧本来就已经过 AA（这几类容器清一色 `color:#fff`），
   所以最省事又自洽的做法是：让图标跟着承载面的文字色走 —— 图标是单色描边图形，
   `brightness(0) invert(1)` 正好等价于「用白色重绘」，且保留 alpha（透明处仍透明）。
   filter 不参与布局，尺寸零影响。
   注意 `.dk-btn--gold` 是深墨压金底，**不能**反白。 */
.dk-feedback--ok .dk-i, .dk-feedback--no .dk-i, .dk-feedback--warn .dk-i,
.dk-btn--vio .dk-i, .dk-btn--no .dk-i, .dk-btn--ok .dk-i, .dk-btn--warn .dk-i,
.dk-alert--ok .dk-i, .dk-alert--no .dk-i{
  filter:brightness(0) invert(1);
}
/* ⚠️ 页面层的状态类（如 test/spell 的 `.feedback.correct` / `.feedback.wrong`）
   不是 kit 的 `dk-feedback--ok/no`，上面这组选择器**够不到**，页面适配表必须自己点名。
   早期这里只写了一行 `.dk-feedback--ok .dk-i{filter:none}` —— 没有对应的反白规则，
   等于什么都没做，`.dk-feedback--ok` 组件的图标一直是「深绿压深绿」。已删。 */

/* ============ 14. 无障碍 ============ */
.dk-btn:focus-visible, .dk-seg-item:focus-visible, .dk-tile:focus-visible,
.dk-iconbtn:focus-visible{
  outline:3px solid var(--dk-vio-deep);
  outline-offset:2px;
}
@media (prefers-reduced-motion: reduce){
  .dk-sky::before, .dk-sky::after, .dk-seg-item.active::after,
  .dk-rail-fill, .dk-btn, .dk-tile, .dk-iconbtn{
    animation:none !important; transition:none !important;
  }
}

/* ============ 15. 响应式工具 ============ */
@media (max-width:400px){
  .dk-chip{ padding:7px 11px; font-size:12.5px; }
  .dk-btn{ padding:0 15px; font-size:14px; }
  .dk-tile{ width:42px; height:42px; font-size:20px; }
  .dk-pool{ gap:7px; }
}
@media (max-width:340px){
  .dk-tile{ width:38px; height:38px; font-size:18px; border-radius:13px; }
  .dk-pool{ gap:6px; }
  .dk-chip{ font-size:12px; padding:6px 9px; }
}

/* =====================================================================
   对比度实算表（WCAG 2.1，相对亮度）
   ---------------------------------------------------------------------
   浅色主题的最坏情况与夜空主题**相反**：
     · 深色文字压浅底 → 最坏 = 底最暗处（天空底部 --dk-sky-4 #ded4f8 / --dk-sky-5）
     · 白色文字压彩色塑料 → 最坏 = 渐变最亮的那个停靠点
   实算（用 .workbuddy/tmp/ui36/wcag.py）：
     墨 #3b2f77 / 天空#d2c6f4 ......... 7.06  PASS（最暗停靠点，最坏情况）
     墨 #3b2f77 / 天空#ded4f8 ......... 8.00  PASS
     墨 #3b2f77 / 天空#faf8ff ......... 10.72 PASS
     副墨 #53468e / 天空#d2c6f4 ....... 4.98  PASS（原 #5a4f95 只有 4.39 FAIL）
     副墨 #5b4f9e / 象牙纸#fffdf7 ..... 6.75  PASS
     次墨 #6b5fa8 / 纸#f7f0dd ......... 4.82  PASS（小字下限，别再调浅）
     白 / 紫 --dk-vio-hi #7a55f0 ...... 4.79  PASS（紫塑料的最亮端）
     白 / 紫 --dk-vio   #6a44ec ....... 5.75  PASS
     白 / 绿 --dk-ok-hi #0a8060 ....... 4.92  PASS（原 #12a377 只有 4.23 FAIL）
     白 / 红 --dk-no-hi #c02246 ....... 5.90  PASS（原 #f0708a 只有 3.26 FAIL）
     白 / 琥珀 --dk-warn-hi #a46000 ... 4.94  PASS（原 #b06a00 只有 4.28 FAIL）
     金字 #7a4a06 / 金底 #ffd76b ...... 5.40  PASS（原 #8a6300 只有 3.93 FAIL）
   ⚠️ 改任何一条亮端色值后，必须重跑页面级审计脚本，别只信这张表。
   ===================================================================== */
