/* ============================================================================
   球球老师 · 设计 token 真源（C·童趣高级）
   ---------------------------------------------------------------------------
   v2 · 2026-09-05：从「13 个颜色」扩成完整体系。
   起因是一次实测审计：全站 992 处硬编码的间距/圆角/字号无处可去，
   而 --text-fade 的对比度只有 2.55:1（连大字 3:1 都不过）却被当文字色用了 135 处。

   **改这里，全站生效；不要再回到各页面本地 :root 里加变量。**
   页面专属的布局尺寸（某页自己的栅格宽度之类）仍留在那个页面的 <style> 里。
   ============================================================================ */

:root{
  /* ---- 底色 ---------------------------------------------------------- */
  --bg:#FAF5EB;
  --bg-deep:#F2E9D3;
  --bg-card:#FFFFFF;

  /* ---- 品牌与语义色（用作填充 / 边框 / 图形）--------------------------
     这些饱和色在浅底上作**文字**全部不达标（紫 2.25 / 绿 1.66 / 橙 1.91），
     所以下面另给了 -strong 变体。填充和边框不受 1.4.3 约束，原值保留不动。 */
  --primary:#FFD93D;
  --purple:#A78BFA;
  --green:#6BCB77;
  --orange:#FF8C42;
  --red:#E5686A;
  --pink:#FFB5A7;
  --kid-blue:#87CEEB;

  /* ---- 语义色的深色变体（一个值，两种用法）----------------------------
     ① 当**文字**压在浅底上 → 用它（对 bg/bg-deep/card 均 ≥4.5:1）
     ② 当**填充**且上面要压白字 → 用它（对 #FFFFFF 均 ≥4.5:1）
     两个数都实测过，列在注释里。 */
  --purple-strong:#6D4CC4;  /* 浅底作文字 4.99 · 承白字 6.03 */
  --green-strong:#2F6E38;   /* 5.10 · 6.16 */
  --orange-strong:#A3521B;  /* 4.60 · 5.56 */
  --red-strong:#A33F41;     /* 5.19 · 6.28 */

  /* ---- 压在**亮色品牌填充**上的文字色 ---------------------------------
     实测得出的关键规律：品牌色都够亮，**承深字全部达标、承白字全部不达标**。
       紫底 #A78BFA：深字 5.65 ✅ / 白字 2.72 ❌
       绿底 #6BCB77：深字 7.64 ✅ / 白字 2.01 ❌
       橙底 #FF8C42：深字 6.65 ✅ / 白字 2.31 ❌
       黄底 #FFD93D：深字 11.17 ✅（本来就这么用，是对的）
     **所以规则是：亮色填充配深字。** 需要白字时，把填充换成上面的 -strong。
     压暗品牌色去迁就白字会让产品变沉，跟「童趣高级」的调性打架——不这么做。 */
  --on-brand:#2A2419;

  /* ---- 文字层级 -------------------------------------------------------
     三级都 ≥4.5:1。代价是层级被压缩了（soft 6.97 → fade 4.85 差距变小）——
     这是无障碍必然的取舍：**层级要更多靠字号和字重来拉开，不能只靠颜色**。 */
  --text:#2A2419;          /* 14.16 · 正文标题 */
  --text-soft:#5C5343;     /*  6.97 · 次要正文 */
  --text-fade:#6B6455;     /*  4.85 · 说明、标签、时间戳
                                 ⚠️ v1 曾是 #A39B85（2.29–2.77），全站 135 处
                                 不达标。改这一个值即全部修复。 */

  /* 纯装饰用的浅色——**只能用于分隔线、禁用态图形、非信息性描边**，
     绝不可用于任何需要读的文字（这正是 v1 的错误）。 */
  --deco-fade:#A39B85;
  --border-soft:#EDE3CD;

  /* ---- 间距尺（4px 基数）----------------------------------------------
     审计发现 398 处硬编码 padding/margin/gap。一律换成这几档，
     不要再写 13px、17px 这种"看着差不多"的值。 */
  --sp-1:4px;  --sp-2:8px;  --sp-3:12px; --sp-4:16px;
  --sp-5:24px; --sp-6:32px; --sp-7:48px; --sp-8:64px;

  /* ---- 圆角尺（205 处硬编码的去处）------------------------------------ */
  --r-sm:6px;    /* 小标签、输入框 */
  --r-md:10px;   /* 按钮、气泡 */
  --r-lg:14px;   /* 卡片 */
  --r-xl:20px;   /* 大容器、手机框 */
  --r-full:999px;/* 胶囊、头像 */

  /* ---- 字号尺（389 处硬编码的去处）------------------------------------
     配套行高：小字行高要更松，长文本才不挤。 */
  --fs-xs:11px;  --lh-xs:1.6;
  --fs-sm:12px;  --lh-sm:1.65;
  --fs-md:14px;  --lh-md:1.7;   /* 正文基准 */
  --fs-lg:16px;  --lh-lg:1.7;
  --fs-xl:18px;  --lh-xl:1.5;
  --fs-2xl:22px; --lh-2xl:1.4;
  --fs-3xl:28px; --lh-3xl:1.3;
  --fs-4xl:36px; --lh-4xl:1.25;

  /* ---- 触控目标最小尺寸（WCAG 2.5.5）----------------------------------
     审计实测：儿童端顶栏三项只有 37px、音量键 26×26；
     家长端返回键 38×38、麦克风 40×40。
     **儿童端用 --tap-kid**：孩子手指更大、精细动作更差，44 是底线不是目标。 */
  --tap:44px;
  --tap-kid:48px;

  /* ---- 焦点环（WCAG 2.4.7）--------------------------------------------
     审计实测：全站 :focus 规则合计 4 条，admin 一条都没有。
     统一用 :focus-visible，只在键盘操作时出现，不打扰鼠标用户。 */
  --focus-ring:0 0 0 3px rgba(167,139,250,.55);
  --focus-offset:2px;

  /* ---- 字体栈 ---------------------------------------------------------- */
  --font:-apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB",sans-serif;
  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,monospace;

  /* ---- 层级阴影 -------------------------------------------------------- */
  --el-1:0 1px 3px rgba(42,36,25,.08);
  --el-2:0 4px 12px rgba(42,36,25,.10);
  --el-3:0 8px 28px rgba(42,36,25,.14);

  /* ---- 动效 ------------------------------------------------------------ */
  --dur-fast:.15s;
  --dur:.25s;
  --dur-slow:.4s;
  --ease:cubic-bezier(.2,.8,.2,1);

  /* ---- 断点（CSS 变量不能用在 @media 里，这里只作口径统一的备忘）------
     审计发现三个页面用了 501 / 520 / 1024 / 1600 四个互不相干的断点。
     **今后统一为三档**：
       手机   < 600px      单列，底部导航
       平板   600–1023px   加宽，仍单列
       桌面   ≥ 1024px     多列 / 侧边导航
     大屏继续用下方的连续 --screen-boost，不再加新断点。 */
}

