﻿/*
Theme Name: XeroFocus Theme
Description: Marketing pages (PHP templates) + React SPA shell for app pages.
Version: 0.1.0
Author: XeroFocus
Text Domain: xerofocus-theme
*/

/* ── Design Tokens — XeroFocus Brand Identity v3（2026-08-09）──────────────────
 *
 * ⚠️ 这一块是 `frontend/src/constants.ts` 里 `:root` 的**镜像**，两处必须一起改。
 *    它服务 PHP 模板（页头页脚、条款/隐私、分享播放页）；constants.ts 那份由
 *    React 注入，服务 app 页面。两份都在同一个文档里生效，值不一致的话
 *    「同一颗按钮在 WP 页面和 app 页面不是一个颜色」，而且没有任何报错。
 *
 * ⚠️ 这一块在 2026-08-09 之前落后了**好几版**：还写着 JetBrains Mono /
 *    Cormorant Garamond / Inter / #1E3247 / #16B8D8 —— 全部是 app 侧早已不存在
 *    的值。凡是**写死具体值**的镜像都会漂，所以改 constants.ts 时请回来看一眼。
 *
 * 值的来源是落地页设计交付件的调色板（见 constants.ts 顶部的说明）。
 */
:root {
  /* Foundation — 三档面色阶梯（2026-08-18 双外观交付件 Light-Dark-0818.zip）。
     外壳 #22384F **与落地页 --bg 完全同色**：登录前后视觉连续。
     ⛔ 08-17 那版「深壳 + 淡内页」的 --xf-face / --xf-panel-face / --xf-face-* 整组
        已删除（Workspace 三个局部作用域一并删了），别照旧版镜回来。 */
  --xf-shell:     #22384F;
  --xf-shell-ink: #FFFFFF;
  --xf-shell-accent: #7EEBFF;
  --xf-on-media: #7EEBFF;
  /* ⚠️ 这七行与 frontend/src/constants.ts 的深色 :root **必须逐值一致**：SPA 走那份、
     WP 主题走这份，少改一处线上就是半深半浅的接缝。
     2026-08-21 交接件 design_handoff_dark_surface_ladder：面色梯子按浅色档的档差比例
     重排，板子色翻正（原来比主区还暗），输入框与气泡各提一档。取值理由写在 constants.ts
     那一份上，别在这里再写一遍口径 —— 两份说明必然漂。 */
  --xf-bg:        #22384F;
  --xf-bg2:       #2C4A62;
  --xf-surface:   #345772;
  --xf-surface2:  #2C4A62;
  --xf-raise:     #3C6480;
  --xf-input:     #45708F;
  --xf-bubble:    #4B7897;
  --xf-card:      rgba(255,255,255,0.085);
  --xf-hero-dark: #0B1018;
  --xf-code-bg:   #1B2D40;

  /* 素材画框：⛔ 两套外观**都是深底**，下面 .xf-light 里也不翻（交付件硬规则）。 */
  /* 素材画框跟主题走（2026-08-24 交接包 3b）。正本与完整理由在
     frontend/src/constants.ts 的 :root —— 这里是镜像，改一处必须两处一起改。 */
  --xf-media:      var(--xf-surface);
  --xf-media-ink:  rgba(255,255,255,0.68);
  --xf-avatar:     #2C6E8E;
  --xf-avatar-ink: #FFFFFF;

  /* Accents — 落地页的 --cyan / --blue / --gold / --amber */
  --xf-accent:        #7EEBFF;
  --xf-accent-ink:    #04121C;
  --xf-accent-bright: #56D6FF;
  --xf-accent-soft:   #2B87FF;
  --xf-action:        #2B87FF;
  --xf-gold:          #FFC933;
  --xf-run:           #FFC933;
  --xf-warn:          #E89A34;
  --xf-online:        #42D9A0;
  --xf-danger:        #FF5C6B;
  /* 旧名，PHP 模板里还有引用；指向新的主青，别再新增用它的地方。 */
  --xf-blue:        var(--xf-accent);
  --xf-cyan-bright: var(--xf-accent-bright);
  --xf-blue2:       var(--xf-accent-soft);

  /* Ink — 纯白按透明度分档 */
  --xf-text:   #FFFFFF;
  --xf-text2:  rgba(255,255,255,0.86);
  --xf-muted:  rgba(255,255,255,0.78);
  --xf-dim:    rgba(255,255,255,0.68);
  --xf-faint:  rgba(255,255,255,0.52);

  /* Lines & glows —— 线带 accent 色相（交付件 --xf-line / -strong / -tint） */
  --xf-border:  rgba(126,235,255,0.22);
  --xf-border2: rgba(126,235,255,0.12);
  --xf-border3: rgba(126,235,255,0.34);
  --xf-tint:    rgba(126,235,255,0.13);
  --xf-bloom:   rgba(63,201,255,0.20);
  --xf-glow:    rgba(53,203,234,0.24);

  /* Typography — UI/正文 IBM Plex Sans（默认 Light 300），标题 Serif，等宽只给 HUD
     ⚠️ 2026-08-14 起 UI 声部并回落地页的 IBM Plex Sans（此前是 Noto Sans）。
     四处字体栈缺一处就静默分叉，理由与另外三处的位置见 frontend/src/constants.ts
     那段 Typography 注释。链尾没有 "Helvetica Neue" 是有意的，别加。 */
  --xf-font:      "IBM Plex Sans", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", system-ui, sans-serif;
  --xf-font-head: "IBM Plex Serif", "Noto Serif SC", "Songti SC", Georgia, serif;
  --xf-font-body: "IBM Plex Sans", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", system-ui, sans-serif;
  --xf-font-mono: "IBM Plex Mono", "Noto Sans SC", "SF Mono", ui-monospace, "PingFang SC", monospace;

  /* Geometry — 控件 2px 硬边，卡片 14px（与落地页的 .cta-primary / .cf-card 同源） */
  --xf-radius-ctl:  2px;
  --xf-radius-card: 14px;

  /* Motion */
  --xf-ease: cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* 浅色外观：与 constants.ts 的 :root.xf-light 同源、同判据 ——
   强调色必须整套压暗，因为主按钮是「background:accent; color:accent-ink」的通式。
   ⚠️ **缺省是 light**（2026-08-18 用户口径；交付件 README 写的是 Dark，用户明确要求
      保持 Light）。判据在 frontend/src/theme.tsx 与两处首帧脚本，三者必须逐字等价。
   ⚠️ 偏好有三档（light / dark / system），生效只有两档；system 由 JS 现算。 */
:root.xf-light {
  /* 2026-08-18 第二版交付件（Light-Dark-081802.zip 6.1/6.3）：三档面色整体压深、
     墨色加重、线改中性。⛔ 这一整块是 frontend/src/constants.ts 的镜像，改一处等于
     没改；改完必须 bump XF_THEME_VERSION，否则线上取的还是缓存里那份。 */
  --xf-shell:#ADC4D0; --xf-shell-ink:rgba(10,31,44,0.78); --xf-shell-accent:#0A6C8A;
  --xf-on-media:#7EEBFF;
  /* 第二档面是 #CFDCE3。2026-08-18 试过 #C2D3DC，用户看过实机后要求退回。 */
  --xf-bg:#ADC4D0; --xf-bg2:#CFDCE3; --xf-surface:#EBF0F5; --xf-surface2:#CFDCE3;
  --xf-raise:#FFFFFF; --xf-input:#FFFFFF; --xf-bubble:#D6E2EC;
  --xf-card:rgba(10,31,44,0.05); --xf-code-bg:#CFDCE3;
  --xf-text:#0A1F2C; --xf-text2:rgba(10,31,44,0.86);
  /* dim .66 保留：.63 在第二档面 #CFDCE3 上只有 4.33:1，本来就没过 AA；.66 是 4.71:1。 */
  --xf-muted:rgba(10,31,44,0.78); --xf-dim:rgba(10,31,44,0.66); --xf-faint:rgba(10,31,44,0.48);
  --xf-border:rgba(10,31,44,0.14); --xf-border2:rgba(10,31,44,0.08);
  --xf-border3:rgba(11,122,155,0.40); --xf-tint:rgba(11,122,155,0.11);
  --xf-accent:#0B7A9B; --xf-accent-ink:#F2F9FB; --xf-accent-bright:#0B7A9B; --xf-accent-soft:#1A5FD0;
  --xf-action:#1A5FD0; --xf-gold:#A5760A; --xf-run:#A5760A; --xf-warn:#A85F14;
  --xf-online:#0E8A62; --xf-danger:#C42D3B;
  /* ⛔ 画框两档不翻（与 :root 同值）：交付件硬规则「素材画框永远深底」。 */
  --xf-media:var(--xf-surface); --xf-media-ink:rgba(10,31,44,0.66);
  --xf-avatar:#0B7A9B; --xf-avatar-ink:#F2F9FB;
  --xf-bloom:rgba(11,122,155,0.10); --xf-glow:rgba(26,95,208,0.14);
}
/* ⛔ 落地页 / 营销页 / API 文档页恒深色，不跟这个开关走 —— 理由与长期修法见
   frontend/src/constants.ts 里同一条规则的注释（那份是这条的正本，两处必须同步）。
   一句话版：landingStyles.ts 里 --ink 映射到了 --xf-text，缺省翻成 light 之后
   会得到近黑字压深底（实测约 1.4:1）。 */
:root.xf-light .xf-landing { --xf-text: #FFFFFF; }

/* â”€â”€ Base Reset â”€â”€ */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  /* ⛔ **不能是 100%**（2026-08-18 大屏事故）：宽屏整体放大把 zoom 挂在 html 上，而
     html 的 min-height:100% 是拿没缩放的视口解的 —— 解出满屏的数再被自己的 zoom
     乘一遍，文档比视口高 40%，页面多出一条竖滚动条、底下露出一片 body 底色。
     --xf-100vh 由 constants.ts 的 :root 定义、由 setAppZoom 刷成精确 px；
     app.js 还没跑起来时走 100vh 兜底。 */
  min-height: var(--xf-100vh, 100vh);
  background: var(--xf-bg);
  color: var(--xf-text);
  font-family: var(--xf-font);
  /* UI 声部的默认字重 2026-08-18 从 300 提到 **400**（用户口径「字太瘦太淡」）。
     字重放在基座上，显式写了 500/600/700 的地方照旧盖过它。
     ⛔ 与 frontend/src/constants.ts 的 body 规则是**一份镜像**，改一处等于没改。
     （顺带：这行注释里的字族早就不是 Noto Sans 了，2026-08-14 起是 IBM Plex Sans。） */
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }
/* 表单控件不继承 body 的字族与字重，必须单列 —— 漏掉它们等于每个输入框退回系统字。 */
button, input, select, textarea { font-family: var(--xf-font); font-weight: 400; }
button { cursor: pointer; }
img { max-width: 100%; display: block; }

:focus-visible { outline: 2px solid var(--xf-accent); outline-offset: 2px; }
::selection { background: var(--xf-accent); color: var(--xf-bg); }

/* â”€â”€ Keyframe Animations â”€â”€ */
@keyframes xf-fadeUp {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes xf-fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes xf-breathe {
  0%, 100% { opacity: 0.6; transform: scale(1); }
  50%       { opacity: 1;   transform: scale(1.15); }
}
@keyframes xf-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--xf-accent) 40%, transparent); }
  50%       { box-shadow: 0 0 0 6px transparent; }
}
@keyframes xf-shimmer {
  0%   { background-position: -200% center; }
  100% { background-position:  200% center; }
}
@keyframes xf-glow-border {
  0%, 100% { border-color: color-mix(in srgb, var(--xf-accent) 20%, transparent); }
  50%       { border-color: color-mix(in srgb, var(--xf-accent) 50%, transparent); }
}
@keyframes xf-scan {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(400%); }
}

