dragon-iso/docs/preview/redesigned-mainwindow.html
Zac Gaetano 6b45c398e0
Some checks failed
CI / build-and-test (push) Failing after 27s
fix(preview): drawer uses display:none + animation when opened
Replace the transform-only approach with display:none / display:flex
switching, plus a @keyframes drawer-slide-in for the entry animation.
The previous translateX trick let the drawer-head close button's SVG
bleed through somehow (likely a browser rendering quirk on a 4K display
with HiDPI scaling); display:none guarantees the hidden state stays
fully hidden across all browsers.

Visual is the same when the drawer is open; only the closed state is
hardened. Drawer still slides in on the rail settings button or the
banner "Open settings" CTA.
2026-05-13 00:26:02 -04:00

799 lines
28 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>TeamsISO — redesigned MainWindow preview</title>
<style>
:root {
/* Dark palette — mirrors src/TeamsISO.App.WinUI/Themes/Tokens.xaml */
--bg-canvas: #0a0a0a;
--bg-rail: #080808;
--bg-surface: #141416;
--bg-elevated: #1c1c1f;
--bg-hover: #26272b;
--bg-active: #33343a;
--border-subtle: #26272b;
--border-strong: #3a3b40;
--fg-primary: #f4f4f6;
--fg-secondary: #a3a4aa;
--fg-tertiary: #6b6c72;
--fg-disabled: #404145;
--fg-on-accent: #0a0a0a;
--accent-cyan-surface: #97edf0;
--accent-cyan-text: #97edf0;
--accent-cyan-hover: #b5f2f4;
--accent-cyan-muted: #1b3537;
--accent-coral: #fb819c;
--accent-coral-bg: #3a1922;
--status-live: #4ade80;
--status-live-bg: #13261a;
--status-warn: #fbbf24;
--status-warn-bg: #3a2e12;
--shadow-drawer: rgba(0,0,0,0.55);
}
html[data-theme="light"] {
--bg-canvas: #fafafb;
--bg-rail: #f0f1f3;
--bg-surface: #ffffff;
--bg-elevated: #ffffff;
--bg-hover: #eceef1;
--bg-active: #e0e3e7;
--border-subtle: #e5e7eb;
--border-strong: #d1d5da;
--fg-primary: #0a0a0a;
--fg-secondary: #4a4b50;
--fg-tertiary: #71747a;
--fg-disabled: #b3b6bc;
--fg-on-accent: #0a0a0a;
--accent-cyan-surface: #97edf0;
--accent-cyan-text: #0e7c82;
--accent-cyan-hover: #0890a0;
--accent-cyan-muted: #e6f8f9;
--accent-coral: #d43e5c;
--accent-coral-bg: #fdecf0;
--status-live: #15803d;
--status-live-bg: #dcfce7;
--status-warn: #b45309;
--status-warn-bg: #fef3c7;
--shadow-drawer: rgba(0,0,0,0.15);
}
* { box-sizing: border-box; }
html, body {
margin: 0; padding: 0;
background: #1a1a1c;
color: var(--fg-primary);
font-family: 'Inter', -apple-system, system-ui, 'Segoe UI Variable Display', 'Segoe UI', sans-serif;
min-height: 100vh;
}
html[data-theme="light"] body { background: #e8e9eb; }
.preview-shell {
max-width: 1304px;
margin: 24px auto;
padding: 0 12px;
}
.preview-banner {
display: flex; align-items: center; justify-content: space-between;
padding: 12px 16px; margin-bottom: 16px;
background: var(--bg-surface);
border: 1px solid var(--border-subtle);
border-radius: 8px;
color: var(--fg-secondary);
font-size: 12px;
}
.preview-banner strong { color: var(--fg-primary); font-weight: 600; }
.preview-banner-actions { display: flex; gap: 8px; }
.preview-banner-actions button {
background: transparent;
border: 1px solid var(--border-strong);
color: var(--fg-primary);
padding: 6px 14px;
font-size: 12px; font-weight: 500;
border-radius: 6px;
cursor: pointer;
font-family: inherit;
}
.preview-banner-actions button:hover { border-color: var(--accent-cyan-text); }
.preview-banner-actions .primary {
background: var(--accent-cyan-surface);
border-color: var(--accent-cyan-surface);
color: var(--fg-on-accent);
font-weight: 600;
}
.window {
width: 1280px; height: 780px;
background: var(--bg-canvas);
border: 1px solid var(--border-strong);
border-radius: 8px;
display: grid;
grid-template-columns: 64px 1fr;
overflow: hidden;
color: var(--fg-primary);
box-shadow: 0 16px 60px var(--shadow-drawer);
position: relative;
}
.rail {
background: var(--bg-rail);
border-right: 1px solid var(--border-subtle);
display: flex; flex-direction: column;
padding: 12px 0 12px 0;
}
.rail-top { flex: 1; display: flex; flex-direction: column; gap: 2px; }
.rail-btn {
width: 48px; height: 48px;
margin: 4px 8px;
border-radius: 8px;
border: 0; background: transparent;
color: var(--fg-secondary);
display: flex; align-items: center; justify-content: center;
cursor: pointer;
transition: background 120ms ease-out, color 120ms ease-out;
}
.rail-btn:hover { background: var(--bg-hover); color: var(--accent-cyan-text); }
.rail-brand {
width: 48px; height: 56px;
margin: 0 8px 8px;
}
.rail-brand .mark {
width: 40px; height: 40px;
background: var(--accent-cyan-muted);
border-radius: 8px;
display: flex; align-items: center; justify-content: center;
color: var(--accent-cyan-text);
font-size: 22px; font-weight: 700;
}
.rail-divider {
height: 1px; background: var(--border-subtle);
margin: 4px 14px 12px;
}
.rail-btn.active {
background: var(--accent-cyan-muted);
color: var(--accent-cyan-text);
}
.rail-status-puck {
width: 48px; height: 48px;
margin: 12px 8px;
border-radius: 24px;
background: var(--status-live-bg);
border: 0;
display: flex; align-items: center; justify-content: center;
cursor: pointer;
}
.rail-status-puck .dot {
width: 10px; height: 10px;
background: var(--status-live);
border-radius: 50%;
}
.icon {
width: 20px; height: 20px;
stroke: currentColor;
fill: none;
stroke-width: 1.6;
stroke-linecap: round; stroke-linejoin: round;
}
.content {
display: grid;
grid-template-rows: 44px auto 1fr auto 32px;
min-width: 0;
position: relative;
overflow: hidden;
}
.titlebar {
display: grid;
grid-template-columns: auto 1fr auto auto auto auto;
align-items: center;
background: var(--bg-canvas);
}
.titlebar-app {
display: flex; align-items: center; gap: 12px;
padding: 0 24px;
}
.titlebar-app .name {
font-size: 14px; font-weight: 600;
}
.titlebar-app .version {
font-family: 'JetBrains Mono', 'Cascadia Mono', Consolas, monospace;
font-size: 11px; color: var(--fg-tertiary);
}
.titlebar-pills {
display: flex; gap: 8px;
padding: 0 12px 0 0;
}
.pill {
height: 22px;
border-radius: 999px;
padding: 0 12px;
display: inline-flex; align-items: center; gap: 6px;
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
background: var(--bg-surface);
border: 1px solid var(--border-subtle);
color: var(--fg-secondary);
}
.pill .dot {
width: 7px; height: 7px; border-radius: 50%;
background: var(--fg-tertiary);
}
.pill.live { background: var(--status-live-bg); border-color: transparent; color: var(--status-live); }
.pill.live .dot { background: var(--status-live); }
.pill.rec { background: var(--accent-coral-bg); border-color: transparent; color: var(--accent-coral); }
.pill.rec .dot { background: var(--accent-coral); }
.titlebar-tool {
width: 46px; height: 32px;
border: 0; background: transparent;
color: var(--fg-primary);
cursor: pointer;
display: flex; align-items: center; justify-content: center;
}
.titlebar-tool:hover { background: var(--bg-hover); }
.titlebar-tool.close:hover { background: #c42b1c; color: white; }
.section-header {
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
padding: 18px 32px 12px;
gap: 12px;
}
.section-title {
display: flex; align-items: center; gap: 12px;
}
.display-title {
font-size: 22px; font-weight: 600; letter-spacing: -0.01em;
color: var(--fg-primary);
}
.count-badge {
height: 22px; padding: 0 12px;
background: var(--bg-surface);
border: 1px solid var(--border-subtle);
border-radius: 999px;
display: inline-flex; align-items: center;
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
color: var(--fg-secondary);
}
.section-actions {
display: flex; gap: 8px; align-items: center;
}
.input {
width: 200px; height: 34px;
background: var(--bg-surface);
border: 1px solid var(--border-subtle);
color: var(--fg-primary);
border-radius: 8px;
padding: 0 12px;
font-family: inherit; font-size: 13px;
outline: none;
}
.input:focus { border-color: var(--accent-cyan-text); }
.input::placeholder { color: var(--fg-tertiary); }
.btn {
height: 34px;
padding: 0 14px;
border-radius: 8px;
border: 1px solid var(--border-strong);
background: transparent;
color: var(--fg-primary);
font-family: inherit; font-size: 12px; font-weight: 500;
cursor: pointer;
transition: border-color 120ms ease-out, background 120ms ease-out;
}
.btn:hover { border-color: var(--accent-cyan-text); background: var(--bg-hover); }
.btn.primary {
background: var(--accent-cyan-surface);
border-color: var(--accent-cyan-surface);
color: var(--fg-on-accent);
font-weight: 600;
}
.btn.primary:hover {
background: var(--accent-cyan-hover);
border-color: var(--accent-cyan-hover);
}
.btn.destructive {
color: var(--accent-coral);
border-color: var(--accent-coral);
}
.table {
padding: 0 32px;
overflow-y: auto;
min-height: 0;
}
.table-head {
display: grid;
grid-template-columns: 56px 2fr 1fr 1.2fr 1.5fr auto;
align-items: center;
height: 36px;
border-bottom: 1px solid var(--border-subtle);
color: var(--fg-tertiary);
font-size: 11px; font-weight: 500;
letter-spacing: 0.08em; text-transform: uppercase;
padding-right: 12px;
}
.table-head > * { padding: 0 4px; }
.row {
display: grid;
grid-template-columns: 56px 2fr 1fr 1.2fr 1.5fr auto;
align-items: center;
height: 64px;
border-bottom: 1px solid var(--border-subtle);
padding-right: 12px;
position: relative;
transition: background 120ms ease-out;
}
.row:hover { background: var(--bg-hover); }
.row.active-speaker {
background: var(--accent-cyan-muted);
}
.row .left-accent {
position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
background: var(--accent-cyan-text);
display: none;
}
.row.active-speaker .left-accent { display: block; }
.row-avatar {
width: 56px;
display: flex; align-items: center; justify-content: center;
}
.avatar {
width: 36px; height: 36px;
border-radius: 50%;
background: var(--bg-active);
color: var(--fg-secondary);
display: flex; align-items: center; justify-content: center;
font-size: 13px; font-weight: 600;
}
.row.active-speaker .avatar {
background: var(--accent-cyan-muted);
color: var(--accent-cyan-text);
}
.row-name { line-height: 1.3; }
.row-name .name {
font-size: 14px; font-weight: 500;
margin-bottom: 2px;
}
.row-name .codec {
font-size: 11px; color: var(--fg-secondary);
}
.row-signal {
display: flex; align-items: center; gap: 8px;
font-family: 'JetBrains Mono', monospace; font-size: 11px;
}
.row-signal .dot {
width: 8px; height: 8px; border-radius: 50%;
}
.row-signal.locked .dot { background: var(--status-live); }
.row-signal.degraded { color: var(--status-warn); }
.row-signal.degraded .dot { background: var(--status-warn); }
.meter { display: flex; align-items: center; gap: 2px; height: 24px; }
.meter span {
width: 4px; border-radius: 2px;
background: var(--bg-active);
}
.meter.active span { background: var(--fg-secondary); }
.row.active-speaker .meter.active span { background: var(--accent-cyan-text); }
.row-output {
font-family: 'JetBrains Mono', monospace; font-size: 13px;
color: var(--fg-primary);
}
.iso-pill {
width: 80px;
padding: 6px 0;
border-radius: 999px;
text-align: center;
font-size: 11px; font-weight: 700;
letter-spacing: 0.06em;
}
.iso-pill.live {
background: var(--status-live-bg);
color: var(--status-live);
border: 1px solid var(--status-live);
}
.iso-pill.off {
background: var(--bg-surface);
color: var(--fg-secondary);
border: 1px solid var(--border-strong);
}
.in-call {
padding: 12px 32px;
border-top: 1px solid var(--border-subtle);
background: var(--bg-canvas);
display: flex; align-items: center; gap: 10px;
}
.in-call .label {
font-size: 11px; font-weight: 500; letter-spacing: 0.08em;
text-transform: uppercase; color: var(--fg-tertiary);
margin-right: 8px;
}
.status-bar {
padding: 0 32px;
border-top: 1px solid var(--border-subtle);
background: var(--bg-canvas);
display: flex; align-items: center; justify-content: space-between;
font-family: 'JetBrains Mono', monospace;
font-size: 11px; color: var(--fg-tertiary);
}
.status-bar .left {
display: flex; align-items: center; gap: 8px;
color: var(--fg-secondary);
}
.status-bar .left .dot {
width: 6px; height: 6px; border-radius: 50%;
background: var(--accent-cyan-text);
}
/* Settings drawer */
.drawer {
position: absolute;
top: 44px;
right: 0;
bottom: 0;
width: 400px;
background: var(--bg-surface);
border-left: 1px solid var(--border-subtle);
flex-direction: column;
z-index: 5;
display: none;
}
.drawer.open {
display: flex;
animation: drawer-slide-in 220ms cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes drawer-slide-in {
from { transform: translateX(420px); }
to { transform: translateX(0); }
}
.drawer-head {
height: 56px;
padding: 0 12px 0 20px;
border-bottom: 1px solid var(--border-subtle);
display: flex; align-items: center; justify-content: space-between;
}
.drawer-head .title {
font-size: 18px; font-weight: 600;
}
.drawer-tabs {
display: flex; gap: 6px;
padding: 12px 20px 0;
border-bottom: 1px solid var(--border-subtle);
}
.drawer-tab {
padding: 8px 12px;
border: 0; background: transparent;
color: var(--fg-tertiary);
font-family: inherit; font-size: 12px; font-weight: 500;
cursor: pointer;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
}
.drawer-tab.active {
color: var(--fg-primary);
border-bottom-color: var(--accent-cyan-text);
}
.drawer-body {
flex: 1;
padding: 20px;
overflow-y: auto;
}
.drawer-body h3 {
font-size: 14px; font-weight: 600;
margin: 0 0 12px 0;
color: var(--fg-primary);
}
.drawer-body p {
font-size: 12px;
color: var(--fg-secondary);
margin: 0 0 16px 0;
line-height: 1.5;
}
.theme-picker { display: flex; gap: 8px; margin-bottom: 16px; }
.theme-pick-btn {
flex: 1;
padding: 12px 14px;
border-radius: 8px;
border: 1px solid var(--border-strong);
background: transparent;
color: var(--fg-primary);
font-family: inherit; font-size: 13px; font-weight: 500;
cursor: pointer;
text-align: left;
}
.theme-pick-btn.active {
border-color: var(--accent-cyan-text);
background: var(--accent-cyan-muted);
}
.accent-swatches { display: flex; gap: 12px; flex-wrap: wrap; }
.swatch {
display: flex; flex-direction: column; gap: 6px;
text-align: center;
}
.swatch .chip {
width: 80px; height: 32px;
border-radius: 6px;
}
.swatch .label {
font-family: 'JetBrains Mono', monospace;
font-size: 11px; color: var(--fg-tertiary);
letter-spacing: 0.06em; text-transform: uppercase;
}
.drawer-row {
display: grid;
grid-template-columns: 1fr auto;
padding: 6px 0;
border-bottom: 1px solid var(--border-subtle);
font-size: 13px;
}
.drawer-row .v {
font-family: 'JetBrains Mono', monospace;
color: var(--fg-secondary);
}
.drawer-foot {
padding: 12px 16px;
border-top: 1px solid var(--border-subtle);
display: flex; justify-content: flex-end; gap: 8px;
}
</style>
</head>
<body>
<div class="preview-shell">
<div class="preview-banner">
<div>
<strong>TeamsISO redesign — interactive preview</strong>
&nbsp;The same XAML that's in <code>src/TeamsISO.App.WinUI/Views/MainWindow.xaml</code>, rendered as HTML so you can see and toggle it before the WinUI 3 .exe activation issue is resolved.
</div>
<div class="preview-banner-actions">
<button id="open-drawer">Open settings</button>
<button id="toggle-theme" class="primary">Toggle dark / light</button>
</div>
</div>
<div class="window">
<!-- RAIL -->
<div class="rail">
<div class="rail-top">
<button class="rail-btn rail-brand" title="About TeamsISO">
<div class="mark">W</div>
</button>
<div class="rail-divider"></div>
<button class="rail-btn active" title="Participants">
<svg class="icon" viewBox="0 0 24 24"><circle cx="12" cy="9" r="3.2"/><path d="M5 19c0-3.5 3.1-6 7-6s7 2.5 7 6"/></svg>
</button>
<button class="rail-btn" title="Launch / surface Teams">
<svg class="icon" viewBox="0 0 24 24"><rect x="3" y="7" width="13" height="10" rx="2"/><path d="M16 11l5-3v8l-5-3z"/></svg>
</button>
<button class="rail-btn" title="Hide / show Teams windows">
<svg class="icon" viewBox="0 0 24 24"><path d="M2 12s4-7 10-7 10 7 10 7-4 7-10 7S2 12 2 12z"/><circle cx="12" cy="12" r="3"/></svg>
</button>
<button class="rail-btn" id="rail-settings" title="Settings">
<svg class="icon" viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3h.1a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8v.1a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z"/></svg>
</button>
</div>
<button class="rail-status-puck" title="Engine status">
<div class="dot"></div>
</button>
</div>
<!-- CONTENT -->
<div class="content">
<!-- Title bar -->
<div class="titlebar">
<div class="titlebar-app">
<span class="name">TeamsISO</span>
<span class="version">v1.0.0-alpha</span>
</div>
<div></div>
<div class="titlebar-pills">
<div class="pill live"><div class="dot"></div>live · 00:14:32</div>
<div class="pill rec"><div class="dot"></div>rec 3 · 00:11:08</div>
<div class="pill">482 GB free</div>
</div>
<button class="titlebar-tool" id="titlebar-theme" title="Theme">
<svg class="icon" viewBox="0 0 24 24" id="theme-icon-mark"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
</button>
<button class="titlebar-tool" title="Minimize">
<svg class="icon" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/></svg>
</button>
<button class="titlebar-tool" title="Maximize">
<svg class="icon" viewBox="0 0 24 24"><rect x="5" y="5" width="14" height="14"/></svg>
</button>
<button class="titlebar-tool close" title="Close">
<svg class="icon" viewBox="0 0 24 24"><line x1="6" y1="6" x2="18" y2="18"/><line x1="18" y1="6" x2="6" y2="18"/></svg>
</button>
</div>
<!-- Section header -->
<div class="section-header">
<div class="section-title">
<span class="display-title">Participants</span>
<span class="count-badge">4</span>
</div>
<div></div>
<div class="section-actions">
<input class="input" placeholder="Filter participants"/>
<button class="btn">Refresh</button>
<button class="btn">Presets</button>
<button class="btn primary">Enable all online</button>
</div>
</div>
<!-- Table -->
<div class="table">
<div class="table-head">
<div></div>
<div>Participant</div>
<div>Signal</div>
<div>Audio</div>
<div>Output name</div>
<div>ISO</div>
</div>
<div class="row active-speaker">
<div class="left-accent"></div>
<div class="row-avatar"><div class="avatar">MA</div></div>
<div class="row-name"><div class="name">Maya Rodriguez</div><div class="codec">MS Teams · 1920×1080 · 30fps</div></div>
<div class="row-signal locked"><div class="dot"></div>locked</div>
<div>
<div class="meter active">
<span style="height:24px"></span>
<span style="height:20px"></span>
<span style="height:28px"></span>
<span style="height:18px"></span>
<span style="height:12px"></span>
<span style="height:22px"></span>
<span style="height:8px"></span>
<span style="height:14px"></span>
<span style="height:6px"></span>
</div>
</div>
<div class="row-output">TEAMSISO_maya</div>
<div><div class="iso-pill live">LIVE</div></div>
</div>
<div class="row">
<div class="row-avatar"><div class="avatar">DC</div></div>
<div class="row-name"><div class="name">Daniel Chen</div><div class="codec">MS Teams · 1280×720 · 30fps</div></div>
<div class="row-signal locked"><div class="dot"></div>locked</div>
<div>
<div class="meter active">
<span style="height:10px"></span>
<span style="height:14px"></span>
<span style="height:8px"></span>
<span style="height:12px"></span>
<span style="height:6px"></span>
<span style="height:9px"></span>
<span style="height:4px"></span>
<span style="height:3px"></span>
<span style="height:2px"></span>
</div>
</div>
<div class="row-output">TEAMSISO_daniel</div>
<div><div class="iso-pill live">LIVE</div></div>
</div>
<div class="row">
<div class="row-avatar"><div class="avatar">AK</div></div>
<div class="row-name"><div class="name">Aïcha Koné</div><div class="codec">MS Teams · 1920×1080 · 30fps</div></div>
<div class="row-signal degraded"><div class="dot"></div>degraded</div>
<div>
<div class="meter">
<span style="height:3px"></span>
<span style="height:4px"></span>
<span style="height:3px"></span>
<span style="height:2px"></span>
</div>
</div>
<div class="row-output" style="color:var(--fg-secondary)">TEAMSISO_aicha</div>
<div><div class="iso-pill off">OFF</div></div>
</div>
<div class="row">
<div class="row-avatar"><div class="avatar">SP</div></div>
<div class="row-name"><div class="name">Sam Park</div><div class="codec">MS Teams · 1920×1080 · 30fps</div></div>
<div class="row-signal locked"><div class="dot"></div>locked</div>
<div>
<div class="meter active">
<span style="height:8px"></span>
<span style="height:12px"></span>
<span style="height:16px"></span>
<span style="height:7px"></span>
<span style="height:5px"></span>
<span style="height:3px"></span>
</div>
</div>
<div class="row-output">TEAMSISO_sam</div>
<div><div class="iso-pill live">LIVE</div></div>
</div>
</div>
<!-- In-call control -->
<div class="in-call">
<span class="label">In-call</span>
<button class="btn destructive">⊘ Muted</button>
<button class="btn">⌗ Camera</button>
<button class="btn">⇪ Share</button>
<button class="btn">▷ Marker</button>
<button class="btn destructive">Leave</button>
<button class="btn" style="width:36px;padding:0;"></button>
</div>
<!-- Status bar -->
<div class="status-bar">
<div class="left">
<div class="dot"></div>
<span>control surface · 127.0.0.1:9755</span>
</div>
<div>F1 help · Ctrl+M marker · Ctrl+Shift+S panic · Ctrl+K command palette</div>
</div>
<!-- Settings drawer -->
<div class="drawer" id="drawer">
<div class="drawer-head">
<div class="title">Settings</div>
<button class="titlebar-tool" id="drawer-close" title="Close (Esc)">
<svg class="icon" viewBox="0 0 24 24"><line x1="6" y1="6" x2="18" y2="18"/><line x1="18" y1="6" x2="6" y2="18"/></svg>
</button>
</div>
<div class="drawer-tabs">
<button class="drawer-tab active">Appearance</button>
<button class="drawer-tab">Routing</button>
<button class="drawer-tab">Display</button>
<button class="drawer-tab">Control</button>
<button class="drawer-tab">Advanced</button>
</div>
<div class="drawer-body">
<h3>Appearance</h3>
<p>Dark is the default for the 1:50am operator scene; light is for daytime production. System follows the Windows app-mode preference.</p>
<div class="theme-picker">
<button class="theme-pick-btn" data-theme="dark">Dark</button>
<button class="theme-pick-btn active" data-theme="dark">System</button>
<button class="theme-pick-btn" data-theme="light">Light</button>
</div>
<h3>Accent peek</h3>
<p>These accents work in both themes. Cyan stays bright as a surface fill (text on top is near-black regardless). For inline text on light, the palette substitutes a darker cyan automatically.</p>
<div class="accent-swatches">
<div class="swatch"><div class="chip" style="background:var(--accent-cyan-surface)"></div><div class="label">Cyan</div></div>
<div class="swatch"><div class="chip" style="background:var(--accent-coral)"></div><div class="label">Coral</div></div>
<div class="swatch"><div class="chip" style="background:var(--status-live)"></div><div class="label">Live</div></div>
<div class="swatch"><div class="chip" style="background:var(--status-warn)"></div><div class="label">Warn</div></div>
</div>
</div>
<div class="drawer-foot">
<button class="btn">Reset to defaults</button>
<button class="btn primary">Apply</button>
</div>
</div>
</div>
</div>
</div>
<script>
const html = document.documentElement;
const themeIcon = document.getElementById('theme-icon-mark');
const sunPath = 'M12 1v2 M12 21v2 M4.2 4.2l1.4 1.4 M18.4 18.4l1.4 1.4 M1 12h2 M21 12h2 M4.2 19.8l1.4-1.4 M18.4 5.6l1.4-1.4 M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8';
const moonPath = 'M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z';
function applyTheme(t) {
html.dataset.theme = t;
themeIcon.setAttribute('d', t === 'light' ? sunPath : moonPath);
themeIcon.parentElement.innerHTML = `<svg class="icon" viewBox="0 0 24 24" id="theme-icon-mark"><path d="${t === 'light' ? sunPath : moonPath}"/></svg>`;
}
function toggle() {
applyTheme(html.dataset.theme === 'light' ? 'dark' : 'light');
}
document.getElementById('toggle-theme').addEventListener('click', toggle);
document.getElementById('titlebar-theme').addEventListener('click', toggle);
const drawer = document.getElementById('drawer');
document.getElementById('rail-settings').addEventListener('click', () => drawer.classList.add('open'));
document.getElementById('open-drawer').addEventListener('click', () => drawer.classList.add('open'));
document.getElementById('drawer-close').addEventListener('click', () => drawer.classList.remove('open'));
document.addEventListener('keydown', (e) => { if (e.key === 'Escape') drawer.classList.remove('open'); });
applyTheme('dark');
</script>
</body>
</html>