/* tokens.css — Develop design tokens (v3).
 *
 * v3 is a NEW, additive version. /v2 is FROZEN (bug-fix only) and untouched;
 * channels migrate to /v3 opt-in by re-pointing their <link>s. Three explicit
 * tiers (the lint-enforced rule):
 *   COMPONENT (--c-*)  -> reference only SEMANTIC
 *   SEMANTIC  (role)   -> reference only PRIMITIVE
 *   PRIMITIVE (--p-*)  -> raw values (INTERNAL; consumers MUST NOT reference)
 *
 * v3 baseline = the 漫剧工坊 "paper" palette AS THE DEFAULT (no data-skin
 * attribute needed): warm parchment canvas, amber/bronze as the brand action
 * accent (--primary aliases it — the solid CTA is amber), teal/blue secondary
 * hues, amber/teal/blue/fig/brick chart ramp. Compact 12px body. Dark mode for
 * BOTH live selector conventions (.dark AND [data-theme="dark"]); consumers
 * must not add a third. High-contrast: [data-contrast="high"]. Skins stay the
 * opt-in overrides: [data-skin="default|warm|forest|violet"] blocks below +
 * the apex `skin` cookie + <dev-skin-picker>. In v3 `default` (the old
 * neutral+blue) is itself an OPT-IN skin block; `paper` matches no block on
 * purpose — it IS :root. */

