@import './study-lab-motion.css';

/*
 * 学习实验页与站点阅读层共用的 design token。
 * 分成两组。语义组（表面、文字、品牌、状态）原本在四个样式表里各存一份副本，
 * 现在只有这里一份；分级组（字号、间距、圆角、阴影、时长、缓动）是新加的刻度，让每个页面从同一张表取值，而不是各写各的数字。
 * 颜色的验证记录留在原处：分类色 --brand / --signal 在两种模式下过五项检查（明度带、彩度下限、色相可分辨、常视力下限、对表面对比度），并且与站点 --vp-c-brand-1 同色相族。状态色作为图元验证到 3:1，作为文字另有 --ink 一档验证到 4.5:1——数据色和文字色不能混用。
 * 分级刻度只定义值，不规定谁该用哪一档。页面按用途取，取错了是页面的问题，不是刻度的问题。 */

:root {
  color-scheme: light dark;

  /* 表面：三层暖白。纯白配纯灰长文读起来偏冷偏平，暖调留出层次。 */
  --page: #faf8f4;
  --surface: rgba(255, 255, 255, 0.92);
  --surface-strong: #ffffff;
  --surface-soft: #f4f1ea;

  --ink: #1f2228;
  --muted: #5b5b66;
  --line: rgba(60, 60, 67, 0.14);
  --line-strong: rgba(60, 60, 67, 0.28);

  --brand: #3157c8;
  --brand-bright: #466fe0;
  --brand-soft: #dfe7ff;

  --signal: #d46b3e;
  /* 文字档：图元色验证到 3:1，正文需要 4.5:1，所以文字取同色相族的深一档。 */
  --signal-ink: #aa4d26;
  --signal-soft: #f5dfd3;

  --allow: #0f7a52;
  --allow-ink: #0f7851;
  --allow-soft: #d9eee5;

  --deny: #b03040;
  --deny-ink: #b83243;
  --deny-soft: #f4dcdf;

  --warning: #b8892a;
  --warning-ink: #8a6410;
  --warning-soft: #f6ecd6;

  /*
   * 数据序列色只在一张图需要区分三条以上同类序列时使用。分组、分类等高基数维度不靠色相区分——那种情况下颜色不可靠，用筛选或位置。   */
  --series-1: #3157c8;
  --series-2: #d46b3e;
  --series-3: #6b4d9e;
  --series-1-wash: #dfe7ff;
  --series-2-wash: #f5dfd3;
  --series-3-wash: #e6dff2;

  /* 字号：10 级。正文取 --text-md，行内 code 取 --text-xs。 */
  --text-2xs: 0.6875rem;
  --text-xs: 0.8rem;
  --text-sm: 0.875rem;
  --text-md: 1rem;
  --text-lg: 1.125rem;
  --text-xl: 1.375rem;
  --text-2xl: 1.75rem;
  --text-3xl: 2.25rem;
  --text-4xl: 3rem;
  --text-5xl: 4.25rem;

  /* 间距：10 级，4px 基准。 */
  --space-3xs: 0.25rem;
  --space-2xs: 0.375rem;
  --space-xs: 0.5rem;
  --space-sm: 0.75rem;
  --space-md: 1rem;
  --space-lg: 1.5rem;
  --space-xl: 2rem;
  --space-2xl: 2.75rem;
  --space-3xl: 3.5rem;
  --space-4xl: 5rem;

  /* 圆角：8 级。--radius-pill 用于胶囊按钮，不是一个尺寸而是一种形状。 */
  --radius-2xs: 3px;
  --radius-xs: 6px;
  --radius-sm: 8px;
  --radius-md: 14px;
  --radius-lg: 22px;
  --radius-xl: 30px;
  --radius-2xl: 38px;
  --radius-3xl: 48px;
  --radius-pill: 999px;

  --shadow-sm: 0 2px 8px rgba(38, 34, 26, 0.05);
  --shadow-md: 0 12px 32px rgba(38, 34, 26, 0.08);
  --shadow-lg: 0 22px 70px rgba(38, 34, 26, 0.11);

  /*
   * 别名，让已有页面不必改规则。--shadow 是四个实验页原来共用的那一档，等于
   * --shadow-lg；--danger 是 bridge 对 --deny 的叫法，语义相同。   */
  --shadow: var(--shadow-lg);
  --danger: var(--deny);
  --danger-soft: var(--deny-soft);

  /*
   * 四档时长配一条曲线。整站的交互反馈走同一条曲线，手感才一致；
   * 各处各写一个 transition 是之前手感散的原因。   */
  --dur-fast: 0.15s;
  --dur: 0.2s;
  --dur-slow: 0.3s;
  --dur-enter: 0.35s;
  --ease: cubic-bezier(0.2, 0.6, 0.3, 1);

  --mono:
    ui-monospace, "SFMono-Regular", "Cascadia Code", "JetBrains Mono", Menlo, Consolas,
    "Liberation Mono", "Sarasa Mono SC", "Noto Sans Mono CJK SC",
    "Microsoft YaHei UI", "Microsoft YaHei", monospace;
  /*
   * Latin 放前面：CJK 字体自带的西文形比专用 Latin 字体差，代码旁边的标识符
   * 和数字会看出来。一个字节都不下载——实验页的 default-src 'self' 禁止字体 CDN，而自托管中文字体要 17 MB 以上。   */
  --sans:
    Inter, -apple-system, BlinkMacSystemFont, "Segoe UI Variable Text", "Segoe UI",
    "PingFang SC", "Hiragino Sans GB", "Source Han Sans SC", "Noto Sans SC", "Noto Sans CJK SC",
    "Microsoft YaHei UI", "Microsoft YaHei", "WenQuanYi Micro Hei",
    ui-sans-serif, system-ui, sans-serif,
    "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji";
}

