/* ============================================================================
 * tokens.css —— 设计令牌。整站唯一的「值」来源。
 *
 * 这里只有自定义属性，没有一条元素样式。tests/test_css_contract.py 会检查：
 * 夹带一条 `.navbar {}` 进来，它就从颜色表退化成「又一个样式文件」。
 *
 * ## 值从哪来
 *
 * 全部取自 style.css 中**当前真实生效**的声明，不是重新配色。
 * 品牌橙 #ea580c 在 style.css 里出现 81 次、深棕文字 #431407 出现 44 次——
 * 这就是用户此刻看到的界面。照抄它，才能在后续从 style.css 摘掉 1805 个
 * `!important` 时页面不变样。若另配一套颜色，那不叫统一 UI，叫换皮。
 *
 * ## 为什么 style.css 里的三个 :root 不算令牌
 *
 * style.css 有三个 :root 块（第 2、3003、3422 行）各自重定义
 * `--primary-color`：蓝 #2563eb → 琥珀 hsl(38,92%,50%) → 橙 #ea580c，
 * 后两个还都带 `!important`。同名变量三种值，读代码的人无法判断哪个生效，
 * 只能开浏览器看。这份文件取最终胜出的那一版，并且是唯一一版。
 * ========================================================================== */

:root {
    /* ── 品牌色 ────────────────────────────────────────────────────────────
     * brand 是主色（按钮、链接、选中态），brand-strong 用于 hover/pressed。
     * strong 取 #c2410c：它是 #ea580c 在 style.css 各处 hover 里的既有搭配。
     */
    --color-brand: #ea580c;
    --color-brand-strong: #c2410c;
    --color-brand-soft: #f97316;
    --color-brand-tint: rgba(251, 146, 60, 0.1);

    /* accent 是琥珀，用在强调徽标与渐变收尾，不用于可点击元素——
     * 它和 warning 同色，做按钮会和「警告」撞语义。 */
    --color-accent: #f59e0b;

    /* 品牌渐变与配套阴影。按钮、聊天气泡、FAB 都用它，是全站最显眼的一处
     * 品牌表达。放进令牌层是因为它含品牌色字面值——散到组件层就又回到
     * 「改主题要全局搜替」的老路。
     * 阴影带橙色调而非中性灰：灰阴影落在暖底上会发青。 */
    --gradient-brand: linear-gradient(135deg, #f97316, #ea580c);
    --shadow-brand: 0 4px 14px rgba(234, 88, 12, 0.3);
    --shadow-brand-strong: 0 6px 20px rgba(234, 88, 12, 0.4);

    /* 品牌底上的前景色。纯白而非 --color-text-inverse(#fffbeb)：
     * 橙色渐变上的奶油白会显脏，这里就是要纯白。 */
    --color-on-brand: #ffffff;

    /* ── 语义色 ────────────────────────────────────────────────────────────
     * success 沿用 style.css 的海青 #0d9488（--success-color / --sea-teal-text），
     * 不用常规绿：暖橙底色上的纯绿显脏，海青是原设计的选择。
     */
    --color-success: #0d9488;
    --color-warning: #f59e0b;
    --color-danger: #ef4444;
    --color-info: #0284c7;

    --color-success-tint: rgba(20, 184, 166, 0.1);
    --color-danger-tint: rgba(239, 68, 68, 0.1);

    /* 标签底色。比 --color-brand-tint（0.1）浓一档：标签是并排出现的小色块，
     * 0.1 在白卡片上几乎看不出边界，一排标签会糊成一条。 */
    --color-brand-wash: rgba(251, 146, 60, 0.14);

    /* ── 文字 ──────────────────────────────────────────────────────────────
     * 深棕而非黑。#431407 是暖底上的正文色，纯黑在 #fffbeb 上对比过硬。
     * muted 的 #7c2d12 对 #fffbeb 的对比度约 7:1，过 WCAG AA 正文要求，
     * 所以次要信息也不必放大字号来补可读性。
     */
    --color-text: #431407;
    --color-text-muted: #7c2d12;
    --color-text-inverse: #fffbeb;

    /* ── 面与线 ────────────────────────────────────────────────────────────
     * surface 是卡片底。半透明是刻意的：整站是玻璃拟态，卡片要透出 body
     * 的三层径向渐变。想要不透明底的地方用 surface-solid。
     */
    --color-surface: rgba(255, 255, 255, 0.65);
    --color-surface-solid: #ffffff;
    --color-bg: #fffbeb;

    --color-border: rgba(251, 146, 60, 0.2);
    --color-border-strong: rgba(234, 88, 12, 0.35);

    /* 玻璃拟态三件套，原样保留——style.css 里有 15 处引用 --glass-*，
     * 它们能直接落到这份定义上，不必改那 15 处。 */
    --glass-bg: rgba(255, 255, 255, 0.45);
    --glass-border: rgba(255, 255, 255, 0.5);
    --glass-shadow: 0 12px 40px rgba(234, 88, 12, 0.06);
    --glass-blur: 25px;

    /* ── 间距 ──────────────────────────────────────────────────────────────
     * 4px 基数。够密以贴合现有版式，又不至于让人再造 5px、7px 这种中间值。
     */
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 24px;
    --space-6: 32px;
    --space-7: 48px;

    /* ── 圆角 ──────────────────────────────────────────────────────────────
     * 取 style.css 里出现最多的三档：8px(23 次)、12px(28 次)、20px(18 次)。
     * 现存的 6/10/18/19/25px 是历次微调的产物，不进令牌——它们和相邻的
     * 标准档肉眼无法区分，保留只会让下一个人继续猜。
     */
    --radius-sm: 8px;
    --radius-md: 12px;
    --radius-lg: 20px;
    --radius-full: 999px;

    /* ── 阴影 ──────────────────────────────────────────────────────────────
     * 带橙色调而非灰调：中性灰阴影落在暖底上会发青。
     */
    --shadow-sm: 0 1px 3px rgba(124, 45, 18, 0.08);
    --shadow-md: 0 4px 12px rgba(124, 45, 18, 0.1);
    --shadow-lg: 0 12px 40px rgba(234, 88, 12, 0.14);

    /* 悬停抬起时的投影。负扩散(-12px)让阴影比元素本身窄一圈，
     * 看起来才像是元素浮在上方而不是套了个光晕。
     * 取自 style.css 第 3285 行卡片 hover 真实生效的值。单独成档而不是让各组件
     * 自己写，是因为「抬起」这个动作在卡片、按钮、门户卡上都有，
     * 三处各写一个数就会出现三种抬起高度。 */
    --shadow-xl: 0 24px 48px -12px rgba(234, 88, 12, 0.18);

    /* 输入框聚焦环。迁移前站内有三种：rgba(245,158,11,0.15)、
     * rgba(234,88,12,0.25)、rgba(59,130,246,0.25)——同一个动作，三种反馈色。
     * 统一成品牌橙 0.22：0.15 在浅底上几乎看不见，0.25 又和错误态的红环
     * 抢注意力。3px 厚度是为了在 border-color 变化之外再给一层可辨识信号，
     * 色觉障碍用户只靠边框变色分辨不出聚焦。 */
    --focus-ring: 0 0 0 3px rgba(234, 88, 12, 0.22);

    /* 禁用态底色。用棕色调的透明黑而非灰：落在暖底卡片上，中性灰会发青。 */
    --color-surface-disabled: rgba(124, 45, 18, 0.07);

    /* 弹层背后的压暗层。同样取品牌最深的棕（#431407）而不是纯黑：暖底页面
     * 上压一层中性黑会整体发青，像换了个主题。0.45 是「背后的卡片还看得出
     * 轮廓、但已经不抢注意力」的档位。 */
    --color-scrim: rgba(67, 20, 7, 0.45);

    /* ── 字体 ──────────────────────────────────────────────────────────────
     * 系统字体栈。style.css 第 3021 行写的是 'Outfit' 打头，但没有任何模板
     * 加载过这个字体文件，所以浏览器一路回落到 -apple-system——今天屏幕上
     * 就是系统字体。令牌照抄真实渲染结果。要用 Outfit 得先加字体链接，
     * 那是一次会改变全站观感的独立决定，不藏在这次分层里。
     */
    --font-family-base: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
        'Helvetica Neue', 'PingFang SC', 'Microsoft YaHei', Arial, sans-serif;

    /* 五档字号，取自 style.css 的实际聚集处（0.72 / 0.85 / 0.9~1 / 1.1 / 1.5rem）。
     * 原文件里 0.78、0.8、0.82、0.88、0.92、0.95rem 六种值混用，
     * 差异小于 1px，不构成层级，只构成不一致——这正是诉求 #5 的来源之一。 */
    --font-size-xs: 0.72rem;
    --font-size-sm: 0.85rem;
    --font-size-md: 1rem;
    --font-size-lg: 1.15rem;
    --font-size-xl: 1.5rem;

    --font-weight-normal: 400;
    --font-weight-medium: 500;
    --font-weight-bold: 700;
    --line-height-tight: 1.3;
    --line-height-base: 1.6;

    /* ── 层级 ──────────────────────────────────────────────────────────────
     * 数值取自 style.css 中各层已有的量级，让新旧代码能共存于同一套秩序。
     *
     * 现状是一场军备竞赛：.navbar 1000、.modal 2000、.toast 3000、
     * .notification-toast 9999、.mobile-bottom-nav 10000、
     * .post-detail-modal-content .close 10001、.toast-container 99999、
     * .image-lightbox 200000。每一个都比前一个大，因为「盖不住就加一位」。
     * 令牌把台阶固定下来：不够高时改令牌，而不是在局部再加一位。
     */
    --z-base: 1;
    --z-dropdown: 100;
    --z-sticky: 1000;
    /* 底栏比顶栏高一档、比弹窗低一档。旧值是 10000，压在弹窗（2000）和
     * 通知（3000）之上——手机上点开帖子详情，底栏浮在遮罩上面。 */
    --z-bottom-nav: 1010;
    /* 底部弹层（手机上的筛选面板）必须盖住底栏：弹层底边和底栏是同一块地方，
     * 排在底栏下面就意味着「重置」那一行被 56px 的底栏压住点不到。
     * 又要留在弹窗（2000）之下——帖子详情弹窗弹出时，筛选面板不该浮在它上面。 */
    --z-sheet-backdrop: 1490;
    --z-sheet: 1500;
    --z-modal-backdrop: 2000;
    --z-modal: 2010;
    --z-toast: 3000;
    --z-lightbox: 4000;

    /* ── 断点 ──────────────────────────────────────────────────────────────
     * 自定义属性在 @media 里用不了（CSS 规范限制），所以这两个值在 CSS 里
     * 只能靠人工对齐。定义它们是为了 JS：设备判断用
     * getComputedStyle(document.documentElement).getPropertyValue('--bp-tablet')
     * 读同一个数，样式和脚本就不会各持一个阈值。
     *
     * 诉求 #4「有些手机看不到底部导航栏」的根因正是阈值不一致：
     * style.css 第 5635 行按 `max-width: 768px` 显示底栏，而 JS 里另有判断。
     * 屏宽 800px 的安卓机两边都不认，底栏就此消失。
     */
    --bp-compact: 480px;
    --bp-tablet: 768px;
    --bp-desktop: 1024px;

    /* ── 安全区 ────────────────────────────────────────────────────────────
     * `env(safe-area-inset-*)` 只在页面声明了 `viewport-fit=cover` 时才有非零值，
     * 而四个模板的 viewport 里目前都没有这一项——所以这四个令牌今天全是 0。
     *
     * 那为什么现在就定义？因为 style.css 已经有地方直接写了
     * `env(safe-area-inset-bottom, 0px)`（第 5734、5735 行的底栏高度与内边距），
     * 后面还会有吐司、悬浮按钮、页面底部内边距要避开同一块区域。散着写的话，
     * 等 viewport 补上 `viewport-fit=cover` 的那一刻，得靠 grep 找齐所有
     * `env(...)` 才知道哪些地方会跟着变。收进令牌，那一刻只有一处需要确认。
     */
    --safe-top: env(safe-area-inset-top, 0px);
    --safe-bottom: env(safe-area-inset-bottom, 0px);
    --safe-left: env(safe-area-inset-left, 0px);
    --safe-right: env(safe-area-inset-right, 0px);

    /* 底部导航栏高度（不含安全区）。style.css 第 5734 行把 56px 写死在
     * `.mobile-bottom-nav` 里，而任何「浮在底部但不该被底栏压住」的元素都得
     * 知道这个数——互动通知弹窗此刻就压在底栏下面（见 components.css 的
     * .notification-toast 处说明）。有了令牌，避让写成
     * `calc(var(--bottom-nav-height) + var(--safe-bottom) + ...)`，
     * 改高度不必再挨个找。 */
    --bottom-nav-height: 56px;

    /* 顶栏高度与离顶距离。移动端不用顶栏，这两个值现在只服务于
     * compact 布局下需要避让顶部的少数元素（公告浮层）。 */
    --navbar-height: 64px;
    --navbar-top: 12px;

    /* 内容区最大宽度。compact 布局下用它。 */
    --content-max-width: 1200px;

    /* ── 桌面外壳 ──────────────────────────────────────────────────────────
     * 电脑端不再复用手机的「顶栏 + 底栏」形态，导航改成常驻左侧栏：鼠标
     * 不需要每次都把指针甩到屏幕上边缘，三个去处永远在同一个位置。
     *
     * --sidebar-width 同时是 .navbar 的宽度和 body 的 padding-left，
     * 两者必须相等，否则内容会被侧栏压住——所以只留一个数。
     */
    --sidebar-width: 232px;

    /* 右侧信息栏（阳光指数、灵感）宽度。这些卡片原来横躺在列表上方，
     * 桌面上等于每次进广场都要先滚过一屏才看见作品。 */
    --rail-width: 300px;

    /* 桌面内容区最大宽度。1200px 是胶囊顶栏时代的值——顶栏与内容左右边缘
     * 要对齐，所以两者同宽。侧栏布局下内容从侧栏右侧起算，还按 1200 收，
     * 1920 屏上会剩 400+px 空白，而用户的原话是「不方便操作」。 */
    --content-max-width-wide: 1560px;

    /* 右侧信息栏的启用阈值。低于它内容区放不下「主栏 + 300px 右栏」，
     * 信息卡回到列表上方。@media 里用不了 var()，值需人工对齐。 */
    --bp-wide: 1400px;

    --transition-fast: 0.15s ease;
    --transition-base: 0.3s ease;

    /* 入场动画的时长与缓动。与 --transition-* 分开是因为 `animation` 简写
     * 需要拆开的两个值，而 `transition: color var(--transition-fast)` 需要合在
     * 一起的一个值——同一个 0.3s 用两种形态出现，不是重复定义。
     * ease-out 曲线取自 style.css 第 3931 行吐司动画的既有值。 */
    --duration-base: 0.3s;
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}