/* â”€â”€ Utility Classes â”€â”€ */
.xf-fade-up { animation: xf-fadeUp 0.6s ease-out both; }
.xf-fade-up-1 { animation: xf-fadeUp 0.6s ease-out 0.1s both; }
.xf-fade-up-2 { animation: xf-fadeUp 0.6s ease-out 0.2s both; }
.xf-fade-up-3 { animation: xf-fadeUp 0.6s ease-out 0.3s both; }
.xf-fade-up-4 { animation: xf-fadeUp 0.6s ease-out 0.4s both; }


/* ── Buttons —— 与落地页的 .cta-primary / .nav-cta 同一套几何 ──────────────
   判据（三条都来自落地页，别只挑好看的抄一条）：
     · **2px 硬边**，不是 5px 的圆角 —— HUD 味来自方，不来自圆；
     · **大写 + 宽字距**，hover 时字距再张开一档（0.14em → 0.16em），
       这个「张开」是落地页按钮唯一的形变语言，比亮度变化更认得出；
     · hover 上浮 1px + 边框转青。
   ⚠️ 字距张开会让按钮变宽 —— 落地页靠 padding 吸收。这里同理，别给按钮设死宽度。 */
.xf-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 9px 20px;
  font-family: var(--xf-font);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  border-radius: var(--xf-radius-ctl);
  border: 1px solid transparent;
  cursor: pointer;
  transition: all 0.35s var(--xf-ease);
}
.xf-btn:hover { letter-spacing: 0.16em; }
.xf-btn--ghost {
  background: transparent;
  border-color: var(--xf-border);
  color: var(--xf-muted);
}
.xf-btn--ghost:hover { border-color: var(--xf-accent); color: var(--xf-accent); }
.xf-btn--primary {
  background: var(--xf-accent);
  color: var(--xf-bg);
  border-color: var(--xf-accent);
  box-shadow: 0 0 18px var(--xf-glow);
}
.xf-btn--primary:hover {
  box-shadow: 0 0 28px var(--xf-glow);
  transform: translateY(-1px);
}

