WebHooker/app/assets/css/main.css
RhenCloud c75567cf15
feat: migrate to Tailwind CSS v4
Replace @nuxtjs/tailwindcss with @tailwindcss/vite, move theme
tokens into @theme inline in main.css, drop tailwind.config.ts.
2026-08-27 00:26:17 +08:00

1276 lines
28 KiB
CSS

@import "tailwindcss";
/* ---------------------------------------------------------------------------
* Theme tokens — RGB triplets so Tailwind opacity modifiers (bg-accent/10)
* work against them; values switch automatically with prefers-color-scheme
* (unless an explicit data-theme="light" is set on <html>).
* ------------------------------------------------------------------------- */
@theme inline {
--font-ui: "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
--font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
--radius-sm: 8px;
--radius: 12px;
--shadow-card: 0 1px 2px rgba(15, 23, 42, 0.04), 0 8px 24px rgba(15, 23, 42, 0.06);
--shadow-card-hover: 0 8px 24px -12px rgba(15, 23, 42, 0.25);
--shadow-accent-lg: 0 12px 28px -10px rgb(var(--accent));
--shadow-drawer: -16px 0 48px rgba(15, 23, 42, 0.12);
--shadow-modal: 0 12px 40px rgba(15, 23, 42, 0.25);
--animate-rise: rise 0.35s cubic-bezier(0.2, 0.7, 0.2, 1) both;
--color-bg: rgb(var(--bg));
--color-surface: rgb(var(--surface));
--color-surface-2: rgb(var(--surface-2));
--color-surface-3: rgb(var(--surface-3));
--color-border: rgb(var(--border));
--color-border-strong: rgb(var(--border-strong));
--color-text: rgb(var(--text));
--color-muted: rgb(var(--muted));
--color-faint: rgb(var(--faint));
--color-accent: rgb(var(--accent));
--color-accent-strong: rgb(var(--accent-strong));
--color-accent-dim: rgb(var(--accent-dim));
--color-accent-text: rgb(var(--accent-text));
--color-accent-border: rgb(var(--accent-border));
--color-ok: rgb(var(--ok));
--color-ok-dim: rgb(var(--ok-dim));
--color-warn: rgb(var(--warn));
--color-warn-dim: rgb(var(--warn-dim));
--color-bad: rgb(var(--bad));
--color-bad-dim: rgb(var(--bad-dim));
--color-info: rgb(var(--info));
--color-info-dim: rgb(var(--info-dim));
--color-body-text: rgb(var(--body-text));
--color-code-bg: rgb(var(--code-bg));
}
@keyframes rise {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
:root {
color-scheme: light;
--header-bg: rgba(255, 255, 255, 0.82);
--scrim: rgba(15, 23, 42, 0.4);
--knob: #ffffff;
--dot: rgba(15, 23, 42, 0.05);
--shadow: 0 1px 2px rgba(15, 23, 42, 0.04), 0 8px 24px rgba(15, 23, 42, 0.06);
--bg: 246 247 249;
--surface: 255 255 255;
--surface-2: 243 244 246;
--surface-3: 236 238 242;
--border: 230 232 236;
--border-strong: 212 216 222;
--text: 15 23 42;
--muted: 91 100 114;
--faint: 154 163 178;
--accent: 79 70 229;
--accent-strong: 67 56 202;
--accent-dim: 238 242 255;
--accent-text: 55 48 163;
--accent-border: 224 231 255;
--ok: 22 163 74;
--ok-dim: 236 253 243;
--warn: 180 83 9;
--warn-dim: 254 243 199;
--bad: 220 38 38;
--bad-dim: 254 242 242;
--info: 37 99 235;
--info-dim: 239 246 255;
--body-text: 48 54 61;
--code-bg: 240 241 243;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
color-scheme: dark;
--header-bg: rgba(15, 20, 28, 0.82);
--scrim: rgba(2, 6, 12, 0.6);
--knob: #dfe4ee;
--dot: rgba(148, 163, 184, 0.08);
--shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 12px 32px rgba(0, 0, 0, 0.5);
--bg: 11 15 23;
--surface: 19 26 36;
--surface-2: 26 34 48;
--surface-3: 35 45 61;
--border: 39 49 67;
--border-strong: 56 70 96;
--text: 230 233 239;
--muted: 154 166 184;
--faint: 107 119 137;
--accent: 99 102 241;
--accent-strong: 129 140 248;
--accent-dim: 28 33 64;
--accent-text: 199 210 254;
--accent-border: 47 55 102;
--ok: 34 197 94;
--ok-dim: 16 36 26;
--warn: 251 191 36;
--warn-dim: 42 36 16;
--bad: 240 82 82;
--bad-dim: 42 22 24;
--info: 59 130 246;
--info-dim: 23 37 84;
--body-text: 195 202 214;
--code-bg: 26 34 48;
}
}
@layer base {
html,
body {
height: 100%;
}
body {
@apply min-h-screen bg-bg text-text font-ui text-sm leading-[1.55] antialiased;
}
body::before {
content: "";
position: fixed;
inset: 0;
z-index: 0;
pointer-events: none;
background-image: radial-gradient(var(--dot) 1px, transparent 1px);
background-size: 22px 22px;
mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.6), transparent 40%);
}
}
@layer components {
/* ---- Layout ---- */
.shell {
@apply relative z-[1] min-h-screen;
}
.header {
@apply sticky top-0 z-20 flex items-center justify-between gap-4 px-8 py-3.5 border-b border-border;
background: var(--header-bg);
backdrop-filter: blur(12px);
}
.brand {
@apply flex items-center gap-3;
}
.brand-mark {
@apply grid place-items-center h-[38px] w-[38px] rounded-[10px] bg-accent text-white font-extrabold text-[15px] tracking-wide;
}
.brand h1 {
@apply text-lg font-extrabold tracking-tight;
}
.tagline {
@apply mt-px block text-[10px] font-semibold uppercase tracking-[2.5px] text-faint;
}
.main {
@apply relative z-[1] mx-auto max-w-[1040px] px-8 pb-24 pt-8 max-sm:px-4 max-sm:pb-20 max-sm:pt-5;
}
/* ---- Buttons ---- */
.btn {
@apply inline-flex cursor-pointer items-center justify-center gap-2 rounded-sm border border-border-strong bg-surface px-4 py-2 font-ui text-[13px] font-semibold text-text no-underline transition-[border-color,background,color,transform] duration-150;
}
.btn:hover {
@apply border-accent text-accent;
}
.btn:active {
@apply translate-y-px;
}
.btn:disabled {
@apply cursor-not-allowed opacity-50;
}
.btn-accent {
@apply border-accent bg-accent text-white;
}
.btn-accent:hover {
@apply border-accent-strong bg-accent-strong text-white;
}
.btn-ghost {
@apply border-transparent bg-transparent;
}
.btn-ghost:hover {
@apply border-transparent bg-surface-2 text-text;
}
.btn-sm {
@apply px-3 py-1.5 text-xs;
}
.btn-lg {
@apply px-6 py-3 text-sm;
}
.icon-btn {
@apply grid h-[30px] w-[30px] place-items-center cursor-pointer rounded-sm border border-border bg-transparent text-[13px] text-muted transition-all duration-150;
}
.icon-btn:hover {
@apply border-accent bg-accent-dim text-accent;
}
.icon-btn:disabled {
@apply cursor-not-allowed opacity-35;
}
.icon-btn:disabled:hover {
@apply border-border bg-transparent text-muted;
}
.icon-btn.danger:hover {
@apply border-bad bg-bad-dim text-bad;
}
/* ---- Cards ---- */
.card {
@apply animate-rise rounded border border-border bg-surface p-5 transition-[border-color,transform] duration-150;
}
.card:hover {
@apply border-border-strong;
}
.card.disabled {
@apply opacity-55;
}
.card-head {
@apply flex items-start justify-between gap-3.5;
}
.card-title {
@apply flex flex-wrap items-center gap-2.5;
}
.route-name {
@apply text-base font-bold tracking-tight;
}
.route-id {
@apply font-mono text-xs text-faint;
}
.badge {
@apply inline-block rounded-full bg-surface-2 px-2 py-0.5 text-[11px] font-semibold text-muted;
}
.badge.lang {
@apply bg-accent-dim text-accent-text;
}
.badge.fallback {
@apply bg-warn-dim text-warn;
}
.badge.stop {
@apply bg-bad-dim text-bad;
}
.card-actions {
@apply flex flex-shrink-0 gap-1.5;
}
/* ---- Route cards ---- */
.route-card {
@apply flex animate-rise items-start gap-4 rounded border border-border bg-surface p-4 transition-[border-color,opacity] duration-150;
}
.route-card:hover {
@apply border-border-strong;
}
.route-card.disabled {
@apply opacity-50;
}
.route-card-main {
@apply min-w-0 flex-1 space-y-3;
}
.route-card-header {
@apply flex flex-wrap items-center gap-2.5;
}
.route-card-title {
@apply flex min-w-0 items-center gap-2;
}
.route-card-badges {
@apply ml-auto flex flex-wrap items-center gap-1.5;
}
.route-badge {
@apply inline-flex items-center gap-1 rounded-full border border-border px-2 py-0.5 text-[10.5px] font-semibold;
}
.route-badge-dot {
@apply inline-block h-1.5 w-1.5 rounded-full;
}
.route-badge-dc {
@apply bg-accent-dim/30 text-accent-text;
}
.route-badge-tg {
@apply bg-info-dim/30 text-info;
}
.route-badge-fallback {
@apply border-warn/30 bg-warn-dim/20 text-warn;
}
.route-badge-stop {
@apply border-bad/30 bg-bad-dim/20 text-bad;
}
.route-badge-role {
@apply border-accent/30 bg-accent-dim/20 text-accent-text;
}
.route-card-filters {
@apply flex flex-wrap gap-1.5;
}
.route-chip {
@apply inline-flex items-center gap-1 rounded border border-border bg-surface-2 px-2 py-0.5 text-[11px];
}
.route-chip-type {
@apply font-bold uppercase tracking-wider text-faint;
}
.route-chip-val {
@apply font-medium text-text;
}
.route-chip.exclude {
@apply border-bad/20 bg-bad-dim/20;
}
.route-chip.exclude .route-chip-type {
@apply text-bad;
}
.route-chip-empty {
@apply italic;
}
.route-card-targets {
@apply space-y-1.5;
}
.route-target {
@apply space-y-1;
}
.route-target-row {
@apply flex items-center gap-2 text-xs;
}
.route-target-label {
@apply shrink-0 rounded border border-border bg-surface-2 px-1.5 py-px text-[10px] font-bold uppercase tracking-wider text-faint;
}
.route-target-id {
@apply rounded-[5px] bg-surface-2 px-1.5 py-px font-mono text-[11.5px] leading-relaxed text-text;
}
.route-card-actions {
@apply flex shrink-0 flex-col gap-0.5;
}
.route-action-btn {
@apply flex h-7 w-7 items-center justify-center rounded text-muted transition-colors hover:bg-surface-2 hover:text-text disabled:pointer-events-none disabled:opacity-25;
}
.route-action-btn-danger:hover {
@apply bg-bad-dim/30 text-bad;
}
/* ---- Toggle switch ---- */
.switch {
@apply relative h-[22px] w-[38px] flex-shrink-0;
}
.switch input {
@apply h-0 w-0 opacity-0;
}
.switch .track {
@apply absolute inset-0 cursor-pointer rounded-full border border-border-strong bg-surface-3 transition-[background,border-color] duration-200;
}
.switch .track::after {
content: "";
position: absolute;
top: 2px;
left: 2px;
width: 16px;
height: 16px;
border-radius: 50%;
background: var(--knob);
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.2);
transition: transform 0.18s;
}
.switch input:checked + .track {
@apply border-accent bg-accent;
}
.switch input:checked + .track::after {
transform: translateX(16px);
}
/* ---- Filter chips ---- */
.chips {
@apply mt-3.5 flex flex-wrap gap-2;
}
.chip {
@apply inline-flex items-center gap-1.5 rounded-full bg-surface-2 px-2.5 py-1 text-xs;
}
.chip .f-type {
@apply text-[10px] font-bold uppercase tracking-wider text-faint;
}
.chip .f-val {
@apply font-medium text-text;
}
.chip.exclude {
@apply bg-bad-dim;
}
.chip.exclude .f-type {
@apply text-bad;
}
/* ---- Targets / meta ---- */
.target {
@apply mt-3 flex flex-wrap gap-x-[18px] gap-y-2 text-xs text-muted;
}
.target b {
@apply mr-1 font-semibold tracking-wider text-faint;
}
.target code {
@apply rounded-[5px] bg-surface-2 px-1.5 py-px font-mono text-text;
}
.empty {
@apply py-[72px] text-center text-muted;
}
.empty p {
@apply mb-4;
}
/* ---- Login ---- */
.login {
@apply grid min-h-[62vh] place-items-center;
}
.login-card {
@apply max-w-[420px] rounded-2xl border border-border bg-surface px-[52px] py-12 text-center;
}
.login-card h2 {
@apply mb-2.5 text-[22px] font-extrabold tracking-tight;
}
.login-card p {
@apply mb-6 leading-relaxed text-muted;
}
.login-card code {
@apply rounded-[5px] bg-accent-dim px-1.5 py-px font-mono text-accent;
}
/* ---- Drawer / overlay ---- */
.overlay {
@apply fixed inset-0 z-40 backdrop-blur-[2px];
background: var(--scrim);
}
.editor {
@apply fixed bottom-0 right-0 top-0 z-50 flex w-[min(520px,100vw)] flex-col border-l border-border bg-surface shadow-drawer;
}
.editor-head {
@apply flex items-center justify-between gap-3 border-b border-border px-6 py-4;
background: var(--header-bg);
backdrop-filter: blur(12px);
}
.editor-heading {
@apply flex min-w-0 flex-col gap-0.5;
}
.editor-eyebrow {
@apply text-[10px] font-bold uppercase tracking-[2px] text-accent;
}
.editor-head h2 {
@apply truncate text-base font-extrabold tracking-tight;
}
.editor-head .icon-btn {
@apply h-8 w-8 rounded-full;
}
.editor-body {
@apply flex-1 overflow-y-auto px-6 py-5;
scrollbar-width: thin;
scrollbar-color: var(--scrim) transparent;
}
.editor-section {
@apply mb-7;
}
.editor-section-title {
@apply mb-3.5 flex items-center gap-2.5 text-[10.5px] font-bold uppercase tracking-[1.5px] text-faint;
}
.editor-section-title::after {
content: "";
@apply h-px flex-1 bg-border;
}
.editor-foot {
@apply flex justify-end gap-2 border-t border-border bg-surface px-6 py-4;
box-shadow: 0 -8px 24px -16px rgba(15, 23, 42, 0.18);
}
/* ---- Forms ---- */
.field {
@apply mb-4;
}
.field > label {
@apply mb-1.5 block text-[11px] font-bold uppercase tracking-[1.2px] text-faint;
}
.lbl-note {
@apply font-medium normal-case tracking-normal text-faint;
}
.hint {
@apply mt-1.5 text-[11px] text-faint;
}
.err {
@apply mt-2 min-h-4 text-xs text-bad;
}
.input {
@apply w-full rounded-sm border border-border-strong bg-surface px-3 py-2.5 font-ui text-[13.5px] text-text transition-[border-color,box-shadow] duration-150;
}
.input:focus {
@apply border-accent outline-none ring-[3px] ring-accent-dim;
}
.select {
@apply w-full cursor-pointer rounded-sm border border-border-strong bg-surface px-3 py-2.5 font-ui text-[13.5px] text-text outline-none;
}
.select:focus {
@apply border-accent ring-[3px] ring-accent-dim;
}
.row2 {
@apply grid grid-cols-2 gap-3 max-sm:grid-cols-1;
}
.inline {
@apply flex items-center gap-2;
}
.inline input[type="checkbox"] {
@apply h-4 w-4 accent-accent;
}
.inline span {
@apply text-[12.5px] font-medium text-muted;
}
.templates {
@apply flex flex-wrap gap-1.5;
}
.template-chip {
@apply cursor-pointer rounded-full border border-border-strong bg-surface-2 px-3 py-1 font-ui text-xs font-semibold text-muted transition-[border-color,color,background] duration-150;
}
.template-chip:hover {
@apply border-accent text-accent;
}
.template-chip.active {
@apply border-accent bg-accent-dim text-accent;
}
.filter-row {
@apply mb-2 grid grid-cols-[130px_1fr_auto_auto] items-center gap-2 rounded-sm border border-border bg-surface-2 p-2.5 max-sm:grid-cols-[100px_1fr_auto];
}
.filter-row select {
@apply w-full rounded border border-border-strong bg-surface px-2 py-1.5 font-ui text-[12.5px] font-medium text-text;
}
.filter-row input[type="text"] {
@apply w-full;
}
.target-row {
@apply mb-2 grid grid-cols-[minmax(130px,1fr)_auto] items-center gap-2 rounded-sm border border-border bg-surface-2 p-2.5 max-sm:grid-cols-[1fr_auto];
grid-template-areas:
"select del"
"in1 in2";
}
.target-row select {
@apply w-full rounded border border-border-strong bg-surface px-2 py-1.5 font-ui text-[12.5px] font-medium text-text;
grid-area: select;
}
.target-row input.tg-in1 {
grid-area: in1;
}
.target-row input.tg-in2 {
grid-area: in2;
}
.target-row > .icon-btn {
grid-area: del;
justify-self: end;
}
.add-filter {
@apply mt-1 w-full justify-center;
}
.forge-source-row {
@apply mb-2 grid items-center gap-2 rounded-sm border border-border bg-surface-2 p-2.5;
grid-template-areas:
"host type del"
"name name name";
grid-template-columns: 1fr auto auto;
}
.forge-source-row .f-host {
grid-area: host;
}
.forge-source-row .select.forge-type {
grid-area: type;
@apply w-[110px];
}
.forge-source-row .f-name {
grid-area: name;
}
.forge-source-row > .icon-btn {
grid-area: del;
justify-self: end;
}
.node-editor {
@apply mb-1;
}
.node-nested {
@apply ml-4 border-l border-border pl-3;
}
.leaf-row {
@apply mb-1.5 flex flex-wrap items-center gap-2 rounded-sm border border-border bg-surface-2 p-2.5;
}
.node-select {
@apply w-[120px] shrink-0 rounded border border-border-strong bg-surface px-2 py-1.5 font-ui text-[12.5px] font-medium text-text;
}
.node-path {
@apply w-[160px] shrink-0;
}
.node-values {
@apply min-w-[180px] flex-1;
}
.node-exclude {
@apply flex shrink-0 cursor-pointer items-center gap-1.5 text-[12px] font-medium text-muted;
}
.node-group {
@apply mb-1.5 rounded-sm border border-border bg-surface-2 p-2.5;
}
.node-group-head {
@apply mb-2 flex flex-wrap items-center gap-2;
}
.node-combo {
@apply w-[130px] rounded border border-border-strong bg-surface px-2 py-1.5 font-ui text-[12.5px] font-semibold text-text;
}
.node-combo-label {
@apply inline-flex items-center rounded border border-border-strong bg-surface px-2 py-1.5 font-ui text-[12.5px] font-semibold text-text;
}
.node-actions {
@apply ml-auto flex flex-wrap items-center gap-1.5;
}
.node-add {
@apply px-2 py-1 text-[12px];
}
.node-children {
@apply flex flex-col gap-1.5;
}
.node-empty {
@apply py-1 text-[12px] italic text-muted;
}
.test-payload {
@apply font-mono text-[12px];
}
.test-result {
@apply mt-1 flex flex-col gap-1.5 rounded-sm border border-border bg-surface-2 p-2.5;
}
.test-result.ok {
@apply border-ok;
}
.test-badge {
@apply inline-flex w-fit items-center rounded-full bg-bad px-2 py-0.5 text-[11px] font-semibold text-white;
}
.test-result.ok .test-badge {
@apply bg-ok;
}
.test-explanation {
@apply font-mono text-[12px] text-muted;
}
.fragments-presets {
@apply mb-2 flex flex-col gap-1.5;
}
.fragments-list {
@apply mb-2 flex flex-col gap-1.5;
}
.fragment-row {
@apply flex items-center gap-2 rounded-sm border border-border bg-surface-2 p-2;
}
.fragment-name {
@apply min-w-0 flex-1 truncate text-[13px] font-medium text-text;
}
.fragment-action {
@apply shrink-0 px-2 py-1 text-[12px];
}
.fragment-save {
@apply flex items-center gap-2;
}
.log-block {
@apply max-h-72 overflow-auto whitespace-pre-wrap break-all rounded-sm border border-border bg-surface-2 p-2.5 font-mono text-[12px] leading-relaxed text-text;
}
/* ---- Toasts ---- */
.toasts {
@apply pointer-events-none fixed bottom-7 left-1/2 z-[60] flex -translate-x-1/2 flex-col items-center gap-2;
}
.toast {
@apply pointer-events-auto cursor-pointer rounded-full bg-text px-[18px] py-2.5 text-[13px] font-semibold text-white;
}
.toast.ok {
@apply bg-ok;
}
.toast.bad {
@apply bg-bad;
}
/* ---- Tabs ---- */
.tabs {
@apply mb-5 inline-flex gap-0.5 rounded-[10px] border border-border bg-surface-2 p-1;
}
.tab {
@apply cursor-pointer rounded-[7px] border-none bg-transparent px-4 py-1.5 font-ui text-[13px] font-semibold text-muted transition-[background,color] duration-150;
}
.tab:hover {
@apply text-text;
}
.tab.active {
@apply bg-surface text-accent shadow-[0_1px_3px_rgba(15,23,42,0.08)];
}
/* ---- Toolbar / KPIs ---- */
.toolbar {
@apply mb-[18px] flex items-center justify-between;
}
.crumbs {
@apply flex items-center gap-3;
}
.kpi-label {
@apply text-[11px] font-bold uppercase tracking-[1.5px] text-faint;
}
.kpi {
@apply ml-2 text-2xl font-extrabold tracking-tight text-accent;
}
.status {
@apply flex items-center gap-2 text-xs font-medium text-muted;
}
.dot {
@apply h-2 w-2 rounded-full bg-border-strong;
}
.dot.ok {
@apply bg-ok;
}
.dot.bad {
@apply bg-bad;
}
/* ---- Logs / audit ---- */
.log-toolbar {
@apply mb-3.5 flex flex-wrap items-center justify-between gap-3;
}
.log-filters {
@apply flex items-center gap-1.5;
}
.filter-label {
@apply text-[11px] font-bold uppercase tracking-wider text-muted;
}
.filter-select {
@apply cursor-pointer rounded border border-border bg-surface px-2 py-1 text-[13px] text-text outline-none;
}
.filter-select:focus {
@apply border-accent;
}
.log-list {
@apply flex flex-col gap-2.5;
}
.log-entry {
@apply rounded border border-border border-l-[3px] border-l-ok bg-surface p-4 transition-colors duration-150;
}
.log-entry:hover {
@apply border-border-strong;
}
.log-entry.fail {
@apply border-l-bad;
}
.log-entry.clickable {
@apply cursor-pointer;
}
.log-head {
@apply flex flex-wrap items-center gap-2.5;
}
.log-route {
@apply text-sm font-bold tracking-tight;
}
.log-event {
@apply rounded-full bg-accent-dim px-2.5 py-0.5 text-[11px] font-bold uppercase tracking-wide text-accent;
}
.log-time {
@apply ml-auto text-xs font-medium text-faint;
}
.log-meta {
@apply mt-2 flex flex-wrap gap-x-[18px] gap-y-1 text-xs text-muted;
}
.log-meta b {
@apply mr-1 font-semibold tracking-wider text-faint;
}
.log-meta code {
@apply rounded-[5px] bg-surface-2 px-1.5 py-px font-mono text-text;
}
.log-error {
@apply mt-2 rounded-sm bg-bad-dim px-2.5 py-2 text-xs font-medium break-all text-bad;
}
.empty-log {
@apply py-14 text-center text-faint;
}
.log-status {
@apply rounded-full px-2.5 py-0.5 text-[11px] font-bold tracking-wide;
}
.log-status.ok {
@apply bg-ok-dim text-ok;
}
.log-status.bad {
@apply bg-bad-dim text-bad;
}
.log-detail {
@apply max-h-[82vh] w-[calc(100vw-48px)] max-w-[720px] overflow-y-auto rounded border border-border bg-surface p-[22px] shadow-modal;
}
.modal-overlay {
@apply fixed inset-0 z-[60] flex items-center justify-center p-6 backdrop-blur-[2px];
background: var(--scrim);
}
.detail-head {
@apply mb-3.5 flex items-center justify-between;
}
.detail-head h3 {
@apply text-[15px] tracking-wide;
}
.detail-grid {
@apply grid grid-cols-[minmax(120px,30%)_1fr] gap-x-4 gap-y-1.5 text-[13px];
}
.detail-grid dt {
@apply pt-1.5 text-[11px] font-semibold tracking-wide text-faint;
}
.detail-grid dd {
@apply break-all pt-1.5 text-text;
}
.detail-grid code {
@apply rounded-[5px] bg-surface-2 px-1.5 py-0.5 font-mono text-xs;
}
.detail-grid dd code {
@apply whitespace-pre-wrap;
}
/* ---- Members / invites ---- */
.members-panel {
@apply mt-7 rounded border border-border bg-surface p-5;
}
.panel-head {
@apply mb-3 flex flex-wrap items-baseline gap-2.5;
}
.panel-head h3 {
@apply text-sm tracking-wide;
}
.members-panel h4 {
@apply my-3.5 mb-2 text-xs;
}
.member-list {
@apply m-0 mb-3 flex list-none flex-col gap-2 p-0;
}
.member-row,
.invite-row {
@apply flex flex-wrap items-center gap-2.5 rounded-sm border border-border bg-surface-2 px-3 py-2;
}
.member-login {
@apply min-w-[120px] flex-1 text-[13px] font-semibold;
}
.role-pill {
@apply rounded-full px-2.5 py-0.5 text-[11px] font-bold uppercase tracking-wide;
}
.role-pill.owner {
@apply bg-accent-dim text-accent;
}
.role-pill.admin {
@apply bg-ok-dim text-ok;
}
.role-pill.viewer {
@apply border border-border bg-surface text-faint;
}
.member-add,
.invite-create {
@apply flex flex-wrap items-center gap-2;
}
.text-input {
@apply min-w-[200px] rounded border border-border bg-surface px-2.5 py-1.5 text-[13px] text-text outline-none;
}
.text-input:focus {
@apply border-accent;
}
.invite-box {
@apply mt-3.5 border-t border-dashed border-border pt-1.5;
}
.invite-list {
@apply m-2.5 mb-0 flex list-none flex-col gap-2 p-0;
}
.invite-token {
@apply font-mono text-xs text-muted;
}
.invite-exp {
@apply text-xs text-faint;
}
/* ---- Legal pages ---- */
.legal-body h2 {
@apply mb-2 mt-7 text-[17px] font-bold;
}
.legal-body p,
.legal-body li {
@apply text-[15px] text-body-text;
}
.legal-body a {
@apply text-accent;
}
.legal-body ul {
@apply pl-5;
}
.legal-body code {
@apply rounded-[6px] border border-border bg-code-bg px-1.5 py-px font-mono text-[13px];
}
/* ---- Webhook panel ---- */
.webhook-panel .wh-row {
@apply mb-2 flex flex-wrap items-center gap-2.5;
}
.webhook-panel .wh-label {
@apply min-w-[52px] text-[11px] font-bold uppercase tracking-wider text-muted;
}
.webhook-panel .wh-value {
@apply min-w-[180px] flex-1 rounded-sm border border-border bg-surface-2 px-2.5 py-1.5 text-[12.5px] break-all;
}
.webhook-panel .wh-actions {
@apply mt-1.5 flex gap-2;
}
.webhook-panel .wh-usage {
@apply mt-3.5;
}
.webhook-panel .wh-usage summary {
@apply cursor-pointer text-xs text-muted;
}
.webhook-panel .wh-code {
@apply mt-2.5 overflow-x-auto rounded-sm border border-border bg-surface-2 p-3 text-[11.5px] leading-relaxed text-muted;
}
/* ---- Metrics / stats ---- */
.metric-kpis {
@apply mb-6 grid grid-cols-2 gap-3 max-md:grid-cols-1 sm:grid-cols-3;
}
.metric-kpi {
@apply rounded-sm border border-border bg-surface p-4;
}
.metric-kpi-value {
@apply block text-2xl font-extrabold tracking-tight tabular-nums;
}
.metric-kpi-label {
@apply mt-1 block text-[11px] font-bold uppercase tracking-[1.2px] text-faint;
}
.metric-kpi.accent .metric-kpi-value {
@apply text-accent;
}
.metric-kpi.ok .metric-kpi-value {
@apply text-ok;
}
.metric-kpi.bad {
@apply border-bad/30 bg-bad/5;
}
.metric-kpi.bad .metric-kpi-value {
@apply text-bad;
}
.metric-kpi.warn .metric-kpi-value {
@apply text-warn;
}
.metric-kpi.info .metric-kpi-value {
@apply text-info;
}
.metric-block {
@apply mb-4 rounded border border-border bg-surface p-5;
}
.metric-block-title {
@apply m-0 text-[11px] font-bold uppercase tracking-[1.2px] text-faint;
}
.metric-block-head {
@apply mb-3 flex items-center justify-between gap-2;
}
.metric-block-head .metric-block-title {
@apply mb-0;
}
.metric-sort-toggle {
@apply rounded px-2 py-0.5 text-[10px] font-bold uppercase tracking-wider text-faint transition-colors;
}
.metric-sort-toggle:hover {
@apply bg-surface-3 text-text;
}
.metric-row {
@apply flex items-center gap-3 border-t border-border py-2.5 first:border-t-0 max-sm:flex-wrap;
}
.metric-key {
@apply w-[110px] shrink-0 truncate font-mono text-[12.5px] text-text;
}
.metric-total {
@apply w-12 shrink-0 text-right text-xs font-semibold tabular-nums text-muted;
}
.metric-bar {
@apply flex h-5 flex-1 overflow-hidden rounded bg-surface-3;
}
.metric-fill {
@apply flex items-center justify-center text-[11px] font-bold tabular-nums leading-none text-white/90;
min-width: 0;
transition: flex 0.3s;
}
.metric-fill.ok {
@apply bg-ok;
}
.metric-fill.bad {
@apply bg-bad;
}
.metric-status-row {
@apply flex flex-wrap gap-1.5;
}
.metric-status {
@apply rounded-full px-2.5 py-0.5 text-[11px] font-bold tabular-nums tracking-wide;
}
.metric-status.ok {
@apply bg-ok-dim text-ok;
}
.metric-status.bad {
@apply bg-bad-dim text-bad;
}
}
/* ---- Vue transition glue (lifecycle classes) ---- */
.toast-enter-active,
.toast-leave-active {
transition:
opacity 0.22s,
transform 0.22s;
}
.toast-enter-from,
.toast-leave-to {
opacity: 0;
transform: translateY(12px);
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.2s;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.slide-enter-active,
.slide-leave-active {
transition: transform 0.28s cubic-bezier(0.32, 0.72, 0, 1);
}
.slide-enter-from,
.slide-leave-to {
transform: translateX(100%);
}