/* ============================================================================
   焦点环 · 全站基线
   任何页面引了 tokens.css 就自动获得可见焦点。想覆盖就在自己页面里重写。
   ============================================================================ */
:where(a, button, input, textarea, select, [tabindex]):focus-visible{
  outline:none;
  box-shadow:var(--focus-ring);
  border-radius:var(--r-sm);
}

/* ============================================================================
   尊重「减少动态效果」（WCAG 2.3.3）
   审计实测：0 个页面处理过这个。球球是个持续动的球，前庭敏感的人会不适。
   ============================================================================ */
@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
    scroll-behavior:auto !important;
  }
}

/* ============================================================================
   暗色模式（**需页面显式 opt-in**）
   ---------------------------------------------------------------------------
   在 <html> 或 <body> 上加 class="dark-ok" 才生效。
   为什么要 opt-in：8 个内部文档页已有暗色，而 child/parent/school 等产品页
   从来只有浅色、配色和插图都是照浅底设计的。如果这里无条件开暗色，
   产品页会在用户切系统主题时突然变样——那是没人验证过的外观。
   产品页要上暗色，应当单独走一次视觉走查，而不是靠这个文件顺带发生。
   ============================================================================ */
@media (prefers-color-scheme: dark){
  .dark-ok{
    --bg:#1A1712;
    --bg-deep:#241F18;
    --bg-card:#211D17;
    --text:#F0EADC;
    --text-soft:#B8AF9C;
    --text-fade:#9C9384;      /* 暗底上重算过：对 #1A1712 为 6.4:1 */
    --deco-fade:#7D7565;
    --border-soft:#332C22;
    /* 语义色在暗底上反过来要调亮才够对比 */
    --purple-strong:#C4AEFF;
    --green-strong:#8FDC99;
    --orange-strong:#FFA96B;
    --red-strong:#F08C8E;
    --on-brand:#1A1712;
    --focus-ring:0 0 0 3px rgba(196,174,255,.6);
  }
}