/*
 * 深色板有两份：媒体查询那份服务系统偏好，也是关掉脚本时唯一生效的一份；
 * 属性那份服务用户的显式选择。CSS 没法让媒体查询作用域内外的两个选择器共用同一个声明块，所以这里是真的两份副本。 *
 * `:not([data-theme="light"])` 让显式选浅色时媒体查询让位；[data-theme="dark"]
 * 让显式选深色时在浅色系统下也生效。 *
 * 两份会漂移，所以 study-tools/verify-theme-parity.mjs 逐 token 比对它们，只改一边会让那道门禁失败。 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --page: #17171a;
    --surface: rgba(32, 33, 39, 0.94);
    --surface-strong: #1b1b1f;
    --surface-soft: #202127;

    --ink: #dfdfd6;
    --muted: #9b9ba4;
    --line: rgba(223, 223, 214, 0.14);
    --line-strong: rgba(223, 223, 214, 0.28);

    --brand: #6b8ae8;
    --brand-bright: #91aaff;
    --brand-soft: #202b55;

    --signal: #d1793f;
    --signal-ink: #d58651;
    --signal-soft: #4c3027;

    --allow: #2b9a70;
    --allow-ink: #37c38e;
    --allow-soft: #1e493c;

    --deny: #cd4a5a;
    --deny-ink: #dc808b;
    --deny-soft: #4c292f;

    --warning: #b8871f;
    --warning-ink: #d7a63c;
    --warning-soft: #43351a;

    --series-1: #6b8ae8;
    --series-2: #d1793f;
    --series-3: #a98ad4;
    --series-1-wash: #202b55;
    --series-2-wash: #4c3027;
    --series-3-wash: #33294a;

    --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.24);
    --shadow-md: 0 12px 34px rgba(0, 0, 0, 0.3);
    --shadow-lg: 0 24px 86px rgba(0, 0, 0, 0.36);
    --shadow: var(--shadow-lg);
  }
}

:root[data-theme="dark"] {
  --page: #17171a;
  --surface: rgba(32, 33, 39, 0.94);
  --surface-strong: #1b1b1f;
  --surface-soft: #202127;

  --ink: #dfdfd6;
  --muted: #9b9ba4;
  --line: rgba(223, 223, 214, 0.14);
  --line-strong: rgba(223, 223, 214, 0.28);

  --brand: #6b8ae8;
  --brand-bright: #91aaff;
  --brand-soft: #202b55;

  --signal: #d1793f;
  --signal-ink: #d58651;
  --signal-soft: #4c3027;

  --allow: #2b9a70;
  --allow-ink: #37c38e;
  --allow-soft: #1e493c;

  --deny: #cd4a5a;
  --deny-ink: #dc808b;
  --deny-soft: #4c292f;

  --warning: #b8871f;
  --warning-ink: #d7a63c;
  --warning-soft: #43351a;

  --series-1: #6b8ae8;
  --series-2: #d1793f;
  --series-3: #a98ad4;
  --series-1-wash: #202b55;
  --series-2-wash: #4c3027;
  --series-3-wash: #33294a;

  --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.24);
  --shadow-md: 0 12px 34px rgba(0, 0, 0, 0.3);
  --shadow-lg: 0 24px 86px rgba(0, 0, 0, 0.36);
  --shadow: var(--shadow-lg);
}

/* 减少动态效果时把四档时长一起归零，页面不必各自再判断。*/
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-fast: 0s;
    --dur: 0s;
    --dur-slow: 0s;
    --dur-enter: 0s;
  }
}

/*
 * Motion master switch (kit installMotionPauseToggle maintains data-motion):
 * "paused" freezes every keyframe animation and makes transitions land
 * instantly — when the reader asks for stillness, state jumps to its final
 * value. Static opacity/visibility presentation is untouched, so content
 * stays readable and print styles keep working.
 */
[data-motion="paused"] *,
[data-motion="paused"] *::before,
[data-motion="paused"] *::after {
  animation-play-state: paused !important;
  transition-duration: 0s !important;
}