/* â”€â”€ Footer â”€â”€ */
.xf-footer {
  border-top: 1px solid var(--xf-border2);
  padding: 24px 60px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 11px;
  color: var(--xf-dim);
  background: var(--xf-bg);
}
.xf-footer__links { display: flex; gap: 20px; }
.xf-footer__links a { color: var(--xf-dim); transition: color 0.2s; }
.xf-footer__links a:hover { color: var(--xf-accent); }

/* ── Cards —— 落地页的卡片是 14px 大圆角 + 玻璃填充，不是 8px 的实底方块 ── */
.xf-card {
  background: var(--xf-card);
  border: 1px solid var(--xf-border);
  border-radius: var(--xf-radius-card);
  padding: 24px 22px;
  transition: box-shadow 0.25s var(--xf-ease), transform 0.25s var(--xf-ease), border-color 0.25s var(--xf-ease);
}
.xf-card:hover {
  box-shadow: 0 0 24px var(--xf-bloom);
  border-color: var(--xf-border3);
  transform: translateY(-2px);
}

/* â”€â”€ Tag / Filter Pills â”€â”€ */
.xf-tag {
  display: inline-flex;
  align-items: center;
  padding: 5px 12px;
  border-radius: 999px;
  font-size: 10px;
  font-family: var(--xf-font);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  border: 1px solid var(--xf-border);
  color: var(--xf-dim);
  background: transparent;
  cursor: pointer;
  transition: all 0.25s var(--xf-ease);
}
.xf-tag:hover, .xf-tag.active {
  border-color: var(--xf-accent);
  color: var(--xf-accent);
  background: color-mix(in srgb, var(--xf-accent) 8%, transparent);
}

