/*
===============================================================================
 Dashboard Visual Theme
 Version: 1.0
===============================================================================
*/

/* layer 順序（tocas-ui < theme < 未分層規則）由 components/header.php 宣告；
   這裡只需要把整份檔案的規則收進 theme layer，不用再用 去硬蓋 tocas
   或賭頁面 <style> 的載入順序——layer 順序本身就保證了優先權。 */
@layer theme {

/* ==========================================================================
   01. DESIGN TOKENS + TOCAS LIGHT-SURFACE REMAP
   ========================================================================== */

:root,
html {
    /* 捷奏數科（Beat）品牌色，目前唯一用途是機器卡片倒數進度條的漸層 */
    --thm-beat-1: #5ebcf9;
    --thm-transition: #a4e5ff;
    --thm-beat-2: #ddf951;

    /* 系統主題強調色階——sidebar 選中項、按鈕等「是這個系統的顏色」都吃這組，
       跟上面的品牌漸層色是兩回事，不要混用。--thm-primary 是色階中間、
       日常使用取的那一階，需要深淺對比時才直接指定 -700/-500/-400 等階。 */
    --thm-primary-050: #f4f8ff;
    --thm-primary-100: #e8f2ff;
    --thm-primary-200: #b4d2fe;
    --thm-primary-300: #7fb1fc;
    --thm-primary-400: #4b91fb;
    --thm-primary-500: #1c73f8;
    --thm-primary-600: #1166e8;
    --thm-primary-700: #0b56cf;
    --thm-primary-800: #0a47ac;
    --thm-primary-900: #073a8a;
    --thm-primary-1000: #08203c;
    --thm-primary: var(--thm-primary-500);

    /* 語意狀態色——不分「一般 UI 用」跟「機器即時狀態燈號用」，統一一組，兩邊都讀這裡。
       每個名字都對應一個實際會顯示的狀態，不是憑空排列組合出來的色階：
       success＝正常/閒置，error＝故障，warning＝警告，info＝運轉中，
       disabled＝人為停用，unavailable＝離線/未連網/未安裝（原本 3 種不同灰藍，合併成一種）。 */
    --thm-success: #12b878;
    --thm-error: #f04452;
    --thm-error-soft: #fff0f1;
    --thm-warning: #ee9f13;
    --thm-warning-soft: #fff6df;
    --thm-info: #20bdea;
    --thm-disabled: #6f8296;
    --thm-unavailable: #8fa0b2;

    --ops-surface: #ffffff;
    --ops-surface-soft: #f7fafe;
    --ops-surface-hover: #f1f7fd;

    --ops-text-strong: #071e3e;
    --ops-text: #102e50;
    --ops-text-secondary: #58738f;
    --ops-text-muted: #8295a9;

    --ops-border: #dce7f1;
    --ops-border-strong: #c8d8e8;
    --ops-divider: #e6eef5;

    --ops-shadow-xs: 0 1px 2px rgba(14, 47, 82, .04);
    --ops-shadow-sm: 0 4px 15px rgba(20, 59, 98, .055);
    --ops-shadow-md: 0 11px 28px rgba(20, 59, 98, .09);

    --ops-speed-fast: 140ms;
    --ops-speed: 220ms;
    --ops-ease: cubic-bezier(.2, .7, .2, 1);

    /* Tocas primary palette */
    --ts-primary-400: var(--thm-primary-400);
    --ts-primary-500: var(--thm-primary-500);
    --ts-primary-600: var(--thm-primary-600);
    --ts-primary-700: var(--thm-primary-700);
    --ts-link-700: var(--thm-primary-600);

    /* html carries a permanent "is-dark" class from legacy markup;
       actual light/dark switching is driven by the html.is-dark block below. */
    color-scheme: light;

    /* --ts-gray-* 是 tocas 自己的變數名稱，框架內部一堆邊框/disabled/陰影都直接讀它，
       這裡直接蓋成帶藍色調的中性色（不是真灰階），讓 tocas 原生元件跟整體藍色調
       設計一致；升級 tocas 時要留意新元件是否假設這是去彩度的灰。 */
    --ts-gray-50: #ffffff;
    --ts-gray-75: #fbfdff;
    --ts-gray-100: #f3f7fb;
    --ts-gray-200: #e7eef5;
    --ts-gray-300: #d7e2ec;
    --ts-gray-400: #bdcbd9;
    --ts-gray-500: #8092a7;
    --ts-gray-600: #617991;
    --ts-gray-800: #054d7d;
    --ts-gray-900: #081f3d;

    --ts-page-background-default: #f3f8fc;
    --ts-page-background-secondary: #edf4f9;
    --ts-page-background-tertiary: #e7eff6;

    --ts-elevated-shadow: var(--ops-shadow-sm);
    --ts-elevated-shadow-modal: 0 26px 70px rgba(8, 31, 60, .18);
    --ts-elevated-shadow-drawer: 12px 0 35px rgba(2, 19, 38, .24);

}


/* ==========================================================================
   01B. DARK MODE TOKEN OVERRIDES (html.is-dark)
   ========================================================================== */

html.is-dark {
    color-scheme: dark;

    /* Warm neutral charcoal (shadcn/Vercel-style) — fully desaturated, no
       blue/navy cast, so the colored accents (buttons, status chips, KPI
       tiles) stay the only color on the page. */
    --ops-surface: #1c1c1c;
    --ops-surface-soft: #242424;
    --ops-surface-hover: #2c2c2c;

    --ops-text-strong: #f5f5f5;
    --ops-text: #ededed;
    --ops-text-secondary: #a3a3a3;
    --ops-text-muted: #7a7a7a;

    --ops-border: #333333;
    --ops-border-strong: #404040;
    --ops-divider: #292929;

    --ops-shadow-xs: 0 1px 2px rgba(0, 0, 0, .3);
    --ops-shadow-sm: 0 4px 15px rgba(0, 0, 0, .32);
    --ops-shadow-md: 0 11px 28px rgba(0, 0, 0, .4);

    --thm-error-soft: rgba(240, 68, 82, .16);
    --thm-warning-soft: rgba(238, 159, 19, .16);

    --thm-primary-100: rgba(28, 115, 248, .18);
    --thm-primary-050: rgba(28, 115, 248, .10);

    --ts-link-700: var(--thm-primary-400);

    /* 同上，直接蓋 tocas 的灰階變數 */
    --ts-gray-50: #141414;
    --ts-gray-75: #181818;
    --ts-gray-100: #1c1c1c;
    --ts-gray-200: #242424;
    --ts-gray-300: #2c2c2c;
    --ts-gray-400: #3f3f3f;
    --ts-gray-500: #6e6e6e;
    --ts-gray-600: #8f8f8f;
    --ts-gray-800: #dcdcdc;
    --ts-gray-900: #f5f5f5;

    --ts-page-background-default: #131313;
    --ts-page-background-secondary: #171717;
    --ts-page-background-tertiary: #1a1a1a;

    --ts-elevated-shadow: var(--ops-shadow-sm);
    --ts-elevated-shadow-modal: 0 26px 70px rgba(0, 0, 0, .55);
    --ts-elevated-shadow-drawer: 12px 0 35px rgba(0, 0, 0, .55);

}


/* ==========================================================================
   01C. HAS-LIGHT FORCE OVERRIDE (project tokens)
   ========================================================================== */

/* tocas 原生的 .has-light 只鎖住它自己的 --ts-gray-* 和 --ts-tonal-* 等變數，
   不知道這個專案疊加上去的 --ops-* 後台配色系統。沒有這條規則，掛 has-light
   的頁面（v2/machine、customer/point、topup 等固定淺色 UI）裡讀 --ops-* 的
   .ts-text/.ts-box 等元件，仍會被 html.is-dark 往下蓋成深色模式那組值，
   跟 has-light「這塊永遠淺色」的用意衝突。比照下面 Swal 淺色鎖定的作法，
   把 --ops-* 也鎖回 01. 定義的淺色值，不用逐頁另外覆寫。 */
.has-light {
    --ops-surface: #ffffff;
    --ops-surface-soft: #f7fafe;
    --ops-surface-hover: #f1f7fd;

    --ops-text-strong: #071e3e;
    --ops-text: #102e50;
    --ops-text-secondary: #58738f;
    --ops-text-muted: #8295a9;

    --ops-border: #dce7f1;
    --ops-border-strong: #c8d8e8;
    --ops-divider: #e6eef5;

    --ops-shadow-xs: 0 1px 2px rgba(14, 47, 82, .04);
    --ops-shadow-sm: 0 4px 15px rgba(20, 59, 98, .055);
    --ops-shadow-md: 0 11px 28px rgba(20, 59, 98, .09);

    --thm-error-soft: #fff0f1;
    --thm-warning-soft: #fff6df;
    --thm-primary-100: #e8f2ff;
    --thm-primary-050: #f4f8ff;
}


/* ==========================================================================
   02. FOUNDATION
   ========================================================================== */

html,
html.is-dark {
    min-height: 100%;
}

body {
    min-height: 100vh;
    margin: 0;
    color: var(--ops-text);
    font-family:
        "Noto Sans TC",
        "PingFang TC",
        "Microsoft JhengHei",
        system-ui,
        -apple-system,
        BlinkMacSystemFont,
        "Segoe UI",
        sans-serif;
    font-feature-settings: "tnum" 1;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
}

::selection {
    color: #fff;
    background: var(--thm-primary-500);
}

a {
    text-underline-offset: .17em;
}

/* ==========================================================================
   05. TYPOGRAPHY / INFORMATION HIERARCHY
   ========================================================================== */

.ts-header,
h1, h2, h3, h4, h5, h6 {
    color: var(--ops-text-strong);
    letter-spacing: -.015em;
}

.ts-header {
    font-weight: 700;
}

.ts-header.is-small,
.ts-header.is-tiny {
    color: var(--ops-text);
    letter-spacing: 0;
}

.ts-text {
    color: var(--ops-text);
}

.ts-text.is-secondary,
.ts-text.is-description {
    color: var(--ops-text-secondary);
}

.ts-text.is-key {
    color: var(--ops-text-secondary);
    background: var(--ops-surface-soft);
    border: 1px solid var(--ops-border);
    border-radius: 5px;
    padding: 1px 4px;
}

.ts-text.is-link {
    color: var(--thm-primary-700);
}

html.is-dark .ts-text.is-link {
    color: var(--thm-primary-400);
}

.ts-text.is-negative {
    color: var(--thm-error);
}

.ts-text.is-positive {
    color: var(--thm-success);
}


/* ==========================================================================
   06. CARD / SURFACE SYSTEM
   ========================================================================== */

.ts-box {
    color: var(--ops-text);
    background: var(--ops-surface);
    border-color: var(--ops-border);
    border-radius: var(--ts-border-radius-container);
    box-shadow: var(--ops-shadow-xs);
}

.ts-box.is-raised {
    border-color: var(--ops-border);
    box-shadow: var(--ops-shadow-sm);
}

/* .ts-grid 本身純排版用，沒有 padding；跟 .ts-box 合併成一個元素（讓排版列直接長成一張卡，
   不必再包一層 .ts-content）時，補這行讓內容跟卡片邊界有留白。 */
.ts-box.ts-grid {
    padding: 1rem;
}

/* A lone .ts-content (first and last at once) takes the full card radius; when
   there's more after/before it (e.g. a header strip above a divider + rows),
   only the edge touching the card's own rounded edge should round — rounding
   all 4 corners on a first-child that has siblings below it makes that child
   look like its own separate rounded chip floating inside the card border. */
.ts-box > .ts-content:first-child:last-child {
    border-radius: inherit;
}

.ts-box > .ts-content:first-child:not(:last-child) {
    border-radius: var(--ts-border-radius-container) var(--ts-border-radius-container) 0 0;
}

.ts-box > .ts-content:last-child:not(:first-child) {
    border-radius: 0 0 var(--ts-border-radius-container) var(--ts-border-radius-container);
}

.ts-box .ts-divider {
    border-color: var(--ops-divider);
}

.ts-box:hover {
    border-color: var(--ops-border-strong);
}

/* General dashboard box lift. No DOM structure changes. */
.ts-box.is-raised {
    transition:
        border-color var(--ops-speed) var(--ops-ease),
        box-shadow var(--ops-speed) var(--ops-ease),
        transform var(--ops-speed) var(--ops-ease);
}

.ts-box.is-raised:hover {
    border-color: var(--ops-border-strong);
    box-shadow: var(--ops-shadow-md);
}

/* 上面幾條用 border-color 一次重設四邊顏色，會連帶蓋掉 Tocas is-*-indicated 系列
   靠 border-{side} 設定的指示色（--indicator-color），讓場域色條、負面/警示提示框
   等搭配 is-raised 的指示卡片全部變回灰色；比照 Tocas 自己 [class*="-indicated"].is-negative
   等變體的做法，在指示的那一側重新套用回去（多疊一個 class 讓特異度自然高於上面幾條，
   不需要靠宣告順序）。 */
.ts-box.is-top-indicated,
.ts-box.is-raised.is-top-indicated,
.ts-box:hover.is-top-indicated,
.ts-box.is-raised:hover.is-top-indicated {
    border-top-color: var(--indicator-color);
}

.ts-box.is-bottom-indicated,
.ts-box.is-raised.is-bottom-indicated,
.ts-box:hover.is-bottom-indicated,
.ts-box.is-raised:hover.is-bottom-indicated {
    border-bottom-color: var(--indicator-color);
}

.ts-box.is-start-indicated,
.ts-box.is-raised.is-start-indicated,
.ts-box:hover.is-start-indicated,
.ts-box.is-raised:hover.is-start-indicated {
    border-left-color: var(--indicator-color);
}

.ts-box.is-end-indicated,
.ts-box.is-raised.is-end-indicated,
.ts-box:hover.is-end-indicated,
.ts-box.is-raised:hover.is-end-indicated {
    border-right-color: var(--indicator-color);
}


/* ==========================================================================
   07. BUTTON SYSTEM
   ========================================================================== */

/* tocas 沒有 .is-primary——它預設沒掛任何 class 的 .ts-button 本身就是主色按鈕，
   .is-secondary/.is-outlined/.is-ghost 才是額外的退場樣式。這裡補一個顯式的 .is-primary，
   讓需要在標記上明確寫出「這顆是主色按鈕」的地方可以掛，效果跟裸的 .ts-button 一致，
   都吃 --thm-primary（系統主題強調色，非上面的 Beat 品牌漸層色）。 */
.ts-button,
.ts-button.is-primary {
    min-height: 37px;
    color: #fff;
    background: linear-gradient(135deg, var(--thm-primary), var(--thm-primary-500));
    border-color: var(--thm-primary);
    border-radius: var(--ts-border-radius-secondary);
    box-shadow: 0 4px 12px rgba(17, 102, 232, .13);
    font-weight: 600;
    transition:
        color var(--ops-speed-fast) ease,
        background-color var(--ops-speed-fast) ease,
        border-color var(--ops-speed-fast) ease,
        box-shadow var(--ops-speed-fast) ease,
        transform var(--ops-speed-fast) var(--ops-ease);
}

.ts-button:hover:not(:disabled):not(.is-disabled) {
    color: #fff;
    opacity: 1;
    background: linear-gradient(135deg, var(--thm-primary-700), var(--thm-primary-600));
    border-color: var(--thm-primary-700);
    box-shadow: 0 7px 17px rgba(17, 102, 232, .19);
    transform: translateY(-1px);
}

.ts-button:active:not(:disabled):not(.is-disabled) {
    transform: translateY(0);
}

.ts-button.is-secondary {
    color: var(--ops-text);
    background: var(--ops-surface-soft);
    border-color: var(--ops-border);
    box-shadow: none;
}

.ts-button.is-secondary:hover:not(:disabled):not(.is-disabled) {
    color: var(--thm-primary-700);
    background: var(--ops-surface-hover);
    border-color: var(--ops-border);
}

.ts-button.is-outlined {
    color: var(--ops-text);
    background: var(--ops-surface);
    border-color: var(--ops-border-strong);
    box-shadow: none;
}

.ts-button.is-outlined:hover:not(:disabled):not(.is-disabled) {
    color: var(--thm-primary-700);
    background: var(--thm-primary-050);
    border-color: var(--ops-border-strong);
}

.ts-button.is-ghost {
    color: var(--ops-text-secondary);
    background: transparent;
    border-color: transparent;
    box-shadow: none;
}

.ts-button.is-ghost:hover:not(:disabled):not(.is-disabled) {
    color: var(--thm-primary-600);
    background: var(--ops-surface-hover);
    border-color: transparent;
    box-shadow: none;
}

.ts-button.is-negative {
    color: #fff;
    background: var(--thm-error);
    border-color: var(--thm-error);
}

.ts-button.is-negative.is-ghost {
    color: var(--thm-error);
    background: transparent;
    border-color: transparent;
}

.ts-button:disabled,
.ts-button.is-disabled,
fieldset:disabled .ts-button {
    color: var(--ops-text-muted);
    background: var(--ops-surface-soft);
    border-color: var(--ops-border);
    box-shadow: none;
    opacity: .72;
}

/* Ghost buttons must stay borderless/transparent even when disabled — the
   generic disabled rule above otherwise draws an unwanted box around them
   (equal specificity, later in source, so it was winning over .is-ghost). */
.ts-button.is-ghost:disabled,
.ts-button.is-ghost.is-disabled,
fieldset:disabled .ts-button.is-ghost {
    background: transparent;
    border-color: transparent;
    box-shadow: none;
}

.ts-button.is-icon {
    border-radius: 9px;
}


/* ==========================================================================
   08. FORM SYSTEM
   ========================================================================== */

.ts-input input,
.ts-input textarea,
.ts-select select {
    color: var(--ops-text);
    background: var(--ops-surface);
    border-color: var(--ops-border-strong);
    border-radius: var(--ts-border-radius-secondary);
    box-shadow: none;
    caret-color: var(--thm-primary-500);
    transition:
        border-color var(--ops-speed-fast) ease,
        box-shadow var(--ops-speed-fast) ease,
        background-color var(--ops-speed-fast) ease;
}

.ts-input input::placeholder,
.ts-input textarea::placeholder {
    color: var(--ops-text-muted);
    opacity: 1;
}

.ts-input input:hover,
.ts-input textarea:hover,
.ts-select select:hover {
    border-color: var(--ops-border-strong);
}

.ts-input input:focus,
.ts-input textarea:focus,
.ts-select select:focus {
    color: var(--ops-text);
    background: var(--ops-surface);
    border-color: var(--thm-primary-400);
    outline: none;
}

.ts-input > .ts-icon,
.ts-input .ts-icon {
    color: var(--ops-text-muted);
}

.ts-select {
    color: var(--ops-text);
}

.ts-checkbox,
.ts-radio,
.ts-switch,
.ts-selection {
    color: var(--ops-text);
}

/* tocas 預設未勾選狀態 border 跟 background 同色（都是 --ts-gray-200），
   淺色主題下幾乎融入白底看不到，改用主題邊框色搭配 surface 背景撐出對比；
   限定 :not(:checked)，否則因為 @layer theme 排在 tocas-ui 後面、優先權天生較高，
   會連勾選狀態的底色都一併蓋成 surface（白/淺色），讓打勾用的白色勾勾圖示直接看不見 */
.ts-checkbox input:not(:checked),
.ts-radio input:not(:checked) {
    background: var(--ops-surface);
    border-color: var(--ops-border-strong);
}

/* 跟 checkbox/radio 不同，.ts-selection 已經有實心色塊標示目前選中的選項，
   不需要再靠外框撐對比——套用上面那顆同一顆規則反而讓整個切換元件多長出一圈框，很像被裝進盒子裡。 */
.ts-selection {
    background: transparent;
    border-color: transparent;
    border-radius: var(--ts-border-radius-secondary);
}

.ts-selection:hover {
    border-color: transparent;
}

/* tocas 的 .ts-selection .item .text 直接把未選中段落的文字設成 --ts-gray-800（偏淡的次要色調），
   這是設在 .text 本身的宣告，不是繼承來的，上面 .ts-selection { color } 那條蓋不到它。拿掉框線後
   這個淡灰字看起來像整顆按鈕都很模糊，改回一般內文的主文字色，跟其他地方預設文字色一致。
   只蓋未勾選（:not(:checked)）這半，勾選中的那半留給 tocas 自己 input:checked + .text 那條
   （白字疊實心底色），不然連選中狀態的白字都會被這裡蓋成深色文字，在藍底上變成看不清楚的髒色。 */
.ts-selection .item input:not(:checked) + .text {
    color: var(--ops-text);
}

.ts-fieldset {
    border-color: var(--ops-border);
    border-radius: var(--ts-border-radius-element);
}


/* ==========================================================================
   09. FILTER / CHIP / TAB / SEGMENT
   ========================================================================== */

.ts-chip {
    color: var(--ops-text-secondary);
    background: var(--ops-surface-soft);
    border-color: var(--ops-border);
    border-radius: 999px;
}

.ts-chip:hover {
    color: var(--thm-primary-700);
    background: var(--thm-primary-100);
    border-color: var(--ops-border-strong);
}

.ts-tab {
    border-color: var(--ops-divider);
}

.ts-tab .item {
    color: var(--ops-text-secondary);
    font-weight: 600;
}

.ts-tab .item:hover {
    color: var(--thm-primary-600);
}

/* pilled 分頁選中時 tocas 原生就有配好對比色的實心底色字（--accent-foreground-color，預設白），
   但上面 .ts-tab .item 那條在 @layer theme 裡，排在 tocas-ui 後面優先權天生較高，
   會無條件蓋成 --ops-text-secondary，跟深色底色太接近看不清楚，這裡蓋回來（含 hover 狀態） */
.ts-tab.is-pilled .item.is-active {
    color: var(--accent-foreground-color, var(--ts-gray-50));
}

/* :not(.is-pilled) — pilled tabs (.ts-tab.is-pilled) already get a solid
   accent-colored pill from tocas itself, with its own contrast-aware text
   color (light text on the pill in light mode, dark text in dark mode via
   --ts-gray-50/--ts-gray-800). Forcing blue text here on top of that pill
   background is what caused blue-on-blue/blue-on-near-white active tabs
   (e.g. 機器新增頁的「單筆新增／批量新增」). Only the plain underline-style
   tab needs this rule, since tocas itself leaves its text color unstyled. */
.ts-tab:not(.is-pilled) .item.is-active {
    color: var(--thm-primary-600);
    font-weight: 700;
}

.ts-tab.is-filled .item.is-active {
    color: var(--thm-primary-700);
    background: var(--thm-primary-100);
}

.ts-segment {
    color: var(--ops-text);
    background: var(--ops-surface);
    border-color: var(--ops-border);
}

.ts-segment .item {
    color: var(--ops-text-secondary);
}

.ts-segment .item.is-active {
    color: var(--thm-primary-700);
    background: var(--thm-primary-100);
}


/* ==========================================================================
   10. TABLE / DATA DENSITY
   ========================================================================== */

.ts-table {
    color: var(--ops-text);
    background: var(--ops-surface);
    border-color: var(--ops-border);
    border-radius: var(--ts-border-radius-element);
}

.ts-table thead th {
    color: var(--ops-text-secondary);
    background: var(--ops-surface-soft);
    border-color: var(--ops-divider);
    font-size: .9em;
    font-weight: 700;
}

.ts-table tbody td {
    color: var(--ops-text);
    border-color: var(--ops-divider);
}

.ts-table.is-striped tbody tr:nth-child(even) {
    background: var(--ops-surface-soft);
}

.ts-table tbody tr {
    transition: background-color var(--ops-speed-fast) ease;
}

.ts-table tbody tr:hover {
    background: var(--ops-surface-hover);
}

/* The category/store summary cards (store/category/list.js, store/list.js)
   reuse .ts-table only to line up a label and a count — it isn't an
   interactive/selectable table, so it shouldn't get the row-hover treatment
   meant for real data tables above; it read as a stray selection box. */
.ts-table.is-fitted.is-truncated tbody tr:hover {
    background: transparent;
}

table thead th {
    background: var(--ops-surface-soft);
}


/* ==========================================================================
   11. MODAL / DIALOG — APPROVED ANNOUNCEMENT REFERENCE LANGUAGE
   ========================================================================== */

dialog.ts-modal {
    color: var(--ops-text);
    background: transparent;
    border: 0;
    border-radius: var(--ts-border-radius-container);
}

dialog.ts-modal::backdrop {
    background: rgba(7, 27, 50, .42);
    -webkit-backdrop-filter: blur(3px);
    backdrop-filter: blur(3px);
}

.ts-modal > .content {
    color: var(--ops-text);
    background: var(--ops-surface);
    border: 1px solid var(--ops-border-strong);
    border-radius: var(--ts-border-radius-container);
    /* box-shadow 不寫在這裡，吃 tocas 原生 dialog.ts-modal > .content 那條規則的
       var(--ts-elevated-shadow-modal)，我們只在 :root 蓋那個變數的值 */
    overflow: hidden;
}

.ts-modal > .content > .ts-content {
    color: var(--ops-text);
    background: var(--ops-surface);
}

.ts-modal > .content > .ts-content.is-secondary,
.ts-modal > .content > .ts-content.is-tertiary {
    background: var(--ops-surface-soft);
}

.ts-modal > .content > .ts-divider {
    border-color: var(--ops-divider);
}

.ts-modal .ts-close {
    color: var(--ops-text-secondary);
    background: var(--ops-surface-soft);
    border-radius: 50%;
}

.ts-modal .ts-close:hover {
    color: var(--ops-text-strong);
    background: var(--ops-surface-hover);
}

.ts-modal .ts-box {
    background: var(--ops-surface-soft);
    border-color: var(--ops-border);
    box-shadow: none;
}


/* ==========================================================================
   12. MENU / DROPDOWN / POPOVER
   ========================================================================== */

.ts-dropdown,
.ts-popover {
    color: var(--ops-text);
    background: var(--ops-surface);
    border-color: var(--ops-border);
    border-radius: var(--ts-border-radius-element);
    box-shadow: var(--ops-shadow-md);
}

.ts-dropdown .item,
.ts-popover .item {
    color: var(--ops-text);
    border-radius: 7px;
}

.ts-dropdown .item:hover,
.ts-popover .item:hover {
    color: var(--ops-text-strong);
    background: var(--ops-surface-hover);
}

.ts-menu.is-separated > .item {
    border-color: var(--ops-divider);
}


/* ==========================================================================
   13. BLANKSLATE / EMPTY STATE / LOADING
   ========================================================================== */

.ts-blankslate {
    color: var(--ops-text-secondary);
}

.ts-blankslate.is-secondary {
    background: transparent;
}

.ts-blankslate > .ts-icon,
.ts-blankslate .ts-icon {
    color: var(--ops-text-muted);
}

.ts-blankslate .header {
    color: var(--ops-text-secondary);
    font-weight: 600;
}

.ts-blankslate .description {
    color: var(--ops-text-secondary);
}

.ts-loading {
    color: var(--thm-primary-500);
}



/* ==========================================================================
   18. ACCORDION / NOTICE / TIMELINE / FILE / LABEL
   ========================================================================== */

.ts-accordion {
    color: var(--ops-text);
    border-color: var(--ops-border);
}

.ts-accordion .item {
    border-color: var(--ops-divider);
}

.ts-notice {
    color: var(--ops-text);
    background: var(--ops-surface);
    border-color: var(--ops-border);
    border-radius: var(--ts-border-radius-element);
    box-shadow: var(--ops-shadow-sm);
}

/* tocas 原生只有 .is-negative，沒有警示（warning）色版本，跟 is-negative 同樣做法自己補一組 */
.ts-notice.is-warning {
    color: #765600;
    background: var(--thm-warning-soft);
    border-color: var(--ts-warning-500, #ffd21a);
}

.ts-notice.is-warning .title {
    color: var(--ops-text);
    background: var(--ops-surface);
    border: 1px solid var(--ops-border);
    font-weight: 500;
}

html.is-dark .ts-notice.is-warning {
    color: #f5cf6b;
}

.ts-timeline {
    color: var(--ops-text);
}

.ts-file,
.ts-label {
    border-color: var(--ops-border);
    border-radius: var(--ts-border-radius-secondary);
}


/* ==========================================================================
   19. SWEETALERT / SNACKBAR — THIRD-PARTY VISUAL ALIGNMENT
   ========================================================================== */

:root {
    --swal2-border-radius: 14px;
    --swal2-backdrop: rgba(7, 27, 50, .42);
    --swal2-confirm-button-background-color: var(--thm-primary-600);
    --swal2-cancel-button-background-color: #718397;
}

/* Swal 一律維持淺色外觀，不隨 html.is-dark 切換。內部 .ts-text 等既有規則讀的是
   --ops-* token，這些 token 會被 html.is-dark 蓋掉並往下繼承進 swal，所以在這個
   scope 內把用得到的 token 重新釘死成淺色值，而不是逐一改 swal 內容裡的 class。 */
div:where(.swal2-container) div:where(.swal2-popup) {
    color-scheme: light;
    --ops-surface: #ffffff;
    --ops-surface-soft: #f7fafe;
    --ops-surface-hover: #f1f7fd;
    --ops-text-strong: #071e3e;
    --ops-text: #102e50;
    --ops-text-secondary: #58738f;
    --ops-text-muted: #8295a9;
    --ops-border: #dce7f1;
    --ops-border-strong: #c8d8e8;
    --ops-divider: #e6eef5;
    --thm-error-soft: #fff0f1;
    --thm-warning-soft: #fff6df;
    --thm-primary-100: #e8f2ff;
    --thm-primary-050: #f4f8ff;
    --swal2-background: var(--ops-surface);
    --swal2-color: var(--ops-text);
    border: 1px solid var(--ops-border);
    box-shadow: var(--ts-elevated-shadow-modal);
}

.ts-snackbar {
    color: var(--ops-text);
    background: var(--ops-surface);
    border: 1px solid var(--ops-border);
    border-radius: var(--ts-border-radius-element);
    box-shadow: var(--ops-shadow-md);
}


/* ==========================================================================
   20. SCROLLBAR
   ========================================================================== */

* {
    scrollbar-width: thin;
    scrollbar-color: #afc0d1 transparent;
}

*::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}

*::-webkit-scrollbar-track {
    background: transparent;
}

*::-webkit-scrollbar-thumb {
    background: #afc0d1;
    border: 2px solid transparent;
    border-radius: 999px;
    background-clip: padding-box;
}

*::-webkit-scrollbar-thumb:hover {
    background: #8da6bd;
    border: 2px solid transparent;
    background-clip: padding-box;
}

html.is-dark {
    scrollbar-color: #3f3f3f transparent;
}

html.is-dark *::-webkit-scrollbar-thumb {
    background: #3f3f3f;
}

html.is-dark *::-webkit-scrollbar-thumb:hover {
    background: #565656;
}

/* ==========================================================================
   21. FOCUS / ACCESSIBILITY / MOTION
   ========================================================================== */

a:focus-visible,
button:focus-visible,
[tabindex]:focus-visible {
    outline: 2px solid var(--thm-primary-400);
    outline-offset: 2px;
}


@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        scroll-behavior: auto !important;
        transition-duration: .001ms !important;
    }
}


