Extend the vnclagoon skin: solid navy login card, cyan hairline border, a thin cyan accent strip on top, soft cyan glow (dark), and an ambient cyan wash behind the card on the login page. Scoped to the login card's unique class combo. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1098 lines
43 KiB
TypeScript
1098 lines
43 KiB
TypeScript
import type { InstalledTheme } from './plugin-types';
|
|
|
|
const quiCSS = `
|
|
:root {
|
|
--color-border: #e4e4e7;
|
|
--color-input: #e4e4e7;
|
|
--color-ring: #3b82f6;
|
|
--color-background: #ffffff;
|
|
--color-foreground: #09090b;
|
|
--color-primary: #3b82f6;
|
|
--color-primary-foreground: #ffffff;
|
|
--color-secondary: #f4f4f5;
|
|
--color-secondary-foreground: #18181b;
|
|
--color-muted: #f4f4f5;
|
|
--color-muted-foreground: #71717a;
|
|
--color-accent: #dbeafe;
|
|
--color-accent-foreground: #1d4ed8;
|
|
--color-destructive: #ef4444;
|
|
--color-destructive-foreground: #ffffff;
|
|
--color-popover: #ffffff;
|
|
--color-popover-foreground: #09090b;
|
|
--color-sidebar: #fafafa;
|
|
--color-sidebar-foreground: #09090b;
|
|
--color-sidebar-border: #e4e4e7;
|
|
--color-sidebar-accent: #f4f4f5;
|
|
--color-sidebar-accent-foreground: #18181b;
|
|
--color-card: #ffffff;
|
|
--color-card-foreground: #09090b;
|
|
--color-success: #22c55e;
|
|
--color-success-foreground: #ffffff;
|
|
--color-warning: #eab308;
|
|
--color-warning-foreground: #ffffff;
|
|
--color-info: #3b82f6;
|
|
--color-info-foreground: #ffffff;
|
|
--color-selection: #dbeafe;
|
|
--color-selection-foreground: #1d4ed8;
|
|
--color-unread: #3b82f6;
|
|
--color-chart-1: #3b82f6;
|
|
--color-chart-2: #22c55e;
|
|
--color-chart-3: #f59e0b;
|
|
--color-chart-4: #ef4444;
|
|
--color-chart-5: #8b5cf6;
|
|
}
|
|
.dark {
|
|
--color-border: #27272a;
|
|
--color-input: #27272a;
|
|
--color-ring: #3b82f6;
|
|
--color-background: #09090b;
|
|
--color-foreground: #fafafa;
|
|
--color-primary: #3b82f6;
|
|
--color-primary-foreground: #ffffff;
|
|
--color-secondary: #18181b;
|
|
--color-secondary-foreground: #fafafa;
|
|
--color-muted: #18181b;
|
|
--color-muted-foreground: #a1a1aa;
|
|
--color-accent: #172554;
|
|
--color-accent-foreground: #93c5fd;
|
|
--color-destructive: #ef4444;
|
|
--color-destructive-foreground: #fafafa;
|
|
--color-popover: #18181b;
|
|
--color-popover-foreground: #fafafa;
|
|
--color-sidebar: #09090b;
|
|
--color-sidebar-foreground: #fafafa;
|
|
--color-sidebar-border: #27272a;
|
|
--color-sidebar-accent: #18181b;
|
|
--color-sidebar-accent-foreground: #fafafa;
|
|
--color-card: #141414;
|
|
--color-card-foreground: #fafafa;
|
|
--color-success: #16a34a;
|
|
--color-success-foreground: #ffffff;
|
|
--color-warning: #ca8a04;
|
|
--color-warning-foreground: #ffffff;
|
|
--color-info: #60a5fa;
|
|
--color-info-foreground: #ffffff;
|
|
--color-selection: rgba(59, 130, 246, 0.25);
|
|
--color-selection-foreground: #93c5fd;
|
|
--color-unread: #60a5fa;
|
|
--color-chart-1: #60a5fa;
|
|
--color-chart-2: #4ade80;
|
|
--color-chart-3: #fbbf24;
|
|
--color-chart-4: #f87171;
|
|
--color-chart-5: #a78bfa;
|
|
}`;
|
|
|
|
const nordCSS = `
|
|
:root {
|
|
--color-border: #d8dee9;
|
|
--color-input: #d8dee9;
|
|
--color-ring: #81a1c1;
|
|
--color-background: #eceff4;
|
|
--color-foreground: #2e3440;
|
|
--color-primary: #5e81ac;
|
|
--color-primary-foreground: #eceff4;
|
|
--color-secondary: #e5e9f0;
|
|
--color-secondary-foreground: #2e3440;
|
|
--color-muted: #d8dee9;
|
|
--color-muted-foreground: #4c566a;
|
|
--color-accent: #81a1c1;
|
|
--color-accent-foreground: #2e3440;
|
|
--color-destructive: #bf616a;
|
|
--color-destructive-foreground: #eceff4;
|
|
--color-popover: #eceff4;
|
|
--color-popover-foreground: #2e3440;
|
|
--color-sidebar: #e5e9f0;
|
|
--color-sidebar-foreground: #2e3440;
|
|
--color-sidebar-border: #d8dee9;
|
|
--color-sidebar-accent: #d8dee9;
|
|
--color-sidebar-accent-foreground: #2e3440;
|
|
--color-card: #eceff4;
|
|
--color-card-foreground: #2e3440;
|
|
--color-success: #a3be8c;
|
|
--color-success-foreground: #2e3440;
|
|
--color-warning: #ebcb8b;
|
|
--color-warning-foreground: #2e3440;
|
|
--color-info: #81a1c1;
|
|
--color-info-foreground: #eceff4;
|
|
--color-selection: #d8dee9;
|
|
--color-selection-foreground: #5e81ac;
|
|
--color-unread: #5e81ac;
|
|
--color-chart-1: #5e81ac;
|
|
--color-chart-2: #a3be8c;
|
|
--color-chart-3: #ebcb8b;
|
|
--color-chart-4: #bf616a;
|
|
--color-chart-5: #b48ead;
|
|
}
|
|
.dark {
|
|
--color-border: #3b4252;
|
|
--color-input: #3b4252;
|
|
--color-ring: #88c0d0;
|
|
--color-background: #2e3440;
|
|
--color-foreground: #eceff4;
|
|
--color-primary: #88c0d0;
|
|
--color-primary-foreground: #2e3440;
|
|
--color-secondary: #3b4252;
|
|
--color-secondary-foreground: #eceff4;
|
|
--color-muted: #3b4252;
|
|
--color-muted-foreground: #d8dee9;
|
|
--color-accent: #434c5e;
|
|
--color-accent-foreground: #88c0d0;
|
|
--color-destructive: #bf616a;
|
|
--color-destructive-foreground: #eceff4;
|
|
--color-popover: #3b4252;
|
|
--color-popover-foreground: #eceff4;
|
|
--color-sidebar: #2e3440;
|
|
--color-sidebar-foreground: #eceff4;
|
|
--color-sidebar-border: #3b4252;
|
|
--color-sidebar-accent: #3b4252;
|
|
--color-sidebar-accent-foreground: #eceff4;
|
|
--color-card: #3b4252;
|
|
--color-card-foreground: #eceff4;
|
|
--color-success: #a3be8c;
|
|
--color-success-foreground: #2e3440;
|
|
--color-warning: #ebcb8b;
|
|
--color-warning-foreground: #2e3440;
|
|
--color-info: #88c0d0;
|
|
--color-info-foreground: #2e3440;
|
|
--color-selection: rgba(136, 192, 208, 0.2);
|
|
--color-selection-foreground: #88c0d0;
|
|
--color-unread: #88c0d0;
|
|
--color-chart-1: #88c0d0;
|
|
--color-chart-2: #a3be8c;
|
|
--color-chart-3: #ebcb8b;
|
|
--color-chart-4: #bf616a;
|
|
--color-chart-5: #b48ead;
|
|
}`;
|
|
|
|
const catppuccinCSS = `
|
|
:root {
|
|
--color-border: #ccd0da;
|
|
--color-input: #ccd0da;
|
|
--color-ring: #8839ef;
|
|
--color-background: #eff1f5;
|
|
--color-foreground: #4c4f69;
|
|
--color-primary: #8839ef;
|
|
--color-primary-foreground: #eff1f5;
|
|
--color-secondary: #e6e9ef;
|
|
--color-secondary-foreground: #4c4f69;
|
|
--color-muted: #dce0e8;
|
|
--color-muted-foreground: #6c6f85;
|
|
--color-accent: #8839ef;
|
|
--color-accent-foreground: #eff1f5;
|
|
--color-destructive: #d20f39;
|
|
--color-destructive-foreground: #eff1f5;
|
|
--color-popover: #eff1f5;
|
|
--color-popover-foreground: #4c4f69;
|
|
--color-sidebar: #e6e9ef;
|
|
--color-sidebar-foreground: #4c4f69;
|
|
--color-sidebar-border: #ccd0da;
|
|
--color-sidebar-accent: #dce0e8;
|
|
--color-sidebar-accent-foreground: #4c4f69;
|
|
--color-card: #eff1f5;
|
|
--color-card-foreground: #4c4f69;
|
|
--color-success: #40a02b;
|
|
--color-success-foreground: #eff1f5;
|
|
--color-warning: #df8e1d;
|
|
--color-warning-foreground: #eff1f5;
|
|
--color-info: #1e66f5;
|
|
--color-info-foreground: #eff1f5;
|
|
--color-selection: #dce0e8;
|
|
--color-selection-foreground: #8839ef;
|
|
--color-unread: #8839ef;
|
|
--color-chart-1: #8839ef;
|
|
--color-chart-2: #40a02b;
|
|
--color-chart-3: #df8e1d;
|
|
--color-chart-4: #d20f39;
|
|
--color-chart-5: #1e66f5;
|
|
}
|
|
.dark {
|
|
--color-border: #45475a;
|
|
--color-input: #45475a;
|
|
--color-ring: #cba6f7;
|
|
--color-background: #1e1e2e;
|
|
--color-foreground: #cdd6f4;
|
|
--color-primary: #cba6f7;
|
|
--color-primary-foreground: #1e1e2e;
|
|
--color-secondary: #313244;
|
|
--color-secondary-foreground: #cdd6f4;
|
|
--color-muted: #313244;
|
|
--color-muted-foreground: #a6adc8;
|
|
--color-accent: #45475a;
|
|
--color-accent-foreground: #cba6f7;
|
|
--color-destructive: #f38ba8;
|
|
--color-destructive-foreground: #1e1e2e;
|
|
--color-popover: #313244;
|
|
--color-popover-foreground: #cdd6f4;
|
|
--color-sidebar: #1e1e2e;
|
|
--color-sidebar-foreground: #cdd6f4;
|
|
--color-sidebar-border: #45475a;
|
|
--color-sidebar-accent: #313244;
|
|
--color-sidebar-accent-foreground: #cdd6f4;
|
|
--color-card: #313244;
|
|
--color-card-foreground: #cdd6f4;
|
|
--color-success: #a6e3a1;
|
|
--color-success-foreground: #1e1e2e;
|
|
--color-warning: #f9e2af;
|
|
--color-warning-foreground: #1e1e2e;
|
|
--color-info: #89b4fa;
|
|
--color-info-foreground: #1e1e2e;
|
|
--color-selection: rgba(203, 166, 247, 0.2);
|
|
--color-selection-foreground: #cba6f7;
|
|
--color-unread: #cba6f7;
|
|
--color-chart-1: #cba6f7;
|
|
--color-chart-2: #a6e3a1;
|
|
--color-chart-3: #f9e2af;
|
|
--color-chart-4: #f38ba8;
|
|
--color-chart-5: #89b4fa;
|
|
}`;
|
|
|
|
const solarizedCSS = `
|
|
:root {
|
|
--color-border: #eee8d5;
|
|
--color-input: #eee8d5;
|
|
--color-ring: #268bd2;
|
|
--color-background: #fdf6e3;
|
|
--color-foreground: #657b83;
|
|
--color-primary: #268bd2;
|
|
--color-primary-foreground: #fdf6e3;
|
|
--color-secondary: #eee8d5;
|
|
--color-secondary-foreground: #586e75;
|
|
--color-muted: #eee8d5;
|
|
--color-muted-foreground: #93a1a1;
|
|
--color-accent: #268bd2;
|
|
--color-accent-foreground: #fdf6e3;
|
|
--color-destructive: #dc322f;
|
|
--color-destructive-foreground: #fdf6e3;
|
|
--color-popover: #fdf6e3;
|
|
--color-popover-foreground: #657b83;
|
|
--color-sidebar: #eee8d5;
|
|
--color-sidebar-foreground: #657b83;
|
|
--color-sidebar-border: #eee8d5;
|
|
--color-sidebar-accent: #eee8d5;
|
|
--color-sidebar-accent-foreground: #586e75;
|
|
--color-card: #fdf6e3;
|
|
--color-card-foreground: #657b83;
|
|
--color-success: #859900;
|
|
--color-success-foreground: #fdf6e3;
|
|
--color-warning: #b58900;
|
|
--color-warning-foreground: #fdf6e3;
|
|
--color-info: #268bd2;
|
|
--color-info-foreground: #fdf6e3;
|
|
--color-selection: #eee8d5;
|
|
--color-selection-foreground: #268bd2;
|
|
--color-unread: #268bd2;
|
|
--color-chart-1: #268bd2;
|
|
--color-chart-2: #859900;
|
|
--color-chart-3: #b58900;
|
|
--color-chart-4: #dc322f;
|
|
--color-chart-5: #6c71c4;
|
|
}
|
|
.dark {
|
|
--color-border: #073642;
|
|
--color-input: #073642;
|
|
--color-ring: #268bd2;
|
|
--color-background: #002b36;
|
|
--color-foreground: #839496;
|
|
--color-primary: #268bd2;
|
|
--color-primary-foreground: #002b36;
|
|
--color-secondary: #073642;
|
|
--color-secondary-foreground: #93a1a1;
|
|
--color-muted: #073642;
|
|
--color-muted-foreground: #586e75;
|
|
--color-accent: #073642;
|
|
--color-accent-foreground: #268bd2;
|
|
--color-destructive: #dc322f;
|
|
--color-destructive-foreground: #fdf6e3;
|
|
--color-popover: #073642;
|
|
--color-popover-foreground: #93a1a1;
|
|
--color-sidebar: #002b36;
|
|
--color-sidebar-foreground: #839496;
|
|
--color-sidebar-border: #073642;
|
|
--color-sidebar-accent: #073642;
|
|
--color-sidebar-accent-foreground: #93a1a1;
|
|
--color-card: #073642;
|
|
--color-card-foreground: #93a1a1;
|
|
--color-success: #859900;
|
|
--color-success-foreground: #002b36;
|
|
--color-warning: #b58900;
|
|
--color-warning-foreground: #002b36;
|
|
--color-info: #268bd2;
|
|
--color-info-foreground: #002b36;
|
|
--color-selection: rgba(38, 139, 210, 0.2);
|
|
--color-selection-foreground: #268bd2;
|
|
--color-unread: #268bd2;
|
|
--color-chart-1: #268bd2;
|
|
--color-chart-2: #859900;
|
|
--color-chart-3: #b58900;
|
|
--color-chart-4: #dc322f;
|
|
--color-chart-5: #6c71c4;
|
|
}`;
|
|
|
|
// Roundcube "Elastic" skin recreation.
|
|
//
|
|
// Colour tokens are lifted from skins/elastic/styles/colors.less (CC BY-SA):
|
|
// accent #37beff font #27353a border #ddd
|
|
// error #ff5552 success #41b849 warning #ffd452
|
|
// task-menu #2f3a3f (always dark, both modes)
|
|
// list-select tint(#37beff, 90%) -> #ebf8ff
|
|
// Dark mode mirrors @color-dark-* (background #21292c, font #c5d1d3, …).
|
|
const elasticCSS = `
|
|
:root {
|
|
--color-border: #dddddd;
|
|
--color-input: #ced4da;
|
|
--color-ring: #37beff;
|
|
--color-background: #ffffff;
|
|
--color-foreground: #27353a;
|
|
--color-primary: #37beff;
|
|
--color-primary-foreground: #ffffff;
|
|
--color-secondary: #f4f4f4;
|
|
--color-secondary-foreground: #27353a;
|
|
--color-muted: #f4f4f4;
|
|
--color-muted-foreground: #737677;
|
|
--color-accent: #e6f6ff;
|
|
--color-accent-foreground: #0070a8;
|
|
--color-destructive: #ff5552;
|
|
--color-destructive-foreground: #ffffff;
|
|
--color-popover: #ffffff;
|
|
--color-popover-foreground: #27353a;
|
|
--color-sidebar: #ffffff;
|
|
--color-sidebar-foreground: #27353a;
|
|
--color-sidebar-border: #dddddd;
|
|
--color-sidebar-accent: #ebf8ff;
|
|
--color-sidebar-accent-foreground: #27353a;
|
|
--color-card: #ffffff;
|
|
--color-card-foreground: #27353a;
|
|
--color-success: #41b849;
|
|
--color-success-foreground: #ffffff;
|
|
--color-warning: #ffd452;
|
|
--color-warning-foreground: #27353a;
|
|
--color-info: #37beff;
|
|
--color-info-foreground: #ffffff;
|
|
--color-selection: #ebf8ff;
|
|
--color-selection-foreground: #27353a;
|
|
--color-unread: #ffd452;
|
|
--color-chart-1: #37beff;
|
|
--color-chart-2: #41b849;
|
|
--color-chart-3: #ffd452;
|
|
--color-chart-4: #ff5552;
|
|
--color-chart-5: #9b59b6;
|
|
/* Elastic is a 14px Roboto skin with tighter list rows than Bulwark's default */
|
|
--font-size-base: 14px;
|
|
--list-item-height: 40px;
|
|
}
|
|
.dark {
|
|
--color-border: #4d6066;
|
|
--color-input: #4d6066;
|
|
--color-ring: #37beff;
|
|
--color-background: #21292c;
|
|
--color-foreground: #ffffff;
|
|
--color-primary: #37beff;
|
|
--color-primary-foreground: #ffffff;
|
|
--color-secondary: #2c373a;
|
|
--color-secondary-foreground: #ffffff;
|
|
--color-muted: #2c373a;
|
|
/* Roundcube keeps most text near the bright font colour, only true hints
|
|
dim out. Bulwark applies muted-foreground far more widely, so brighten it
|
|
toward @color-dark-font (#c5d1d3) to match Elastic's overall brightness. */
|
|
--color-muted-foreground: #b3bec1;
|
|
--color-accent: #374549;
|
|
--color-accent-foreground: #37beff;
|
|
--color-destructive: #ff5552;
|
|
--color-destructive-foreground: #ffffff;
|
|
--color-popover: #161b1d;
|
|
--color-popover-foreground: #ffffff;
|
|
--color-sidebar: #21292c;
|
|
--color-sidebar-foreground: #ffffff;
|
|
--color-sidebar-border: #4d6066;
|
|
--color-sidebar-accent: #374549;
|
|
--color-sidebar-accent-foreground: #c5d1d3;
|
|
--color-card: #1a2225;
|
|
--color-card-foreground: #ffffff;
|
|
--color-success: #41b849;
|
|
--color-success-foreground: #ffffff;
|
|
--color-warning: #ffd452;
|
|
--color-warning-foreground: #21292c;
|
|
--color-info: #37beff;
|
|
--color-info-foreground: #ffffff;
|
|
--color-selection: #374549;
|
|
--color-selection-foreground: #37beff;
|
|
--color-unread: #b88a00;
|
|
--color-chart-1: #37beff;
|
|
--color-chart-2: #41b849;
|
|
--color-chart-3: #ffd452;
|
|
--color-chart-4: #ff5552;
|
|
--color-chart-5: #b48ead;
|
|
}`;
|
|
|
|
// Component-level overrides that the colour tokens alone can't express:
|
|
// Roboto typography and Elastic's signature dark "task menu" rail (which is
|
|
// dark in both light and dark mode). Scoped under the skin body attribute so
|
|
// it cleanly detaches when the theme is switched off.
|
|
const elasticSkin = `
|
|
body[data-theme-skin="builtin-roundcube-elastic"] {
|
|
font-family: Roboto, "Helvetica Neue", "Segoe UI", Arial, "Noto Sans", sans-serif;
|
|
}
|
|
|
|
/* ── Task menu (left navigation rail) ─────────────────────────── */
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .w-14.bg-secondary {
|
|
background-color: #2f3a3f !important;
|
|
border-right: 1px solid rgba(0, 0, 0, 0.25) !important;
|
|
}
|
|
/* In dark mode the black hairline vanishes against the dark canvas - use a
|
|
light one so the rail still reads as a distinct column. (.dark lives on
|
|
<html>, so it must be an ancestor of the skinned <body>.) */
|
|
.dark body[data-theme-skin="builtin-roundcube-elastic"] .w-14.bg-secondary {
|
|
border-right-color: rgba(255, 255, 255, 0.1) !important;
|
|
}
|
|
/* Light icons + labels on the dark rail */
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .w-14.bg-secondary a,
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .w-14.bg-secondary button,
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .w-14.bg-secondary .text-muted-foreground {
|
|
color: #e7edee !important;
|
|
}
|
|
/* Hover slab */
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .w-14.bg-secondary a:hover,
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .w-14.bg-secondary button:hover {
|
|
background-color: #41525a !important;
|
|
color: #ffffff !important;
|
|
}
|
|
/* Selected task: brighter slab, accent-blue glyph (matches Elastic) */
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .w-14.bg-secondary .bg-primary\\/10 {
|
|
background-color: #41525a !important;
|
|
}
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .w-14.bg-secondary .text-primary {
|
|
color: #37beff !important;
|
|
}
|
|
|
|
/* ── Flatten Bulwark's soft radii to Elastic's Bootstrap-flat look ── */
|
|
/* Elastic uses ~4px corners on buttons/inputs/cards; rounded-full (pills,
|
|
avatars, toggles) is intentionally left alone. */
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .rounded-md,
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .rounded-lg,
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .rounded-xl,
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .rounded-2xl,
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .rounded-3xl,
|
|
body[data-theme-skin="builtin-roundcube-elastic"] input,
|
|
body[data-theme-skin="builtin-roundcube-elastic"] textarea,
|
|
body[data-theme-skin="builtin-roundcube-elastic"] button:not(.rounded-full) {
|
|
border-radius: 4px !important;
|
|
}
|
|
|
|
/* ── Unify panel backgrounds like Roundcube ───────────────────── */
|
|
/* In Elastic the folder list, message list and content pane all share one
|
|
canvas (white / dark); only the narrow task rail is dark. Bulwark's folder
|
|
sidebar uses \`bg-secondary\` (a grey panel), so repaint it with the main
|
|
background. The folder sidebar carries the \`border-r\` class; the dark task
|
|
rail uses \`bg-secondary\` WITHOUT it (inline-styled border), so this
|
|
qualifier leaves the rail dark. */
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .bg-secondary.border-r {
|
|
background-color: var(--color-background) !important;
|
|
}
|
|
/* The empty "No conversation selected" pane uses a muted diagonal gradient;
|
|
flatten it to the plain canvas so the content area is one solid colour. */
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .bg-gradient-to-br.from-muted\\/30.to-muted\\/50 {
|
|
background: var(--color-background) !important;
|
|
}
|
|
|
|
/* The message-viewer body sits on a faint muted backing (bg-muted/30); flatten
|
|
it to the plain canvas so the whole content pane - search bar, action
|
|
toolbar, mail header and body - is one uniform background colour. The
|
|
search/toolbar/header are bordered \`bg-background\` strips, so they already
|
|
match once we leave them untinted. */
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .bg-muted\\/30 {
|
|
background-color: var(--color-background) !important;
|
|
}
|
|
|
|
/* ── Elastic primary buttons (.btn-primary) ──────────────────── */
|
|
/* Solid accent fill, white label + icon, hairline border, focus halo. Light
|
|
= @color-main (#37beff); dark = @color-dark-main (darken 30% -> #006a9d)
|
|
with the bright #37beff outline, exactly like the on-switch. */
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .bg-primary.text-primary-foreground {
|
|
background-color: #37beff !important;
|
|
border: 1px solid #37beff !important;
|
|
color: #ffffff !important;
|
|
}
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .bg-primary.text-primary-foreground:hover {
|
|
background-color: #19b6fe !important;
|
|
border-color: #0bb0ff !important;
|
|
}
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .bg-primary.text-primary-foreground:focus-visible {
|
|
box-shadow: 0 0 0 0.2rem rgba(55, 190, 255, 0.3) !important;
|
|
}
|
|
.dark body[data-theme-skin="builtin-roundcube-elastic"] .bg-primary.text-primary-foreground {
|
|
background-color: #006a9d !important;
|
|
border-color: #37beff !important;
|
|
color: #ffffff !important;
|
|
}
|
|
.dark body[data-theme-skin="builtin-roundcube-elastic"] .bg-primary.text-primary-foreground:hover {
|
|
background-color: #0079b3 !important;
|
|
}
|
|
|
|
/* ── Elastic on/off switch (.custom-switch) ──────────────────── */
|
|
/* Track + knob restyled to the Bootstrap-derived Elastic switch. The toggle
|
|
is a [role="switch"] button with a single inner <span> knob. */
|
|
body[data-theme-skin="builtin-roundcube-elastic"] [role="switch"] {
|
|
background-color: #ced4da !important;
|
|
border: 1px solid #b8c0c8 !important;
|
|
}
|
|
body[data-theme-skin="builtin-roundcube-elastic"] [role="switch"] > span {
|
|
background-color: #ffffff !important;
|
|
}
|
|
body[data-theme-skin="builtin-roundcube-elastic"] [role="switch"][aria-checked="true"] {
|
|
background-color: #37beff !important;
|
|
border-color: #37beff !important;
|
|
}
|
|
.dark body[data-theme-skin="builtin-roundcube-elastic"] [role="switch"] {
|
|
background-color: #4d6066 !important;
|
|
border-color: #5d7077 !important;
|
|
}
|
|
.dark body[data-theme-skin="builtin-roundcube-elastic"] [role="switch"] > span {
|
|
background-color: #c5d1d3 !important;
|
|
}
|
|
.dark body[data-theme-skin="builtin-roundcube-elastic"] [role="switch"][aria-checked="true"] {
|
|
background-color: #006a9d !important;
|
|
border-color: #37beff !important;
|
|
}
|
|
|
|
/* ── Recipient name/email rendered as links (like Roundcube) ──── */
|
|
/* Sender + recipient triggers (RecipientPopover) sit at \`text-foreground\`
|
|
and only turn blue on hover; Elastic shows them link-blue at rest
|
|
(@color-link #00acff, brighter in dark). The three-class combo is unique
|
|
to these recipient buttons. */
|
|
body[data-theme-skin="builtin-roundcube-elastic"] button.hover\\:text-primary.hover\\:underline.cursor-pointer {
|
|
color: #00acff !important;
|
|
}
|
|
.dark body[data-theme-skin="builtin-roundcube-elastic"] button.hover\\:text-primary.hover\\:underline.cursor-pointer {
|
|
color: #37beff !important;
|
|
}
|
|
/* The sender's email address printed under the name is muted grey; Roundcube
|
|
shows it link-blue too. It's the div immediately after the name row
|
|
(.flex.items-center.flex-wrap), which the contact-card org line is not, so
|
|
this sibling selector scopes it to the sender email only. */
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .flex.items-center.flex-wrap + div.text-muted-foreground.truncate {
|
|
color: #00acff !important;
|
|
}
|
|
.dark body[data-theme-skin="builtin-roundcube-elastic"] .flex.items-center.flex-wrap + div.text-muted-foreground.truncate {
|
|
color: #37beff !important;
|
|
}
|
|
|
|
/* ── Elastic context / popup menus ───────────────────────────── */
|
|
/* Roundcube highlights the hovered menu entry with a solid accent fill and
|
|
white text (@color-menu-hover-background: @color-main, @color-menu-hover:
|
|
#fff) - the same in light and dark. */
|
|
body[data-theme-skin="builtin-roundcube-elastic"] [role="menu"] [role="menuitem"]:hover,
|
|
body[data-theme-skin="builtin-roundcube-elastic"] [role="menu"] [role="menuitem"]:focus,
|
|
body[data-theme-skin="builtin-roundcube-elastic"] [role="menu"] [role="menuitem"]:focus-visible {
|
|
background-color: #37beff !important;
|
|
color: #ffffff !important;
|
|
}
|
|
/* Icons (currentColor) and muted accessories (shortcuts, submenu chevron)
|
|
follow the white text on hover. */
|
|
body[data-theme-skin="builtin-roundcube-elastic"] [role="menu"] [role="menuitem"]:hover svg,
|
|
body[data-theme-skin="builtin-roundcube-elastic"] [role="menu"] [role="menuitem"]:focus svg,
|
|
body[data-theme-skin="builtin-roundcube-elastic"] [role="menu"] [role="menuitem"]:hover .text-muted-foreground {
|
|
color: #ffffff !important;
|
|
}
|
|
|
|
/* ── Elastic folder list: unread count as a rounded pill ─────── */
|
|
/* Roundcube shows the unread count in a small grey pill on the right, and no
|
|
badge at all when a folder has nothing unread. Bulwark renders plain
|
|
"unread / total" text; the counts container is
|
|
span.ml-2.flex-shrink-0.gap-1.items-baseline holding an unread span
|
|
(.font-semibold), an optional "/" (.text-muted-foreground/60) and the total
|
|
(.text-muted-foreground). Reshape it into a pill, drop the total + slash,
|
|
and hide the whole badge when there's no unread span. */
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .bg-secondary.border-r span.ml-2.flex-shrink-0.gap-1.items-baseline {
|
|
align-items: center !important;
|
|
justify-content: center;
|
|
min-width: 1.6rem;
|
|
height: 1.2rem;
|
|
padding: 0 0.45rem;
|
|
border-radius: 0.75rem;
|
|
background-color: #e4e8ea;
|
|
}
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .bg-secondary.border-r span.ml-2.flex-shrink-0.gap-1.items-baseline > span.text-muted-foreground,
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .bg-secondary.border-r span.ml-2.flex-shrink-0.gap-1.items-baseline > span.text-muted-foreground\\/60 {
|
|
display: none !important;
|
|
}
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .bg-secondary.border-r span.ml-2.flex-shrink-0.gap-1.items-baseline > span {
|
|
color: #5e6b70 !important;
|
|
font-weight: 600 !important;
|
|
}
|
|
/* No unread span -> no badge (matches Sent/Drafts in Roundcube). */
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .bg-secondary.border-r span.ml-2.flex-shrink-0.gap-1.items-baseline:not(:has(span.font-semibold)) {
|
|
display: none !important;
|
|
}
|
|
.dark body[data-theme-skin="builtin-roundcube-elastic"] .bg-secondary.border-r span.ml-2.flex-shrink-0.gap-1.items-baseline {
|
|
background-color: #3f4e55;
|
|
}
|
|
.dark body[data-theme-skin="builtin-roundcube-elastic"] .bg-secondary.border-r span.ml-2.flex-shrink-0.gap-1.items-baseline > span {
|
|
color: #c9d3d5 !important;
|
|
}
|
|
|
|
/* A slightly bolder accent bar on the selected folder, like Elastic. */
|
|
body[data-theme-skin="builtin-roundcube-elastic"] .bg-secondary.border-r .border-l-2.border-primary {
|
|
border-left-width: 3px !important;
|
|
}`;
|
|
|
|
// "Aurora Glass" - an ultra-modern glassmorphism skin. Vibrant indigo→cyan
|
|
// accents float over a fixed gradient-mesh canvas; every structural surface
|
|
// (nav rail, folder sidebar, cards, popovers, menus, dialogs, toolbars) is a
|
|
// translucent frosted pane with heavy backdrop-blur + saturation, hairline
|
|
// luminous borders and soft glow on the primary action.
|
|
//
|
|
// The colour tokens stay near-solid for legible text contrast; the frosted
|
|
// translucency + blur all live in the skin, where a single selector can pair
|
|
// an rgba background with the matching backdrop-filter.
|
|
const auroraCSS = `
|
|
:root {
|
|
--color-border: rgba(13, 18, 45, 0.10);
|
|
--color-input: rgba(13, 18, 45, 0.12);
|
|
--color-ring: #6d5cff;
|
|
--color-background: #eef1fb;
|
|
--color-foreground: #14162e;
|
|
--color-primary: #6d5cff;
|
|
--color-primary-foreground: #ffffff;
|
|
--color-secondary: #e3e7f7;
|
|
--color-secondary-foreground: #14162e;
|
|
--color-muted: #e7eaf6;
|
|
--color-muted-foreground: #5b6080;
|
|
--color-accent: #e0e7ff;
|
|
--color-accent-foreground: #4338ca;
|
|
--color-destructive: #f43f5e;
|
|
--color-destructive-foreground: #ffffff;
|
|
--color-popover: #ffffff;
|
|
--color-popover-foreground: #14162e;
|
|
--color-sidebar: #eef1fb;
|
|
--color-sidebar-foreground: #14162e;
|
|
--color-sidebar-border: rgba(13, 18, 45, 0.08);
|
|
--color-sidebar-accent: rgba(109, 92, 255, 0.10);
|
|
--color-sidebar-accent-foreground: #4338ca;
|
|
--color-card: #ffffff;
|
|
--color-card-foreground: #14162e;
|
|
--color-success: #10b981;
|
|
--color-success-foreground: #ffffff;
|
|
--color-warning: #f59e0b;
|
|
--color-warning-foreground: #14162e;
|
|
--color-info: #06b6d4;
|
|
--color-info-foreground: #ffffff;
|
|
--color-selection: rgba(109, 92, 255, 0.14);
|
|
--color-selection-foreground: #4338ca;
|
|
--color-unread: #6d5cff;
|
|
--color-chart-1: #6d5cff;
|
|
--color-chart-2: #06b6d4;
|
|
--color-chart-3: #ec4899;
|
|
--color-chart-4: #f59e0b;
|
|
--color-chart-5: #10b981;
|
|
}
|
|
.dark {
|
|
--color-border: rgba(255, 255, 255, 0.08);
|
|
--color-input: rgba(255, 255, 255, 0.10);
|
|
--color-ring: #8b7bff;
|
|
--color-background: #06070f;
|
|
--color-foreground: #eef0ff;
|
|
--color-primary: #8b7bff;
|
|
--color-primary-foreground: #ffffff;
|
|
--color-secondary: rgba(255, 255, 255, 0.06);
|
|
--color-secondary-foreground: #eef0ff;
|
|
--color-muted: rgba(255, 255, 255, 0.05);
|
|
--color-muted-foreground: #9aa0c4;
|
|
--color-accent: rgba(139, 123, 255, 0.16);
|
|
--color-accent-foreground: #c4bbff;
|
|
--color-destructive: #fb7185;
|
|
--color-destructive-foreground: #1a0b10;
|
|
--color-popover: #12132a;
|
|
--color-popover-foreground: #eef0ff;
|
|
--color-sidebar: #08091a;
|
|
--color-sidebar-foreground: #eef0ff;
|
|
--color-sidebar-border: rgba(255, 255, 255, 0.07);
|
|
--color-sidebar-accent: rgba(139, 123, 255, 0.18);
|
|
--color-sidebar-accent-foreground: #c4bbff;
|
|
--color-card: rgba(255, 255, 255, 0.04);
|
|
--color-card-foreground: #eef0ff;
|
|
--color-success: #34d399;
|
|
--color-success-foreground: #052e1f;
|
|
--color-warning: #fbbf24;
|
|
--color-warning-foreground: #1a1405;
|
|
--color-info: #22d3ee;
|
|
--color-info-foreground: #04222a;
|
|
--color-selection: rgba(139, 123, 255, 0.22);
|
|
--color-selection-foreground: #c4bbff;
|
|
--color-unread: #8b7bff;
|
|
--color-chart-1: #8b7bff;
|
|
--color-chart-2: #22d3ee;
|
|
--color-chart-3: #f472b6;
|
|
--color-chart-4: #fbbf24;
|
|
--color-chart-5: #34d399;
|
|
}`;
|
|
|
|
// Glassmorphism skin: the frosted translucency, backdrop-blur, gradient-mesh
|
|
// canvas, luminous borders and glow that the colour tokens alone can't carry.
|
|
// Scoped under the skin body attribute so it detaches cleanly on switch-off.
|
|
const auroraSkin = `
|
|
body[data-theme-skin="builtin-aurora-glass"] {
|
|
font-family: "Inter", "SF Pro Display", "Segoe UI", system-ui, -apple-system, sans-serif;
|
|
letter-spacing: -0.01em;
|
|
}
|
|
|
|
/* ── Gradient-mesh canvas ──────────────────────────────────────── */
|
|
/* A multi-stop radial mesh painted onto the app-shell root (the unique
|
|
.bg-background.overflow-hidden container) so the frosted panes have
|
|
something luminous to blur. Painting it directly on the shell - rather than
|
|
a fixed body::before with z-indexed children - avoids creating stacking
|
|
contexts on portaled popups/dialogs (Radix portals render as direct <body>
|
|
children), which would otherwise break their layering. */
|
|
body[data-theme-skin="builtin-aurora-glass"] .bg-background.overflow-hidden {
|
|
background-color: var(--color-background);
|
|
background-image:
|
|
radial-gradient(60rem 60rem at 12% -10%, rgba(109, 92, 255, 0.22), transparent 60%),
|
|
radial-gradient(50rem 50rem at 105% 5%, rgba(6, 182, 212, 0.18), transparent 55%),
|
|
radial-gradient(55rem 55rem at 80% 110%, rgba(236, 72, 153, 0.16), transparent 60%),
|
|
radial-gradient(45rem 45rem at -5% 95%, rgba(16, 185, 129, 0.12), transparent 55%);
|
|
}
|
|
.dark body[data-theme-skin="builtin-aurora-glass"] .bg-background.overflow-hidden {
|
|
background-image:
|
|
radial-gradient(60rem 60rem at 12% -10%, rgba(109, 92, 255, 0.16), transparent 58%),
|
|
radial-gradient(50rem 50rem at 105% 5%, rgba(6, 182, 212, 0.11), transparent 52%),
|
|
radial-gradient(55rem 55rem at 80% 110%, rgba(236, 72, 153, 0.10), transparent 58%),
|
|
radial-gradient(45rem 45rem at -5% 95%, rgba(16, 185, 129, 0.07), transparent 52%);
|
|
}
|
|
|
|
/* ── Pill-soft radii everywhere ───────────────────────────────── */
|
|
body[data-theme-skin="builtin-aurora-glass"] .rounded-md,
|
|
body[data-theme-skin="builtin-aurora-glass"] .rounded-lg {
|
|
border-radius: 0.85rem !important;
|
|
}
|
|
body[data-theme-skin="builtin-aurora-glass"] .rounded-xl,
|
|
body[data-theme-skin="builtin-aurora-glass"] .rounded-2xl {
|
|
border-radius: 1.25rem !important;
|
|
}
|
|
|
|
/* ── Frosted panes: the shared glass recipe ───────────────────── */
|
|
/* Nav rail, folder sidebar, content backing, cards, popovers, dialogs and
|
|
menus all share one frosted treatment - translucent fill + heavy backdrop
|
|
blur + saturation so the mesh and neighbours bleed through softly. */
|
|
body[data-theme-skin="builtin-aurora-glass"] .w-14.bg-secondary,
|
|
body[data-theme-skin="builtin-aurora-glass"] .bg-secondary.border-r {
|
|
background-color: rgba(255, 255, 255, 0.55) !important;
|
|
backdrop-filter: blur(26px) saturate(180%);
|
|
-webkit-backdrop-filter: blur(26px) saturate(180%);
|
|
border-color: rgba(13, 18, 45, 0.08) !important;
|
|
}
|
|
.dark body[data-theme-skin="builtin-aurora-glass"] .w-14.bg-secondary,
|
|
.dark body[data-theme-skin="builtin-aurora-glass"] .bg-secondary.border-r {
|
|
background-color: rgba(8, 9, 22, 0.82) !important;
|
|
border-color: rgba(255, 255, 255, 0.07) !important;
|
|
}
|
|
|
|
/* The "no conversation selected" empty pane sits inside an opaque
|
|
bg-background column, so it can't inherit the shell mesh - paint the same
|
|
gradient mesh directly onto it so the placeholder reads as glass too. */
|
|
body[data-theme-skin="builtin-aurora-glass"] .bg-gradient-to-br.from-muted\\/30.to-muted\\/50 {
|
|
background-color: var(--color-background) !important;
|
|
background-image:
|
|
radial-gradient(50rem 50rem at 15% 0%, rgba(109, 92, 255, 0.22), transparent 60%),
|
|
radial-gradient(45rem 45rem at 100% 10%, rgba(6, 182, 212, 0.18), transparent 55%),
|
|
radial-gradient(50rem 50rem at 85% 105%, rgba(236, 72, 153, 0.16), transparent 60%) !important;
|
|
}
|
|
.dark body[data-theme-skin="builtin-aurora-glass"] .bg-gradient-to-br.from-muted\\/30.to-muted\\/50 {
|
|
background-image:
|
|
radial-gradient(50rem 50rem at 15% 0%, rgba(109, 92, 255, 0.18), transparent 58%),
|
|
radial-gradient(45rem 45rem at 100% 10%, rgba(6, 182, 212, 0.12), transparent 52%),
|
|
radial-gradient(50rem 50rem at 85% 105%, rgba(236, 72, 153, 0.11), transparent 58%) !important;
|
|
}
|
|
/* The reading-pane message backing goes clear glass so the frosted panes and
|
|
gradient bleed through softly. */
|
|
body[data-theme-skin="builtin-aurora-glass"] .bg-muted\\/30 {
|
|
background: transparent !important;
|
|
}
|
|
|
|
/* Cards, popovers and dialogs: brighter frosted glass with a luminous edge. */
|
|
body[data-theme-skin="builtin-aurora-glass"] .bg-card,
|
|
body[data-theme-skin="builtin-aurora-glass"] .bg-popover,
|
|
body[data-theme-skin="builtin-aurora-glass"] [role="menu"],
|
|
body[data-theme-skin="builtin-aurora-glass"] [role="dialog"],
|
|
body[data-theme-skin="builtin-aurora-glass"] [role="listbox"] {
|
|
background-color: rgba(255, 255, 255, 0.72) !important;
|
|
backdrop-filter: blur(28px) saturate(190%);
|
|
-webkit-backdrop-filter: blur(28px) saturate(190%);
|
|
border: 1px solid rgba(255, 255, 255, 0.6) !important;
|
|
box-shadow: 0 12px 40px -12px rgba(20, 22, 46, 0.28), inset 0 1px 0 rgba(255, 255, 255, 0.7) !important;
|
|
}
|
|
.dark body[data-theme-skin="builtin-aurora-glass"] .bg-card,
|
|
.dark body[data-theme-skin="builtin-aurora-glass"] .bg-popover,
|
|
.dark body[data-theme-skin="builtin-aurora-glass"] [role="menu"],
|
|
.dark body[data-theme-skin="builtin-aurora-glass"] [role="dialog"],
|
|
.dark body[data-theme-skin="builtin-aurora-glass"] [role="listbox"] {
|
|
background-color: rgba(16, 17, 38, 0.86) !important;
|
|
border: 1px solid rgba(255, 255, 255, 0.10) !important;
|
|
box-shadow: 0 16px 48px -12px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.08) !important;
|
|
}
|
|
|
|
/* ── Primary action: gradient fill + glow ─────────────────────── */
|
|
body[data-theme-skin="builtin-aurora-glass"] .bg-primary.text-primary-foreground {
|
|
background-image: linear-gradient(135deg, #7c5cff 0%, #6d5cff 45%, #4f9bff 100%) !important;
|
|
border: none !important;
|
|
color: #ffffff !important;
|
|
box-shadow: 0 6px 20px -4px rgba(109, 92, 255, 0.55), inset 0 1px 0 rgba(255, 255, 255, 0.35) !important;
|
|
transition: box-shadow 160ms ease, filter 160ms ease;
|
|
}
|
|
body[data-theme-skin="builtin-aurora-glass"] .bg-primary.text-primary-foreground:hover {
|
|
filter: brightness(1.08);
|
|
box-shadow: 0 10px 30px -4px rgba(109, 92, 255, 0.7), inset 0 1px 0 rgba(255, 255, 255, 0.4) !important;
|
|
}
|
|
.dark body[data-theme-skin="builtin-aurora-glass"] .bg-primary.text-primary-foreground {
|
|
background-image: linear-gradient(135deg, #8b7bff 0%, #6d5cff 50%, #22d3ee 130%) !important;
|
|
box-shadow: 0 6px 24px -4px rgba(139, 123, 255, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.2) !important;
|
|
}
|
|
|
|
/* ── Selected folder / row: soft tinted glass + accent bar ────── */
|
|
body[data-theme-skin="builtin-aurora-glass"] .bg-secondary.border-r .border-l-2.border-primary {
|
|
border-left-width: 3px !important;
|
|
}
|
|
|
|
/* ── On/off switch: gradient when active ──────────────────────── */
|
|
body[data-theme-skin="builtin-aurora-glass"] [role="switch"][aria-checked="true"] {
|
|
background-image: linear-gradient(135deg, #7c5cff, #4f9bff) !important;
|
|
border-color: transparent !important;
|
|
box-shadow: 0 2px 10px -1px rgba(109, 92, 255, 0.6) !important;
|
|
}
|
|
.dark body[data-theme-skin="builtin-aurora-glass"] [role="switch"][aria-checked="true"] {
|
|
background-image: linear-gradient(135deg, #8b7bff, #22d3ee) !important;
|
|
}
|
|
|
|
/* ── Menu hover: tinted accent slab (keeps glass legible) ─────── */
|
|
body[data-theme-skin="builtin-aurora-glass"] [role="menu"] [role="menuitem"]:hover,
|
|
body[data-theme-skin="builtin-aurora-glass"] [role="menu"] [role="menuitem"]:focus,
|
|
body[data-theme-skin="builtin-aurora-glass"] [role="menu"] [role="menuitem"]:focus-visible {
|
|
background-color: rgba(109, 92, 255, 0.14) !important;
|
|
color: var(--color-foreground) !important;
|
|
}
|
|
.dark body[data-theme-skin="builtin-aurora-glass"] [role="menu"] [role="menuitem"]:hover,
|
|
.dark body[data-theme-skin="builtin-aurora-glass"] [role="menu"] [role="menuitem"]:focus,
|
|
.dark body[data-theme-skin="builtin-aurora-glass"] [role="menu"] [role="menuitem"]:focus-visible {
|
|
background-color: rgba(139, 123, 255, 0.22) !important;
|
|
}`;
|
|
|
|
// "VNClagoon" — VNC's brand theme. Deep-navy grounds (#0A0E1A) with the
|
|
// VNClagoon cyan (#00D4FF) as the single accent, DM Sans for body and Syne for
|
|
// display. Dark is the brand-primary variant; the light variant deepens the
|
|
// cyan (#00A5CC) so it stays legible on white. Fonts are self-hosted under
|
|
// /fonts (OFL) so they render offline / behind the CSP.
|
|
const vnclagoonCSS = `
|
|
@font-face { font-family: 'DM Sans'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/dmsans-400.woff2') format('woff2'); }
|
|
@font-face { font-family: 'DM Sans'; font-style: normal; font-weight: 500; font-display: swap; src: url('/fonts/dmsans-500.woff2') format('woff2'); }
|
|
@font-face { font-family: 'DM Sans'; font-style: normal; font-weight: 700; font-display: swap; src: url('/fonts/dmsans-700.woff2') format('woff2'); }
|
|
@font-face { font-family: 'Syne'; font-style: normal; font-weight: 700; font-display: swap; src: url('/fonts/syne-700.woff2') format('woff2'); }
|
|
@font-face { font-family: 'Syne'; font-style: normal; font-weight: 800; font-display: swap; src: url('/fonts/syne-800.woff2') format('woff2'); }
|
|
:root {
|
|
--color-border: #dce3ee;
|
|
--color-input: #dce3ee;
|
|
--color-ring: #00a5cc;
|
|
--color-background: #ffffff;
|
|
--color-foreground: #0a0e1a;
|
|
--color-primary: #00a5cc;
|
|
--color-primary-foreground: #ffffff;
|
|
--color-secondary: #eef2f8;
|
|
--color-secondary-foreground: #0a0e1a;
|
|
--color-muted: #eef2f8;
|
|
--color-muted-foreground: #5a6478;
|
|
--color-accent: #e3f7fd;
|
|
--color-accent-foreground: #006f8c;
|
|
--color-destructive: #e5484d;
|
|
--color-destructive-foreground: #ffffff;
|
|
--color-popover: #ffffff;
|
|
--color-popover-foreground: #0a0e1a;
|
|
--color-sidebar: #f7f9fc;
|
|
--color-sidebar-foreground: #0a0e1a;
|
|
--color-sidebar-border: #dce3ee;
|
|
--color-sidebar-accent: #eef2f8;
|
|
--color-sidebar-accent-foreground: #0a0e1a;
|
|
--color-card: #ffffff;
|
|
--color-card-foreground: #0a0e1a;
|
|
--color-success: #16a34a;
|
|
--color-success-foreground: #ffffff;
|
|
--color-warning: #ca8a04;
|
|
--color-warning-foreground: #ffffff;
|
|
--color-info: #00a5cc;
|
|
--color-info-foreground: #ffffff;
|
|
--color-selection: #e3f7fd;
|
|
--color-selection-foreground: #006f8c;
|
|
--color-unread: #00a5cc;
|
|
--color-chart-1: #00a5cc;
|
|
--color-chart-2: #16a34a;
|
|
--color-chart-3: #ca8a04;
|
|
--color-chart-4: #e5484d;
|
|
--color-chart-5: #6d8bff;
|
|
}
|
|
.dark {
|
|
--color-border: #1e2740;
|
|
--color-input: #1e2740;
|
|
--color-ring: #00d4ff;
|
|
--color-background: #0a0e1a;
|
|
--color-foreground: #e8ecf4;
|
|
--color-primary: #00d4ff;
|
|
--color-primary-foreground: #05121b;
|
|
--color-secondary: #141b2e;
|
|
--color-secondary-foreground: #e8ecf4;
|
|
--color-muted: #141b2e;
|
|
--color-muted-foreground: #8a97b0;
|
|
--color-accent: #10263a;
|
|
--color-accent-foreground: #7fe6ff;
|
|
--color-destructive: #ff5a5f;
|
|
--color-destructive-foreground: #ffffff;
|
|
--color-popover: #111726;
|
|
--color-popover-foreground: #e8ecf4;
|
|
--color-sidebar: #080b14;
|
|
--color-sidebar-foreground: #e8ecf4;
|
|
--color-sidebar-border: #1e2740;
|
|
--color-sidebar-accent: #141b2e;
|
|
--color-sidebar-accent-foreground: #e8ecf4;
|
|
--color-card: #111726;
|
|
--color-card-foreground: #e8ecf4;
|
|
--color-success: #22c55e;
|
|
--color-success-foreground: #05121b;
|
|
--color-warning: #f6c544;
|
|
--color-warning-foreground: #05121b;
|
|
--color-info: #00d4ff;
|
|
--color-info-foreground: #05121b;
|
|
--color-selection: rgba(0, 212, 255, 0.20);
|
|
--color-selection-foreground: #7fe6ff;
|
|
--color-unread: #00d4ff;
|
|
--color-chart-1: #00d4ff;
|
|
--color-chart-2: #22c55e;
|
|
--color-chart-3: #f6c544;
|
|
--color-chart-4: #ff5a5f;
|
|
--color-chart-5: #6d8bff;
|
|
}`;
|
|
|
|
// Syne display face on headings; DM Sans everywhere else. Scoped to the skin
|
|
// so it detaches cleanly when the theme is switched off.
|
|
const vnclagoonSkin = `
|
|
body[data-theme-skin="builtin-vnclagoon"] {
|
|
font-family: "DM Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
}
|
|
body[data-theme-skin="builtin-vnclagoon"] h1,
|
|
body[data-theme-skin="builtin-vnclagoon"] h2,
|
|
body[data-theme-skin="builtin-vnclagoon"] h3 {
|
|
font-family: "Syne", "DM Sans", sans-serif;
|
|
letter-spacing: -0.01em;
|
|
}
|
|
|
|
/* ── Login card — VNClagoon treatment ─────────────────────────── */
|
|
/* Solid navy card (var --color-card) with a cyan hairline and a thin cyan
|
|
accent strip along the top. The login card is the only .rounded-2xl with
|
|
.bg-background/80 + .backdrop-blur-sm, so this scopes cleanly to it. */
|
|
body[data-theme-skin="builtin-vnclagoon"] .rounded-2xl.border.bg-background\\/80.backdrop-blur-sm {
|
|
position: relative;
|
|
background-color: var(--color-card) !important;
|
|
border-color: rgba(0, 212, 255, 0.16) !important;
|
|
}
|
|
body[data-theme-skin="builtin-vnclagoon"] .rounded-2xl.border.bg-background\\/80.backdrop-blur-sm::before {
|
|
content: "";
|
|
position: absolute;
|
|
left: 0;
|
|
right: 0;
|
|
top: 0;
|
|
height: 3px;
|
|
background: linear-gradient(90deg, transparent, #00d4ff 35%, #00d4ff 65%, transparent);
|
|
}
|
|
/* Depth + soft cyan glow, dark-first */
|
|
.dark body[data-theme-skin="builtin-vnclagoon"] .rounded-2xl.border.bg-background\\/80.backdrop-blur-sm {
|
|
box-shadow:
|
|
0 24px 60px -24px rgba(0, 0, 0, 0.7),
|
|
0 0 0 1px rgba(0, 212, 255, 0.06),
|
|
0 0 48px -16px rgba(0, 212, 255, 0.22) !important;
|
|
}
|
|
/* Ambient cyan wash behind the card on the login page */
|
|
.dark body[data-theme-skin="builtin-vnclagoon"] .min-h-screen.bg-gradient-to-br {
|
|
background-color: var(--color-background) !important;
|
|
background-image: radial-gradient(56rem 38rem at 50% -12%, rgba(0, 212, 255, 0.10), transparent 60%) !important;
|
|
}`;
|
|
|
|
export const BUILTIN_THEMES: InstalledTheme[] = [
|
|
{
|
|
id: 'builtin-vnclagoon',
|
|
name: 'VNClagoon',
|
|
version: '1.0.0',
|
|
author: 'VNC',
|
|
description: 'VNClagoon brand theme — deep navy with cyan accent, DM Sans + Syne',
|
|
css: vnclagoonCSS,
|
|
skin: vnclagoonSkin,
|
|
variants: ['light', 'dark'],
|
|
typography: { fontSans: '"DM Sans", system-ui, -apple-system, "Segoe UI", sans-serif' },
|
|
enabled: true,
|
|
builtIn: true,
|
|
},
|
|
{
|
|
id: 'builtin-qui',
|
|
name: 'Qui',
|
|
version: '1.0.0',
|
|
author: 'Built-in',
|
|
description: 'Clean, modern zinc-and-blue theme inspired by autobrr/qui',
|
|
css: quiCSS,
|
|
variants: ['light', 'dark'],
|
|
enabled: true,
|
|
builtIn: true,
|
|
},
|
|
{
|
|
id: 'builtin-nord',
|
|
name: 'Nord',
|
|
version: '1.0.0',
|
|
author: 'Built-in',
|
|
description: 'Arctic, north-bluish color palette inspired by nordtheme.com',
|
|
css: nordCSS,
|
|
variants: ['light', 'dark'],
|
|
enabled: true,
|
|
builtIn: true,
|
|
},
|
|
{
|
|
id: 'builtin-catppuccin',
|
|
name: 'Catppuccin',
|
|
version: '1.0.0',
|
|
author: 'Built-in',
|
|
description: 'Soothing pastel theme with Latte (light) and Mocha (dark) variants',
|
|
css: catppuccinCSS,
|
|
variants: ['light', 'dark'],
|
|
enabled: true,
|
|
builtIn: true,
|
|
},
|
|
{
|
|
id: 'builtin-solarized',
|
|
name: 'Solarized',
|
|
version: '1.0.0',
|
|
author: 'Built-in',
|
|
description: 'Precision colors for machines and people by Ethan Schoonover',
|
|
css: solarizedCSS,
|
|
variants: ['light', 'dark'],
|
|
enabled: true,
|
|
builtIn: true,
|
|
},
|
|
{
|
|
id: 'builtin-roundcube-elastic',
|
|
name: 'Roundcube Elastic',
|
|
version: '1.0.0',
|
|
author: 'Built-in',
|
|
description: 'Faithful recreation of Roundcube\'s Elastic skin - Roboto, the #37beff blue, and the dark task-menu rail',
|
|
css: elasticCSS,
|
|
skin: elasticSkin,
|
|
variants: ['light', 'dark'],
|
|
typography: { fontSans: 'Roboto, "Helvetica Neue", Arial, sans-serif', baseFontSize: '14px' },
|
|
enabled: true,
|
|
builtIn: true,
|
|
},
|
|
{
|
|
id: 'builtin-aurora-glass',
|
|
name: 'Aurora Glass',
|
|
version: '1.0.0',
|
|
author: 'Built-in',
|
|
description: 'Ultra-modern glassmorphism - frosted blurred panes floating over a vibrant indigo→cyan gradient mesh, with glowing gradient actions',
|
|
css: auroraCSS,
|
|
skin: auroraSkin,
|
|
variants: ['light', 'dark'],
|
|
typography: { fontSans: '"Inter", "SF Pro Display", "Segoe UI", system-ui, sans-serif' },
|
|
enabled: true,
|
|
builtIn: true,
|
|
},
|
|
];
|