:root {
  /* :root paints the LIGHT palette, so pin the UA's native controls (scrollbars,
     select popups, date pickers, autofill) to light here; `.dark`/[data-theme=
     "dark"] flip it to dark below. `light dark` was wrong: it let the UA render
     native controls dark per the OS on a forced-LIGHT page (the "dark date input
     on a light page" tell). Dark mode is always driven by the explicit class. */
  color-scheme: light;

  /* ============================================================
     TIER 1 — PRIMITIVE  (--p-*, internal; never referenced by consumers)
     ============================================================ */

  /* Neutral ramp — fixed role per step (Radix-style), authored per theme
     (light here, dark below), NOT lightness-flipped. v3 baseline = the paper
     warm ramp (hue ~70–95). gray-2 sits ABOVE gray-1 on purpose: side panels
     (#faf9f6) are lighter than the canvas (#f6f4ef) in this palette.
       1 app bg · 2 subtle bg · 3 component bg · 4 hover · 5 active/line ·
       6 border · 7 border-strong · 8 disabled-fg · 9 muted text/placeholder ·
       10 secondary text · 11 strong text · 12 max-contrast text */
  --p-gray-0: oklch(0.968 0.004 95);   /* ≈ #fdfcfa card */
  --p-gray-1: oklch(0.948 0.008 95);   /* ≈ #f6f4ef canvas */
  --p-gray-2: oklch(0.96 0.005 95);   /* ≈ #faf9f6 panel */
  /* 凹陷面(表头 / 列表头 / 卡片头 / alert / .code / .tag)。2026-08-09 把它与画布的
     落差从 0.02 拉到 0.048 —— operator 反馈「表头背景还是浅」。上一轮把整条梯子等量
     下移,亮度是沉了,但**这一档与画布的间距一点没变**,所以表头相对背景还是一样淡:
     看得见的是落差,不是绝对亮度。上限由表头文字定死:它用 --muted-foreground
     (0.495),底色压到 0.898 时是 4.52,再深就跌破 AA 4.5;取 0.900 留余量。 */
  --p-gray-3: oklch(0.900 0.009 95);   /* chip / sunken */
  --p-gray-4: oklch(0.885 0.010 95);   /* ≈ #edeae2 hover */
  --p-gray-5: oklch(0.858 0.012 92);   /* ≈ #e3dfd6 border */
  --p-gray-6: oklch(0.828 0.013 92);   /* ≈ #d5d0c4 strong border */
  --p-gray-7: oklch(0.795 0.014 90);    /* ≈ #c8c2b4 */
  --p-gray-8: oklch(0.70 0.015 88);    /* ≈ #a8a190 placeholder */
  --p-gray-9: oklch(0.495 0.018 85);   /* warm muted — 达标线要按**卡片**底色算,不只是画布:实测 .dim 小字在任务卡上 4.49,差 0.01 */
  --p-gray-10: oklch(0.50 0.015 80);   /* ≈ #6d675c */
  --p-gray-11: oklch(0.42 0.012 75);   /* ≈ #4a463c */
  --p-gray-12: oklch(0.25 0.010 70);   /* ≈ #2b2822 ink */

  /* Status hues — oklch (perceptually even color-mix tints).
     --p-red carries the SAME lightness contract as --p-accent: .btn-danger-solid
     / .tag-solid-danger put near-white --danger-foreground on it as 11–12px
     TEXT, so it must clear AA 4.5:1, not the 3:1 UI floor. 0.58 L only reached
     4.34:1; 0.55 L reaches 4.92:1. Hue/chroma untouched (27 / 0.21, still inside
     sRGB — max chroma at 0.55 L is 0.225), so the red stays the same red, just
     one step deeper — and it now separates from the WARM skin's clay accent
     (oklch(0.58 0.145 40)) by LIGHTNESS too, not only by chroma. */
  --p-green: oklch(0.63 0.17 149);
  --p-amber: oklch(0.75 0.15 75);
  --p-red:   oklch(0.55 0.21 27);
  --p-blue:  oklch(0.55 0.2 256);

  /* Action accent — amber/bronze (≈ #a06816 family), the v3 brand voice from
     the 漫剧工坊 design. Drives the solid primary button + every selected/
     active wash. Kept SEPARATE from the decorative --p-brand-* gradient.
     LIGHTNESS IS A CONTRAST CONTRACT, not taste: the solid CTA carries an
     11–12px white label (--ui-accent-fg), so #fff on this color must clear
     WCAG AA 4.5:1 for normal text — NOT the 3:1 UI floor an earlier pass aimed
     at. 0.60 L only reached 4.07:1; 0.565 gives 4.68:1. Hue/chroma unchanged —
     re-pointing a skin re-points this one knob and inherits the same rule
     (tests/v3-contrast.test.mjs enforces it for every skin × theme block). */
  --p-accent:      oklch(0.565 0.115 70);
  --p-accent-deep: oklch(0.52 0.11 68);

  /* Brand gradient stops — amber→teal→blue, the design's secondary hues. */
  --p-brand-1: oklch(0.62 0.12 70);
  --p-brand-2: oklch(0.58 0.08 185);
  --p-brand-3: oklch(0.60 0.09 255);

  /* ============================================================
     TIER 2 — SEMANTIC  (role tokens; the consumer/contract surface)
     ============================================================ */

  /* Surface ladder (bg -> raised card -> overlay/popover -> sunken well). */
  --background:       var(--p-gray-1);
  --surface:          var(--p-gray-1);
  --surface-raised:   var(--p-gray-0);
  --surface-overlay:  var(--p-gray-0);
  --surface-sunken:   var(--p-gray-3);
  /* Surface bridge — v3's paper surfaces are authored INTO the warm ramp
     itself (an amber-tinted card would read orange), so card/accent/sidebar
     stay ramp-neutral here. The cool "default" skin block re-introduces the
     2–8% accent mix (its original v2 recipe). */
  --card:             var(--p-gray-0);
  --popover:          var(--p-gray-0);
  --secondary:        var(--p-gray-3);
  --muted:            var(--p-gray-4);
  --accent:           var(--p-gray-3);

  /* Text. */
  --foreground:           var(--p-gray-12);
  --card-foreground:      var(--p-gray-12);
  --popover-foreground:   var(--p-gray-12);
  --secondary-foreground: var(--p-gray-11);
  --accent-foreground:    var(--p-gray-12);
  --muted-foreground:     var(--p-gray-9);
  --foreground-subtle:    var(--p-gray-10);
  /* Placeholder copy is still secondary, but must clear normal-text contrast
     on both raised and sunken fields; gray-8 was only a disabled-ink step. */
  --placeholder:          var(--p-gray-9);

  /* Lines. */
  --border:        var(--p-gray-5);
  --border-strong: var(--p-gray-7);
  --border-hover:  var(--p-gray-7);
  --input:         var(--border);
  --ring:          var(--p-gray-10);
  --border-focus:  var(--ring);

  /* Primary = the brand ACTION color (v3: solid amber; a skin re-points it via
     --p-accent). v2's neutral near-black primary is retired — the CTA, checked
     controls, current-page pill and solid tag all speak the accent voice. */
  --primary:            var(--p-accent);
  --primary-foreground: #fff;

  /* Intent recipes — five names each, tints derived via color-mix so a filled
     chip always has a guaranteed-contrast on-color.
     `--*-text` is the INK step, the exact counterpart of --ui-accent-text: the
     bare `--success` / `--danger` are FILL tones, tuned so a near-white
     `-foreground` can sit ON them, which is the same constraint upside-down as
     "readable when painted on a light canvas". Using the fill tone as ink is
     what shipped .btn-danger at 3.74:1 and .metric-delta.is-up at 3.14:1. The
     mix ratio is not taste — it is whatever the hue's own lightness demands;
     65% is the step that carries BOTH families (green is the light one: at 78%,
     the accent's ratio, green ink on its own 12% tint is still 3.77:1).
     2026-07-28 起 warning/info 也各有墨水档(--warning-text / --info-text):
     琥珀更亮,所以混得更狠(55%),蓝按 65%,两者都在十个上下文里过了 AA。 */
  --success: var(--p-green);
  /* Dark ink, like --warning-foreground and like this very token in the .dark
     block below — green is a LIGHT hue: near-white on it was 2.96:1 (the worst
     on-color in the system), dark ink is 4.91:1. Deepening --p-green instead is
     not available: oklch(L 0.17 149) leaves sRGB below 0.63 L, so every step
     down would be silently channel-clipped, i.e. a chroma change in disguise. */
  --success-foreground: var(--p-gray-12);
  --success-bg: color-mix(in oklab, var(--p-green) 12%, var(--surface));
  --success-border: color-mix(in oklab, var(--p-green) 35%, transparent);
  --success-text: color-mix(in oklab, var(--p-green) 60%, var(--foreground));

  --warning: var(--p-amber);
  --warning-foreground: var(--p-gray-12);
  --warning-bg: color-mix(in oklab, var(--p-amber) 14%, var(--surface));
  --warning-border: color-mix(in oklab, var(--p-amber) 38%, transparent);
  /* 墨水档:压在同族底纹上的文字色。success / danger 一直有,warning / info 却缺席,
     于是组件只能拿填充调(--warning / --info)当文字色压在自己 12-14% 的底纹上 ——
     那是这套体系里最常见的一处低对比。琥珀比红绿更亮,所以混得更狠一点。 */
  --warning-text: color-mix(in oklab, var(--p-amber) 46%, var(--foreground));

  --danger: var(--p-red);
  /* 实底徽标/按钮上的**近白墨**。故意写成字面值,不再引用 `--p-gray-1`(画布)——
     它引用画布时,任何一次「把页面底色调深一点」都会顺带把这层白墨调暗,而白墨
     的亮度是 AA 契约的一半:2026-08-09 把纸感梯子整体压深 0.02 时,`.tag-solid-info`
     当场从 4.5 掉到 4.26,而改的人根本没碰过 info 这一族。底色与 on-color 是两件事。 */
  --danger-foreground: oklch(0.968 0.008 95);
  --danger-bg: color-mix(in oklab, var(--p-red) 12%, var(--surface));
  --danger-border: color-mix(in oklab, var(--p-red) 35%, transparent);
  --danger-text: color-mix(in oklab, var(--p-red) 65%, var(--foreground));
  --destructive: var(--p-red);            /* v1-compat alias */

  --info: var(--p-blue);
  --info-foreground: oklch(0.968 0.008 95);
  --info-bg: color-mix(in oklab, var(--p-blue) 12%, var(--surface));
  --info-border: color-mix(in oklab, var(--p-blue) 35%, transparent);
  --info-text: color-mix(in oklab, var(--p-blue) 65%, var(--foreground));

  /* State layers — overlays composited on a surface for hover/press/select. */
  --state-hover:    color-mix(in oklab, var(--foreground) 5%, transparent);
  --state-pressed:  color-mix(in oklab, var(--foreground) 9%, transparent);
  --state-selected: color-mix(in oklab, var(--foreground) 7%, transparent);
  --state-disabled-opacity: 0.5;
  --surface-hover:  var(--accent);

  /* Brand gradient. */
  --brand-gradient: linear-gradient(95deg,
    var(--p-brand-1) 0%, var(--p-brand-2) 50%, var(--p-brand-3) 100%);
  --brand-gradient-fg: oklch(0.99 0 0);
  /* Brand as a SOLID accent + soft tints — for active rails, selected nav,
     accent underlines. Semantic tier so components never touch --p-brand-*. */
  --brand: var(--p-brand-2);
  --brand-soft: color-mix(in oklab, var(--p-brand-2) 10%, transparent);
  --brand-soft-hover: color-mix(in oklab, var(--p-brand-2) 16%, transparent);
  --brand-text: color-mix(in oklab, var(--p-brand-2) 72%, var(--foreground));

  /* Interactive accent (品牌蓝) — the UI's action/selection color: solid CTA fill,
     switch/checkbox checked, calendar selected day, active tab, selected item,
     active tool. DISTINCT from the decorative --brand* (hero art / opt-in brand
     chips), which stays blue→purple. Soft/text adapt per theme via color-mix. */
  --ui-accent:            var(--p-accent);
  --ui-accent-hover:      var(--p-accent-deep);
  --ui-accent-fg:         #fff;
  --ui-accent-soft:       color-mix(in oklab, var(--p-accent) 13%, transparent);
  --ui-accent-soft-hover: color-mix(in oklab, var(--p-accent) 20%, transparent);
  --ui-accent-text:       color-mix(in oklab, var(--p-accent) 78%, var(--foreground));

  /* Solid action button (primary CTA) — brand-blue; aliases the interactive accent.
     The gradient is a token so hover/selected can RE-ASSERT it (the base .btn:hover
     uses `background:` shorthand which would otherwise wipe the image → white flash).
     On no-color-mix engines the token is invalid → background-image unsets → flat. */
  --btn-solid-bg:       var(--ui-accent);
  --btn-solid-bg-hover: var(--ui-accent-hover);
  --btn-solid-fg:       var(--ui-accent-fg);
  --btn-solid-gradient: linear-gradient(180deg, color-mix(in oklab, var(--btn-solid-bg) 88%, #fff), var(--btn-solid-bg-hover));

  /* Default/outline buttons — NEUTRAL (the reference consoles' discipline:
     surface buttons carry no hue; ONLY the primary CTA and selected states
     do). The old blue tonal wash on every default button is what made whole
     screens read "blue". */
  --btn-outline-bg:           var(--surface-raised);
  --btn-outline-bg-hover:     color-mix(in oklab, var(--foreground) 5%, var(--surface-raised));
  --btn-outline-fg:           var(--foreground);
  --btn-outline-border:       var(--border);
  --btn-outline-border-hover: var(--border-strong);
  /* Tonal wash — now reserved for SELECTED/pressed states (accent family). */
  --btn-tonal-bg:           color-mix(in oklab, var(--p-accent) 13%, var(--surface));
  --btn-tonal-bg-hover:     color-mix(in oklab, var(--p-accent) 20%, var(--surface));
  --btn-tonal-selected-bg:  color-mix(in oklab, var(--p-accent) 14%, var(--surface));
  --btn-tonal-fg:           color-mix(in oklab, var(--p-accent) 72%, var(--foreground));
  --btn-tonal-border:       color-mix(in oklab, var(--p-accent) 40%, var(--border));
  --btn-tonal-border-hover: color-mix(in oklab, var(--p-accent) 55%, var(--border));

  /* Data-viz categorical ramp — the PLATFORM STANDARD (operator 2026-07-14):
     traditional bright blue leads. Six slots validated as a SET for the light
     surface (lightness band, chroma floor, adjacent-pair CVD separation ΔE
     24.2, contrast). Slot ORDER is the colorblind-safety mechanism — never
     reorder, cycle, or insert. The dark block re-steps the SAME hues for the
     dark surface (selected, not auto-flipped). */
  --chart-1: oklch(0.66 0.12 70);   /* amber  (≈ #b0762e) */
  --chart-2: oklch(0.58 0.08 185);  /* teal   (≈ #2f8d84) */
  --chart-3: oklch(0.60 0.09 255);  /* blue   (≈ #4a7ec2) */
  --chart-4: oklch(0.58 0.11 310);  /* fig    (≈ #8a56b0) */
  --chart-5: oklch(0.55 0.12 25);   /* brick  (≈ #b0453a) */
  --chart-6: oklch(0.52 0.09 150);  /* moss — overflow slot beyond the five-color paper ramp */
  --sidebar: var(--p-gray-2);
  --sidebar-foreground: var(--p-gray-11);
  --sidebar-primary: var(--p-gray-12);
  --sidebar-primary-foreground: var(--p-gray-1);
  --sidebar-accent: color-mix(in oklab, var(--p-gray-12) 6%, transparent);
  --sidebar-accent-foreground: var(--p-gray-12);
  --sidebar-border: var(--p-gray-5);
  --sidebar-ring: var(--ring);

  /* Fonts + type scale (raw ladder kept for direct use). */
  /* Platform type system = the OS-native stacks (operator rule 2026-07-10):
     users download NO font files, text renders in each OS's own face with
     zero FOUT. The old var(--font-geist*) indirection is removed on purpose —
     it let Next.js channels inject downloaded webfonts and drift from the
     non-Next channels; nothing may reintroduce a webfont or @font-face. */
  --font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
    "PingFang SC", "Microsoft YaHei", "Hiragino Sans GB", sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;
  --text-xs: 0.75rem; --text-sm: 0.875rem; --text-base: 1rem; --text-lg: 1.125rem;
  --text-xl: 1.25rem; --text-2xl: 1.5rem; --text-3xl: 1.875rem; --text-4xl: 2.25rem;

  /* Type ROLES — compact 12px base. Reference roles, not raw steps. */
  --text-micro:   0.6875rem;  /* 11px */
  --text-caption: 0.75rem;    /* 12px */
  --text-body:    0.75rem;    /* 12px — canonical base */
  --text-menu:    0.8125rem;  /* 13px — sidebar/menu item text. The platform
                                 standard for left-nav rows (matches AI对话 and
                                 AI短剧); body copy stays on the 12px base. */
  --text-title:   0.875rem;   /* 14px */
  --text-heading: 1rem;       /* 16px */
  --text-subheading: 1.125rem; /* 18px — h2 / sub-section */
  --text-display: 1.375rem;   /* 22px */
  /* Marketing poster scale — fluid hero/section type for landing pages, beyond
     --text-display (UI cap). Use via .text-poster-{sm,md,lg}. */
  --text-poster-sm: clamp(1.75rem, 1.2rem + 2.6vw, 2.5rem);   /* ~28→40px */
  --text-poster-md: clamp(2.25rem, 1.3rem + 4.5vw, 4rem);     /* ~36→64px */
  --text-poster-lg: clamp(2.75rem, 1.4rem + 6.5vw, 5.5rem);   /* ~44→88px */

  --weight-normal: 400; --weight-medium: 500; --weight-semibold: 600; --weight-bold: 700;
  --tracking-tight: -0.01em; --tracking-normal: 0; --tracking-wide: 0.02em;
  --leading-tight: 1.2; --leading-snug: 1.35; --leading-normal: 1.6;
  --leading-heading: var(--leading-tight); --leading-body: 1.5;

  /* Spacing (4px unit). */
  --sp-px: 1px; --sp-0_5: 2px;
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 20px; --sp-6: 24px;
  --sp-7: 28px; --sp-8: 32px; --sp-9: 36px; --sp-10: 40px; --sp-11: 44px; --sp-12: 48px;

  /* Radius — derived off the base so retheming reshapes everything.
     10px base (was 8px): controls read a touch softer; CARDS take the bigger
     jump via --c-card-radius: --radius-xl (14px) — the "soft surface" tell of
     the reference consoles without going pill-shaped at our 30px control height. */
  --radius: 0.625rem;                        /* 10px — tool-grade controls */
  --radius-sm: calc(var(--radius) - 2px);    /* 8px */
  --radius-md: var(--radius);
  --radius-lg: calc(var(--radius) + 2px);    /* 12px */
  --radius-xl: calc(var(--radius) + 4px);    /* 14px */
  --radius-2xl: calc(var(--radius) + 8px);   /* 18px — hero panels / dashboards */
  --radius-full: 9999px;

  /* Elevation ladder (each gets a dark counterpart below). */
  --elevation-0: none;
  --elevation-1: 0 1px 2px oklch(0 0 0 / 0.05), 0 1px 1px oklch(0 0 0 / 0.03);
  --elevation-2: 0 4px 12px oklch(0 0 0 / 0.06), 0 1px 4px oklch(0 0 0 / 0.04);
  --elevation-3: 0 12px 24px oklch(0 0 0 / 0.08), 0 4px 8px oklch(0 0 0 / 0.05);
  --elevation-4: 0 20px 48px oklch(0 0 0 / 0.1), 0 8px 16px oklch(0 0 0 / 0.06);
  /* 遮罩:模态压住页面时那层暗。以前每个模态各写各的(对话框 rgba(15,23,42,.5)、
     抽屉与命令面板 oklch(0.2 0 0/.42)),同一套界面里深浅不一。收成一个令牌,
     暗色下要更重一些 —— 暗底上太淡的遮罩压不住下面的内容。 */
  --scrim: oklch(0.2 0 0 / 0.42);
  /* 浮层的高度上限。缺了它,长列表会直接顶出视口 —— 底部那几项永远点不到,
     消费方只能往共享组件上写内联 style 兜底(xapi-tool 的控制台就在这么干)。 */
  --c-popover-max-h: min(60vh, 25rem);
  --shadow-card: var(--elevation-1);     /* v1-compat names */
  --shadow-float: var(--elevation-3);
  --shadow-inset: inset 0 1px 1px oklch(0 0 0 / 0.04);

  /* Motion. */
  --duration-fast: 120ms; --duration-normal: 180ms; --duration-slow: 280ms;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-smooth: cubic-bezier(0.4, 0, 0.2, 1);
  /* --ease-standard 是 --ease-smooth 的别名:全仓 8 处在用它,却从来没有定义过 ——
     没有回退的 var() 引用不存在的令牌,浏览器把整条声明丢掉,那些动效其实一直没生效。 */
  --ease-standard: var(--ease-smooth);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);

  /* Z-index ladder (gaps of 10). */
  /* 局部层叠:同一个卡片/表格内部的前后关系,不参与全局层级。
     它们存在的意义是「不要再写裸数字」—— 层级是体系,不是谁的数字大。 */
  --z-raised: 1; --z-raised-2: 2;
  --z-base: 0; --z-dropdown: 1000; --z-sticky: 1010; --z-overlay: 1020;
  --z-modal: 1030; --z-popover: 1040; --z-toast: 1050; --z-tooltip: 1060;

  /* Icon sizes (aligned to type). */
  --icon-sm: 14px; --icon-md: 16px; --icon-lg: 20px; --icon-xl: 24px;

  /* Breakpoint reference constants. NOTE: custom properties CANNOT drive
     @media/@container conditions — these document the vocabulary; the literals
     30rem/48rem/64rem are used in @container rules. */
  --bp-sm: 30rem; --bp-md: 48rem; --bp-lg: 64rem;

  /* Focus ring recipe (ONE look, used by every control via :focus-visible). */
  /* 焦点走 outline 通道,不再走 box-shadow。两个原因,都是实测出来的:
     一、旧的三种环都是「颜色 × 百分比混透明」,真正画出来的对比度只有 1.60-2.77,
         WCAG 2.2 对非文本界面的下限是 3:1 —— 一个都没达标。实色就没有这个问题。
     二、环画在 box-shadow 上,而 `.btn:active` 与 `.btn-ghost:hover` 都写了
         `box-shadow: none` 且权重更高 —— 键盘聚焦的淡按钮一被鼠标碰到,环就消失了。
         outline 与 box-shadow 不是同一个属性,碰不到。
     --focus-ring* 这三个 box-shadow 变量保留给还没迁移的消费方,新代码不要再用。 */
  --focus-outline: 2px solid var(--ring);
  --focus-outline-brand: 2px solid var(--ui-accent);
  --focus-outline-danger: 2px solid var(--danger);
  --focus-outline-offset: 2px;

  --focus-ring: 0 0 0 2px var(--background), 0 0 0 4px color-mix(in oklab, var(--ring) 55%, transparent);
  --focus-ring-danger: 0 0 0 2px var(--background), 0 0 0 4px color-mix(in oklab, var(--danger) 50%, transparent);
  /* Text-entry controls focus with the BRAND accent (inputs/textarea/select) — the focus
     moment is where a form reads as intentional vs generic. A thin accent ring only; the
     resting look stays neutral (blue-purple is otherwise reserved for buttons/titles). */
  --focus-ring-brand: 0 0 0 2px var(--background), 0 0 0 4px color-mix(in oklab, var(--ui-accent) 42%, transparent);

  /* ============================================================
     TIER 3 — COMPONENT  (--c-*, override hooks; default to semantics)
     ============================================================ */
  --control-h: 1.875rem;             /* compact control height (30px) — buttons + inputs share this */
  --control-h-sm: 1.625rem;          /* 26px */
  --control-h-lg: 2.5rem;            /* 40px */
  --c-btn-h: var(--control-h);
  /* 顶栏那排图标控件(主题 / 皮肤 / 语言 / 通知 / 头像)比正文按钮大一档:它们是
     全站常驻的 chrome,点击目标要更稳。以前这个尺寸是四个组件里各写一遍的 `36px`
     字面量 —— 改一次要改四处,而且没人知道它和 --control-h 是什么关系。 */
  --c-chrome-btn-h: 2.25rem;         /* 36px */
  --c-btn-px: 0.875rem;              /* 14px — optical breathing room */
  --c-btn-radius: var(--radius);
  --c-input-h: var(--control-h);
  --c-input-bg: var(--surface-raised);
  --c-input-border: var(--border);
  /* Native <select> caret, tokenised so it re-colours per theme (a hardcoded gray SVG
     disappeared against the dark surface). Overridden with a lighter stroke in dark mode. */
  --c-select-caret: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2371717a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  --c-card-radius: var(--radius-xl);
  --c-card-pad: var(--sp-4);
  /* Cards get a soft ambient float (not just a hairline) so surfaces read as
     layered, not flat — the premium tell. Kept low-opacity + tight so nested
     cards don't pile up. Dark override below. */
  --c-card-shadow: 0 1px 2px oklch(0 0 0 / 0.04), 0 5px 18px -6px oklch(0 0 0 / 0.09);
  --c-tag-radius: var(--radius-full);
  /* 主对话框 —— 全平台那一个「说点什么」的盒子(AI对话定稿的形状)。
     它比卡片更圆、更沉:一块 30% 的 muted 玻璃,不投影 —— 页面已经在它背后了。 */
  --c-composer-radius: var(--radius-2xl);
  /* 30% 的 --border 兑水 —— 和 AI对话 那个盒子逐像素同一块玻璃(那边是 input/30,
     两个 token 在本皮肤下同值)。比 --muted 再淡一档,正文才浮得出来。 */
  --c-composer-bg: color-mix(in oklab, var(--border) 30%, transparent);
  --c-composer-min-h: 6rem;          /* 96px —— 三行,写一段分镜不用先撑开 */
  --c-composer-max-h: 12rem;         /* 192px —— 再长就滚,不许顶穿页面 */
  /* 正文比 12px 基准大一档:这是全站唯一一个「真的要在里面写东西」的输入框,
     和左栏 --text-menu 同理 —— 平台标准由这个面自己定,不跟基准。 */
  --c-composer-font: var(--text-title);
  --c-composer-send-size: 2rem;      /* 32px —— 工具条上唯一一个实心圆,和 AI对话 同尺寸 */
}

/* ---- Dark theme (both selector conventions) — warm near-black paper,
   amber stays the voice ---- */
.dark,
[data-theme="dark"] {
  color-scheme: dark;
  --p-gray-0: oklch(0.235 0.008 75);  /* raised card (above bg) */
  --p-gray-1: oklch(0.205 0.007 75);  /* app bg */
  --p-gray-2: oklch(0.22 0.008 75);
  --p-gray-3: oklch(0.27 0.009 75);
  --p-gray-4: oklch(0.175 0.006 75);  /* muted (recessed) */
  --p-gray-5: oklch(0.31 0.010 75);
  --p-gray-6: oklch(0.28 0.009 75);
  --p-gray-7: oklch(0.39 0.010 75);
  --p-gray-8: oklch(0.46 0.010 78);
  --p-gray-9: oklch(0.638 0.012 82);   /* 暗色下次要文字压在**卡片**上实测 4.18-4.41,低于 4.5 —— 亮色早就按卡片底色调过,暗色没有。 */
  --p-gray-10: oklch(0.71 0.012 85);
  --p-gray-11: oklch(0.76 0.012 88);
  --p-gray-12: oklch(0.94 0.006 92);
  /* gray-9 clears AA on light fields, but dark raised fields need the next
     text step (about 5.8:1 on the darkest supported sunken surface). */
  --placeholder: var(--p-gray-10);

  --p-green: oklch(0.7 0.16 150);
  --p-amber: oklch(0.8 0.14 78);
  --p-red:   oklch(0.7 0.18 25);
  --p-blue:  oklch(0.68 0.16 254);

  /* Accent kept at light-mode depth: white --ui-accent-fg is TEXT on the solid
     CTA, so it must clear 4.5:1, not the 3:1 UI floor (0.68 L reached 2.9:1,
     0.60 L reached 4.05:1, 0.565 L reaches 4.66:1). */
  --p-accent:      oklch(0.565 0.115 72);
  --p-accent-deep: oklch(0.53 0.11 70);

  --p-brand-1: oklch(0.72 0.12 70);
  --p-brand-2: oklch(0.66 0.08 185);
  --p-brand-3: oklch(0.68 0.09 255);

  /* Data-viz categorical ramp, dark — the SAME hues as the light block,
     re-stepped for the dark surface (see light block). */
  --chart-1: oklch(0.74 0.12 70);   /* amber */
  --chart-2: oklch(0.68 0.08 185);  /* teal  */
  --chart-3: oklch(0.70 0.09 255);  /* blue  */
  --chart-4: oklch(0.68 0.10 310);  /* fig   */
  --chart-5: oklch(0.66 0.11 25);   /* brick */
  --chart-6: oklch(0.64 0.09 150);  /* moss  */

  --primary-foreground: #fff;
  --border: var(--p-gray-6);   /* keep dark border one step below (light uses gray-5) */
  /* Surface bridge, dark — same discipline as light: warm surfaces are
     authored into the ramp, no accent mix. */
  --card:   var(--p-gray-0);
  --accent: var(--p-gray-3);
  --sidebar: var(--p-gray-2);
  /* lighter caret so the <select> arrow stays legible on the dark surface */
  --c-select-caret: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23a1a1aa' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");

  /* Tonal buttons — louder brand-blue mix on dark so the wash survives the dark surface. */
  --btn-tonal-bg:           color-mix(in oklab, var(--p-accent) 24%, var(--p-gray-3));
  --btn-tonal-bg-hover:     color-mix(in oklab, var(--p-accent) 34%, var(--p-gray-3));
  --btn-tonal-selected-bg:  color-mix(in oklab, var(--p-accent) 30%, var(--p-gray-3));
  --btn-tonal-fg:           color-mix(in oklab, var(--p-accent) 50%, var(--p-gray-12));
  --btn-tonal-border:       color-mix(in oklab, var(--p-accent) 40%, var(--border));
  --btn-tonal-border-hover: color-mix(in oklab, var(--p-accent) 55%, var(--border));
  --success-foreground: oklch(0.16 0 0);
  --danger-foreground: oklch(0.16 0 0);
  --info-foreground: oklch(0.16 0 0);
  /* 琥珀在暗色下更亮,压白字只有 1.59:1 —— success/danger/info 都在这儿钉过深墨,
     唯独 warning 漏了(:root 的 var(--p-gray-12) 在暗色下翻成近白)。 */
  --warning-foreground: oklch(0.16 0 0);

  --elevation-1: inset 0 1px 0 oklch(1 0 0 / 0.04), 0 1px 2px oklch(0 0 0 / 0.25);
  --elevation-2: 0 4px 12px oklch(0 0 0 / 0.4), 0 1px 4px oklch(0 0 0 / 0.25);
  --elevation-3: 0 12px 28px oklch(0 0 0 / 0.45), 0 4px 10px oklch(0 0 0 / 0.3);
  --elevation-4: 0 20px 48px oklch(0 0 0 / 0.55), 0 8px 16px oklch(0 0 0 / 0.35);
  --shadow-inset: inset 0 1px 1px oklch(0 0 0 / 0.2);
  /* On dark, a top inset highlight + a deeper ambient shadow reads as a raised
     surface (a flat shadow alone is invisible on a dark page). */
  --c-card-shadow: inset 0 1px 0 oklch(1 0 0 / 0.04), 0 2px 10px oklch(0 0 0 / 0.36);
  --scrim: oklch(0.12 0 0 / 0.62);
}

/* ============================================================
   SKINS — [data-skin="<id>"] on <html>, composable with the dark axis
   (.dark / [data-theme="dark"] on the SAME element). A skin overrides
   PRIMITIVES (like dark does) — plus, where a canvas swap demands it,
   the surface-bridge semantics — so every component recipe retints
   automatically. The `skin` apex cookie mirrors the attribute; lib's
   bundle applies it at load (see components-src). v3 flips the axis:
   NO attribute = the paper palette above (the baseline). Opt-in blocks:
     default — the v2 neutral+blue console palette (cool canvas, blue
               accent, the v2 six-slot chart ramp).
     warm    — Anthropic-inspired editorial: cream canvas, warm graphite
               ink, clay accent, dormant chart palette (olive/sky/fig/…).
     forest  — neutral canvas + deep emerald actions/selection.
     violet  — neutral canvas + violet actions/selection.
   `paper` deliberately matches NO block — a data-skin="paper" cookie
   from a v2 surface simply renders :root.
   ============================================================ */

/* ---- default / forest / violet (light) — the v2 neutral canvas. forest and
   violet then re-point only the accent (their v2 meaning: cool neutral gray +
   a hue-shifted action color). Surface bridge returns to the v2 accent-mix
   recipe so raised surfaces carry the accent whisper again. ---- */
[data-skin="default"], [data-skin="forest"], [data-skin="violet"] {
  --p-gray-0: oklch(1 0 0);
  --p-gray-1: oklch(0.985 0 0);
  --p-gray-2: oklch(0.972 0 0);
  --p-gray-3: oklch(0.965 0 0);
  --p-gray-4: oklch(0.94 0 0);
  --p-gray-5: oklch(0.922 0 0);
  --p-gray-6: oklch(0.9 0 0);
  --p-gray-7: oklch(0.83 0 0);
  --p-gray-8: oklch(0.7 0 0);
  --p-gray-9: oklch(0.52 0 0);
  --p-gray-10: oklch(0.45 0 0);
  --p-gray-11: oklch(0.38 0 0);
  --p-gray-12: oklch(0.12 0 0);

  /* 0.585 L only carried white at 4.24:1 (see :root — 4.5 is the floor). */
  --p-accent:      oklch(0.565 0.16 256);
  --p-accent-deep: oklch(0.50 0.16 256);

  --p-brand-1: oklch(0.54 0.23 266);
  --p-brand-2: oklch(0.52 0.26 296);
  --p-brand-3: oklch(0.55 0.27 324);

  --chart-1: #2a78d6;  /* blue   */
  --chart-2: #1baf7a;  /* aqua   */
  --chart-3: #eda100;  /* yellow */
  --chart-4: #008300;  /* green  */
  --chart-5: #4a3aa7;  /* violet */
  --chart-6: #e34948;  /* red    */

  --card:    color-mix(in oklab, var(--p-accent) 2%, var(--p-gray-0));
  --accent:  color-mix(in oklab, var(--p-accent) 8%, var(--p-gray-2));
  --sidebar: color-mix(in oklab, var(--p-accent) 2%, var(--p-gray-2));
}
/* ---- default / forest / violet (dark) ---- */
.dark[data-skin="default"], [data-theme="dark"][data-skin="default"],
.dark[data-skin="forest"], [data-theme="dark"][data-skin="forest"],
.dark[data-skin="violet"], [data-theme="dark"][data-skin="violet"] {
  --p-gray-0: oklch(0.225 0 0);
  --p-gray-1: oklch(0.195 0 0);
  --p-gray-2: oklch(0.21 0 0);
  --p-gray-3: oklch(0.26 0 0);
  --p-gray-4: oklch(0.165 0 0);
  --p-gray-5: oklch(0.3 0 0);
  --p-gray-6: oklch(0.27 0 0);
  --p-gray-7: oklch(0.38 0 0);
  --p-gray-8: oklch(0.45 0 0);
  --p-gray-9: oklch(0.635 0 0);   /* 暗色下次要文字压在**卡片**上实测 4.18-4.41,低于 4.5 —— 亮色早就按卡片底色调过,暗色没有。 */
  --p-gray-10: oklch(0.7 0 0);
  --p-gray-11: oklch(0.75 0 0);
  --p-gray-12: oklch(0.94 0 0);

  --p-accent:      oklch(0.565 0.16 256);
  --p-accent-deep: oklch(0.50 0.16 256);

  --p-brand-1: oklch(0.64 0.21 266);
  --p-brand-2: oklch(0.62 0.25 296);
  --p-brand-3: oklch(0.65 0.26 324);

  --chart-1: #3987e5;  /* blue   */
  --chart-2: #199e70;  /* aqua   */
  --chart-3: #c98500;  /* yellow */
  --chart-4: #008300;  /* green  */
  --chart-5: #9085e9;  /* violet */
  --chart-6: #e66767;  /* red    */

  --card:    color-mix(in oklab, var(--p-accent) 4%, var(--p-gray-0));
  --accent:  color-mix(in oklab, var(--p-accent) 12%, var(--p-gray-3));
  --sidebar: color-mix(in oklab, var(--p-accent) 3%, var(--p-gray-2));
}

/* ---- warm (light) ---- */
[data-skin="warm"] {
  /* Warm neutral ramp (hue ~60–95, chroma ≤0.01) — cream canvas, ink text. */
  --p-gray-0: oklch(0.995 0.003 95);
  --p-gray-1: oklch(0.984 0.005 95);   /* ≈ #faf9f5 cream */
  --p-gray-2: oklch(0.972 0.006 92);
  --p-gray-3: oklch(0.955 0.008 92);
  --p-gray-4: oklch(0.935 0.009 92);
  --p-gray-5: oklch(0.905 0.01 92);    /* ≈ #e8e6dc warm border */
  --p-gray-6: oklch(0.885 0.01 92);
  --p-gray-7: oklch(0.82 0.012 90);
  --p-gray-8: oklch(0.69 0.012 85);
  --p-gray-9: oklch(0.51 0.01 75);     /* ≈ #5e5d59 warm muted */
  --p-gray-10: oklch(0.44 0.01 70);
  --p-gray-11: oklch(0.37 0.008 65);
  --p-gray-12: oklch(0.205 0.005 60);  /* ≈ #141413 warm ink */

  /* Clay/coral accent (≈ #d97757 family, darkened for white-on-fill AA:
     0.60 L was 4.18:1, 0.58 L is 4.58:1). */
  --p-accent:      oklch(0.580 0.145 40);
  --p-accent-deep: oklch(0.52 0.14 40);

  /* Decorative gradient re-tuned clay→fig so hero art stays in-family. */
  --p-brand-1: oklch(0.62 0.15 40);
  --p-brand-2: oklch(0.60 0.13 15);
  --p-brand-3: oklch(0.58 0.12 355);

  /* Anthropic dormant palette for data-viz: clay/olive/sky/fig/cactus. */
  --chart-1: oklch(0.685 0.142 38);
  --chart-2: oklch(0.59 0.082 130);
  --chart-3: oklch(0.67 0.075 248);
  --chart-4: oklch(0.7 0.115 0);
  --chart-5: oklch(0.65 0.06 175);

  /* Re-neutralize the surface bridge — a clay-tinted card reads pink; warm
     surfaces are authored INTO the ramp above instead (the reference system
     makes the same exception for its warm preset). */
  --card:    var(--p-gray-0);
  --accent:  var(--p-gray-3);
  --sidebar: var(--p-gray-2);
}
/* ---- warm (dark) — warm near-black, keeps the editorial personality ---- */
.dark[data-skin="warm"],
[data-theme="dark"][data-skin="warm"] {
  --p-gray-0: oklch(0.235 0.006 60);
  --p-gray-1: oklch(0.205 0.005 60);
  --p-gray-2: oklch(0.22 0.006 60);
  --p-gray-3: oklch(0.27 0.007 60);
  --p-gray-4: oklch(0.175 0.005 60);
  --p-gray-5: oklch(0.31 0.008 60);
  --p-gray-6: oklch(0.28 0.007 60);
  --p-gray-7: oklch(0.39 0.008 60);
  --p-gray-8: oklch(0.46 0.008 65);
  --p-gray-9: oklch(0.638 0.008 70);   /* 暗色下次要文字压在**卡片**上实测 4.18-4.41,低于 4.5 —— 亮色早就按卡片底色调过,暗色没有。 */
  --p-gray-10: oklch(0.71 0.008 75);
  --p-gray-11: oklch(0.76 0.008 80);
  --p-gray-12: oklch(0.94 0.005 90);

  /* Was 0.66 L — the worst white-on-fill in the system at 3.27:1. Brought to
     light-mode depth (the discipline the paper dark block already follows). */
  --p-accent:      oklch(0.575 0.13 42);
  --p-accent-deep: oklch(0.50 0.13 42);

  --p-brand-1: oklch(0.70 0.14 40);
  --p-brand-2: oklch(0.68 0.12 15);
  --p-brand-3: oklch(0.66 0.11 355);

  --chart-1: oklch(0.72 0.13 40);
  --chart-2: oklch(0.68 0.09 130);
  --chart-3: oklch(0.72 0.08 248);
  --chart-4: oklch(0.74 0.11 0);
  --chart-5: oklch(0.70 0.06 175);

  --card:    var(--p-gray-0);
  --accent:  var(--p-gray-3);
  --sidebar: var(--p-gray-2);
}

/* ---- forest / violet — accent re-point on top of the shared neutral canvas
   block above (one knob, both modes) ---- */
[data-skin="forest"] {
  --p-accent:      oklch(0.50 0.12 155);
  --p-accent-deep: oklch(0.43 0.12 155);
}
.dark[data-skin="forest"],
[data-theme="dark"][data-skin="forest"] {
  --p-accent:      oklch(0.550 0.12 155);
  --p-accent-deep: oklch(0.48 0.12 155);
}
[data-skin="violet"] {
  --p-accent:      oklch(0.51 0.19 296);
  --p-accent-deep: oklch(0.44 0.19 296);
}
.dark[data-skin="violet"],
[data-theme="dark"][data-skin="violet"] {
  --p-accent:      oklch(0.580 0.17 296);
  --p-accent-deep: oklch(0.52 0.17 296);
}

/* ---- High-contrast — manual [data-contrast=high] OR OS prefers-contrast.
   Its own mapping (heavier lines + AAA text), not a filter. ---- */
[data-contrast="high"] {
  --border: var(--p-gray-12);
  --border-strong: var(--p-gray-12);
  --muted-foreground: var(--p-gray-12);
  --foreground-subtle: var(--p-gray-12);
  --placeholder: var(--p-gray-11);
  --ring: var(--p-gray-12);
}
@media (prefers-contrast: more) {
  :root {
    --border: var(--p-gray-12);
    --border-strong: var(--p-gray-12);
    --muted-foreground: var(--p-gray-12);
    --foreground-subtle: var(--p-gray-12);
    --placeholder: var(--p-gray-11);
    --ring: var(--p-gray-12);
  }
}

/* ============================================================
   FALLBACKS — a NO-BUILD system has no compiler to down-level color, so it must
   render on engines without oklch()/color-mix() (older Safari, in-app WebViews).
   Default values above stay oklch/color-mix (modern path, untouched); these
   blocks only fire where the feature is ABSENT.
   ============================================================ */
@supports not (color: oklch(0 0 0)) {
  :root {
    --p-gray-0: #fdfcfa; --p-gray-1: #f6f4ef; --p-gray-2: #faf9f6;
    --p-gray-3: #f1eee7; --p-gray-4: #edeae2; --p-gray-5: #e3dfd6;
    --p-gray-6: #d5d0c4; --p-gray-7: #c8c2b4; --p-gray-8: #a8a190;
    --p-gray-9: #746d5e; --p-gray-10: #6d675c; --p-gray-11: #4a463c;
    --p-gray-12: #2b2822;
    --p-green: #16a34a; --p-amber: #d97706; --p-red: #d01d21; --p-blue: #2563eb;
    --p-accent: #a06816; --p-accent-deep: #96621f;
    --p-brand-1: #b0762e; --p-brand-2: #2f8d84; --p-brand-3: #4a7ec2;
    --brand-gradient-fg: #ffffff;
    --chart-1: #b0762e; --chart-2: #2f8d84; --chart-3: #4a7ec2; --chart-4: #8a56b0; --chart-5: #b0453a; --chart-6: #4c7a52;
  }
  .dark, [data-theme="dark"] {
    --p-gray-0: #272420; --p-gray-1: #201d19; --p-gray-2: #24211d;
    --p-gray-3: #2d2a25; --p-gray-4: #1a1714; --p-gray-5: #363229;
    --p-gray-6: #302c26; --p-gray-7: #45403a; --p-gray-8: #544f47;
    --p-gray-9: #958e80; --p-gray-10: #a29c8f; --p-gray-11: #b1aca0;
    --p-gray-12: #f2f0ea;
    --p-green: #22c55e; --p-amber: #fbbf24; --p-red: #f87171; --p-blue: #60a5fa;
    --p-accent: #9f6913; --p-accent-deep: #9c6820;
    --p-brand-1: #cf9a54; --p-brand-2: #55a89e; --p-brand-3: #6f9cd6;
  }
}
@supports not (color: color-mix(in oklab, red, blue)) {
  :root {
    --card: #fdfcfa; --accent: #f1eee7; --sidebar: #faf9f6;
    --btn-outline-bg-hover: #efece4;
    --success-bg: #eaf4e9; --success-border: #a9d8b0; --success-text: #30753d;
    --warning-bg: #faf0dc; --warning-border: #eecd93; --warning-text: #7a5312;
    --danger-bg:  #f9e8e4; --danger-border:  #efafa6; --danger-text: #942e26;
    --info-bg:    #e9eff7; --info-border:    #accaee; --info-text: #2b5192;
    --state-hover: rgba(43,40,34,0.05); --state-pressed: rgba(43,40,34,0.09);
    --state-selected: rgba(43,40,34,0.07);
    --btn-tonal-bg: #f4e6d2; --btn-tonal-bg-hover: #eeddc2; --btn-tonal-selected-bg: #f1e1ca;
    --btn-tonal-fg: #6f4a17; --btn-tonal-border: #dcbd91; --btn-tonal-border-hover: #c9a469;
    --ui-accent-soft: rgba(160,104,22,0.13); --ui-accent-soft-hover: rgba(160,104,22,0.2); --ui-accent-text: #6f4a17;
    --focus-ring: 0 0 0 2px var(--background), 0 0 0 4px rgba(109,103,92,0.55);
    --focus-ring-danger: 0 0 0 2px var(--background), 0 0 0 4px rgba(220,38,38,0.5);
    --focus-ring-brand: 0 0 0 2px var(--background), 0 0 0 4px rgba(160,104,22,0.42);
  }
  .dark, [data-theme="dark"] {
    --card: #272420; --accent: #2d2a25; --sidebar: #24211d;
    --btn-outline-bg-hover: #302c26;
    --success-bg: #17251a; --success-border: #2c5840; --success-text: #83d691;
    --warning-bg: #2a2213; --warning-border: #5a4a28; --warning-text: #f2c46b;
    --danger-bg:  #2a1817; --danger-border:  #5a3434; --danger-text: #fba09b;
    --info-bg:    #17223a; --info-border:    #2c4470; --info-text: #96b8f2;
    --state-hover: rgba(255,255,255,0.06); --state-pressed: rgba(255,255,255,0.1);
    --state-selected: rgba(255,255,255,0.08);
    --btn-tonal-bg: #4a3a20; --btn-tonal-bg-hover: #574526; --btn-tonal-selected-bg: #514023;
    --btn-tonal-fg: #e2b878; --btn-tonal-border: #6b5530; --btn-tonal-border-hover: #86693a;
    --ui-accent-soft: rgba(207,154,84,0.16); --ui-accent-soft-hover: rgba(207,154,84,0.24); --ui-accent-text: #e2b878;
    --focus-ring: 0 0 0 2px var(--background), 0 0 0 4px rgba(162,156,143,0.5);
    --focus-ring-danger: 0 0 0 2px var(--background), 0 0 0 4px rgba(248,113,113,0.5);
    --focus-ring-brand: 0 0 0 2px var(--background), 0 0 0 4px rgba(207,154,84,0.45);
  }
}
