diff --git a/web/components/date-display/date-display.css b/web/components/date-display/date-display.css
new file mode 100644
index 0000000..06c3390
--- /dev/null
+++ b/web/components/date-display/date-display.css
@@ -0,0 +1,38 @@
+:host {
+ display: block;
+ background: #1e1e2e;
+ border: 1px solid #313244;
+ border-radius: 8px;
+ padding: 16px 20px;
+ font-family: monospace;
+ color: #cdd6f4;
+ min-width: 260px;
+}
+
+.label {
+ font-size: 11px;
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+ color: #6c7086;
+ margin-bottom: 6px;
+}
+
+.time {
+ font-size: 28px;
+ font-weight: 600;
+ color: #89b4fa;
+}
+
+.date {
+ font-size: 13px;
+ color: #a6adc8;
+ margin-top: 4px;
+}
+
+.agent {
+ margin-top: 12px;
+ font-size: 11px;
+ color: #585b70;
+ border-top: 1px solid #313244;
+ padding-top: 10px;
+}
diff --git a/web/components/date-display/date-display.js b/web/components/date-display/date-display.js
index dab208e..c008c93 100644
--- a/web/components/date-display/date-display.js
+++ b/web/components/date-display/date-display.js
@@ -1,53 +1,19 @@
import { config } from '../../core/config.js'
+const CSS = new URL('./date-display.css', import.meta.url).href
+
class DateDisplay extends HTMLElement {
#interval = null
connectedCallback() {
this.attachShadow({ mode: 'open' })
this.shadowRoot.innerHTML = `
-
+
Current time
agent →
`
-
this.shadowRoot.getElementById('agent-url').textContent = config.agent_url
this.#tick()
this.#interval = setInterval(() => this.#tick(), 1000)
diff --git a/web/components/login-gate/login-gate.css b/web/components/login-gate/login-gate.css
new file mode 100644
index 0000000..f843d38
--- /dev/null
+++ b/web/components/login-gate/login-gate.css
@@ -0,0 +1,81 @@
+* { box-sizing: border-box; margin: 0; padding: 0; }
+
+.overlay {
+ position: fixed;
+ inset: 0;
+ background: #181825;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 9999;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
+}
+
+.card {
+ background: #1e1e2e;
+ border: 1px solid #313244;
+ border-radius: 12px;
+ padding: 36px 40px;
+ width: 100%;
+ max-width: 420px;
+ display: flex;
+ flex-direction: column;
+ gap: 24px;
+}
+
+@media (max-width: 480px) {
+ .card { padding: 24px 20px; margin: 0 12px; }
+}
+
+.header { display: flex; flex-direction: column; gap: 6px; }
+
+.header h1 {
+ font-size: 20px;
+ font-weight: 600;
+ color: #89b4fa;
+ letter-spacing: 0.02em;
+}
+
+.header p { font-size: 13px; color: #6c7086; }
+
+.fields { display: flex; flex-direction: column; gap: 14px; }
+.field { display: flex; flex-direction: column; gap: 6px; }
+
+label {
+ font-size: 12px;
+ font-weight: 500;
+ color: #a6adc8;
+ text-transform: uppercase;
+ letter-spacing: 0.06em;
+}
+
+input {
+ background: #181825;
+ border: 1px solid #313244;
+ border-radius: 6px;
+ padding: 9px 12px;
+ color: #cdd6f4;
+ font-size: 14px;
+ font-family: monospace;
+ outline: none;
+ transition: border-color 0.15s;
+ width: 100%;
+}
+
+input:focus { border-color: #89b4fa; }
+input::placeholder { color: #45475a; }
+
+button {
+ background: #89b4fa;
+ color: #1e1e2e;
+ border: none;
+ border-radius: 6px;
+ padding: 10px 16px;
+ font-size: 14px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: background 0.15s;
+ width: 100%;
+}
+
+button:hover { background: #b4d0fa; }
diff --git a/web/components/login-gate/login-gate.js b/web/components/login-gate/login-gate.js
index 247fa06..1de65de 100644
--- a/web/components/login-gate/login-gate.js
+++ b/web/components/login-gate/login-gate.js
@@ -18,6 +18,7 @@
// Phase 2: swap for that resolves ready with a JWT — api-client unchanged.
const SESSION_KEY = 'two:credentials'
+const CSS = new URL('./login-gate.css', import.meta.url).href
class LoginGate extends HTMLElement {
#resolve = null
@@ -57,107 +58,7 @@ class LoginGate extends HTMLElement {
const overlay = document.createElement('div')
overlay.attachShadow({ mode: 'open' })
overlay.shadowRoot.innerHTML = `
-
-
+