/* ==========================================================================
   理嘉 · 原子工具层
   --------------------------------------------------------------------------
   对应：视觉规范 §5.4（焦点环两套值）· §8（无素材策略的 fade-up）
        信息架构 §6.4（键盘导航）· §6.5（动效边界）

   ★ 本文件刻意只有 4 类内容，**不扩张**。
     不允许出现间距工具类（mt-8 / space-y-4 一类）——区块节奏与段落节奏
     都在 layout / typography 里按设计规范写死，用工具类堆叠会让
     「同一区块在不同页面 padding 不同」这种事故无法用 code review 拦住。
   ========================================================================== */

@layer reset, tokens, base, layout, components, utilities;

@layer utilities {
  /* ══════════════════════════════════════════════════════════════════════
     1. 视觉隐藏｜给屏幕阅读器的文本（不影响布局，仍可被读屏访问）
     ══════════════════════════════════════════════════════════════════════ */
  .visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }

  /* ══════════════════════════════════════════════════════════════════════
     2. on-dark 作用域｜视觉规范 §5.4「焦点环：两套值，按底色切换（硬规则）」
     ----------------------------------------------------------------------
     用法：给深色区块加 .on-dark，区块内**所有**可聚焦元素自动切换到
     --lj-shadow-focus-on-dark。

       <section class="band-dark on-dark"> …
       <section class="band-cta  on-dark"> …
       <footer   class="site-footer on-dark"> …

     ★ 为什么必须这样做，而不是让组件自己判断：
       切换依据是「元素所在的最近祖先区块的底色」，不是元素自身的填充色。
       深色区里的浅色填充按钮（.btn--on-dark）**同样**用 on-dark 焦点环，
       因为它浮在深色底上。组件看不到自己的祖先，所以必须由作用域统一接管。
     ★ 浅色版外环 #141413 在 #141413 底上只有 1:1，视觉上等于没有焦点提示。
       这三个区块合计覆盖全站约 70% 的 focusable 元素，漏掉等于键盘不可用。
     ★ 选择器特异性 = (0,2,1)，高于 .btn:focus-visible 的 (0,2,0)，
       所以不需要 !important。**不要改成 !important**，那会挡住将来的正常覆写。
     ══════════════════════════════════════════════════════════════════════ */
  .on-dark :is(a, button, summary, select, textarea, input, [tabindex]):focus-visible {
    box-shadow: var(--lj-shadow-focus-on-dark);
  }

  /* 深色区里 input 类元素的占位与文字色（当前无表单，仅作将来兜底） */
  .on-dark :is(input, textarea, select) {
    color-scheme: dark;
  }

  /* ══════════════════════════════════════════════════════════════════════
     3. 滚动渐显（fade-up 8px / 800ms / 一次性）｜视觉规范 §5.5 + 信息架构 §6.5
     ----------------------------------------------------------------------
     允许范围：**只用于区块容器整体进入视口**，不用于区块内的单个卡片。
     禁止：卡片逐条错位淡入（stagger）、数字滚动计数、视差、缩放入场。

     ★ 关键实现约束（信息架构 §6.5 最后一条）：
       fade-up 必须「直接置为最终态」，**不能用 visibility: hidden 等 JS 触发**，
       否则禁用 JS 或 prefers-reduced-motion 时内容永久不可见。
       这里用两层保护：
         a. 隐藏态挂在 .js 上 —— JS 未执行时（禁用 / 加载失败）没有任何隐藏规则；
         b. main.js 若在建立 IntersectionObserver 时抛错，会主动移除 .js，
            内容立刻回到可见态。
     ══════════════════════════════════════════════════════════════════════ */
  .js [data-reveal] {
    opacity: 0;
    transform: translateY(var(--lj-reveal-shift));
    /* transition 必须写在**隐藏态**上。若只在 .is-visible 里写，
       属性变更与 transition 声明发生在同一次样式计算，浏览器不会补间。 */
    transition:
      opacity var(--lj-dur-enter) var(--lj-ease),
      transform var(--lj-dur-enter) var(--lj-ease);
  }

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

  /* reduced-motion 下不淡入，直接显示（transition-duration 已由 typography.css
     全局压到 0.01ms，这里再显式确保位移为零，避免出现 8px 的瞬时跳动） */
  @media (prefers-reduced-motion: reduce) {
    .js [data-reveal] {
      opacity: 1;
      transform: none;
      transition: none;
    }
  }

  /* ══════════════════════════════════════════════════════════════════════
     4. 文本对齐（只有两个值，且各有明确用途）
     ══════════════════════════════════════════════════════════════════════ */

  /* 类型 8（引述）与类型 10（页尾 CTA）的居中；其余区块一律左对齐 */
  .txt-center {
    text-align: center;
  }

  /* 移动端居中引述的保留钩子：仅当文案确认 ≤16 字/行且 ≤3 行时使用 */
  @media (max-width: 767px) {
    .txt-center-mobile {
      text-align: center;
    }
  }
}