/* ============================================================================
   大屏适配（桌面 / 32 寸 4K 竖屏展示）
   ---------------------------------------------------------------------------
   ⚠️ 2026-09-05 修了一个长期 bug：原写法是
       calc(1.2 + (100vw - 900px) * 0.0009)
   这是「无量纲数字 + 长度」，**CSS 非法**，整个 --screen-boost 求值失败。
   连锁后果：所有 calc(Npx * var(--fs-scale)) 一并失效、回落成默认 16px——
   也就是说**大屏放大从未生效，而且连手机上的字号都是错的**
   （.welcome-text 本该 22px 却渲染成 16px）。.wrap 的 zoom 同一个病。
   正解是除以一个长度让它无量纲：(100vw - 900px) / 1000px * 0.9，
   换算后与原注释记录的意图完全一致（1080≈1.36 / 1440≈1.69 / 2160≈2.33）。
   受控实验确证：写法③ 算出 16px（非法），写法④ 算出 26.4px（有效）。

   用「连续 vw 自适应」而不是固定断点跳档——踩过的坑：4K 屏在系统/浏览器
   150%-200% 缩放下，CSS 视口只有 1080-1440px，固定的 1900px 断点一档都命中
   不到，现场看到的还是小小的手机版式。现在从 900px 起就随视口连续放大，
   缩放设成多少都对。
   两类页面两套策略：
   · app 型（parent/child 的 .phone）：内部是精确 absolute 布局 + 电话模式的
     fixed 全屏层，zoom 会让 fixed 坐标系错位 → 用「加宽容器 + 放大字号变量」。
     --screen-boost 与用户自选字号 --fs-user 相乘（见各页 body 的 --fs-scale）。
   · 文档型（index/about/how-it-works/school 的 .wrap）：纯流式、字号写死 px、
     零 fixed 子元素 → 直接 zoom，标题正文间距一起等比放大。
   ============================================================================ */
:root { --screen-boost: 1; }

/* ---------------------------------------------------------------------------
   iPad 竖屏档（768–899px）—— 2026-09-05 补
   ---------------------------------------------------------------------------
   实测发现的缺口：--screen-boost 从 900px 起才生效，而 **iPad 竖屏正好落在
   768（iPad/mini）和 834（Air）**，一档都命中不到：
     iPad 竖 768   boost=1  框宽 500  占屏 65%  字号 16px
     iPad Air 834  boost=1  框宽 500  占屏 60%  字号 16px
   也就是说 10 英寸平板上跑的是原样的手机版式，35–40% 屏幕空着，
   而平板通常拿得比手机远，16px 在这个距离上视觉更小。
   **iPad 恰恰是孩子最可能用的设备**，这一档不能空着。

   为什么不直接把 900 改成 768：900 那档的斜率（0.0009/px）是为大屏定的，
   套到 768 会让 iPad 直接跳到 1.2 倍且宽度到 90vw；分开定义能让 899→900
   平滑衔接（实测两侧都是 1.200，无跳档）。
   --------------------------------------------------------------------------- */
@media (min-width: 768px) and (max-width: 899px) {
  :root { --screen-boost: clamp(1.15, calc(1.15 + (100vw - 768px) / 1000px * 0.38), 1.2); }
  /* 88vw 上限 640px：再宽行字数会超出中文舒适区。
     实测 768 → 29 字/行、834 → 28 字/行，都在 20–42 的舒适区内。 */
  .phone { max-width: min(640px, 88vw) !important; }
  .wrap  { zoom: clamp(1.1, calc(1.1 + (100vw - 768px) / 1000px * 0.76), 1.2); }
}

@media (min-width: 900px) {
  /* 900px→1.2 倍，每多 1px 视口加 0.0009 倍，最高 2.4 倍
     （1080px≈1.36 / 1440px≈1.69 / 2160px≈2.33） */
  :root { --screen-boost: clamp(1.2, calc(1.2 + (100vw - 900px) / 1000px * 0.9), 2.4); }
  /* 宽度跟随视口：min() 保证既撑得开、又不会宽到一行字读不完 */
  .phone { max-width: min(1700px, 90vw) !important; }
  .wrap  { zoom: clamp(1.2, calc(1.2 + (100vw - 900px) / 1000px * 1.0), 2.6); }
}

/* 超高屏（4K 竖屏 3840px 高）：app 容器限高并垂直居中——拉满全高的话底部 tab
   栏会远在视线之外，得抬头低头找；居中成一块"大平板"更好看也更好用。
   电话模式的 call-overlay 是 body 下的 fixed 全屏层，不受这里影响。 */
@media (min-height: 1500px) {
  body { align-items: center; }
  .phone { max-height: min(1600px, 88vh); box-shadow: 0 0 80px rgba(42,36,25,.14); border-radius: 20px; }
}

/* 运营后台是 PC 控制面板，本来就全宽——只放大字号，不动布局 */
@media (min-width: 1600px) { body.admin-body { font-size: 17px; } }
@media (min-width: 2000px) { body.admin-body { font-size: 19px; } }
