// Three themes on one attribute: . // The grid is painted only by --jt-* variables (its defaults sit on :where(:root), so any value below wins); // Material (checkboxes, buttons, dialog, snack bar of the grid) takes its colors from the same variables. @use '@angular/material' as mat; @use '@jambotron/aria-grid/styles/aria-grid'; // --------------------------------------------------------------------------------------------------------------------- // Jambotron light — the tokens of jambotron.com (_tokens.scss), the part the grid and this page use [data-theme='jambotron-light'] { color-scheme: light; --app-bg: radial-gradient(1200px 600px at 10% -10%, #d7f6fb 0%, transparent 60%), radial-gradient(900px 500px at 110% 10%, #fde9c4 0%, transparent 55%), #eef2f7; --app-panel: #e7edf3c2; --app-panel-border: rgba(10, 16, 48, 0.12); --app-surface: #f3f6fa; --app-code-bg: rgba(10, 16, 48, 0.05); --app-font: Roboto, 'Helvetica Neue', sans-serif; --app-font-display: Orbitron, Roboto, sans-serif; --app-title: #0b6e80; --jt-accent: #14c8e6; --jt-accent-text: #074b5a; --jt-on-accent: #050a24; --jt-on-accent-text: #ffffff; --jt-danger: #ef4444; --jt-danger-text: #8a1414; --jt-success: #22c55e; --jt-success-text: #0c4f26; --jt-warning: #ff9a2e; --jt-warning-text: #6b3a00; --jt-text: #141a33; --jt-text-muted: #39425f; --jt-text-disabled: rgba(20, 26, 51, 0.45); --jt-divider: rgba(10, 16, 48, 0.12); --jt-field-bg: rgba(255, 255, 255, 0.55); --jt-field-border: rgba(10, 16, 48, 0.28); --jt-focus-ring: 0 0 0 3px rgba(20, 200, 230, 0.45); --jt-glow-accent: 0 0 10px rgba(20, 200, 230, 0.35); --jt-popup-bg: #eef2f7e6; --jt-popup-border: rgba(10, 16, 48, 0.12); --jt-shadow-lg: 0 16px 48px rgba(10, 16, 48, 0.2); } // Jambotron dark — night sky, neon cyan [data-theme='jambotron-dark'] { color-scheme: dark; --app-bg: radial-gradient(1200px 700px at 15% -10%, #1c2a6b 0%, transparent 60%), radial-gradient(900px 600px at 110% 0%, #3b1d5e 0%, transparent 55%), #050a24; --app-panel: rgba(10, 16, 44, 0.72); --app-panel-border: rgba(62, 230, 255, 0.22); --app-surface: #0c1234; --app-code-bg: rgba(5, 10, 36, 0.6); --app-font: Roboto, 'Helvetica Neue', sans-serif; --app-font-display: Orbitron, Roboto, sans-serif; --app-title: #7ff0ff; --jt-accent: #3ee6ff; --jt-accent-text: #7ff0ff; --jt-on-accent: #050a24; --jt-on-accent-text: #050a24; --jt-danger: #f87171; --jt-danger-text: #fecaca; --jt-success: #34d399; --jt-success-text: #86efac; --jt-warning: #ff9a2e; --jt-warning-text: #ffd98a; --jt-text: #eef2ff; --jt-text-muted: #ccd4ec; --jt-text-disabled: rgba(238, 242, 255, 0.45); --jt-divider: rgba(195, 204, 230, 0.16); --jt-field-bg: rgba(5, 10, 36, 0.55); --jt-field-border: rgba(195, 204, 230, 0.3); --jt-focus-ring: 0 0 0 3px rgba(62, 230, 255, 0.5); --jt-glow-accent: 0 0 14px rgba(62, 230, 255, 0.55); --jt-popup-bg: rgba(8, 12, 36, 0.95); --jt-popup-border: rgba(62, 230, 255, 0.22); --jt-shadow-lg: 0 16px 48px rgba(0, 0, 0, 0.55); } // Synthwave — the colors of reactive-mail-server's web mail (frontend/src/material.scss there) [data-theme='synthwave'] { color-scheme: dark; --app-bg: linear-gradient(180deg, transparent 55%, rgba(255, 0, 127, 0.18) 100%), repeating-linear-gradient(90deg, rgba(255, 0, 127, 0.12) 0 1px, transparent 1px 64px), repeating-linear-gradient(0deg, rgba(0, 240, 255, 0.08) 0 1px, transparent 1px 64px), #0d0221; --app-panel: rgba(15, 12, 35, 0.78); --app-panel-border: rgba(255, 0, 127, 0.4); --app-surface: #140a2e; --app-code-bg: rgba(2, 6, 23, 0.7); --app-font: Rajdhani, sans-serif; --app-font-display: Orbitron, sans-serif; --app-title: #ff007f; --jt-accent: #00f0ff; --jt-accent-text: #00f0ff; --jt-on-accent: #0d0221; --jt-on-accent-text: #0d0221; --jt-danger: #ff4d6d; --jt-danger-text: #ff8fa3; --jt-success: #00ff88; --jt-success-text: #7dffbf; --jt-warning: #ffbe0b; --jt-warning-text: #ffd76a; --jt-text: #e2e8f0; --jt-text-muted: #94a3b8; --jt-text-disabled: rgba(226, 232, 240, 0.4); --jt-divider: rgba(0, 240, 255, 0.14); --jt-field-bg: rgba(2, 6, 23, 0.6); --jt-field-border: rgba(0, 240, 255, 0.35); --jt-focus-ring: 0 0 0 3px #ffbe0b; --jt-glow-accent: 0 0 12px rgba(0, 240, 255, 0.6); --jt-popup-bg: rgba(10, 5, 24, 0.97); --jt-popup-border: rgba(255, 0, 127, 0.45); --jt-shadow-lg: 0 16px 48px rgba(0, 0, 0, 0.6), 0 0 20px rgba(255, 0, 127, 0.25); --jt-radius-sm: 8px; --jt-radius-md: 12px; .jt-table { font-size: 0.95rem; th { font-family: Orbitron, sans-serif; font-size: 0.68rem; letter-spacing: 0.08em; color: #00f0ff; } } } // --------------------------------------------------------------------------------------------------------------------- // Material: light or dark by color-scheme (set by the theme above), roles mapped to the --jt-* variables html { @include mat.theme( ( color: (primary: mat.$cyan-palette, tertiary: mat.$violet-palette, theme-type: color-scheme), typography: (plain-family: var(--app-font), brand-family: var(--app-font-display)), density: 0, ), ( primary: var(--jt-accent-text), on-primary: var(--jt-on-accent-text), error: var(--jt-danger-text), on-error: var(--jt-on-accent-text), background: var(--app-surface), on-background: var(--jt-text), surface: var(--app-surface), on-surface: var(--jt-text), on-surface-variant: var(--jt-text-muted), surface-container: var(--app-surface), surface-container-high: var(--app-surface), surface-container-highest: var(--app-surface), outline: var(--jt-field-border), outline-variant: var(--jt-divider), inverse-surface: var(--jt-text), inverse-on-surface: var(--app-surface), ) ); @include mat.checkbox-overrides(( selected-icon-color: var(--jt-accent), selected-hover-icon-color: var(--jt-accent), selected-focus-icon-color: var(--jt-accent), selected-checkmark-color: var(--jt-on-accent), )); } // --------------------------------------------------------------------------------------------------------------------- // Page *, *::before, *::after { box-sizing: border-box; } html, body { margin: 0; min-height: 100%; } body { background: var(--app-bg); background-attachment: fixed; color: var(--jt-text); font-family: var(--app-font); line-height: 1.5; transition: background var(--jt-duration-base) var(--jt-easing), color var(--jt-duration-base) var(--jt-easing); } a { color: var(--jt-accent-text); } code { font-family: 'JetBrains Mono', Consolas, monospace; font-size: 0.85em; } .top { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px; max-width: 1180px; margin: 0 auto; padding: 28px 16px 8px; } .brand { display: flex; align-items: center; gap: 14px; h1 { margin: 0; font-family: var(--app-font-display); font-size: clamp(1.2rem, 3vw, 1.7rem); color: var(--app-title); text-shadow: var(--jt-glow-accent); } p { margin: 2px 0 0; color: var(--jt-text-muted); } } .brand-mark { display: grid; place-items: center; width: 44px; height: 44px; border-radius: var(--jt-radius-md); background: var(--jt-accent); color: var(--jt-on-accent); font-size: 1.6rem; box-shadow: var(--jt-glow-accent); } .switches { display: flex; flex-wrap: wrap; gap: 12px; jt-select { min-width: 220px; } } main { display: grid; gap: 24px; max-width: 1180px; margin: 0 auto; padding: 16px; } .panel { min-width: 0; padding: 20px; border: 1px solid var(--app-panel-border); border-radius: var(--jt-radius-md); background: var(--app-panel); backdrop-filter: blur(8px); h2 { display: flex; align-items: center; gap: 10px; margin: 0 0 6px; font-family: var(--app-font-display); font-size: 1.05rem; letter-spacing: 0.02em; span { display: grid; place-items: center; width: 26px; height: 26px; border-radius: 50%; background: var(--jt-accent); color: var(--jt-on-accent); font-size: 0.8rem; } } } .lead { margin: 0 0 16px; color: var(--jt-text-muted); max-width: 85ch; } .filter { display: inline-flex; flex-direction: column; gap: 4px; margin-bottom: 12px; font-size: 0.8rem; color: var(--jt-text-muted); input { width: min(320px, 80vw); padding: 8px 12px; border: 1px solid var(--jt-field-border); border-radius: var(--jt-radius-sm); background: var(--jt-field-bg); color: var(--jt-text); font: inherit; font-size: 0.95rem; &:focus-visible { outline: none; box-shadow: var(--jt-focus-ring); } } } .chip { display: inline-block; margin-right: 4px; padding: 1px 8px; border-radius: var(--jt-radius-pill); font-size: 0.75rem; font-weight: 500; border: 1px solid currentColor; } .chip--running { color: var(--jt-success-text); } .chip--stopped { color: var(--jt-text-muted); } .chip--error { color: var(--jt-danger-text); } .chip--locked { color: var(--jt-warning-text); } // CPU load bar .meter { display: inline-flex; align-items: center; justify-content: flex-end; width: 90px; height: 18px; padding: 0 6px; border-radius: var(--jt-radius-sm); background: linear-gradient(90deg, color-mix(in srgb, var(--jt-accent) 35%, transparent) calc(var(--value) * 1%), var(--jt-divider) 0); font-variant-numeric: tabular-nums; font-size: 0.8rem; } .log { min-height: 1.5em; margin: 12px 0 4px; color: var(--jt-text-muted); font-size: 0.9rem; } .details { margin-top: 12px; padding: 10px 14px; border-left: 3px solid var(--jt-accent); border-radius: var(--jt-radius-sm); background: color-mix(in srgb, var(--jt-accent) 10%, transparent); } .link { margin-left: 8px; padding: 0; border: 0; background: none; color: var(--jt-accent-text); font: inherit; text-decoration: underline; cursor: pointer; } .code { margin-top: 12px; summary { cursor: pointer; color: var(--jt-accent-text); font-weight: 500; } pre { overflow-x: auto; margin: 8px 0 0; padding: 14px; border: 1px solid var(--jt-divider); border-radius: var(--jt-radius-sm); background: var(--app-code-bg); font-size: 0.82rem; line-height: 1.45; } } // The grid's own empty state uses this class .jt-muted { color: var(--jt-text-muted); } .foot { max-width: 1180px; margin: 0 auto; padding: 8px 16px 32px; color: var(--jt-text-muted); font-size: 0.85rem; }