Files
web-app-launcher/design-mockups/02-aurora-glass.html
T
alexei.dolgolyov 5dcadd1c20 feat(ui): migrate entire UI to "Cozy Home" design
Warm, friendly redesign replacing the generic cold-shadcn look. Built as a
swappable token bundle so other presets can be added later; dark mode and the
user-tunable accent hue are retained.

Foundation
- app.css: warm cream (light) + "dusk" (dark) token system; terracotta accent
  (default hue 16); pastel --room-* palette; vivid --status-* (dots/bars) plus
  AA-legible --status-*-ink (text); soft warm shadows; --radius 1rem; font tokens
- Fonts: Fraunces (display) + Figtree (body), self-hosted in static/fonts
  (no Google CDN) so offline/LAN installs work; system-ui fallbacks kept
- h1/h2/h3 render in Fraunces via base layer

Chrome and surfaces
- Sidebar, Header, home, AppCard/BoardCard, BoardHeader, sections, favorites
- 29 widgets + integration renderers: cozy card shells, room-palette charts
- Default background is a static warm "cozy" glow (mesh demoted, rAF gated on
  prefers-reduced-motion)

System-wide
- Status colors tokenized (no raw bg/text-*-500 or status hex); success/warning
  to status tokens, categorical to room palette, errors to destructive
- Inputs rounded-xl; buttons rounded-xl; cards/dialogs rounded-[1.4rem];
  soft-shadow vocabulary only; focus-visible:ring-primary/30
- Forms, admin tables (now cozy cards), dialogs, popovers, auth screens

a11y: reduced-motion guards; darker status "ink" text for AA on cream.
Known tradeoff: terracotta primary + white button text ~2.96:1 (signature color,
user-tunable).

Verified: svelte-check 0/0, build ok, 274 tests pass, eslint 0 errors.
Design refs + system sheet in design-mockups/.
2026-05-27 23:04:47 +03:00