/* ==========================================================================
   22. RESPONSIVE REFINEMENT
   ========================================================================== */

@media (max-width: 799px) {
    .ts-box {
        border-radius: var(--ts-border-radius-element);
    }

    dialog.ts-modal {
        max-width: calc(100vw - 14px);
    }

    .ts-modal > .content {
        border-radius: var(--ts-border-radius-element);
    }
}

@media (max-width: 600px) {
    .ts-button,
    .ts-input input,
    .ts-select select {
        min-height: 40px;
    }
}


/* ==========================================================================
   23. PRINT SAFETY
   ========================================================================== */

@media print {
    html,
    html.is-dark,
    body {
        color-scheme: light !important;
        color: #111;
        background: var(--ops-surface);
    }

    .ts-box,
    .ts-modal > .content {
        box-shadow: none;
    }
}

/* ==========================================================================
   24. DARK MODE TEXT CONTRAST SAFETY NET
   ========================================================================== */

/* Keep ordinary content readable after html.is-dark token remapping.
   側邊欄的例外收在 sidebar 元件自己的 <style> 裡，不在這裡重複處理。
   用 :where() 包住排除清單——它本身 0 specificity，六個 :not() 疊起來不會
   把這條規則的優先權衝到比元件自己的 is-active/is-selected 還高，害元件蓋不回自己的顏色。 */
html.is-dark body .ts-text:not(:where(.is-secondary, .is-description, .is-negative, .is-positive, .is-link, .is-key)) {
    color: var(--ops-text);
}


/* 表格外層/空狀態卡片已經全部改用 .ts-box is-raised／.ts-blankslate ts-box is-raised（見各自
   page markup），不用再逐頁寫一次。Billing 的表格外層 .ts-box 例外沒有掛 is-raised：它已經包在
   有自己邊框/陰影的 .masked-area 裡面（見 assets/css/dashboard/billing/style.css），再疊一層
   等於雙重卡片邊框。 */

} /* @layer theme */