/* â”€â”€ React SPA Shell â”€â”€ */
/* ⛔ **这两条的 min-height 不能是裸 100vh**（2026-08-18 外接大屏事故的真凶）：
   宽屏整体放大把 zoom 挂在 html 上，而 **zoom 不缩放 vh** —— 实测 zoom 1.2 时一个
   min-height:100vh 的盒子渲染出 1296px（视口才 1080），zoom 1.4 就是 1.4 倍。
   于是 #xf-app 比视口高出 40%：React 那层外壳自己是准的（吃 --xf-100vh），多出来的
   是它下面一片 body 底色，页面还凭空多一条竖滚动条。用户报的就是这个。
   ⚠️ 这两条**只存在于主题里**，本地 standalone（Vite 的 index.html）没有 #xf-app 这
      一层 —— 所以在本地怎么量都是好的，只有 WP 站上才复现。改这类"只在一边存在"的
      规则时，别拿 standalone 的验证结果当数。 */
#xf-app {
  min-height: var(--xf-100vh, 100vh);
  background: var(--xf-bg);
}
.xf-app-loading {
  min-height: var(--xf-100vh, 100vh);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 12px;
  color: var(--xf-dim);
  font-size: 12px;
  font-family: var(--xf-font);
}
.xf-app-loading__dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--xf-accent);
  animation: xf-breathe 1.4s ease-in-out infinite;
}

