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 , so it must be an ancestor of the skinned
.) */ .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 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 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; }`; // "SRC" — SRC Advisory brand. Swiss red (#D52B1E) on white, light-first, with a // near-black stone-grey neutral. Dark variant brightens the red (#EF4444) on a // warm near-black. Info stays blue so it never collides with the red accent. const srcCSS = ` @font-face { font-family: 'Inter'; font-style: normal; font-weight: 100 900; font-display: swap; src: url('/fonts/inter-var-latin.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: 'Inter'; font-style: normal; font-weight: 100 900; font-display: swap; src: url('/fonts/inter-var-latin-ext.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: 'Spectral'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/spectral-400-latin.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: 'Spectral'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/spectral-400-latin-ext.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: 'Spectral'; font-style: normal; font-weight: 600; font-display: swap; src: url('/fonts/spectral-600-latin.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: 'Spectral'; font-style: normal; font-weight: 600; font-display: swap; src: url('/fonts/spectral-600-latin-ext.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: 'Spectral'; font-style: normal; font-weight: 700; font-display: swap; src: url('/fonts/spectral-700-latin.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: 'Spectral'; font-style: normal; font-weight: 700; font-display: swap; src: url('/fonts/spectral-700-latin-ext.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: 'Spectral'; font-style: normal; font-weight: 800; font-display: swap; src: url('/fonts/spectral-800-latin.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: 'Spectral'; font-style: normal; font-weight: 800; font-display: swap; src: url('/fonts/spectral-800-latin-ext.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } :root { --color-border: #e7e5e4; --color-input: #e7e5e4; --color-ring: #d52b1e; --color-background: #ffffff; --color-foreground: #1c1917; --color-primary: #d52b1e; --color-primary-foreground: #ffffff; --color-secondary: #f5f5f4; --color-secondary-foreground: #1c1917; --color-muted: #f5f5f4; --color-muted-foreground: #78716c; --color-accent: #fdecea; --color-accent-foreground: #a91b12; --color-destructive: #b91c1c; --color-destructive-foreground: #ffffff; --color-popover: #ffffff; --color-popover-foreground: #1c1917; --color-sidebar: #fafaf9; --color-sidebar-foreground: #1c1917; --color-sidebar-border: #e7e5e4; --color-sidebar-accent: #f5f5f4; --color-sidebar-accent-foreground: #1c1917; --color-card: #ffffff; --color-card-foreground: #1c1917; --color-success: #16a34a; --color-success-foreground: #ffffff; --color-warning: #ca8a04; --color-warning-foreground: #ffffff; --color-info: #2563eb; --color-info-foreground: #ffffff; --color-selection: #fdecea; --color-selection-foreground: #a91b12; --color-unread: #d52b1e; --color-chart-1: #d52b1e; --color-chart-2: #2563eb; --color-chart-3: #ca8a04; --color-chart-4: #16a34a; --color-chart-5: #7c3aed; } .dark { --color-border: #292524; --color-input: #292524; --color-ring: #ef4444; --color-background: #1c1917; --color-foreground: #f5f5f4; --color-primary: #ef4444; --color-primary-foreground: #ffffff; --color-secondary: #292524; --color-secondary-foreground: #f5f5f4; --color-muted: #292524; --color-muted-foreground: #a8a29e; --color-accent: #3a1e1b; --color-accent-foreground: #fca5a5; --color-destructive: #dc2626; --color-destructive-foreground: #ffffff; --color-popover: #262322; --color-popover-foreground: #f5f5f4; --color-sidebar: #171412; --color-sidebar-foreground: #f5f5f4; --color-sidebar-border: #292524; --color-sidebar-accent: #292524; --color-sidebar-accent-foreground: #f5f5f4; --color-card: #242120; --color-card-foreground: #f5f5f4; --color-success: #22c55e; --color-success-foreground: #ffffff; --color-warning: #eab308; --color-warning-foreground: #1c1917; --color-info: #60a5fa; --color-info-foreground: #1c1917; --color-selection: rgba(213, 43, 30, 0.25); --color-selection-foreground: #fca5a5; --color-unread: #ef4444; --color-chart-1: #ef4444; --color-chart-2: #60a5fa; --color-chart-3: #eab308; --color-chart-4: #22c55e; --color-chart-5: #a78bfa; }`; // MD3 component overrides for the SRC theme — shape scale, filled buttons, // text fields, cards, dialogs, state layers, switches, login card treatment. // All scoped under the skin body attribute so they detach cleanly on switch-off. const srcSkin = ` body[data-theme-skin="builtin-src"] { font-family: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif; } body[data-theme-skin="builtin-src"] h1, body[data-theme-skin="builtin-src"] h2, body[data-theme-skin="builtin-src"] h3 { font-family: "Spectral", "Inter", Georgia, serif; font-weight: 700; letter-spacing: -0.01em; } /* ── MD3 Shape scale ─────────────────────────────────────────── */ /* Remap Tailwind rounded-* to M3 shape tokens. rounded-full (pill */ /* avatars, badges, toggles) is intentionally left untouched. */ body[data-theme-skin="builtin-src"] .rounded-sm { border-radius: 4px !important; } body[data-theme-skin="builtin-src"] .rounded { border-radius: 4px !important; } body[data-theme-skin="builtin-src"] .rounded-md { border-radius: 8px !important; } body[data-theme-skin="builtin-src"] .rounded-lg { border-radius: 12px !important; } body[data-theme-skin="builtin-src"] .rounded-xl { border-radius: 16px !important; } body[data-theme-skin="builtin-src"] .rounded-2xl { border-radius: 28px !important; } body[data-theme-skin="builtin-src"] .rounded-3xl { border-radius: 28px !important; } /* ── MD3 Buttons: full shape (20 dp) ─────────────────────────── */ /* All button variants (filled, tonal, outlined, text) use 20 dp */ /* corners per M3. Circle icon buttons (.rounded-full) are skipped; */ /* switches ([role="switch"]) are handled separately. */ body[data-theme-skin="builtin-src"] button:not(.rounded-full):not([role="switch"]) { border-radius: 20px !important; } /* MD3 filled button — primary surface, M3 label-large, state layers */ body[data-theme-skin="builtin-src"] .bg-primary.text-primary-foreground:not(.rounded-full) { border-radius: 20px !important; padding-inline: 24px !important; min-height: 40px !important; font-weight: 500 !important; letter-spacing: 0.0063em !important; border: none !important; box-shadow: none !important; transition: box-shadow 200ms ease, filter 200ms ease; } /* hover: M3 elevation 1 + 8 % on-primary state layer */ body[data-theme-skin="builtin-src"] .bg-primary.text-primary-foreground:not(.rounded-full):hover { box-shadow: 0 1px 2px rgba(0, 0, 0, 0.30), 0 2px 6px 2px rgba(0, 0, 0, 0.15) !important; filter: brightness(1.06); } /* focus: +12 % tint + M3 focus ring */ body[data-theme-skin="builtin-src"] .bg-primary.text-primary-foreground:not(.rounded-full):focus-visible { filter: brightness(1.10) !important; outline: 3px solid var(--color-ring) !important; outline-offset: 2px !important; } /* pressed: +12 % darker, no shadow */ body[data-theme-skin="builtin-src"] .bg-primary.text-primary-foreground:not(.rounded-full):active { box-shadow: none !important; filter: brightness(0.94) !important; } /* ── MD3 Text fields: outlined style, extra-small (4 dp) ─────── */ body[data-theme-skin="builtin-src"] input:not([type="checkbox"]):not([type="radio"]):not([type="range"]), body[data-theme-skin="builtin-src"] textarea, body[data-theme-skin="builtin-src"] select { border-radius: 4px !important; transition: outline 150ms ease; } body[data-theme-skin="builtin-src"] input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):focus-visible, body[data-theme-skin="builtin-src"] textarea:focus-visible, body[data-theme-skin="builtin-src"] select:focus-visible { outline: 2px solid var(--color-primary) !important; outline-offset: -2px !important; } /* ── MD3 Cards: elevated (level 1), medium shape (12 dp) ─────── */ body[data-theme-skin="builtin-src"] .bg-card { border-radius: 12px !important; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.10), 0 1px 3px 1px rgba(0, 0, 0, 0.06) !important; } .dark body[data-theme-skin="builtin-src"] .bg-card { box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35), 0 1px 3px 1px rgba(0, 0, 0, 0.20) !important; } /* ── MD3 Menus / popovers / listboxes: extra-small (4 dp) ───── */ body[data-theme-skin="builtin-src"] .bg-popover, body[data-theme-skin="builtin-src"] [role="listbox"] { border-radius: 4px !important; border: none !important; box-shadow: 0 2px 6px 2px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.30) !important; } .dark body[data-theme-skin="builtin-src"] .bg-popover, .dark body[data-theme-skin="builtin-src"] [role="listbox"] { box-shadow: 0 2px 8px 2px rgba(0, 0, 0, 0.50), 0 1px 2px rgba(0, 0, 0, 0.60) !important; } /* ── MD3 Dialogs: extra-large shape (28 dp) ──────────────────── */ body[data-theme-skin="builtin-src"] [role="dialog"] { border-radius: 28px !important; border: none !important; box-shadow: 0 6px 10px 4px rgba(0, 0, 0, 0.15), 0 2px 3px rgba(0, 0, 0, 0.30) !important; } .dark body[data-theme-skin="builtin-src"] [role="dialog"] { box-shadow: 0 6px 10px 4px rgba(0, 0, 0, 0.50), 0 2px 3px rgba(0, 0, 0, 0.60) !important; } /* ── MD3 Menu items: 8 % on-surface state layer on hover ─────── */ body[data-theme-skin="builtin-src"] [role="menu"] [role="menuitem"]:hover, body[data-theme-skin="builtin-src"] [role="menu"] [role="menuitem"]:focus, body[data-theme-skin="builtin-src"] [role="menu"] [role="menuitem"]:focus-visible { background-color: color-mix(in srgb, var(--color-foreground) 8%, transparent) !important; color: var(--color-foreground) !important; } .dark body[data-theme-skin="builtin-src"] [role="menu"] [role="menuitem"]:hover, .dark body[data-theme-skin="builtin-src"] [role="menu"] [role="menuitem"]:focus { background-color: color-mix(in srgb, var(--color-foreground) 10%, transparent) !important; } /* ── MD3 Switch ──────────────────────────────────────────────── */ /* M3 switch: unselected = outline + icon; selected = primary fill */ body[data-theme-skin="builtin-src"] [role="switch"] { background-color: var(--color-input) !important; border: 2px solid var(--color-muted-foreground) !important; transition: background-color 150ms ease, border-color 150ms ease; } body[data-theme-skin="builtin-src"] [role="switch"] > span { background-color: var(--color-muted-foreground) !important; } body[data-theme-skin="builtin-src"] [role="switch"][aria-checked="true"] { background-color: var(--color-primary) !important; border-color: var(--color-primary) !important; } body[data-theme-skin="builtin-src"] [role="switch"][aria-checked="true"] > span { background-color: var(--color-primary-foreground) !important; } .dark body[data-theme-skin="builtin-src"] [role="switch"] { background-color: #3a2524 !important; border-color: var(--color-muted-foreground) !important; } .dark body[data-theme-skin="builtin-src"] [role="switch"][aria-checked="true"] { background-color: var(--color-primary) !important; border-color: var(--color-primary) !important; } .dark body[data-theme-skin="builtin-src"] [role="switch"][aria-checked="true"] > span { background-color: #1c1917 !important; } /* ── Selected folder: M3 active-indicator treatment ─────────── */ /* M3 uses a pill-shaped tonal container for the active nav item. */ /* Bulwark's left-border accent becomes a 3 dp primary accent line */ /* + secondary-container (--color-accent) fill + gentle corner. */ body[data-theme-skin="builtin-src"] .bg-secondary.border-r .border-l-2.border-primary { border-left-width: 3px !important; border-left-color: var(--color-primary) !important; background-color: var(--color-accent) !important; border-radius: 0 12px 12px 0 !important; } /* ── Login card: MD3 extra-large + SRC red top accent strip ───── */ body[data-theme-skin="builtin-src"] .rounded-2xl.border.bg-background\\/80.backdrop-blur-sm { position: relative; background-color: var(--color-card) !important; border-color: rgba(213, 43, 30, 0.14) !important; border-radius: 28px !important; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08), 0 8px 32px rgba(0, 0, 0, 0.06) !important; overflow: hidden; } body[data-theme-skin="builtin-src"] .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, #d52b1e 30%, #d52b1e 70%, transparent); pointer-events: none; } /* Login page background: faint SRC red ambient wash */ body[data-theme-skin="builtin-src"] .min-h-screen.bg-gradient-to-br { background-color: #f9f7f7 !important; background-image: radial-gradient(56rem 38rem at 50% -12%, rgba(213, 43, 30, 0.05), transparent 60%) !important; } .dark body[data-theme-skin="builtin-src"] .rounded-2xl.border.bg-background\\/80.backdrop-blur-sm { border-color: rgba(239, 68, 68, 0.18) !important; box-shadow: 0 4px 16px rgba(0, 0, 0, 0.45), 0 0 40px -20px rgba(239, 68, 68, 0.18) !important; } .dark body[data-theme-skin="builtin-src"] .rounded-2xl.border.bg-background\\/80.backdrop-blur-sm::before { background: linear-gradient(90deg, transparent, #ef4444 30%, #ef4444 70%, transparent); } .dark body[data-theme-skin="builtin-src"] .min-h-screen.bg-gradient-to-br { background-color: var(--color-background) !important; background-image: radial-gradient(56rem 38rem at 50% -12%, rgba(239, 68, 68, 0.07), transparent 60%) !important; } /* ── Single-surface panes (M3 has no gradient empty states) ───── */ body[data-theme-skin="builtin-src"] .bg-gradient-to-br.from-muted\\/30.to-muted\\/50 { background: var(--color-background) !important; } body[data-theme-skin="builtin-src"] .bg-muted\\/30 { background-color: var(--color-background) !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, logoLightUrl: '/branding/vncmail-wordmark-on-light.svg', logoDarkUrl: '/branding/vncmail-wordmark-on-dark.svg', variants: ['light', 'dark'], typography: { fontSans: '"DM Sans", system-ui, -apple-system, "Segoe UI", sans-serif' }, enabled: true, builtIn: true, }, { id: 'builtin-src', name: 'SRC', version: '1.1.0', author: 'VNC', description: 'SRC Advisory brand theme — Swiss red on white, MD3 components, light-first', css: srcCSS, skin: srcSkin, logoLightUrl: '/branding/SRC_Symbol.png', logoDarkUrl: '/branding/SRC_Symbol.png', variants: ['light', 'dark'], typography: { fontSans: '"Inter", 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, }, ];