916 lines
23 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Web App Launcher — Aurora Glass</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&family=Manrope:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<style>
:root {
--bg: #0a0a14;
--ink: #f3f2fb;
--ink-dim: #a7a6c4;
--ink-faint: #6f6e90;
--accent-h: 265; /* user-tunable hue → this is the killer feature */
--accent: hsl(var(--accent-h) 90% 66%);
--accent-2: hsl(calc(var(--accent-h) + 60) 85% 64%);
--accent-soft: hsl(var(--accent-h) 90% 66% / 0.14);
--glass: rgba(255, 255, 255, 0.05);
--glass-2: rgba(255, 255, 255, 0.07);
--glass-line: rgba(255, 255, 255, 0.1);
--ok: #34e0a1;
--warn: #ffc24b;
--bad: #ff5d73;
--radius: 18px;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
}
body {
background: var(--bg);
color: var(--ink);
font-family: 'Manrope', system-ui, sans-serif;
-webkit-font-smoothing: antialiased;
overflow-x: hidden;
position: relative;
}
/* aurora mesh */
body::before {
content: '';
position: fixed;
inset: -20%;
z-index: 0;
pointer-events: none;
filter: blur(60px);
opacity: 0.9;
background:
radial-gradient(40% 40% at 18% 22%, hsl(var(--accent-h) 90% 60% / 0.55), transparent 70%),
radial-gradient(
38% 38% at 82% 18%,
hsl(calc(var(--accent-h) + 70) 90% 60% / 0.42),
transparent 70%
),
radial-gradient(
45% 45% at 70% 85%,
hsl(calc(var(--accent-h) - 40) 90% 58% / 0.4),
transparent 72%
),
radial-gradient(
40% 40% at 25% 90%,
hsl(calc(var(--accent-h) + 120) 80% 55% / 0.3),
transparent 72%
);
animation: drift 22s ease-in-out infinite alternate;
}
@keyframes drift {
0% {
transform: translate(0, 0) scale(1);
}
100% {
transform: translate(-3%, 2%) scale(1.08);
}
}
body::after {
content: '';
position: fixed;
inset: 0;
z-index: 0;
pointer-events: none;
background: radial-gradient(
120% 120% at 50% -10%,
transparent 40%,
rgba(10, 10, 20, 0.6) 100%
);
}
.shell {
position: relative;
z-index: 1;
display: grid;
grid-template-columns: 248px 1fr;
min-height: 100vh;
}
/* sidebar (glass) */
.side {
margin: 16px 0 16px 16px;
border-radius: 24px;
padding: 20px;
background: var(--glass);
border: 1px solid var(--glass-line);
backdrop-filter: blur(26px) saturate(160%);
-webkit-backdrop-filter: blur(26px) saturate(160%);
display: flex;
flex-direction: column;
}
.brand {
display: flex;
align-items: center;
gap: 11px;
margin-bottom: 26px;
padding: 4px 6px;
}
.brand .mark {
width: 38px;
height: 38px;
border-radius: 12px;
background: linear-gradient(135deg, var(--accent), var(--accent-2));
display: grid;
place-items: center;
color: #fff;
box-shadow: 0 8px 24px -6px var(--accent);
}
.brand .mark svg {
width: 20px;
height: 20px;
}
.brand .name {
font-family: 'Outfit';
font-weight: 600;
font-size: 17px;
letter-spacing: -0.01em;
}
.brand .name span {
display: block;
font-family: 'Manrope';
font-weight: 500;
font-size: 11px;
color: var(--ink-faint);
letter-spacing: 0.04em;
}
.nav-grp {
font-family: 'Outfit';
text-transform: uppercase;
letter-spacing: 0.13em;
font-size: 10px;
color: var(--ink-faint);
margin: 14px 8px 8px;
}
.nav-i {
display: flex;
align-items: center;
gap: 12px;
padding: 11px 12px;
border-radius: 12px;
color: var(--ink-dim);
font-weight: 500;
font-size: 14.5px;
cursor: pointer;
transition: 0.18s;
position: relative;
}
.nav-i svg {
width: 19px;
height: 19px;
opacity: 0.85;
}
.nav-i:hover {
color: var(--ink);
background: var(--glass-2);
}
.nav-i.on {
color: var(--ink);
background: var(--accent-soft);
box-shadow: inset 0 0 0 1px hsl(var(--accent-h) 90% 66% / 0.35);
}
.nav-i.on::before {
content: '';
position: absolute;
left: -20px;
top: 9px;
bottom: 9px;
width: 3px;
border-radius: 3px;
background: var(--accent);
}
.nav-i .dot {
margin-left: auto;
font-size: 11px;
color: var(--ink-faint);
font-weight: 600;
}
.side-foot {
margin-top: auto;
display: flex;
align-items: center;
gap: 11px;
padding: 10px;
border-radius: 14px;
background: var(--glass);
border: 1px solid var(--glass-line);
}
.av {
width: 34px;
height: 34px;
border-radius: 10px;
background: linear-gradient(135deg, var(--accent), var(--accent-2));
display: grid;
place-items: center;
font-weight: 700;
color: #fff;
font-size: 13px;
}
.side-foot .who {
font-size: 13px;
font-weight: 600;
line-height: 1.1;
}
.side-foot .who span {
display: block;
font-size: 11px;
color: var(--ink-faint);
font-weight: 500;
}
/* main */
.main {
padding: 30px 34px;
min-width: 0;
}
.head {
display: flex;
align-items: flex-end;
gap: 20px;
margin-bottom: 26px;
}
.hello {
font-family: 'Outfit';
font-weight: 600;
font-size: 30px;
letter-spacing: -0.02em;
line-height: 1.05;
}
.hello em {
font-style: normal;
background: linear-gradient(120deg, var(--accent), var(--accent-2));
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.sub {
color: var(--ink-dim);
font-size: 14px;
margin-top: 6px;
}
.searchwrap {
margin-left: auto;
display: flex;
align-items: center;
gap: 10px;
}
.search {
display: flex;
align-items: center;
gap: 10px;
width: 300px;
background: var(--glass);
border: 1px solid var(--glass-line);
backdrop-filter: blur(20px);
border-radius: 14px;
padding: 11px 14px;
color: var(--ink-faint);
font-size: 13.5px;
cursor: text;
}
.search svg {
width: 16px;
height: 16px;
}
.search .k {
margin-left: auto;
font-size: 11px;
background: var(--glass-2);
border-radius: 6px;
padding: 2px 7px;
}
.gbtn {
width: 42px;
height: 42px;
border-radius: 14px;
background: var(--glass);
border: 1px solid var(--glass-line);
backdrop-filter: blur(20px);
display: grid;
place-items: center;
color: var(--ink-dim);
cursor: pointer;
transition: 0.18s;
}
.gbtn:hover {
color: var(--ink);
background: var(--glass-2);
}
.gbtn svg {
width: 18px;
height: 18px;
}
/* metric row */
.metrics {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px;
margin-bottom: 28px;
}
.metric {
background: var(--glass);
border: 1px solid var(--glass-line);
backdrop-filter: blur(22px) saturate(150%);
border-radius: var(--radius);
padding: 18px 20px;
position: relative;
overflow: hidden;
}
.metric .ic {
width: 34px;
height: 34px;
border-radius: 11px;
display: grid;
place-items: center;
background: var(--accent-soft);
color: var(--accent);
margin-bottom: 14px;
}
.metric .ic svg {
width: 18px;
height: 18px;
}
.metric .v {
font-family: 'Outfit';
font-size: 27px;
font-weight: 600;
letter-spacing: -0.02em;
}
.metric .l {
color: var(--ink-dim);
font-size: 13px;
margin-top: 2px;
}
.metric .trend {
position: absolute;
top: 18px;
right: 18px;
font-size: 12px;
font-weight: 600;
color: var(--ok);
background: rgba(52, 224, 161, 0.12);
padding: 3px 9px;
border-radius: 20px;
}
.metric .trend.dn {
color: var(--bad);
background: rgba(255, 93, 115, 0.12);
}
.sectitle {
display: flex;
align-items: center;
justify-content: space-between;
margin: 8px 0 16px;
}
.sectitle h2 {
font-family: 'Outfit';
font-weight: 600;
font-size: 18px;
letter-spacing: -0.01em;
}
.sectitle a {
font-size: 13px;
color: var(--accent);
font-weight: 600;
text-decoration: none;
}
.apps {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(225px, 1fr));
gap: 16px;
}
.card {
background: var(--glass);
border: 1px solid var(--glass-line);
backdrop-filter: blur(22px) saturate(150%);
-webkit-backdrop-filter: blur(22px) saturate(150%);
border-radius: var(--radius);
padding: 18px;
cursor: pointer;
position: relative;
overflow: hidden;
transition:
transform 0.22s cubic-bezier(0.2, 0.7, 0.2, 1),
box-shadow 0.22s,
border-color 0.22s;
}
.card::after {
content: '';
position: absolute;
inset: 0;
border-radius: var(--radius);
background: linear-gradient(180deg, rgba(255, 255, 255, 0.06), transparent 40%);
pointer-events: none;
}
.card:hover {
transform: translateY(-5px);
border-color: hsl(var(--accent-h) 90% 66% / 0.5);
box-shadow: 0 24px 50px -20px hsl(var(--accent-h) 90% 50% / 0.55);
}
.card .row {
display: flex;
align-items: center;
gap: 13px;
}
.ico {
width: 46px;
height: 46px;
border-radius: 13px;
display: grid;
place-items: center;
font-size: 22px;
background: rgba(255, 255, 255, 0.06);
border: 1px solid var(--glass-line);
flex-shrink: 0;
}
.nm {
font-family: 'Outfit';
font-weight: 600;
font-size: 15.5px;
letter-spacing: -0.01em;
}
.ct {
font-size: 12px;
color: var(--ink-faint);
margin-top: 1px;
}
.pill {
margin-left: auto;
display: flex;
align-items: center;
gap: 6px;
font-size: 11px;
font-weight: 600;
padding: 5px 10px;
border-radius: 20px;
}
.pill.ok {
color: var(--ok);
background: rgba(52, 224, 161, 0.13);
}
.pill.warn {
color: var(--warn);
background: rgba(255, 194, 75, 0.13);
}
.pill.bad {
color: var(--bad);
background: rgba(255, 93, 115, 0.13);
}
.pill .b {
width: 6px;
height: 6px;
border-radius: 50%;
background: currentColor;
box-shadow: 0 0 8px currentColor;
}
.meta {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 16px;
}
.meta .up {
font-size: 12.5px;
color: var(--ink-dim);
}
.meta .up b {
color: var(--ink);
font-weight: 600;
}
.spark {
height: 24px;
width: 84px;
}
@keyframes rise {
from {
opacity: 0;
transform: translateY(14px);
}
to {
opacity: 1;
transform: none;
}
}
.metric,
.card {
animation: rise 0.55s both;
}
.metric:nth-child(2) {
animation-delay: 0.06s;
}
.metric:nth-child(3) {
animation-delay: 0.12s;
}
.metric:nth-child(4) {
animation-delay: 0.18s;
}
.apps .card:nth-child(1) {
animation-delay: 0.1s;
}
.apps .card:nth-child(2) {
animation-delay: 0.16s;
}
.apps .card:nth-child(3) {
animation-delay: 0.22s;
}
.apps .card:nth-child(4) {
animation-delay: 0.28s;
}
.apps .card:nth-child(5) {
animation-delay: 0.34s;
}
.apps .card:nth-child(6) {
animation-delay: 0.4s;
}
.apps .card:nth-child(7) {
animation-delay: 0.46s;
}
.apps .card:nth-child(8) {
animation-delay: 0.52s;
}
.swatches {
display: flex;
gap: 8px;
align-items: center;
margin-top: 30px;
justify-content: center;
color: var(--ink-faint);
font-size: 12px;
}
.sw {
width: 18px;
height: 18px;
border-radius: 6px;
cursor: pointer;
border: 1px solid var(--glass-line);
}
</style>
</head>
<body>
<div class="shell">
<!-- Sidebar -->
<aside class="side">
<div class="brand">
<div class="mark">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="3" width="7" height="7" rx="1" />
<rect x="14" y="3" width="7" height="7" rx="1" />
<rect x="14" y="14" width="7" height="7" rx="1" />
<rect x="3" y="14" width="7" height="7" rx="1" />
</svg>
</div>
<div class="name">Launcher<span>home cloud</span></div>
</div>
<div class="nav-grp">Workspace</div>
<div class="nav-i on">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
<rect x="3" y="3" width="18" height="18" rx="3" />
<path d="M3 9h18M9 21V9" />
</svg>
Overview
</div>
<div class="nav-i">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
<circle cx="12" cy="12" r="9" />
<path d="M3 12h18M12 3a14 14 0 0 1 0 18 14 14 0 0 1 0-18" />
</svg>
All Apps <span class="dot">10</span>
</div>
<div class="nav-i">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
<path d="M22 12h-4l-3 9L9 3l-3 9H2" />
</svg>
Status
</div>
<div class="nav-grp">Boards</div>
<div class="nav-i">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
<rect x="3" y="3" width="18" height="18" rx="3" />
</svg>
Media Center
</div>
<div class="nav-i">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
<rect x="3" y="3" width="18" height="18" rx="3" />
</svg>
Infrastructure
</div>
<div class="nav-i">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
<path d="M12 5v14M5 12h14" />
</svg>
New board…
</div>
<div class="side-foot">
<div class="av">AD</div>
<div class="who">Alexei<span>Administrator</span></div>
</div>
</aside>
<!-- Main -->
<main class="main">
<div class="head">
<div>
<div class="hello">Good evening, <em>Alexei</em></div>
<div class="sub">All systems nominal — 8 of 10 services responding</div>
</div>
<div class="searchwrap">
<div class="search">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="7" />
<line x1="21" y1="21" x2="16.65" y2="16.65" />
</svg>
Search… <span class="k">⌘K</span>
</div>
<div class="gbtn">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
<path d="M18 8a6 6 0 1 0-12 0c0 7-3 9-3 9h18s-3-2-3-9" />
<path d="M13.7 21a2 2 0 0 1-3.4 0" />
</svg>
</div>
<div class="gbtn">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
<circle cx="12" cy="12" r="4" />
<path
d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"
/>
</svg>
</div>
</div>
</div>
<!-- metrics -->
<div class="metrics">
<div class="metric">
<div class="ic">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M20 6 9 17l-5-5" />
</svg>
</div>
<div class="v">8<span style="color: var(--ink-faint); font-size: 18px">/10</span></div>
<div class="l">Services online</div>
<span class="trend">+2</span>
</div>
<div class="metric">
<div class="ic">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="9" />
<path d="M12 7v5l3 2" />
</svg>
</div>
<div class="v">142<span style="color: var(--ink-faint); font-size: 16px">ms</span></div>
<div class="l">Avg response</div>
<span class="trend dn">+18ms</span>
</div>
<div class="metric">
<div class="ic">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M3 12h4l3 8 4-16 3 8h4" />
</svg>
</div>
<div class="v">99.4%</div>
<div class="l">Uptime · 30d</div>
<span class="trend">+0.2</span>
</div>
<div class="metric">
<div class="ic">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M13 2 3 14h7l-1 8 10-12h-7z" />
</svg>
</div>
<div class="v">61%</div>
<div class="l">UPS load · 38m</div>
<span class="trend dn">batt</span>
</div>
</div>
<div class="sectitle">
<h2>Favorites</h2>
<a href="#">View all apps →</a>
</div>
<div class="apps">
<div class="card">
<div class="row">
<div class="ico">🎬</div>
<div>
<div class="nm">Jellyfin</div>
<div class="ct">Media</div>
</div>
<div class="pill ok"><span class="b"></span>Up</div>
</div>
<div class="meta">
<span class="up"><b>99.9%</b> uptime</span
><svg class="spark" viewBox="0 0 84 24" preserveAspectRatio="none">
<polyline
fill="none"
stroke="var(--accent)"
stroke-width="2"
points="0,18 11,15 22,17 33,9 44,12 55,7 66,11 76,5 84,8"
/>
</svg>
</div>
</div>
<div class="card">
<div class="row">
<div class="ico">📷</div>
<div>
<div class="nm">Immich</div>
<div class="ct">Photos</div>
</div>
<div class="pill ok"><span class="b"></span>Up</div>
</div>
<div class="meta">
<span class="up"><b>100%</b> uptime</span
><svg class="spark" viewBox="0 0 84 24" preserveAspectRatio="none">
<polyline
fill="none"
stroke="var(--accent)"
stroke-width="2"
points="0,13 11,14 22,12 33,13 44,11 55,12 66,10 76,12 84,11"
/>
</svg>
</div>
</div>
<div class="card">
<div class="row">
<div class="ico">🌿</div>
<div>
<div class="nm">Gitea</div>
<div class="ct">Git server</div>
</div>
<div class="pill ok"><span class="b"></span>Up</div>
</div>
<div class="meta">
<span class="up"><b>99.8%</b> uptime</span
><svg class="spark" viewBox="0 0 84 24" preserveAspectRatio="none">
<polyline
fill="none"
stroke="var(--accent)"
stroke-width="2"
points="0,15 11,10 22,13 33,8 44,12 55,9 66,14 76,8 84,10"
/>
</svg>
</div>
</div>
<div class="card">
<div class="row">
<div class="ico">🐳</div>
<div>
<div class="nm">Portainer</div>
<div class="ct">Containers</div>
</div>
<div class="pill warn"><span class="b"></span>Slow</div>
</div>
<div class="meta">
<span class="up"><b>98.1%</b> uptime</span
><svg class="spark" viewBox="0 0 84 24" preserveAspectRatio="none">
<polyline
fill="none"
stroke="var(--warn)"
stroke-width="2"
points="0,11 11,13 22,9 33,16 44,11 55,19 66,12 76,17 84,13"
/>
</svg>
</div>
</div>
<div class="card">
<div class="row">
<div class="ico">🛡️</div>
<div>
<div class="nm">Pi-hole</div>
<div class="ct">DNS · Ads</div>
</div>
<div class="pill ok"><span class="b"></span>Up</div>
</div>
<div class="meta">
<span class="up"><b>100%</b> uptime</span
><svg class="spark" viewBox="0 0 84 24" preserveAspectRatio="none">
<polyline
fill="none"
stroke="var(--accent)"
stroke-width="2"
points="0,14 11,12 22,13 33,11 44,12 55,10 66,11 76,9 84,10"
/>
</svg>
</div>
</div>
<div class="card">
<div class="row">
<div class="ico">📋</div>
<div>
<div class="nm">Planka</div>
<div class="ct">Kanban</div>
</div>
<div class="pill ok"><span class="b"></span>Up</div>
</div>
<div class="meta">
<span class="up"><b>99.5%</b> uptime</span
><svg class="spark" viewBox="0 0 84 24" preserveAspectRatio="none">
<polyline
fill="none"
stroke="var(--accent)"
stroke-width="2"
points="0,16 11,13 22,15 33,12 44,13 55,11 66,13 76,10 84,12"
/>
</svg>
</div>
</div>
<div class="card">
<div class="row">
<div class="ico">⬇️</div>
<div>
<div class="nm">Deluge</div>
<div class="ct">Downloads</div>
</div>
<div class="pill bad"><span class="b"></span>Down</div>
</div>
<div class="meta">
<span class="up" style="color: var(--bad)"
><b style="color: var(--bad)">offline</b> · 4m</span
><svg class="spark" viewBox="0 0 84 24" preserveAspectRatio="none">
<polyline
fill="none"
stroke="var(--bad)"
stroke-width="2"
points="0,10 11,12 22,15 33,13 44,19 55,17 66,21 76,20 84,22"
/>
</svg>
</div>
</div>
<div class="card">
<div class="row">
<div class="ico">🔀</div>
<div>
<div class="nm">Proxy Mgr</div>
<div class="ct">Network</div>
</div>
<div class="pill ok"><span class="b"></span>Up</div>
</div>
<div class="meta">
<span class="up"><b>99.9%</b> uptime</span
><svg class="spark" viewBox="0 0 84 24" preserveAspectRatio="none">
<polyline
fill="none"
stroke="var(--accent)"
stroke-width="2"
points="0,13 11,12 22,13 33,11 44,12 55,12 66,10 76,11 84,10"
/>
</svg>
</div>
</div>
</div>
<div class="swatches">
Accent (user-tunable):
<span
class="sw"
style="background: hsl(265 90% 66%)"
onclick="document.documentElement.style.setProperty('--accent-h', '265')"
></span>
<span
class="sw"
style="background: hsl(210 90% 60%)"
onclick="document.documentElement.style.setProperty('--accent-h', '210')"
></span>
<span
class="sw"
style="background: hsl(150 80% 55%)"
onclick="document.documentElement.style.setProperty('--accent-h', '150')"
></span>
<span
class="sw"
style="background: hsl(20 90% 62%)"
onclick="document.documentElement.style.setProperty('--accent-h', '20')"
></span>
<span
class="sw"
style="background: hsl(330 85% 65%)"
onclick="document.documentElement.style.setProperty('--accent-h', '330')"
></span>
— try clicking; the whole UI + aurora retints live
</div>
</main>
</div>
</body>
</html>