/*
 * 进场动画的两个状态。study-lab-reveal.js 负责按 class，这里只定义外观。 *
 * 只动 opacity 和 transform——SVG 的 r、width 等几何属性各浏览器支持不一，而这两个属性走合成器，不触发重排。动画结束后与不做动画完全一致。 */
[data-reveal] {
  transition:
    opacity var(--dur-enter) var(--ease),
    transform var(--dur-enter) var(--ease);
}

[data-reveal].awaits-reveal {
  opacity: 0;
  /* 点和柱从各自的基准线方向长出来，由 transform-origin 决定，不改坐标。*/
  transform: scale(0.4);
  transform-box: fill-box;
  transform-origin: center;
}

[data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}

/* 柱子从底部长起，缩放的原点在下沿。*/
rect[data-reveal].awaits-reveal {
  transform: scaleY(0.02);
  transform-origin: bottom;
}

/*
 * 减少动态效果时：没有过渡，也没有起始态。这里不依赖 JS 判断，所以脚本失效时也不会留下一批 opacity:0 的隐形标记。 */
@media (prefers-reduced-motion: reduce) {
  [data-reveal],
  [data-reveal].awaits-reveal,
  [data-reveal].is-revealed {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/*
 * 主题切换按钮。三态（跟随系统／浅色／深色），所以状态由可见文字和 aria-label
 * 承担，aria-pressed 只报告「是否覆盖了系统偏好」这一个布尔量。 */
.theme-toggle {
  display: inline-flex;
  min-height: 44px;
  align-items: center;
  gap: var(--space-2xs);
  padding: var(--space-2xs) var(--space-sm);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill);
  color: var(--ink);
  background: color-mix(in srgb, var(--surface-strong) 65%, transparent);
  cursor: pointer;
  font-family: var(--mono);
  font-size: var(--text-xs);
  font-weight: 700;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}

.theme-toggle:hover {
  border-color: var(--brand);
  background: color-mix(in srgb, var(--brand) 8%, var(--surface-strong));
}

/* 覆盖了系统偏好时给一个可见标记，不只靠 aria-pressed。*/
.theme-toggle[aria-pressed="true"] {
  border-color: var(--brand);
  color: var(--brand);
}

.theme-toggle .icon { flex: 0 0 auto; }

@media (prefers-reduced-motion: reduce) {
  .theme-toggle { transition: none; }
}

/*
 * 预测题门控。门控只挡探索性控件，不挡阅读——图、表格、oracle 和证据边界从一开始就完整可见，所以这里没有任何遮罩或模糊。 */
.prediction-gate {
  margin-bottom: var(--space-md);
  padding: var(--space-md);
  border: 1px solid color-mix(in srgb, var(--brand) 30%, var(--line));
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--brand-soft) 46%, var(--surface));
}

.gate-question { margin: 0 0 var(--space-sm); font-size: var(--text-sm); }
.gate-options { display: grid; gap: var(--space-2xs); }

.gate-option {
  display: flex;
  gap: var(--space-2xs);
  align-items: baseline;
  padding: var(--space-2xs) var(--space-xs);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: var(--text-sm);
}

.gate-option:hover { border-color: var(--line-strong); background: color-mix(in srgb, var(--surface-strong) 60%, transparent); }
.gate-option input { margin: 0; }
.gate-actions { display: flex; flex-wrap: wrap; gap: var(--space-2xs); margin-top: var(--space-sm); }

/*
 * inert 已经挡住指针、键盘和辅助技术，这里只把「现在不能用」画出来。用 opacity 而不是隐藏：控件要看得见，读者才知道解锁后会得到什么。 */
#gated-controls[data-gated="locked"] {
  opacity: 0.5;
  transition: opacity var(--dur) var(--ease);
}

#gated-controls[data-gated="unlocked"],
#gated-controls[data-gated="skipped"] {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  #gated-controls[data-gated="locked"] { transition: none; }
}

/* 视觉打磨：预测选项的选中态、统一缓动、数字对齐、滑块品牌色。*/
:root { --ease-out-soft: cubic-bezier(0.22, 0.61, 0.36, 1); }
.gate-option { border-radius: 10px; transition: border-color var(--dur-fast) ease, background var(--dur-fast) ease, transform 160ms var(--ease-out-soft); }
.gate-option:hover { transform: translateX(2px); }
.gate-option:has(input:checked) {
  border-color: var(--brand);
  background: color-mix(in srgb, var(--brand) 8%, transparent);
}
.gate-option:has(input:focus-visible) { outline: 2px solid var(--brand); outline-offset: 1px; }
input[type="range"] { accent-color: var(--brand); }
dd, td, th { font-variant-numeric: tabular-nums; }
@media (prefers-reduced-motion: reduce) {
  .gate-option, .gate-option:hover { transform: none; transition: none; }
}
