@import "tailwindcss"; /* Edge: suppress the hover "visual search / 视觉搜索" overlay icon on images and videos (legacy-Edge -ms-touch-action trick). Doesn't affect clicks. */ img, video { -ms-touch-action: none; } :root { font-family: "Inter", ui-sans-serif, system-ui, -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif; --tw-ring-color: rgb(15 23 42 / 0.08); /* ===== Theme palette — LIGHT (default) ===== Drives the app chrome (rails/header) and the public marketing pages. The `.dark` class on flips these to the dark values below. Text over generated images keeps a literal text-white (handled in markup). */ --app-bg: rgb(250 250 251); /* page background */ --fg: rgb(15 23 42); /* primary heading/text */ --fg-2: rgb(15 23 42 / 0.62); /* body / secondary */ --fg-3: rgb(15 23 42 / 0.45); /* muted */ --fg-faint: rgb(15 23 42 / 0.3); /* labels / hints */ --surface: rgb(255 255 255 / 0.7); /* raised card on page bg */ --surface-2: rgb(15 23 42 / 0.035); /* subtle inset panel (counter cells) */ --hairline: rgb(15 23 42 / 0.08); /* borders / rings */ --hover: rgb(15 23 42 / 0.05); /* hover wash */ /* solid CTA button that sits on the page bg — inverts per theme */ --btn-solid-bg: rgb(15 23 42); --btn-solid-bg-h: rgb(30 41 59); --btn-solid-fg: #fff; --menu-bg: #ffffff; /* dropdown / popover panel */ } html.dark { --app-bg: #08090d; --fg: rgb(255 255 255 / 0.92); --fg-2: rgb(255 255 255 / 0.55); --fg-3: rgb(255 255 255 / 0.4); --fg-faint: rgb(255 255 255 / 0.3); --surface: rgb(255 255 255 / 0.03); --surface-2: rgb(255 255 255 / 0.04); --hairline: rgb(255 255 255 / 0.06); --hover: rgb(255 255 255 / 0.06); --btn-solid-bg: #fff; --btn-solid-bg-h: rgb(255 255 255 / 0.9); --btn-solid-fg: rgb(2 6 23); --menu-bg: #15171f; } /* Smooth the flip so toggling doesn't hard-cut. */ body, .theme-x { transition: background-color 0.25s ease, color 0.25s ease; } /* Footer CTA band — soft tinted panel that flips with the theme. */ .cta-band { background: radial-gradient(at 30% 20%, rgb(168 85 247 / 0.16) 0%, transparent 50%), radial-gradient(at 80% 70%, rgb(244 114 182 / 0.14) 0%, transparent 55%), linear-gradient(180deg, rgb(255 255 255), rgb(246 244 251)); } html.dark .cta-band { background: radial-gradient(at 30% 20%, rgb(168 85 247 / 0.35) 0%, transparent 50%), radial-gradient(at 80% 70%, rgb(244 114 182 / 0.3) 0%, transparent 55%), linear-gradient(180deg, #0f1117, #080a10); } /* ===== Light-mode rescue for hardcoded-dark pages ===== The admin shell + settings/workbench views were authored dark with literal text-white / white-alpha / bg-white utilities (not the slate system). In LIGHT mode, remap those neutral whites to the dark-on-light palette. Scoped to a `.theme-text` wrapper so the marketing homepage's over-image whites are never touched. Un-layered, so these win over Tailwind's @layer utilities. */ html:not(.dark) .theme-text :is(.text-white, [class*="text-white/9"], [class*="text-white/8"]) { color: rgb(15 23 42 / 0.95); } html:not(.dark) .theme-text :is([class*="text-white/7"], [class*="text-white/6"]) { color: rgb(15 23 42 / 0.7); } html:not(.dark) .theme-text :is([class*="text-white/5"], [class*="text-white/4"]) { color: rgb(15 23 42 / 0.52); } html:not(.dark) .theme-text :is([class*="text-white/3"], [class*="text-white/2"], [class*="text-white/1"]) { color: rgb(15 23 42 / 0.4); } html:not(.dark) .theme-text [class*="bg-white/"] { background-color: var(--surface-2); } html:not(.dark) .theme-text [class*="border-white/"] { border-color: var(--hairline); } html:not(.dark) .theme-text [class*="ring-white/"] { --tw-ring-color: var(--hairline); } /* White placeholders (placeholder:text-white/30 etc.) — the rescue above only recolors element text, not the ::placeholder pseudo. */ html:not(.dark) .theme-text [class*="placeholder:text-white"]::placeholder { color: var(--fg-faint); } /* Exception: "selected" pills / dark buttons keep their white text. They paint a genuinely dark surface (bg-slate-900/800, bg-black) so the rescue must NOT flip their text to dark — that's where it goes invisible. */ html:not(.dark) .theme-text :is([class*="bg-slate-900"], [class*="bg-slate-800"], [class*="bg-black"])[class*="text-white"] { color: #fff !important; } /* Pastel -200/-300 accent text (labels, KPI numbers, badges) is tuned for a dark shell and washes out on white. In LIGHT mode, darken to the -600 tone. The matcher also catches the /80 opacity variants. Badges keep their pale tinted bg (bg-*-500/10) which reads fine on white. */ html:not(.dark) .theme-text :is([class*="text-indigo-300"], [class*="text-indigo-200"]) { color: rgb(79 70 229); } html:not(.dark) .theme-text :is([class*="text-violet-300"], [class*="text-violet-200"]) { color: rgb(124 58 237); } html:not(.dark) .theme-text :is([class*="text-fuchsia-300"], [class*="text-fuchsia-200"]) { color: rgb(192 38 211); } html:not(.dark) .theme-text :is([class*="text-emerald-300"], [class*="text-emerald-200"]) { color: rgb(5 150 105); } html:not(.dark) .theme-text :is([class*="text-sky-300"], [class*="text-sky-200"]) { color: rgb(2 132 199); } html:not(.dark) .theme-text :is([class*="text-amber-300"], [class*="text-amber-200"]) { color: rgb(217 119 6); } html:not(.dark) .theme-text :is([class*="text-rose-300"], [class*="text-rose-200"]) { color: rgb(225 29 72); } html:not(.dark) .theme-text :is([class*="text-teal-300"], [class*="text-teal-200"]) { color: rgb(13 148 136); } /* Per-view scoped pills / buttons / chips hardcode white for the dark shell. Recolor them centrally in light mode — the extra .theme-text class outranks the scoped `.x[data-v-*]` rules. Dark mode keeps the scoped look (gated on :not(.dark)). */ html:not(.dark) .theme-text :is(.fp, .pg, .act, .filter-pill, .kind-btn, .preset-btn, .opt, .chip-x, .ro-chip) { color: var(--fg-2); background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--hairline); } html:not(.dark) .theme-text :is(.fp, .pg, .act, .filter-pill, .kind-btn, .preset-btn, .opt, .chip-x):hover { color: var(--fg); background: var(--hover); } html:not(.dark) .theme-text :is(.fp-on, .pg-on, .seg-on, .opt-on) { background: rgb(15 23 42); color: #fff; box-shadow: none; } /* Tag chips (TagInput) — near-white violet text is unreadable on white; keep the violet tint but switch the label to dark ink. */ html:not(.dark) .theme-text .chip { color: rgb(15 23 42 / 0.9); } html:not(.dark) .theme-text .chip .chip-x { color: rgb(15 23 42 / 0.55); background: transparent; box-shadow: none; } html:not(.dark) .theme-text .chip .chip-x:hover { color: #fff; background: rgb(244 63 94 / 0.6); } /* ShowcaseView marks the selected filter/kind tab with an `.on` modifier on `.filter-pill`/`.kind-btn` (not the `-on` class above). Without this, the neutral `.filter-pill`/`.kind-btn` rescue paints selected == unselected and the highlight vanishes on a white page. Equal-or-higher specificity, later. */ html:not(.dark) .theme-text :is(.filter-pill, .kind-btn).on { background: rgb(15 23 42); color: #fff; box-shadow: none; } /* Selected COLORED filter pills — their scoped (dark) selected colors get overridden by the neutral `.fp` rescue above, so re-state a light-mode variant (tinted bg + dark-enough text + colored ring) with equal specificity placed later, so the selection reads on a white page. */ html:not(.dark) .theme-text .fp-emerald { background: rgb(16 185 129 / 0.14); color: rgb(4 120 87); box-shadow: inset 0 0 0 1px rgb(16 185 129 / 0.45); } html:not(.dark) .theme-text .fp-rose { background: rgb(244 63 94 / 0.12); color: rgb(190 18 60); box-shadow: inset 0 0 0 1px rgb(244 63 94 / 0.45); } html:not(.dark) .theme-text .fp-fuchsia { background: rgb(217 70 239 / 0.12); color: rgb(162 28 175); box-shadow: inset 0 0 0 1px rgb(217 70 239 / 0.45); } html:not(.dark) .theme-text .fp-amber { background: rgb(245 158 11 / 0.16); color: rgb(180 83 9); box-shadow: inset 0 0 0 1px rgb(245 158 11 / 0.5); } html:not(.dark) .theme-text .fp-violet { background: rgb(139 92 246 / 0.14); color: rgb(109 40 217); box-shadow: inset 0 0 0 1px rgb(139 92 246 / 0.45); } html:not(.dark) .theme-text .fp-purple { background: rgb(168 85 247 / 0.14); color: rgb(107 33 168); box-shadow: inset 0 0 0 1px rgb(168 85 247 / 0.45); } html:not(.dark) .theme-text .fp-slate { background: rgb(100 116 139 / 0.14); color: rgb(51 65 85); box-shadow: inset 0 0 0 1px rgb(100 116 139 / 0.45); } html:not(.dark) .theme-text .fp-sky { background: rgb(14 165 233 / 0.14); color: rgb(3 105 161); box-shadow: inset 0 0 0 1px rgb(14 165 233 / 0.45); } html:not(.dark) .theme-text .fp-teal { background: rgb(20 184 166 / 0.14); color: rgb(15 118 110); box-shadow: inset 0 0 0 1px rgb(20 184 166 / 0.45); } /* Custom checkbox for admin tables (). Replaces the plain accent-color box with a rounded, branded one + white check. Neutral border + transparent bg so it reads on both the dark admin shell and light mode; fills fuchsia when checked. */ .chk { appearance: none; -webkit-appearance: none; width: 1rem; height: 1rem; flex: none; border-radius: 0.3rem; border: 1.5px solid rgb(148 163 184 / 0.55); background: transparent; cursor: pointer; display: inline-grid; place-content: center; vertical-align: middle; transition: background 0.15s, border-color 0.15s; } .chk:hover:not(:checked) { border-color: rgb(217 70 239 / 0.7); } .chk:checked { background: rgb(217 70 239); border-color: rgb(217 70 239); } .chk:checked::after { content: ""; width: 0.3rem; height: 0.55rem; border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg); margin-top: -0.12rem; } .chk:focus-visible { outline: 2px solid rgb(217 70 239 / 0.45); outline-offset: 1px; } /* Account identity tags (AccountsView: 子号 / 母号 / 普号 / 限额). The colors live here rather than as inline dark-palette utilities, which were invisible on the light theme: light values first, html.dark override after. */ .acct-tag { display: inline-flex; align-items: center; flex-shrink: 0; padding: 0.1rem 0.35rem; border-radius: 0.25rem; font-size: 10px; line-height: 1.5; font-weight: 500; white-space: nowrap; } .acct-tag-sub { background: rgb(14 165 233 / 0.14); color: rgb(3 105 161); box-shadow: inset 0 0 0 1px rgb(14 165 233 / 0.4); } .acct-tag-master { background: rgb(139 92 246 / 0.14); color: rgb(109 40 217); box-shadow: inset 0 0 0 1px rgb(139 92 246 / 0.4); } .acct-tag-free { background: rgb(100 116 139 / 0.14); color: rgb(51 65 85); box-shadow: inset 0 0 0 1px rgb(100 116 139 / 0.4); } .acct-tag-limit { background: rgb(245 158 11 / 0.16); color: rgb(180 83 9); box-shadow: inset 0 0 0 1px rgb(245 158 11 / 0.4); } html.dark .acct-tag-sub { background: rgb(14 165 233 / 0.18); color: rgb(125 211 252); box-shadow: inset 0 0 0 1px rgb(56 189 248 / 0.35); } html.dark .acct-tag-master { background: rgb(139 92 246 / 0.22); color: rgb(196 181 253); box-shadow: inset 0 0 0 1px rgb(167 139 250 / 0.35); } html.dark .acct-tag-free { background: rgb(148 163 184 / 0.22); color: rgb(226 232 240); box-shadow: inset 0 0 0 1px rgb(148 163 184 / 0.35); } html.dark .acct-tag-limit { background: rgb(245 158 11 / 0.18); color: rgb(252 211 77); box-shadow: inset 0 0 0 1px rgb(251 191 36 / 0.35); } /* Capability chips (ModelsView): all variants need bg + ring + color reset in light mode. The scoped dark-shell values (white-alpha bg/ring, pale text) are invisible on white. */ html:not(.dark) .theme-text .cap-emerald { background: rgb(16 185 129 / 0.12); color: rgb(4 120 87); box-shadow: inset 0 0 0 1px rgb(16 185 129 / 0.4); } html:not(.dark) .theme-text .cap-amber { background: rgb(245 158 11 / 0.12); color: rgb(180 83 9); box-shadow: inset 0 0 0 1px rgb(245 158 11 / 0.45); } html:not(.dark) .theme-text :is(.cap-slate, .cap-mono, .seg) { color: var(--fg-2); background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--hairline); } /* Price chips (ModelsView): the white-alpha bg/ring disappear on a white card. */ html:not(.dark) .theme-text .price-chip { background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--hairline); } /* fp-white selected pill: on white bg the all-white fill vanishes — use a neutral dark variant. */ html:not(.dark) .theme-text .fp-white { background: var(--surface-2); color: var(--fg-2); box-shadow: inset 0 0 0 1px var(--hairline); } /* label / hint text classes (form labels in modals & config) */ html:not(.dark) .theme-text .lbl { color: var(--fg); } html:not(.dark) .theme-text :is(.hint, .flbl) { color: var(--fg-3); } /* Delete icon button: a clean neutral button with a red glyph (not a heavy pink box), filling solid red on hover. */ html:not(.dark) .theme-text .act.danger { color: rgb(225 29 72); background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--hairline); } html:not(.dark) .theme-text .act.danger:hover { color: #fff; background: rgb(244 63 94); box-shadow: inset 0 0 0 1px rgb(225 29 72); } /* Soft "danger" toolbar buttons (删除选中 / 删除异常账号 …): a muted red, not a heavy pink fill; solid red on hover. Outranks the per-view scoped pink. */ html:not(.dark) .theme-text .btn-soft.danger { color: rgb(190 18 60); background: rgb(244 63 94 / 0.08); box-shadow: inset 0 0 0 1px rgb(244 63 94 / 0.22); } html:not(.dark) .theme-text .btn-soft.danger:hover { color: #fff; background: rgb(225 29 72); box-shadow: none; } /* ===== Media card ===== An image/video thumbnail whose overlay text sits ON the media — it must stay white even when the surrounding page is in LIGHT mode. The page itself stays light; only these cards keep the dark-on-image treatment. */ html:not(.dark) .media-card :is(.text-white, [class*="text-white/9"], [class*="text-white/8"], [class*="text-white/7"], [class*="text-white/6"]) { color: rgb(255 255 255 / 0.95) !important; } html:not(.dark) .media-card :is([class*="text-white/5"], [class*="text-white/4"]) { color: rgb(255 255 255 / 0.6) !important; } html:not(.dark) .media-card :is([class*="text-white/3"], [class*="text-white/2"]) { color: rgb(255 255 255 / 0.45) !important; } html:not(.dark) .media-card [class*="bg-white/"] { background-color: rgb(255 255 255 / 0.12) !important; } html:not(.dark) .media-card :is([class*="border-white/"], [class*="ring-white/"]) { border-color: rgb(255 255 255 / 0.12) !important; --tw-ring-color: rgb(255 255 255 / 0.12) !important; } /* Accent text inside a media-card sits on dark imagery too — keep it at its bright (dark-mode) shade instead of the darkened light-theme rescue above. */ html:not(.dark) .media-card :is([class*="text-emerald-3"], [class*="text-emerald-2"]) { color: rgb(110 231 183) !important; } html:not(.dark) .media-card :is([class*="text-fuchsia-3"], [class*="text-fuchsia-2"]) { color: rgb(240 171 252) !important; } html:not(.dark) .media-card :is([class*="text-indigo-3"], [class*="text-indigo-2"]) { color: rgb(165 180 252) !important; } html:not(.dark) .media-card :is([class*="text-violet-3"], [class*="text-violet-2"]) { color: rgb(196 181 253) !important; } html:not(.dark) .media-card :is([class*="text-sky-3"], [class*="text-sky-2"]) { color: rgb(125 211 252) !important; } html:not(.dark) .media-card :is([class*="text-amber-3"], [class*="text-amber-2"]) { color: rgb(252 211 77) !important; } /* Code example blocks (docs) read like an editor — solid dark surface in BOTH themes. Paired with .media-card so the code/title text stays light in light mode instead of being darkened by the rescue above. */ .doc-code { background-color: #0f172a; } /* `.public-dark code` gives the inner its faint highlight in dark mode; doc-code is dark in BOTH themes, so re-apply the same in light mode. */ html:not(.dark) .doc-code code { background: rgb(255 255 255 / 0.08); color: rgb(255 255 255 / 0.9); } html { scroll-behavior: smooth; /* Kill the bounce/glow when scrolling past the top or bottom of any scroll surface (the dark admin shell has fixed viewport height and we don't want a rubber-band-y feel at the edges of inner scroll areas). */ overscroll-behavior: none; } body { margin: 0; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; overscroll-behavior: none; /* Subtle ambient gradient + grain (used by PublicLayout via .ambient-bg) */ } ::selection { background: rgb(99 102 241 / 0.22); color: rgb(15 23 42); } /* Tailwind v4 / preflight leaves