Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesPull RequestsActionsSecurityInsightsSettings
✨ AI
More
Blame · Line-by-line history

layout.tsx

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

layout.tsxBlame2245 lines · 2 contributors
fc1817aClaude1import type { FC, PropsWithChildren } from "hono/jsx";
06d5ffeClaude2import type { User } from "../db/schema";
3import { hljsThemeCss } from "../lib/highlight";
45e31d0Claude4import { clientJs } from "./client-js";
05cdb85Claude5import { getBuildInfo } from "../lib/build-info";
fc1817aClaude6
06d5ffeClaude7export const Layout: FC<
3ef4c9dClaude8 PropsWithChildren<{
9 title?: string;
10 user?: User | null;
11 notificationCount?: number;
6fc53bdClaude12 theme?: "dark" | "light";
3ef4c9dClaude13 }>
6fc53bdClaude14> = ({ children, title, user, notificationCount, theme }) => {
15 const initialTheme = theme === "light" ? "light" : "dark";
05cdb85Claude16 const build = getBuildInfo();
fc1817aClaude17 return (
6fc53bdClaude18 <html lang="en" data-theme={initialTheme}>
fc1817aClaude19 <head>
20 <meta charset="UTF-8" />
21 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
eae38d1Claude22 <meta name="theme-color" content="#0d1117" />
23 <link rel="manifest" href="/manifest.webmanifest" />
24 <link rel="icon" type="image/svg+xml" href="/icon.svg" />
4c47454Claude25 <link rel="preconnect" href="https://fonts.googleapis.com" />
26 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="" />
27 <link
28 rel="stylesheet"
29 href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap"
30 />
fc1817aClaude31 <title>{title ? `${title} — gluecron` : "gluecron"}</title>
6fc53bdClaude32 <script>{themeInitScript}</script>
fc1817aClaude33 <style>{css}</style>
06d5ffeClaude34 <style>{hljsThemeCss}</style>
fc1817aClaude35 </head>
36 <body>
4a52a98Claude37 <div class="prelaunch-banner" role="status" aria-live="polite">
38 Pre-launch &mdash; Gluecron is in final validation. Public signups
39 and git hosting for non-owner users open after launch review.
40 </div>
fc1817aClaude41 <header>
42 <nav>
43 <a href="/" class="logo">
44 gluecron
45 </a>
3ef4c9dClaude46 <div class="nav-search">
001af43Claude47 <form method="get" action="/search">
3ef4c9dClaude48 <input
49 type="search"
50 name="q"
51 placeholder="Search (press /)"
52 aria-label="Search"
53 />
54 </form>
55 </div>
06d5ffeClaude56 <div class="nav-right">
6fc53bdClaude57 <a
58 href="/theme/toggle"
59 class="nav-link nav-theme"
60 title="Toggle theme"
61 aria-label="Toggle theme"
62 >
63 <span class="theme-icon-dark">{"\u263E"}</span>
64 <span class="theme-icon-light">{"\u2600"}</span>
65 </a>
c81ab7aClaude66 <a href="/explore" class="nav-link">
67 Explore
68 </a>
06d5ffeClaude69 {user ? (
70 <>
f1ab587Claude71 <a href="/dashboard" class="nav-link" style="font-weight: 600">
72 Dashboard
73 </a>
bdbd0deClaude74 <a href="/import" class="nav-link">
75 Import
76 </a>
06d5ffeClaude77 <a href="/new" class="btn btn-sm btn-primary">
78 + New
79 </a>
80 <a href={`/${user.username}`} class="nav-user">
81 {user.displayName || user.username}
82 </a>
83 <a href="/settings" class="nav-link">
84 Settings
85 </a>
86 <a href="/logout" class="nav-link">
87 Sign out
88 </a>
89 </>
90 ) : (
91 <>
92 <a href="/login" class="nav-link">
93 Sign in
94 </a>
95 <a href="/register" class="btn btn-sm btn-primary">
96 Register
97 </a>
98 </>
99 )}
100 </div>
fc1817aClaude101 </nav>
102 </header>
45e31d0Claude103 <main id="main-content">{children}</main>
fc1817aClaude104 <footer>
958d26aClaude105 <div class="footer-inner">
106 <div class="footer-brand">
107 <a href="/" class="logo">gluecron</a>
108 <p class="footer-tag">
109 AI-native code intelligence. Self-hosted git, automated CI,
110 push-time gates. Software that ships itself.
111 </p>
112 </div>
113 <div class="footer-links">
114 <div class="footer-col">
115 <div class="footer-col-title">Product</div>
b0148e9Claude116 <a href="/features">Features</a>
117 <a href="/pricing">Pricing</a>
958d26aClaude118 <a href="/explore">Explore</a>
119 <a href="/marketplace">Marketplace</a>
120 </div>
121 <div class="footer-col">
122 <div class="footer-col-title">Platform</div>
b0148e9Claude123 <a href="/help">Quickstart</a>
958d26aClaude124 <a href="/status">Status</a>
125 <a href="/api/graphql">GraphQL</a>
126 <a href="/mcp">MCP server</a>
127 </div>
128 <div class="footer-col">
b0148e9Claude129 <div class="footer-col-title">Company</div>
130 <a href="/about">About</a>
958d26aClaude131 <a href="/terms">Terms</a>
132 <a href="/privacy">Privacy</a>
133 <a href="/acceptable-use">Acceptable use</a>
134 </div>
135 </div>
136 </div>
137 <div class="footer-bottom">
138 <span>&copy; {new Date().getFullYear()} gluecron</span>
05cdb85Claude139 <span class="footer-build" title={`commit ${build.shaFull}\nbuilt ${build.builtAt}`}>
140 <span class="footer-build-dot" aria-hidden="true" />
141 {build.sha} · {build.branch}
142 </span>
36b4cbdClaude143 </div>
fc1817aClaude144 </footer>
05cdb85Claude145 {/* Live update poller — checks /api/version every 15s, prompts
146 reload when the running sha changes. Pure progressive-
147 enhancement; degrades to nothing if JS is off. */}
148 <div
149 id="version-banner"
150 style="display:none;position:fixed;bottom:18px;left:50%;transform:translateX(-50%);z-index:9999;background:var(--bg-elevated);border:1px solid rgba(140,109,255,0.45);border-radius:9999px;padding:8px 14px 8px 14px;font-size:13px;color:var(--text-strong);box-shadow:0 12px 28px -8px rgba(0,0,0,0.55),0 0 24px -6px rgba(140,109,255,0.40);font-family:var(--font-sans);align-items:center;gap:10px"
151 >
152 <span style="display:inline-flex;align-items:center;gap:8px">
153 <span style="width:8px;height:8px;border-radius:50%;background:#34d399;box-shadow:0 0 10px rgba(52,211,153,0.6)" />
154 <span>New version available</span>
155 </span>
156 <button
157 type="button"
158 id="version-banner-reload"
159 style="background:linear-gradient(135deg,#8c6dff 0%,#36c5d6 100%);color:#fff;border:0;border-radius:9999px;padding:5px 12px;font-size:12px;font-weight:600;cursor:pointer;font-family:inherit"
160 >
161 Reload
162 </button>
163 </div>
164 <script>{versionPollerScript}</script>
699e5c7Claude165 {/* Block I4 — Command palette shell (hidden by default) */}
166 <div
167 id="cmdk-backdrop"
168 style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:9998"
169 />
170 <div
171 id="cmdk-panel"
172 style="display:none;position:fixed;top:10%;left:50%;transform:translateX(-50%);width:min(560px,92vw);background:var(--bg-secondary);border:1px solid var(--border);border-radius:var(--radius);box-shadow:0 12px 32px rgba(0,0,0,0.4);z-index:9999;overflow:hidden"
173 >
174 <input
175 id="cmdk-input"
176 type="text"
177 placeholder="Type a command..."
178 aria-label="Command palette"
179 style="width:100%;padding:12px 16px;background:transparent;color:var(--text);border:0;border-bottom:1px solid var(--border);outline:none;font-size:14px"
180 />
181 <div id="cmdk-list" style="max-height:60vh;overflow-y:auto" />
182 </div>
45e31d0Claude183 <script>{clientJs}</script>
699e5c7Claude184 <script>{pwaRegisterScript}</script>
185 <script>{navScript}</script>
fc1817aClaude186 </body>
187 </html>
188 );
189};
190
05cdb85Claude191// Live version poller. Checks /api/version every 15s; if the sha differs
192// from the one we booted with, reveal the floating 'New version' pill so
193// the user can reload onto the new code without manually refreshing.
194const versionPollerScript = `
195 (function(){
196 var loadedSha = null;
197 var banner, btn;
198 function poll(){
199 fetch('/api/version', { cache: 'no-store' })
200 .then(function(r){ return r.ok ? r.json() : null; })
201 .then(function(j){
202 if (!j || !j.sha) return;
203 if (loadedSha === null) { loadedSha = j.sha; return; }
204 if (j.sha !== loadedSha && banner) {
205 banner.style.display = 'inline-flex';
206 }
207 })
208 .catch(function(){});
209 }
210 function init(){
211 banner = document.getElementById('version-banner');
212 btn = document.getElementById('version-banner-reload');
213 if (btn) btn.addEventListener('click', function(){ window.location.reload(); });
214 poll();
215 setInterval(poll, 15000);
216 }
217 if (document.readyState === 'loading') {
218 document.addEventListener('DOMContentLoaded', init);
219 } else {
220 init();
221 }
222 })();
223`;
224
6fc53bdClaude225// Runs before paint — reads the theme cookie and flips data-theme so there's
226// no dark-to-light flash on load. SSR default is dark.
227const themeInitScript = `
228 (function(){
229 try {
230 var m = document.cookie.match(/(?:^|; )theme=([^;]+)/);
231 var t = m ? decodeURIComponent(m[1]) : 'dark';
232 if (t !== 'light' && t !== 'dark') t = 'dark';
233 document.documentElement.setAttribute('data-theme', t);
234 } catch(_){}
235 })();
236`;
237
eae38d1Claude238// Block G1 — register service worker for offline / install support.
239// Kept inline (and tiny) so we don't block first paint.
240const pwaRegisterScript = `
241 if ('serviceWorker' in navigator) {
242 window.addEventListener('load', function(){
243 navigator.serviceWorker.register('/sw.js').catch(function(){});
244 });
245 }
246`;
247
3ef4c9dClaude248const navScript = `
249 (function(){
250 var chord = null;
251 var chordTimer = null;
252 function isTyping(t){
253 t = t || {};
254 var tag = (t.tagName || '').toLowerCase();
255 return tag === 'input' || tag === 'textarea' || t.isContentEditable;
256 }
71cd5ecClaude257
258 // ---------- Block I4 — Command palette ----------
259 var COMMANDS = [
260 { label: 'Go to Dashboard', href: '/dashboard', kw: 'home' },
261 { label: 'Go to Explore', href: '/explore', kw: 'browse discover' },
262 { label: 'Go to Notifications', href: '/notifications', kw: 'inbox' },
263 { label: 'Go to Ask AI', href: '/ask', kw: 'chat assistant' },
264 { label: 'Create new repository', href: '/new', kw: 'add create' },
265 { label: 'Marketplace', href: '/marketplace', kw: 'apps store' },
266 { label: 'Installed apps', href: '/settings/apps', kw: 'my apps' },
267 { label: 'Register new app', href: '/developer/apps-new', kw: 'developer create' },
268 { label: 'Keyboard shortcuts', href: '/shortcuts', kw: 'help keys' },
269 { label: 'Settings (profile)', href: '/settings', kw: 'account' },
270 { label: '2FA settings', href: '/settings/2fa', kw: 'two factor security' },
271 { label: 'Passkeys settings', href: '/settings/passkeys', kw: 'webauthn' },
272 { label: 'Personal access tokens', href: '/settings/tokens', kw: 'pat api' },
273 { label: 'Billing + quotas', href: '/settings/billing', kw: 'plans money' },
274 { label: 'Audit log (personal)', href: '/settings/audit', kw: 'history' },
275 { label: 'Gists', href: '/gists', kw: 'snippets' },
276 { label: 'GraphQL explorer', href: '/api/graphql', kw: 'api query' },
277 { label: 'Admin dashboard', href: '/admin', kw: 'superuser' },
278 { label: 'Toggle theme', href: '/theme/toggle', kw: 'dark light mode' }
279 ];
280
281 function fuzzyMatch(item, q){
282 if (!q) return true;
283 var hay = (item.label + ' ' + (item.kw||'') + ' ' + item.href).toLowerCase();
284 q = q.toLowerCase();
285 var qi = 0;
286 for (var i = 0; i < hay.length && qi < q.length; i++) {
287 if (hay[i] === q[qi]) qi++;
288 }
289 return qi === q.length;
290 }
291
292 var backdrop, panel, input, list, selected = 0, filtered = COMMANDS.slice();
293
294 function render(){
295 if (!list) return;
296 var html = '';
297 for (var i = 0; i < filtered.length; i++) {
298 var item = filtered[i];
299 var cls = i === selected ? 'cmdk-item cmdk-active' : 'cmdk-item';
300 var bg = i === selected ? 'background:var(--bg);' : '';
ea52715copilot-swe-agent[bot]301 html += '<div class="' + cls + '" data-idx="' + i + '" data-url="' + item.href + '"' +
71cd5ecClaude302 ' style="padding:10px 16px;cursor:pointer;border-bottom:1px solid var(--border);' + bg + '">' +
303 '<div>' + item.label + '</div>' +
304 '<div style="font-size:11px;color:var(--text-muted)">' + item.href + '</div>' +
305 '</div>';
306 }
307 if (filtered.length === 0) {
308 html = '<div style="padding:16px;color:var(--text-muted);text-align:center">No matches.</div>';
309 }
310 list.innerHTML = html;
311 }
312
313 function openPalette(){
314 backdrop = document.getElementById('cmdk-backdrop');
315 panel = document.getElementById('cmdk-panel');
316 input = document.getElementById('cmdk-input');
317 list = document.getElementById('cmdk-list');
318 if (!backdrop || !panel) return;
319 backdrop.style.display = 'block';
320 panel.style.display = 'block';
321 input.value = '';
322 selected = 0;
323 filtered = COMMANDS.slice();
324 render();
325 input.focus();
326 }
327 function closePalette(){
328 if (backdrop) backdrop.style.display = 'none';
329 if (panel) panel.style.display = 'none';
330 }
331 function go(href){ closePalette(); window.location.href = href; }
332
333 document.addEventListener('click', function(e){
334 var t = e.target;
335 if (t && t.id === 'cmdk-backdrop') { closePalette(); return; }
336 var item = t && t.closest && t.closest('.cmdk-item');
ea52715copilot-swe-agent[bot]337 if (item) { go(item.getAttribute('data-url')); }
71cd5ecClaude338 });
339
340 document.addEventListener('input', function(e){
341 if (e.target && e.target.id === 'cmdk-input') {
342 var q = e.target.value;
343 filtered = COMMANDS.filter(function(c){ return fuzzyMatch(c, q); });
344 selected = 0;
345 render();
346 }
347 });
348
3ef4c9dClaude349 document.addEventListener('keydown', function(e){
71cd5ecClaude350 // Palette-scoped keys take priority when open
351 if (panel && panel.style.display === 'block') {
352 if (e.key === 'Escape') { e.preventDefault(); closePalette(); return; }
353 if (e.key === 'ArrowDown') {
354 e.preventDefault();
355 selected = Math.min(filtered.length - 1, selected + 1);
356 render();
357 return;
358 }
359 if (e.key === 'ArrowUp') {
360 e.preventDefault();
361 selected = Math.max(0, selected - 1);
362 render();
363 return;
364 }
365 if (e.key === 'Enter') {
366 e.preventDefault();
367 var item = filtered[selected];
368 if (item) go(item.href);
369 return;
370 }
371 return;
372 }
373
3ef4c9dClaude374 if (isTyping(e.target)) return;
375 // Single key shortcuts
376 if (e.key === '/') {
377 var el = document.querySelector('.nav-search input');
378 if (el) { e.preventDefault(); el.focus(); return; }
379 }
380 if ((e.metaKey||e.ctrlKey) && e.key.toLowerCase() === 'k') {
71cd5ecClaude381 e.preventDefault();
382 openPalette();
383 return;
3ef4c9dClaude384 }
385 if (e.key === '?' && !e.ctrlKey && !e.metaKey) {
386 e.preventDefault(); window.location.href = '/shortcuts'; return;
387 }
388 if (e.key === 'n' && !e.ctrlKey && !e.metaKey) {
389 e.preventDefault(); window.location.href = '/new'; return;
390 }
391 // "g" chord
392 if (e.key === 'g' && !e.ctrlKey && !e.metaKey) {
393 chord = 'g';
394 clearTimeout(chordTimer);
395 chordTimer = setTimeout(function(){ chord = null; }, 1200);
396 return;
397 }
398 if (chord === 'g') {
399 if (e.key === 'd') { e.preventDefault(); window.location.href = '/dashboard'; }
400 else if (e.key === 'n') { e.preventDefault(); window.location.href = '/notifications'; }
401 else if (e.key === 'e') { e.preventDefault(); window.location.href = '/explore'; }
402 else if (e.key === 'a') { e.preventDefault(); window.location.href = '/ask'; }
403 chord = null;
404 }
405 });
406 })();
407`;
408
fc1817aClaude409const css = `
2ce1d0bClaude410 /* ================================================================
958d26aClaude411 * Gluecron design system — 2026.05 "Editorial-Technical"
412 * Slate-noir base · refined violet signature · hairline geometry ·
413 * mono-as-feature · cinematic motion · Inter Tight + JetBrains Mono.
414 * All class names preserved for back-compat across 50+ route views.
2ce1d0bClaude415 * ============================================================== */
6fc53bdClaude416 :root, :root[data-theme='dark'] {
958d26aClaude417 /* Surfaces — slate, not black. More depth, less crush. */
418 --bg: #08090f;
419 --bg-secondary: #0c0d14;
420 --bg-tertiary: #11131c;
421 --bg-elevated: #0f111a;
422 --bg-surface: #161826;
423 --bg-hover: rgba(255,255,255,0.04);
424 --bg-active: rgba(255,255,255,0.08);
425 --bg-inset: rgba(0,0,0,0.30);
426
427 /* Borders — three weights, used deliberately */
428 --border: rgba(255,255,255,0.06);
429 --border-subtle: rgba(255,255,255,0.035);
430 --border-strong: rgba(255,255,255,0.13);
431 --border-focus: rgba(140,109,255,0.55);
432
433 /* Text */
434 --text: #ededf2;
435 --text-strong: #f7f7fb;
436 --text-muted: #8b8c9c;
437 --text-faint: #555665;
438 --text-link: #b69dff;
439
440 /* Accent — refined violet (less candy), warm amber as secondary signal */
441 --accent: #8c6dff;
442 --accent-2: #36c5d6;
443 --accent-warm: #ffb45e;
444 --accent-hover: #a48bff;
445 --accent-pressed:#7559e8;
446 --accent-gradient: linear-gradient(135deg, #8c6dff 0%, #36c5d6 100%);
447 --accent-gradient-soft: linear-gradient(135deg, rgba(140,109,255,0.18) 0%, rgba(54,197,214,0.18) 100%);
448 --accent-gradient-faint: linear-gradient(135deg, rgba(140,109,255,0.07) 0%, rgba(54,197,214,0.07) 100%);
449 --accent-glow: 0 0 24px rgba(140,109,255,0.28);
450
451 /* Semantic */
452 --green: #34d399;
453 --red: #f87171;
454 --yellow: #fbbf24;
455 --amber: #fbbf24;
456 --blue: #60a5fa;
457
458 /* Type — Inter Tight for sans (tighter metrics) */
4c47454Claude459 --font-mono: 'JetBrains Mono', 'SF Mono', 'Cascadia Code', 'Fira Code', ui-monospace, monospace;
958d26aClaude460 --font-sans: 'Inter Tight', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
461 --font-display: 'Inter Tight', 'Inter', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
462 --mono-feat: 'calt', 'liga', 'ss01';
463
464 /* Radius — sharper than before */
465 --r-sm: 5px;
466 --r: 7px;
467 --r-md: 9px;
468 --r-lg: 12px;
469 --r-xl: 16px;
470 --r-2xl: 22px;
471 --r-full: 9999px;
472 --radius: 7px;
473
474 /* Type scale — bigger display sizes for editorial feel */
475 --t-xs: 11px;
476 --t-sm: 13px;
477 --t-base: 14px;
478 --t-md: 16px;
479 --t-lg: 20px;
480 --t-xl: 28px;
481 --t-2xl: 40px;
482 --t-3xl: 56px;
483 --t-display: 72px;
484 --t-display-lg:96px;
485
486 /* Spacing — 4px base */
2ce1d0bClaude487 --s-0: 0;
958d26aClaude488 --s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px;
489 --s-5: 20px; --s-6: 24px; --s-7: 28px; --s-8: 32px;
490 --s-10:40px; --s-12:48px; --s-14:56px; --s-16:64px;
491 --s-20:80px; --s-24:96px; --s-32:128px;
492
493 /* Elevation — softer + more layered */
494 --elev-0: 0 0 0 1px var(--border);
495 --elev-1: 0 1px 2px rgba(0,0,0,0.50), 0 0 0 1px var(--border);
496 --elev-2: 0 8px 24px -8px rgba(0,0,0,0.60), 0 0 0 1px var(--border);
497 --elev-3: 0 20px 48px -12px rgba(0,0,0,0.70), 0 0 0 1px var(--border-strong);
498 --elev-glow: 0 0 0 1px rgba(140,109,255,0.40), 0 0 32px -4px rgba(140,109,255,0.30);
499 --ring: 0 0 0 3px rgba(140,109,255,0.28);
500 --ring-warn: 0 0 0 3px rgba(251,191,36,0.28);
501 --ring-err: 0 0 0 3px rgba(248,113,113,0.28);
502
503 /* Motion */
504 --ease: cubic-bezier(0.16, 1, 0.3, 1);
505 --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
506 --ease-out-expo: cubic-bezier(0.19, 1, 0.22, 1);
507 --ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
508 --t-fast: 120ms;
509 --t-base: 200ms;
510 --t-slow: 360ms;
511 --t-slower:560ms;
512
513 --header-h: 60px;
fc1817aClaude514 }
515
6fc53bdClaude516 :root[data-theme='light'] {
958d26aClaude517 --bg: #fbfbfc;
4c47454Claude518 --bg-secondary: #ffffff;
958d26aClaude519 --bg-tertiary: #f3f3f6;
520 --bg-elevated: #ffffff;
521 --bg-surface: #f6f6f9;
522 --bg-hover: rgba(0,0,0,0.035);
523 --bg-active: rgba(0,0,0,0.07);
524 --bg-inset: rgba(0,0,0,0.04);
525
526 --border: rgba(15,16,28,0.08);
527 --border-subtle: rgba(15,16,28,0.04);
528 --border-strong: rgba(15,16,28,0.16);
529
530 --text: #0e1020;
531 --text-strong: #050617;
532 --text-muted: #5a5b70;
533 --text-faint: #8a8b9e;
534 --text-link: #6d4dff;
535
536 --accent: #6d4dff;
537 --accent-2: #0891b2;
538 --accent-hover: #5a3df0;
539 --accent-pressed:#4a30d6;
540 --accent-glow: 0 0 24px rgba(109,77,255,0.18);
541
542 --green: #059669;
543 --red: #dc2626;
4c47454Claude544 --yellow: #d97706;
958d26aClaude545
546 --elev-1: 0 1px 2px rgba(15,16,28,0.06), 0 0 0 1px var(--border);
547 --elev-2: 0 8px 24px -10px rgba(15,16,28,0.10), 0 0 0 1px var(--border);
548 --elev-3: 0 20px 48px -16px rgba(15,16,28,0.14), 0 0 0 1px var(--border-strong);
6fc53bdClaude549 }
550
551 /* Theme toggle — show the icon for the *opposite* theme so users see what they'll switch to. */
958d26aClaude552 .nav-theme { display: inline-flex; align-items: center; font-size: 15px; line-height: 1; opacity: 0.85; }
553 .nav-theme:hover { opacity: 1; }
6fc53bdClaude554 :root[data-theme='dark'] .theme-icon-dark { display: none; }
555 :root[data-theme='light'] .theme-icon-light { display: none; }
556
fc1817aClaude557 * { margin: 0; padding: 0; box-sizing: border-box; }
958d26aClaude558 *::selection { background: rgba(140,109,255,0.32); color: var(--text-strong); }
2ce1d0bClaude559
958d26aClaude560 html { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-rendering: optimizeLegibility; }
fc1817aClaude561
562 body {
563 font-family: var(--font-sans);
564 background: var(--bg);
565 color: var(--text);
2ce1d0bClaude566 line-height: 1.55;
958d26aClaude567 letter-spacing: -0.011em;
fc1817aClaude568 min-height: 100vh;
569 display: flex;
570 flex-direction: column;
958d26aClaude571 font-feature-settings: 'cv11', 'ss01', 'ss03', 'calt';
2ce1d0bClaude572 }
573
958d26aClaude574 /* Whole-page atmosphere: very subtle gradient + dot-grid layered behind everything.
575 Keeps every page feeling like part of the same product without competing with hero art. */
2ce1d0bClaude576 body::before {
577 content: '';
578 position: fixed;
579 inset: 0;
580 pointer-events: none;
958d26aClaude581 z-index: -2;
2ce1d0bClaude582 background:
958d26aClaude583 radial-gradient(70% 55% at 85% -20%, rgba(140,109,255,0.07), transparent 65%),
584 radial-gradient(55% 45% at -10% 115%, rgba(54,197,214,0.05), transparent 65%);
585 }
586 body::after {
587 content: '';
588 position: fixed;
589 inset: 0;
590 pointer-events: none;
591 z-index: -1;
592 background-image: radial-gradient(rgba(255,255,255,0.025) 1px, transparent 1px);
593 background-size: 28px 28px;
594 background-position: 0 0;
595 opacity: 0.55;
596 mask-image: radial-gradient(ellipse at 50% 0%, #000 0%, transparent 70%);
597 -webkit-mask-image: radial-gradient(ellipse at 50% 0%, #000 0%, transparent 70%);
598 }
599 :root[data-theme='light'] body::before { opacity: 0.55; }
600 :root[data-theme='light'] body::after {
601 background-image: radial-gradient(rgba(15,16,28,0.06) 1px, transparent 1px);
602 opacity: 0.4;
fc1817aClaude603 }
2ce1d0bClaude604
605 a { color: var(--text-link); text-decoration: none; transition: color var(--t-fast) var(--ease); }
606 a:hover { color: var(--accent-hover); text-decoration: none; }
fc1817aClaude607
958d26aClaude608 /* Heading scale — confident, editorial, tight tracking */
609 h1, h2, h3, h4, h5, h6 {
610 font-family: var(--font-display);
2ce1d0bClaude611 font-weight: 600;
958d26aClaude612 letter-spacing: -0.022em;
613 line-height: 1.18;
614 color: var(--text-strong);
615 }
616 h1 { font-size: var(--t-xl); letter-spacing: -0.028em; }
617 h2 { font-size: var(--t-lg); letter-spacing: -0.022em; }
618 h3 { font-size: var(--t-md); font-weight: 600; letter-spacing: -0.015em; }
619 h4 { font-size: var(--t-base); font-weight: 600; letter-spacing: -0.01em; }
620 h5, h6 { font-size: var(--t-sm); font-weight: 600; letter-spacing: -0.005em; }
621
622 /* Editorial display heading utility — used by landing + marketing pages */
623 .display {
624 font-family: var(--font-display);
625 font-size: clamp(40px, 7.5vw, 96px);
626 line-height: 0.98;
627 letter-spacing: -0.04em;
628 font-weight: 600;
629 color: var(--text-strong);
2ce1d0bClaude630 }
fc1817aClaude631
958d26aClaude632 /* Eyebrow — uppercase mono label that sits above section headings */
633 .eyebrow {
634 display: inline-flex;
635 align-items: center;
636 gap: 8px;
637 font-family: var(--font-mono);
638 font-size: 11px;
639 font-weight: 500;
640 letter-spacing: 0.14em;
641 text-transform: uppercase;
642 color: var(--accent);
643 margin-bottom: var(--s-3);
644 }
645 .eyebrow::before {
646 content: '';
647 width: 18px;
648 height: 1px;
649 background: currentColor;
650 opacity: 0.6;
651 }
652
653 /* Section header — paired eyebrow + title + lede */
654 .section-header { max-width: 720px; margin: 0 auto var(--s-10); text-align: center; }
655 .section-header.left { text-align: left; margin-left: 0; margin-right: auto; }
656 .section-header h2 {
657 font-size: clamp(28px, 4vw, 44px);
658 line-height: 1.05;
659 letter-spacing: -0.028em;
660 margin-bottom: var(--s-3);
661 }
662 .section-header p {
663 color: var(--text-muted);
664 font-size: var(--t-md);
665 line-height: 1.6;
666 max-width: 580px;
667 margin: 0 auto;
668 }
669 .section-header.left p { margin-left: 0; }
670
671 code, kbd, samp {
2ce1d0bClaude672 font-family: var(--font-mono);
958d26aClaude673 font-feature-settings: var(--mono-feat);
674 }
675 code {
676 font-size: 0.9em;
2ce1d0bClaude677 background: var(--bg-tertiary);
958d26aClaude678 border: 1px solid var(--border-subtle);
2ce1d0bClaude679 padding: 1px 6px;
680 border-radius: var(--r-sm);
681 color: var(--text);
682 }
958d26aClaude683 kbd, .kbd {
684 display: inline-flex;
685 align-items: center;
686 padding: 1px 6px;
687 font-family: var(--font-mono);
688 font-size: 11px;
689 background: var(--bg-elevated);
690 border: 1px solid var(--border);
691 border-bottom-width: 2px;
692 border-radius: 4px;
693 color: var(--text);
694 line-height: 1.5;
695 vertical-align: middle;
696 }
2ce1d0bClaude697
958d26aClaude698 /* Mono utility for technical chrome (paths, IDs, dates) */
699 .mono { font-family: var(--font-mono); font-feature-settings: var(--mono-feat); font-size: 0.96em; }
700 .meta-mono { font-family: var(--font-mono); font-size: var(--t-xs); color: var(--text-muted); letter-spacing: 0; }
701
702 /* Pre-launch banner — slim, refined, mono caption */
4a52a98Claude703 .prelaunch-banner {
958d26aClaude704 position: relative;
2ce1d0bClaude705 background:
958d26aClaude706 linear-gradient(180deg, rgba(251,191,36,0.10), rgba(251,191,36,0.03)),
2ce1d0bClaude707 var(--bg);
958d26aClaude708 border-bottom: 1px solid rgba(251,191,36,0.28);
4a52a98Claude709 color: var(--yellow);
958d26aClaude710 padding: 7px 24px;
711 font-family: var(--font-mono);
712 font-size: 11px;
4a52a98Claude713 font-weight: 500;
714 text-align: center;
2ce1d0bClaude715 line-height: 1.5;
958d26aClaude716 letter-spacing: 0.04em;
717 text-transform: uppercase;
718 }
719 .prelaunch-banner::before {
720 content: '◆';
721 margin-right: 8px;
722 font-size: 9px;
723 opacity: 0.7;
724 vertical-align: 1px;
4a52a98Claude725 }
726
958d26aClaude727 /* Header — sticky, blurred, hairline border, taller for breathing room */
fc1817aClaude728 header {
2ce1d0bClaude729 position: sticky;
730 top: 0;
731 z-index: 100;
fc1817aClaude732 border-bottom: 1px solid var(--border);
2ce1d0bClaude733 padding: 0 24px;
734 height: var(--header-h);
958d26aClaude735 background: rgba(8,9,15,0.72);
736 backdrop-filter: saturate(180%) blur(18px);
737 -webkit-backdrop-filter: saturate(180%) blur(18px);
fc1817aClaude738 }
958d26aClaude739 :root[data-theme='light'] header { background: rgba(251,251,252,0.78); }
fc1817aClaude740
06d5ffeClaude741 header nav {
742 display: flex;
743 align-items: center;
958d26aClaude744 gap: 18px;
745 max-width: 1240px;
06d5ffeClaude746 margin: 0 auto;
2ce1d0bClaude747 height: 100%;
748 }
749 .logo {
958d26aClaude750 font-family: var(--font-display);
751 font-size: 16px;
2ce1d0bClaude752 font-weight: 700;
958d26aClaude753 letter-spacing: -0.025em;
754 color: var(--text-strong);
2ce1d0bClaude755 display: inline-flex;
756 align-items: center;
958d26aClaude757 gap: 9px;
758 transition: opacity var(--t-fast) var(--ease);
06d5ffeClaude759 }
2ce1d0bClaude760 .logo::before {
761 content: '';
958d26aClaude762 width: 20px; height: 20px;
763 border-radius: 6px;
2ce1d0bClaude764 background: var(--accent-gradient);
958d26aClaude765 box-shadow:
766 inset 0 1px 0 rgba(255,255,255,0.25),
767 0 0 0 1px rgba(140,109,255,0.45),
768 0 0 20px rgba(140,109,255,0.30);
2ce1d0bClaude769 flex-shrink: 0;
958d26aClaude770 transition: transform var(--t-base) var(--ease-spring), box-shadow var(--t-base) var(--ease);
771 }
772 .logo:hover { text-decoration: none; color: var(--text-strong); }
773 .logo:hover::before {
774 transform: rotate(8deg) scale(1.05);
775 box-shadow:
776 inset 0 1px 0 rgba(255,255,255,0.30),
777 0 0 0 1px rgba(140,109,255,0.55),
778 0 0 28px rgba(140,109,255,0.45);
2ce1d0bClaude779 }
fc1817aClaude780
2ce1d0bClaude781 .nav-search {
782 flex: 1;
958d26aClaude783 max-width: 360px;
784 margin: 0 4px 0 8px;
785 position: relative;
2ce1d0bClaude786 }
787 .nav-search input {
788 width: 100%;
958d26aClaude789 padding: 7px 12px 7px 32px;
2ce1d0bClaude790 background: var(--bg-tertiary);
791 border: 1px solid var(--border);
792 border-radius: var(--r-sm);
793 color: var(--text);
794 font-family: var(--font-sans);
795 font-size: var(--t-sm);
958d26aClaude796 transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
797 }
798 .nav-search::before {
799 content: '';
800 position: absolute;
801 left: 11px; top: 50%;
802 transform: translateY(-50%);
803 width: 12px; height: 12px;
804 border: 1.5px solid var(--text-faint);
805 border-radius: 50%;
806 pointer-events: none;
807 }
808 .nav-search::after {
809 content: '';
810 position: absolute;
811 left: 19px; top: calc(50% + 4px);
812 width: 5px; height: 1.5px;
813 background: var(--text-faint);
814 transform: rotate(45deg);
815 pointer-events: none;
2ce1d0bClaude816 }
817 .nav-search input::placeholder { color: var(--text-faint); }
818 .nav-search input:focus {
819 outline: none;
820 background: var(--bg-secondary);
958d26aClaude821 border-color: var(--border-focus);
822 box-shadow: var(--ring);
2ce1d0bClaude823 }
06d5ffeClaude824
958d26aClaude825 .nav-right { display: flex; align-items: center; gap: 2px; margin-left: auto; }
2ce1d0bClaude826 .nav-link {
958d26aClaude827 position: relative;
2ce1d0bClaude828 color: var(--text-muted);
829 font-size: var(--t-sm);
830 font-weight: 500;
958d26aClaude831 padding: 7px 11px;
2ce1d0bClaude832 border-radius: var(--r-sm);
958d26aClaude833 transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
2ce1d0bClaude834 }
835 .nav-link:hover {
958d26aClaude836 color: var(--text-strong);
2ce1d0bClaude837 background: var(--bg-hover);
838 text-decoration: none;
839 }
958d26aClaude840 .nav-link.active { color: var(--text-strong); }
841 .nav-link.active::after {
842 content: '';
843 position: absolute;
844 left: 11px; right: 11px;
845 bottom: -1px;
846 height: 2px;
847 background: var(--accent-gradient);
848 border-radius: 2px;
849 }
2ce1d0bClaude850 .nav-user {
958d26aClaude851 color: var(--text-strong);
2ce1d0bClaude852 font-weight: 600;
853 font-size: var(--t-sm);
854 padding: 6px 10px;
855 border-radius: var(--r-sm);
958d26aClaude856 margin-left: 6px;
2ce1d0bClaude857 transition: background var(--t-fast) var(--ease);
858 }
958d26aClaude859 .nav-user::before {
860 content: '';
861 display: inline-block;
862 width: 8px; height: 8px;
863 background: var(--green);
864 border-radius: 50%;
865 margin-right: 7px;
866 box-shadow: 0 0 8px rgba(52,211,153,0.5);
867 vertical-align: 1px;
868 }
2ce1d0bClaude869 .nav-user:hover { background: var(--bg-hover); text-decoration: none; }
870
871 main {
958d26aClaude872 max-width: 1240px;
2ce1d0bClaude873 margin: 0 auto;
958d26aClaude874 padding: 36px 24px 80px;
2ce1d0bClaude875 flex: 1;
876 width: 100%;
877 }
fc1817aClaude878
958d26aClaude879 /* Editorial footer: link grid + tagline row */
fc1817aClaude880 footer {
881 border-top: 1px solid var(--border);
958d26aClaude882 padding: 56px 24px 40px;
883 color: var(--text-muted);
884 font-size: var(--t-sm);
885 background:
886 linear-gradient(180deg, transparent 0%, rgba(140,109,255,0.025) 100%),
887 var(--bg);
888 }
889 footer .footer-inner {
890 max-width: 1240px;
891 margin: 0 auto;
892 display: grid;
893 grid-template-columns: 1fr auto;
894 gap: 48px;
895 align-items: start;
896 }
897 footer .footer-brand .logo { margin-bottom: var(--s-3); }
898 footer .footer-tag {
899 color: var(--text-muted);
900 font-size: var(--t-sm);
901 max-width: 320px;
902 line-height: 1.55;
903 }
904 footer .footer-links {
905 display: grid;
906 grid-template-columns: repeat(3, minmax(120px, auto));
907 gap: 0 56px;
908 }
909 footer .footer-col-title {
910 font-family: var(--font-mono);
911 font-size: 11px;
912 text-transform: uppercase;
913 letter-spacing: 0.14em;
914 color: var(--text-faint);
915 margin-bottom: var(--s-3);
916 }
917 footer .footer-col a {
918 display: block;
919 color: var(--text-muted);
920 font-size: var(--t-sm);
921 padding: 5px 0;
922 transition: color var(--t-fast) var(--ease);
923 }
924 footer .footer-col a:hover { color: var(--text-strong); text-decoration: none; }
925 footer .footer-bottom {
926 max-width: 1240px;
927 margin: 40px auto 0;
928 padding-top: 24px;
929 border-top: 1px solid var(--border-subtle);
930 display: flex;
931 justify-content: space-between;
932 align-items: center;
2ce1d0bClaude933 color: var(--text-faint);
934 font-size: var(--t-xs);
958d26aClaude935 font-family: var(--font-mono);
936 letter-spacing: 0.02em;
937 }
938 footer .footer-bottom a { color: var(--text-faint); }
939 footer .footer-bottom a:hover { color: var(--text-muted); text-decoration: none; }
05cdb85Claude940 footer .footer-build {
941 display: inline-flex;
942 align-items: center;
943 gap: 6px;
944 color: var(--text-faint);
945 font-family: var(--font-mono);
946 font-size: 11px;
947 cursor: help;
948 }
949 footer .footer-build-dot {
950 width: 6px; height: 6px;
951 border-radius: 50%;
952 background: var(--green);
953 box-shadow: 0 0 6px rgba(52,211,153,0.55);
954 animation: footer-build-pulse 2.4s ease-in-out infinite;
955 }
956 @keyframes footer-build-pulse {
957 0%, 100% { opacity: 0.6; }
958 50% { opacity: 1; }
959 }
958d26aClaude960 @media (max-width: 768px) {
961 footer .footer-inner { grid-template-columns: 1fr; gap: 32px; }
962 footer .footer-links { grid-template-columns: repeat(2, 1fr); gap: 24px 32px; }
963 footer .footer-bottom { flex-direction: column; gap: 8px; text-align: center; }
fc1817aClaude964 }
965
2ce1d0bClaude966 /* ============================================================ */
967 /* Buttons */
968 /* ============================================================ */
06d5ffeClaude969 .btn {
970 display: inline-flex;
971 align-items: center;
2ce1d0bClaude972 justify-content: center;
958d26aClaude973 gap: 7px;
2ce1d0bClaude974 padding: 7px 14px;
975 border-radius: var(--r-sm);
958d26aClaude976 font-family: var(--font-sans);
2ce1d0bClaude977 font-size: var(--t-sm);
06d5ffeClaude978 font-weight: 500;
979 border: 1px solid var(--border);
2ce1d0bClaude980 background: var(--bg-elevated);
06d5ffeClaude981 color: var(--text);
982 cursor: pointer;
983 text-decoration: none;
958d26aClaude984 line-height: 1.25;
985 letter-spacing: -0.008em;
2ce1d0bClaude986 transition:
987 background var(--t-fast) var(--ease),
988 border-color var(--t-fast) var(--ease),
989 transform var(--t-fast) var(--ease),
958d26aClaude990 box-shadow var(--t-fast) var(--ease),
991 color var(--t-fast) var(--ease);
2ce1d0bClaude992 user-select: none;
993 white-space: nowrap;
958d26aClaude994 position: relative;
06d5ffeClaude995 }
2ce1d0bClaude996 .btn:hover {
997 background: var(--bg-surface);
998 border-color: var(--border-strong);
958d26aClaude999 color: var(--text-strong);
2ce1d0bClaude1000 text-decoration: none;
1001 }
958d26aClaude1002 .btn:active { transform: translateY(1px); }
2ce1d0bClaude1003 .btn:focus-visible { outline: none; box-shadow: var(--ring); }
1004
1005 .btn-primary {
1006 background: var(--accent-gradient);
1007 border-color: transparent;
1008 color: #fff;
1009 font-weight: 600;
958d26aClaude1010 text-shadow: 0 1px 0 rgba(0,0,0,0.15);
2ce1d0bClaude1011 box-shadow:
958d26aClaude1012 inset 0 1px 0 rgba(255,255,255,0.22),
1013 inset 0 -1px 0 rgba(0,0,0,0.10),
1014 0 1px 2px rgba(0,0,0,0.40),
1015 0 0 0 1px rgba(140,109,255,0.30);
1016 }
1017 .btn-primary::before {
1018 content: '';
1019 position: absolute;
1020 inset: 0;
1021 border-radius: inherit;
1022 background: linear-gradient(180deg, rgba(255,255,255,0.18), transparent 60%);
1023 opacity: 0;
1024 transition: opacity var(--t-fast) var(--ease);
1025 pointer-events: none;
2ce1d0bClaude1026 }
1027 .btn-primary:hover {
958d26aClaude1028 color: #fff;
2ce1d0bClaude1029 background: var(--accent-gradient);
958d26aClaude1030 border-color: transparent;
2ce1d0bClaude1031 box-shadow:
958d26aClaude1032 inset 0 1px 0 rgba(255,255,255,0.30),
1033 inset 0 -1px 0 rgba(0,0,0,0.10),
1034 0 6px 18px -4px rgba(140,109,255,0.45),
1035 0 0 0 1px rgba(140,109,255,0.45);
2ce1d0bClaude1036 }
958d26aClaude1037 .btn-primary:hover::before { opacity: 1; }
2ce1d0bClaude1038
1039 .btn-danger {
1040 background: transparent;
958d26aClaude1041 border-color: rgba(248,113,113,0.40);
2ce1d0bClaude1042 color: var(--red);
1043 }
1044 .btn-danger:hover {
958d26aClaude1045 background: rgba(248,113,113,0.08);
2ce1d0bClaude1046 border-color: var(--red);
958d26aClaude1047 color: var(--red);
2ce1d0bClaude1048 }
958d26aClaude1049 .btn-danger:focus-visible { box-shadow: var(--ring-err); }
2ce1d0bClaude1050
1051 .btn-ghost {
1052 background: transparent;
1053 border-color: transparent;
1054 color: var(--text-muted);
1055 }
1056 .btn-ghost:hover {
1057 background: var(--bg-hover);
958d26aClaude1058 color: var(--text-strong);
2ce1d0bClaude1059 border-color: var(--border);
1060 }
1061
958d26aClaude1062 .btn-secondary {
1063 background: var(--bg-elevated);
1064 border-color: var(--border-strong);
1065 color: var(--text-strong);
1066 }
1067 .btn-secondary:hover {
1068 background: var(--bg-surface);
1069 border-color: var(--border-strong);
1070 }
1071
1072 .btn-sm { padding: 4px 10px; font-size: var(--t-xs); border-radius: var(--r-sm); gap: 5px; }
1073 .btn-lg { padding: 11px 22px; font-size: var(--t-base); border-radius: var(--r); }
1074 .btn-xl { padding: 14px 28px; font-size: var(--t-md); border-radius: var(--r); font-weight: 600; }
1075 .btn-block { width: 100%; }
2ce1d0bClaude1076
1077 .btn:disabled, .btn[aria-disabled='true'] {
958d26aClaude1078 opacity: 0.45;
2ce1d0bClaude1079 cursor: not-allowed;
1080 pointer-events: none;
1081 }
1082
1083 /* ============================================================ */
1084 /* Forms */
1085 /* ============================================================ */
1086 .form-group { margin-bottom: 20px; }
1087 .form-group label {
1088 display: block;
1089 font-size: var(--t-sm);
1090 font-weight: 500;
1091 margin-bottom: 6px;
1092 color: var(--text);
1093 letter-spacing: -0.005em;
1094 }
1095 .form-group input,
1096 .form-group textarea,
1097 .form-group select,
1098 input[type='text'], input[type='email'], input[type='password'],
1099 input[type='url'], input[type='search'], input[type='number'],
1100 textarea, select {
06d5ffeClaude1101 width: 100%;
2ce1d0bClaude1102 padding: 9px 12px;
1103 background: var(--bg-secondary);
06d5ffeClaude1104 border: 1px solid var(--border);
2ce1d0bClaude1105 border-radius: var(--r-sm);
06d5ffeClaude1106 color: var(--text);
2ce1d0bClaude1107 font-size: var(--t-sm);
06d5ffeClaude1108 font-family: var(--font-sans);
2ce1d0bClaude1109 transition:
1110 border-color var(--t-fast) var(--ease),
1111 background var(--t-fast) var(--ease),
1112 box-shadow var(--t-fast) var(--ease);
1113 }
1114 .form-group input::placeholder, textarea::placeholder, input::placeholder {
1115 color: var(--text-faint);
06d5ffeClaude1116 }
2ce1d0bClaude1117 .form-group input:hover, textarea:hover, select:hover,
1118 input[type='text']:hover, input[type='email']:hover, input[type='password']:hover {
1119 border-color: var(--border-strong);
1120 }
1121 .form-group input:focus, .form-group textarea:focus, .form-group select:focus,
1122 input:focus, textarea:focus, select:focus {
06d5ffeClaude1123 outline: none;
2ce1d0bClaude1124 background: var(--bg);
1125 border-color: var(--border-focus);
1126 box-shadow: var(--ring);
06d5ffeClaude1127 }
2ce1d0bClaude1128 textarea { font-family: var(--font-mono); font-size: var(--t-sm); line-height: 1.55; }
06d5ffeClaude1129 .input-disabled { opacity: 0.5; cursor: not-allowed; }
1130
2ce1d0bClaude1131 /* ============================================================ */
1132 /* Auth (register / login / verify) */
1133 /* ============================================================ */
1134 .auth-container {
1135 max-width: 420px;
1136 margin: 64px auto;
1137 padding: 32px;
1138 background: var(--bg-elevated);
1139 border: 1px solid var(--border);
1140 border-radius: var(--r-lg);
1141 box-shadow: var(--elev-2);
1142 }
1143 .auth-container h2 {
1144 margin-bottom: 6px;
1145 font-size: var(--t-lg);
1146 letter-spacing: -0.02em;
1147 }
1148 .auth-container > p {
1149 color: var(--text-muted);
1150 font-size: var(--t-sm);
1151 margin-bottom: 24px;
1152 }
1153 .auth-container .btn-primary { width: 100%; padding: 10px 16px; }
06d5ffeClaude1154 .auth-error {
958d26aClaude1155 background: rgba(248,113,113,0.08);
1156 border: 1px solid rgba(248,113,113,0.35);
06d5ffeClaude1157 color: var(--red);
2ce1d0bClaude1158 padding: 10px 14px;
1159 border-radius: var(--r-sm);
06d5ffeClaude1160 margin-bottom: 16px;
2ce1d0bClaude1161 font-size: var(--t-sm);
06d5ffeClaude1162 }
1163 .auth-success {
958d26aClaude1164 background: rgba(52,211,153,0.08);
1165 border: 1px solid rgba(52,211,153,0.35);
06d5ffeClaude1166 color: var(--green);
2ce1d0bClaude1167 padding: 10px 14px;
1168 border-radius: var(--r-sm);
06d5ffeClaude1169 margin-bottom: 16px;
2ce1d0bClaude1170 font-size: var(--t-sm);
1171 }
1172 .auth-switch {
1173 margin-top: 20px;
1174 font-size: var(--t-sm);
1175 color: var(--text-muted);
1176 text-align: center;
1177 }
1178 .banner {
1179 background: var(--accent-gradient-faint);
958d26aClaude1180 border: 1px solid rgba(140,109,255,0.35);
2ce1d0bClaude1181 color: var(--text);
1182 padding: 10px 14px;
1183 border-radius: var(--r-sm);
1184 font-size: var(--t-sm);
06d5ffeClaude1185 }
1186
2ce1d0bClaude1187 /* ============================================================ */
1188 /* Settings */
1189 /* ============================================================ */
1190 .settings-container { max-width: 720px; }
1191 .settings-container h2 { margin-bottom: 8px; font-size: var(--t-xl); letter-spacing: -0.02em; }
1192 .settings-container > h2 + p { color: var(--text-muted); font-size: var(--t-sm); margin-bottom: 24px; }
1193 .settings-container h3 { font-size: var(--t-md); margin-bottom: 12px; margin-top: 28px; }
1194 .settings-container h3:first-of-type { margin-top: 0; }
06d5ffeClaude1195 .ssh-keys-list { margin-bottom: 24px; }
1196 .ssh-key-item {
1197 display: flex;
1198 justify-content: space-between;
1199 align-items: center;
2ce1d0bClaude1200 padding: 14px 16px;
06d5ffeClaude1201 border: 1px solid var(--border);
2ce1d0bClaude1202 border-radius: var(--r-md);
06d5ffeClaude1203 margin-bottom: 8px;
2ce1d0bClaude1204 background: var(--bg-elevated);
1205 transition: border-color var(--t-fast) var(--ease);
06d5ffeClaude1206 }
2ce1d0bClaude1207 .ssh-key-item:hover { border-color: var(--border-strong); }
1208 .ssh-key-meta { font-size: var(--t-xs); color: var(--text-muted); margin-top: 4px; }
1209 .ssh-key-meta code { font-size: var(--t-xs); background: var(--bg-tertiary); padding: 1px 6px; border-radius: 3px; margin-right: 8px; }
06d5ffeClaude1210
2ce1d0bClaude1211 /* ============================================================ */
1212 /* Repo header + nav */
1213 /* ============================================================ */
fc1817aClaude1214 .repo-header {
1215 display: flex;
1216 align-items: center;
debcf27Claude1217 gap: 12px;
1218 margin-bottom: 22px;
1219 }
1220 .repo-header-title {
1221 display: flex;
1222 align-items: center;
1223 gap: 10px;
1224 font-family: var(--font-display);
1225 font-size: 24px;
1226 letter-spacing: -0.025em;
1227 flex-wrap: wrap;
1228 }
1229 .repo-header .owner {
1230 color: var(--text-muted);
1231 font-weight: 500;
1232 transition: color var(--t-fast) var(--ease);
1233 }
1234 .repo-header .owner:hover { color: var(--text-link); text-decoration: none; }
1235 .repo-header .separator { color: var(--text-faint); font-weight: 300; }
1236 .repo-header .name {
1237 color: var(--text-strong);
1238 font-weight: 700;
1239 letter-spacing: -0.028em;
fc1817aClaude1240 }
2ce1d0bClaude1241 .repo-header .name:hover { color: var(--text-link); text-decoration: none; }
debcf27Claude1242 .repo-header-fork {
1243 font-family: var(--font-mono);
1244 font-size: 11px;
1245 color: var(--text-muted);
1246 margin-top: 4px;
1247 letter-spacing: 0.01em;
1248 }
1249 .repo-header-fork a { color: var(--text-muted); }
1250 .repo-header-fork a:hover { color: var(--accent); }
1251 .repo-header-pill {
1252 display: inline-flex;
1253 align-items: center;
1254 padding: 2px 10px;
1255 border-radius: var(--r-full);
1256 font-family: var(--font-mono);
1257 font-size: 10px;
1258 font-weight: 600;
1259 letter-spacing: 0.12em;
1260 text-transform: uppercase;
1261 line-height: 1.6;
1262 vertical-align: 4px;
1263 }
1264 .repo-header-pill-archived {
1265 background: rgba(251,191,36,0.10);
1266 color: var(--yellow);
1267 border: 1px solid rgba(251,191,36,0.30);
1268 }
1269 .repo-header-pill-template {
1270 background: var(--accent-gradient-faint);
1271 color: var(--accent);
1272 border: 1px solid rgba(140,109,255,0.30);
1273 }
06d5ffeClaude1274 .repo-header-actions { margin-left: auto; display: flex; gap: 8px; align-items: center; }
fc1817aClaude1275
1276 .repo-nav {
1277 display: flex;
debcf27Claude1278 gap: 1px;
fc1817aClaude1279 border-bottom: 1px solid var(--border);
debcf27Claude1280 margin-bottom: 28px;
2ce1d0bClaude1281 overflow-x: auto;
1282 scrollbar-width: thin;
fc1817aClaude1283 }
2ce1d0bClaude1284 .repo-nav::-webkit-scrollbar { height: 0; }
fc1817aClaude1285 .repo-nav a {
debcf27Claude1286 position: relative;
1287 padding: 11px 14px;
fc1817aClaude1288 color: var(--text-muted);
1289 border-bottom: 2px solid transparent;
2ce1d0bClaude1290 font-size: var(--t-sm);
1291 font-weight: 500;
1292 margin-bottom: -1px;
debcf27Claude1293 transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
2ce1d0bClaude1294 white-space: nowrap;
1295 }
debcf27Claude1296 .repo-nav a:hover { text-decoration: none; color: var(--text-strong); background: var(--bg-hover); }
2ce1d0bClaude1297 .repo-nav a.active {
debcf27Claude1298 color: var(--text-strong);
1299 font-weight: 600;
1300 }
1301 .repo-nav a.active::after {
1302 content: '';
1303 position: absolute;
1304 left: 14px;
1305 right: 14px;
1306 bottom: -1px;
1307 height: 2px;
1308 background: var(--accent-gradient);
1309 border-radius: 2px;
1310 }
1311 /* AI links in the right-side cluster — sparkle accent */
1312 .repo-nav-ai {
1313 color: var(--accent) !important;
1314 font-weight: 500;
1315 }
1316 .repo-nav-ai:hover {
1317 color: var(--accent-hover) !important;
1318 background: var(--accent-gradient-faint) !important;
1319 }
1320 .repo-nav-ai.active {
1321 color: var(--accent-hover) !important;
2ce1d0bClaude1322 font-weight: 600;
fc1817aClaude1323 }
1324
2ce1d0bClaude1325 .breadcrumb {
1326 display: flex;
debcf27Claude1327 gap: 6px;
2ce1d0bClaude1328 align-items: center;
debcf27Claude1329 margin-bottom: 18px;
2ce1d0bClaude1330 color: var(--text-muted);
1331 font-size: var(--t-sm);
1332 font-family: var(--font-mono);
debcf27Claude1333 font-feature-settings: var(--mono-feat);
2ce1d0bClaude1334 }
1335 .breadcrumb a { color: var(--text-link); font-weight: 500; }
1336 .breadcrumb a:hover { color: var(--accent-hover); }
debcf27Claude1337 .breadcrumb strong {
1338 color: var(--text-strong);
1339 font-weight: 600;
1340 }
1341
1342 /* Page header — eyebrow + title + optional actions row.
1343 Use on dashboard, settings, admin, any "section landing" page. */
1344 .page-header {
1345 display: flex;
1346 align-items: flex-end;
1347 justify-content: space-between;
1348 gap: 16px;
1349 margin-bottom: 28px;
1350 padding-bottom: 20px;
1351 border-bottom: 1px solid var(--border-subtle);
1352 flex-wrap: wrap;
1353 }
1354 .page-header-text { flex: 1; min-width: 280px; }
1355 .page-header .eyebrow { margin-bottom: var(--s-2); }
1356 .page-header h1 {
1357 font-family: var(--font-display);
1358 font-size: clamp(24px, 3vw, 36px);
1359 line-height: 1.1;
1360 letter-spacing: -0.028em;
1361 margin-bottom: 6px;
1362 }
1363 .page-header p {
1364 color: var(--text-muted);
1365 font-size: var(--t-sm);
1366 line-height: 1.55;
1367 max-width: 640px;
1368 }
1369 .page-header-actions { display: flex; gap: 8px; align-items: center; }
fc1817aClaude1370
2ce1d0bClaude1371 /* ============================================================ */
1372 /* File browser table */
1373 /* ============================================================ */
1374 .file-table {
1375 width: 100%;
1376 border: 1px solid var(--border);
1377 border-radius: var(--r-md);
1378 overflow: hidden;
1379 background: var(--bg-elevated);
debcf27Claude1380 border-collapse: collapse;
2ce1d0bClaude1381 }
debcf27Claude1382 .file-table tr { border-bottom: 1px solid var(--border-subtle); transition: background var(--t-fast) var(--ease); }
fc1817aClaude1383 .file-table tr:last-child { border-bottom: none; }
debcf27Claude1384 .file-table td {
1385 padding: 9px 16px;
1386 font-size: var(--t-sm);
1387 font-family: var(--font-mono);
1388 font-feature-settings: var(--mono-feat);
1389 }
2ce1d0bClaude1390 .file-table tr:hover { background: var(--bg-hover); }
debcf27Claude1391 .file-icon {
1392 width: 22px;
1393 color: var(--text-faint);
1394 font-size: 13px;
1395 text-align: center;
1396 }
1397 .file-name a {
1398 color: var(--text);
1399 font-weight: 500;
1400 transition: color var(--t-fast) var(--ease);
1401 }
1402 .file-name a:hover { color: var(--accent); text-decoration: none; }
fc1817aClaude1403
2ce1d0bClaude1404 /* ============================================================ */
1405 /* Blob view */
1406 /* ============================================================ */
fc1817aClaude1407 .blob-view {
1408 border: 1px solid var(--border);
2ce1d0bClaude1409 border-radius: var(--r-md);
fc1817aClaude1410 overflow: hidden;
2ce1d0bClaude1411 background: var(--bg-elevated);
fc1817aClaude1412 }
1413 .blob-header {
1414 background: var(--bg-secondary);
2ce1d0bClaude1415 padding: 10px 16px;
fc1817aClaude1416 border-bottom: 1px solid var(--border);
2ce1d0bClaude1417 font-size: var(--t-sm);
fc1817aClaude1418 color: var(--text-muted);
06d5ffeClaude1419 display: flex;
1420 justify-content: space-between;
1421 align-items: center;
fc1817aClaude1422 }
1423 .blob-code {
1424 overflow-x: auto;
1425 font-family: var(--font-mono);
2ce1d0bClaude1426 font-size: var(--t-sm);
1427 line-height: 1.65;
fc1817aClaude1428 }
1429 .blob-code table { width: 100%; border-collapse: collapse; }
1430 .blob-code .line-num {
1431 width: 1%;
2ce1d0bClaude1432 min-width: 56px;
1433 padding: 0 14px;
fc1817aClaude1434 text-align: right;
2ce1d0bClaude1435 color: var(--text-faint);
fc1817aClaude1436 user-select: none;
1437 white-space: nowrap;
1438 border-right: 1px solid var(--border);
1439 }
2ce1d0bClaude1440 .blob-code .line-content { padding: 0 16px; white-space: pre; }
1441 .blob-code tr:hover { background: var(--bg-hover); }
fc1817aClaude1442
2ce1d0bClaude1443 /* ============================================================ */
1444 /* Commits + diffs */
1445 /* ============================================================ */
1446 .commit-list {
1447 border: 1px solid var(--border);
1448 border-radius: var(--r-md);
1449 overflow: hidden;
1450 background: var(--bg-elevated);
1451 }
fc1817aClaude1452 .commit-item {
1453 display: flex;
1454 justify-content: space-between;
1455 align-items: center;
debcf27Claude1456 padding: 14px 18px;
1457 border-bottom: 1px solid var(--border-subtle);
2ce1d0bClaude1458 transition: background var(--t-fast) var(--ease);
fc1817aClaude1459 }
1460 .commit-item:last-child { border-bottom: none; }
2ce1d0bClaude1461 .commit-item:hover { background: var(--bg-hover); }
debcf27Claude1462 .commit-message {
1463 font-size: var(--t-sm);
1464 font-weight: 500;
1465 line-height: 1.45;
1466 color: var(--text-strong);
1467 letter-spacing: -0.005em;
1468 }
1469 .commit-meta {
1470 font-family: var(--font-mono);
1471 font-size: 11px;
1472 color: var(--text-muted);
1473 margin-top: 5px;
1474 letter-spacing: 0.01em;
1475 }
fc1817aClaude1476 .commit-sha {
1477 font-family: var(--font-mono);
debcf27Claude1478 font-feature-settings: var(--mono-feat);
1479 font-size: 11px;
1480 padding: 4px 9px;
fc1817aClaude1481 background: var(--bg-tertiary);
1482 border: 1px solid var(--border);
2ce1d0bClaude1483 border-radius: var(--r-sm);
debcf27Claude1484 color: var(--accent);
1485 font-weight: 600;
1486 letter-spacing: 0.02em;
2ce1d0bClaude1487 transition: all var(--t-fast) var(--ease);
fc1817aClaude1488 }
debcf27Claude1489 .commit-sha:hover {
1490 border-color: rgba(140,109,255,0.40);
1491 background: var(--accent-gradient-faint);
1492 color: var(--accent-hover);
1493 text-decoration: none;
1494 }
fc1817aClaude1495
1496 .diff-view { margin-top: 16px; }
1497 .diff-file {
1498 border: 1px solid var(--border);
2ce1d0bClaude1499 border-radius: var(--r-md);
fc1817aClaude1500 margin-bottom: 16px;
1501 overflow: hidden;
2ce1d0bClaude1502 background: var(--bg-elevated);
fc1817aClaude1503 }
1504 .diff-file-header {
1505 background: var(--bg-secondary);
2ce1d0bClaude1506 padding: 10px 16px;
fc1817aClaude1507 border-bottom: 1px solid var(--border);
1508 font-family: var(--font-mono);
2ce1d0bClaude1509 font-size: var(--t-sm);
1510 font-weight: 500;
fc1817aClaude1511 }
1512 .diff-content {
1513 overflow-x: auto;
1514 font-family: var(--font-mono);
2ce1d0bClaude1515 font-size: var(--t-sm);
1516 line-height: 1.65;
fc1817aClaude1517 }
958d26aClaude1518 .diff-content .line-add { background: rgba(52,211,153,0.10); color: var(--green); }
1519 .diff-content .line-del { background: rgba(248,113,113,0.08); color: var(--red); }
1520 .diff-content .line-hunk { background: rgba(140,109,255,0.06); color: var(--text-link); }
2ce1d0bClaude1521 .diff-content .line { padding: 0 16px; white-space: pre; display: block; }
fc1817aClaude1522
1523 .stat-add { color: var(--green); font-weight: 600; }
1524 .stat-del { color: var(--red); font-weight: 600; }
1525
2ce1d0bClaude1526 /* ============================================================ */
1527 /* Empty state */
1528 /* ============================================================ */
fc1817aClaude1529 .empty-state {
1530 text-align: center;
958d26aClaude1531 padding: 96px 24px;
fc1817aClaude1532 color: var(--text-muted);
2ce1d0bClaude1533 border: 1px dashed var(--border);
1534 border-radius: var(--r-lg);
958d26aClaude1535 background:
1536 radial-gradient(60% 60% at 50% 0%, rgba(140,109,255,0.05), transparent 70%),
1537 var(--bg-elevated);
1538 position: relative;
1539 overflow: hidden;
1540 }
1541 .empty-state::before {
1542 content: '';
1543 position: absolute;
1544 inset: 0;
1545 background-image: radial-gradient(rgba(255,255,255,0.025) 1px, transparent 1px);
1546 background-size: 24px 24px;
1547 opacity: 0.5;
1548 pointer-events: none;
1549 mask-image: radial-gradient(ellipse at center, #000 30%, transparent 70%);
1550 -webkit-mask-image: radial-gradient(ellipse at center, #000 30%, transparent 70%);
1551 }
1552 :root[data-theme='light'] .empty-state::before {
1553 background-image: radial-gradient(rgba(15,16,28,0.08) 1px, transparent 1px);
fc1817aClaude1554 }
958d26aClaude1555 .empty-state > * { position: relative; z-index: 1; }
2ce1d0bClaude1556 .empty-state h2 {
958d26aClaude1557 font-size: var(--t-xl);
2ce1d0bClaude1558 margin-bottom: 8px;
958d26aClaude1559 color: var(--text-strong);
1560 letter-spacing: -0.022em;
2ce1d0bClaude1561 }
958d26aClaude1562 .empty-state p { font-size: var(--t-md); max-width: 480px; margin: 0 auto; line-height: 1.55; }
fc1817aClaude1563 .empty-state pre {
1564 text-align: left;
1565 display: inline-block;
1566 background: var(--bg-secondary);
958d26aClaude1567 padding: 18px 24px;
1568 border-radius: var(--r-md);
fc1817aClaude1569 border: 1px solid var(--border);
1570 font-family: var(--font-mono);
958d26aClaude1571 font-feature-settings: var(--mono-feat);
2ce1d0bClaude1572 font-size: var(--t-sm);
958d26aClaude1573 margin-top: 24px;
fc1817aClaude1574 line-height: 1.8;
2ce1d0bClaude1575 color: var(--text);
958d26aClaude1576 box-shadow: var(--elev-1);
fc1817aClaude1577 }
1578
2ce1d0bClaude1579 /* ============================================================ */
1580 /* Badges */
1581 /* ============================================================ */
fc1817aClaude1582 .badge {
2ce1d0bClaude1583 display: inline-flex;
1584 align-items: center;
1585 gap: 4px;
1586 padding: 2px 9px;
1587 border-radius: var(--r-full);
1588 font-size: var(--t-xs);
fc1817aClaude1589 font-weight: 500;
1590 background: var(--bg-tertiary);
1591 border: 1px solid var(--border);
1592 color: var(--text-muted);
2ce1d0bClaude1593 line-height: 1.5;
fc1817aClaude1594 }
1595
2ce1d0bClaude1596 /* ============================================================ */
1597 /* Branch dropdown */
1598 /* ============================================================ */
fc1817aClaude1599 .branch-selector {
1600 display: inline-flex;
1601 align-items: center;
2ce1d0bClaude1602 gap: 6px;
1603 padding: 6px 12px;
1604 background: var(--bg-elevated);
fc1817aClaude1605 border: 1px solid var(--border);
2ce1d0bClaude1606 border-radius: var(--r-sm);
1607 font-size: var(--t-sm);
fc1817aClaude1608 color: var(--text);
1609 margin-bottom: 12px;
2ce1d0bClaude1610 transition: border-color var(--t-fast) var(--ease);
fc1817aClaude1611 }
2ce1d0bClaude1612 .branch-selector:hover { border-color: var(--border-strong); }
fc1817aClaude1613
06d5ffeClaude1614 .branch-dropdown {
1615 position: relative;
1616 display: inline-block;
1617 margin-bottom: 12px;
1618 }
1619 .branch-dropdown-content {
1620 display: none;
1621 position: absolute;
2ce1d0bClaude1622 top: calc(100% + 4px);
06d5ffeClaude1623 left: 0;
1624 z-index: 10;
2ce1d0bClaude1625 min-width: 220px;
1626 background: var(--bg-elevated);
1627 border: 1px solid var(--border-strong);
1628 border-radius: var(--r-md);
1629 overflow: hidden;
1630 box-shadow: var(--elev-3);
06d5ffeClaude1631 }
1632 .branch-dropdown:hover .branch-dropdown-content,
1633 .branch-dropdown:focus-within .branch-dropdown-content { display: block; }
1634 .branch-dropdown-content a {
1635 display: block;
2ce1d0bClaude1636 padding: 9px 14px;
1637 font-size: var(--t-sm);
06d5ffeClaude1638 color: var(--text);
1639 border-bottom: 1px solid var(--border);
2ce1d0bClaude1640 transition: background var(--t-fast) var(--ease);
06d5ffeClaude1641 }
1642 .branch-dropdown-content a:last-child { border-bottom: none; }
2ce1d0bClaude1643 .branch-dropdown-content a:hover { background: var(--bg-hover); text-decoration: none; }
1644 .branch-dropdown-content a.active-branch { color: var(--text-link); font-weight: 600; background: var(--accent-gradient-faint); }
06d5ffeClaude1645
2ce1d0bClaude1646 /* ============================================================ */
1647 /* Card grid */
1648 /* ============================================================ */
1649 .card-grid {
1650 display: grid;
1651 grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
1652 gap: 16px;
1653 }
fc1817aClaude1654 .card {
1655 border: 1px solid var(--border);
2ce1d0bClaude1656 border-radius: var(--r-md);
958d26aClaude1657 padding: 20px;
2ce1d0bClaude1658 background: var(--bg-elevated);
1659 transition:
958d26aClaude1660 border-color var(--t-base) var(--ease),
1661 transform var(--t-base) var(--ease-out-quart),
2ce1d0bClaude1662 box-shadow var(--t-base) var(--ease);
1663 position: relative;
1664 overflow: hidden;
958d26aClaude1665 isolation: isolate;
1666 }
1667 .card::before {
1668 content: '';
1669 position: absolute;
1670 inset: 0;
1671 background: linear-gradient(135deg, rgba(140,109,255,0.06), transparent 50%);
1672 opacity: 0;
1673 transition: opacity var(--t-base) var(--ease);
1674 pointer-events: none;
1675 z-index: -1;
2ce1d0bClaude1676 }
1677 .card:hover {
1678 border-color: var(--border-strong);
1679 box-shadow: var(--elev-2);
958d26aClaude1680 transform: translateY(-2px);
2ce1d0bClaude1681 }
958d26aClaude1682 .card:hover::before { opacity: 1; }
1683 .card h3 { font-size: var(--t-md); margin-bottom: 6px; letter-spacing: -0.012em; }
2ce1d0bClaude1684 .card h3 a { color: var(--text); font-weight: 600; }
1685 .card h3 a:hover { color: var(--text-link); }
1686 .card p { font-size: var(--t-sm); color: var(--text-muted); line-height: 1.5; }
1687 .card-meta {
1688 display: flex;
1689 gap: 14px;
1690 margin-top: 14px;
1691 padding-top: 14px;
1692 border-top: 1px solid var(--border);
1693 font-size: var(--t-xs);
1694 color: var(--text-muted);
1695 }
1696 .card-meta span { display: flex; align-items: center; gap: 5px; }
1697
1698 /* ============================================================ */
1699 /* Stat card / box */
1700 /* ============================================================ */
1701 .stat-card {
1702 background: var(--bg-elevated);
1703 border: 1px solid var(--border);
1704 border-radius: var(--r-md);
fc1817aClaude1705 padding: 16px;
2ce1d0bClaude1706 transition: border-color var(--t-fast) var(--ease);
1707 }
1708 .stat-card:hover { border-color: var(--border-strong); }
1709 .stat-label {
1710 font-size: var(--t-xs);
1711 color: var(--text-muted);
1712 text-transform: uppercase;
1713 letter-spacing: 0.06em;
1714 font-weight: 500;
1715 }
1716 .stat-value {
1717 font-size: var(--t-xl);
1718 font-weight: 700;
1719 margin-top: 4px;
1720 letter-spacing: -0.025em;
1721 color: var(--text);
1722 font-feature-settings: 'tnum';
fc1817aClaude1723 }
06d5ffeClaude1724
2ce1d0bClaude1725 /* ============================================================ */
1726 /* Star button */
1727 /* ============================================================ */
06d5ffeClaude1728 .star-btn {
1729 display: inline-flex;
1730 align-items: center;
1731 gap: 6px;
2ce1d0bClaude1732 padding: 5px 12px;
1733 background: var(--bg-elevated);
06d5ffeClaude1734 border: 1px solid var(--border);
2ce1d0bClaude1735 border-radius: var(--r-sm);
06d5ffeClaude1736 color: var(--text);
2ce1d0bClaude1737 font-size: var(--t-sm);
1738 font-weight: 500;
06d5ffeClaude1739 cursor: pointer;
2ce1d0bClaude1740 transition: all var(--t-fast) var(--ease);
1741 }
1742 .star-btn:hover { background: var(--bg-surface); border-color: var(--border-strong); text-decoration: none; }
1743 .star-btn.starred {
1744 color: var(--yellow);
958d26aClaude1745 border-color: rgba(251,191,36,0.4);
1746 background: rgba(251,191,36,0.08);
06d5ffeClaude1747 }
1748
2ce1d0bClaude1749 /* ============================================================ */
1750 /* User profile */
1751 /* ============================================================ */
06d5ffeClaude1752 .user-profile {
1753 display: flex;
1754 gap: 32px;
1755 margin-bottom: 32px;
2ce1d0bClaude1756 padding: 24px;
1757 background: var(--bg-elevated);
1758 border: 1px solid var(--border);
1759 border-radius: var(--r-lg);
06d5ffeClaude1760 }
1761 .user-avatar {
1762 width: 96px;
1763 height: 96px;
2ce1d0bClaude1764 border-radius: var(--r-full);
1765 background: var(--accent-gradient-soft);
1766 border: 1px solid var(--border-strong);
06d5ffeClaude1767 display: flex;
1768 align-items: center;
1769 justify-content: center;
2ce1d0bClaude1770 font-size: 36px;
1771 font-weight: 600;
1772 color: var(--text);
06d5ffeClaude1773 flex-shrink: 0;
2ce1d0bClaude1774 letter-spacing: -0.02em;
06d5ffeClaude1775 }
2ce1d0bClaude1776 .user-info h2 { font-size: var(--t-xl); margin-bottom: 2px; letter-spacing: -0.025em; }
1777 .user-info .username { font-size: var(--t-md); color: var(--text-muted); }
1778 .user-info .bio { font-size: var(--t-sm); color: var(--text-muted); margin-top: 10px; line-height: 1.55; }
06d5ffeClaude1779
2ce1d0bClaude1780 /* ============================================================ */
1781 /* New repo form */
1782 /* ============================================================ */
1783 .new-repo-form { max-width: 640px; }
1784 .new-repo-form h2 { margin-bottom: 24px; font-size: var(--t-xl); letter-spacing: -0.025em; }
1785 .visibility-options { display: flex; gap: 12px; margin-bottom: 20px; }
06d5ffeClaude1786 .visibility-option {
1787 flex: 1;
2ce1d0bClaude1788 padding: 16px;
06d5ffeClaude1789 border: 1px solid var(--border);
2ce1d0bClaude1790 border-radius: var(--r-md);
1791 background: var(--bg-elevated);
06d5ffeClaude1792 cursor: pointer;
2ce1d0bClaude1793 text-align: left;
1794 transition: all var(--t-fast) var(--ease);
1795 }
1796 .visibility-option:hover { border-color: var(--border-strong); background: var(--bg-surface); }
1797 .visibility-option:has(input:checked) {
1798 border-color: var(--accent);
1799 background: var(--accent-gradient-faint);
1800 box-shadow: 0 0 0 1px var(--accent);
06d5ffeClaude1801 }
1802 .visibility-option input { display: none; }
2ce1d0bClaude1803 .visibility-option .vis-label { font-size: var(--t-sm); font-weight: 600; margin-bottom: 4px; }
1804 .visibility-option .vis-desc { font-size: var(--t-xs); color: var(--text-muted); }
79136bbClaude1805
2ce1d0bClaude1806 /* ============================================================ */
1807 /* Issues */
1808 /* ============================================================ */
1809 .issue-tabs { display: flex; gap: 4px; }
1810 .issue-tabs a {
1811 color: var(--text-muted);
1812 font-size: var(--t-sm);
1813 font-weight: 500;
1814 padding: 6px 12px;
1815 border-radius: var(--r-sm);
1816 transition: all var(--t-fast) var(--ease);
1817 }
1818 .issue-tabs a:hover { color: var(--text); background: var(--bg-hover); text-decoration: none; }
1819 .issue-tabs a.active { color: var(--text); background: var(--bg-elevated); }
79136bbClaude1820
2ce1d0bClaude1821 .issue-list {
1822 border: 1px solid var(--border);
1823 border-radius: var(--r-md);
1824 overflow: hidden;
1825 background: var(--bg-elevated);
1826 }
79136bbClaude1827 .issue-item {
1828 display: flex;
2ce1d0bClaude1829 gap: 14px;
79136bbClaude1830 align-items: flex-start;
2ce1d0bClaude1831 padding: 14px 16px;
79136bbClaude1832 border-bottom: 1px solid var(--border);
2ce1d0bClaude1833 transition: background var(--t-fast) var(--ease);
79136bbClaude1834 }
1835 .issue-item:last-child { border-bottom: none; }
2ce1d0bClaude1836 .issue-item:hover { background: var(--bg-hover); }
1837 .issue-state-icon {
1838 font-size: 14px;
1839 padding-top: 2px;
1840 width: 18px;
1841 height: 18px;
1842 display: inline-flex;
1843 align-items: center;
1844 justify-content: center;
1845 border-radius: var(--r-full);
1846 flex-shrink: 0;
1847 }
79136bbClaude1848 .state-open { color: var(--green); }
958d26aClaude1849 .state-closed { color: #b69dff; }
2ce1d0bClaude1850 .issue-title {
debcf27Claude1851 font-family: var(--font-display);
1852 font-size: var(--t-md);
2ce1d0bClaude1853 font-weight: 600;
debcf27Claude1854 line-height: 1.35;
1855 letter-spacing: -0.012em;
1856 }
1857 .issue-title a { color: var(--text-strong); transition: color var(--t-fast) var(--ease); }
1858 .issue-title a:hover { color: var(--accent); text-decoration: none; }
1859 .issue-meta {
1860 font-family: var(--font-mono);
1861 font-size: 11px;
1862 color: var(--text-muted);
1863 margin-top: 5px;
1864 letter-spacing: 0.01em;
2ce1d0bClaude1865 }
79136bbClaude1866
1867 .issue-badge {
1868 display: inline-flex;
1869 align-items: center;
2ce1d0bClaude1870 gap: 6px;
79136bbClaude1871 padding: 4px 12px;
2ce1d0bClaude1872 border-radius: var(--r-full);
1873 font-size: var(--t-sm);
79136bbClaude1874 font-weight: 500;
2ce1d0bClaude1875 line-height: 1.4;
79136bbClaude1876 }
958d26aClaude1877 .badge-open { background: rgba(52,211,153,0.10); color: var(--green); border: 1px solid rgba(52,211,153,0.35); }
1878 .badge-closed { background: rgba(182,157,255,0.10); color: #b69dff; border: 1px solid rgba(182,157,255,0.35); }
1879 .badge-merged { background: rgba(140,109,255,0.10); color: var(--accent); border: 1px solid rgba(140,109,255,0.35); }
2ce1d0bClaude1880 .state-merged { color: var(--accent); }
958d26aClaude1881 .ai-review { border-color: var(--accent); box-shadow: 0 0 0 1px rgba(140,109,255,0.3); }
79136bbClaude1882
2ce1d0bClaude1883 .issue-detail { max-width: 920px; }
79136bbClaude1884 .issue-comment-box {
1885 border: 1px solid var(--border);
2ce1d0bClaude1886 border-radius: var(--r-md);
79136bbClaude1887 margin-bottom: 16px;
1888 overflow: hidden;
2ce1d0bClaude1889 background: var(--bg-elevated);
79136bbClaude1890 }
1891 .comment-header {
1892 background: var(--bg-secondary);
2ce1d0bClaude1893 padding: 10px 16px;
1894 border-bottom: 1px solid var(--border);
1895 font-size: var(--t-sm);
1896 color: var(--text-muted);
1897 }
1898
1899 /* ============================================================ */
1900 /* Panel — flexible container used across many pages */
1901 /* ============================================================ */
1902 .panel {
1903 background: var(--bg-elevated);
1904 border: 1px solid var(--border);
1905 border-radius: var(--r-md);
1906 overflow: hidden;
1907 }
1908 .panel-item {
1909 display: flex;
1910 align-items: center;
1911 gap: 12px;
1912 padding: 12px 16px;
79136bbClaude1913 border-bottom: 1px solid var(--border);
2ce1d0bClaude1914 transition: background var(--t-fast) var(--ease);
1915 }
1916 .panel-item:last-child { border-bottom: none; }
1917 .panel-item:hover { background: var(--bg-hover); }
1918 .panel-empty {
1919 padding: 24px;
1920 text-align: center;
79136bbClaude1921 color: var(--text-muted);
2ce1d0bClaude1922 font-size: var(--t-sm);
79136bbClaude1923 }
1924
2ce1d0bClaude1925 /* ============================================================ */
1926 /* Search */
1927 /* ============================================================ */
79136bbClaude1928 .search-results .diff-file { margin-bottom: 12px; }
16b325cClaude1929
2ce1d0bClaude1930 /* ============================================================ */
1931 /* Timeline */
1932 /* ============================================================ */
1933 .timeline { position: relative; padding-left: 28px; }
16b325cClaude1934 .timeline::before {
1935 content: '';
1936 position: absolute;
1937 left: 4px;
1938 top: 8px;
1939 bottom: 8px;
1940 width: 2px;
2ce1d0bClaude1941 background: linear-gradient(180deg, var(--border) 0%, transparent 100%);
16b325cClaude1942 }
2ce1d0bClaude1943 .timeline-item { position: relative; padding-bottom: 16px; }
16b325cClaude1944 .timeline-dot {
1945 position: absolute;
2ce1d0bClaude1946 left: -28px;
1947 top: 8px;
1948 width: 12px;
1949 height: 12px;
1950 border-radius: var(--r-full);
1951 background: var(--accent-gradient);
16b325cClaude1952 border: 2px solid var(--bg);
2ce1d0bClaude1953 box-shadow: 0 0 0 1px var(--border-strong);
16b325cClaude1954 }
1955 .timeline-content {
2ce1d0bClaude1956 background: var(--bg-elevated);
16b325cClaude1957 border: 1px solid var(--border);
2ce1d0bClaude1958 border-radius: var(--r-md);
1959 padding: 14px 16px;
16b325cClaude1960 }
f1ab587Claude1961
2ce1d0bClaude1962 /* ============================================================ */
1963 /* Toggle switch */
1964 /* ============================================================ */
f1ab587Claude1965 .toggle-switch {
1966 position: relative;
1967 display: inline-block;
2ce1d0bClaude1968 width: 40px;
1969 height: 22px;
f1ab587Claude1970 flex-shrink: 0;
1971 margin-left: 16px;
1972 }
1973 .toggle-switch input { opacity: 0; width: 0; height: 0; }
1974 .toggle-slider {
1975 position: absolute;
1976 cursor: pointer;
1977 top: 0; left: 0; right: 0; bottom: 0;
1978 background: var(--bg-tertiary);
1979 border: 1px solid var(--border);
2ce1d0bClaude1980 border-radius: var(--r-full);
1981 transition: all var(--t-base) var(--ease);
f1ab587Claude1982 }
1983 .toggle-slider::before {
1984 content: '';
1985 position: absolute;
2ce1d0bClaude1986 height: 16px;
1987 width: 16px;
f1ab587Claude1988 left: 2px;
1989 bottom: 2px;
1990 background: var(--text-muted);
2ce1d0bClaude1991 border-radius: var(--r-full);
1992 transition: all var(--t-base) var(--ease);
f1ab587Claude1993 }
1994 .toggle-switch input:checked + .toggle-slider {
2ce1d0bClaude1995 background: var(--accent-gradient);
1996 border-color: transparent;
958d26aClaude1997 box-shadow: 0 0 0 1px rgba(140,109,255,0.4);
f1ab587Claude1998 }
1999 .toggle-switch input:checked + .toggle-slider::before {
2ce1d0bClaude2000 transform: translateX(18px);
f1ab587Claude2001 background: #fff;
2002 }
2ce1d0bClaude2003
2004 /* ============================================================ */
958d26aClaude2005 /* Utilities — gradient text, surfaces, dot-grid, skeleton */
2ce1d0bClaude2006 /* ============================================================ */
2007 .gradient-text {
2008 background: var(--accent-gradient);
2009 -webkit-background-clip: text;
2010 background-clip: text;
2011 -webkit-text-fill-color: transparent;
958d26aClaude2012 color: transparent;
2ce1d0bClaude2013 }
2014 .surface { background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--r-md); }
2015 .surface-elevated { background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--r-md); box-shadow: var(--elev-1); }
958d26aClaude2016 .surface-glow {
2017 background: var(--bg-elevated);
2018 border: 1px solid var(--border-strong);
2019 border-radius: var(--r-lg);
2020 box-shadow: var(--elev-2), var(--accent-glow);
2021 }
2022
2023 /* Dot-grid background utility — for hero surfaces, empty states, terminal blocks */
2024 .dot-grid {
2025 background-image: radial-gradient(rgba(255,255,255,0.04) 1px, transparent 1px);
2026 background-size: 22px 22px;
2027 }
2028 :root[data-theme='light'] .dot-grid {
2029 background-image: radial-gradient(rgba(15,16,28,0.06) 1px, transparent 1px);
2030 }
2031
2032 /* Hairline-grid background utility */
2033 .grid-lines {
2034 background-image:
2035 linear-gradient(to right, var(--border-subtle) 1px, transparent 1px),
2036 linear-gradient(to bottom, var(--border-subtle) 1px, transparent 1px);
2037 background-size: 56px 56px;
2038 }
2039
2040 /* Skeleton loader */
2041 .skeleton {
2042 background: linear-gradient(90deg, var(--bg-tertiary) 0%, var(--bg-surface) 50%, var(--bg-tertiary) 100%);
2043 background-size: 200% 100%;
2044 animation: skel 1.4s ease-in-out infinite;
2045 border-radius: var(--r-sm);
2046 }
2047 @keyframes skel { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
2048
2049 /* Inline divider */
2050 .divider {
2051 border: 0;
2052 border-top: 1px solid var(--border);
2053 margin: var(--s-6) 0;
2054 }
2055 .divider-vert {
2056 width: 1px;
2057 align-self: stretch;
2058 background: var(--border);
2059 margin: 0 var(--s-3);
2060 }
2061
2062 /* Stagger fade-in helper — apply to a parent, animate children */
2063 .stagger > * {
2064 opacity: 0;
2065 transform: translateY(10px);
2066 animation: stagger-in 600ms var(--ease-out-expo) forwards;
2067 }
2068 .stagger > *:nth-child(1) { animation-delay: 0ms; }
2069 .stagger > *:nth-child(2) { animation-delay: 60ms; }
2070 .stagger > *:nth-child(3) { animation-delay: 120ms; }
2071 .stagger > *:nth-child(4) { animation-delay: 180ms; }
2072 .stagger > *:nth-child(5) { animation-delay: 240ms; }
2073 .stagger > *:nth-child(6) { animation-delay: 300ms; }
2074 .stagger > *:nth-child(7) { animation-delay: 360ms; }
2075 .stagger > *:nth-child(8) { animation-delay: 420ms; }
2076 @keyframes stagger-in {
2077 to { opacity: 1; transform: translateY(0); }
2078 }
2079
2080 /* Tag pill — used for labels, topics */
2081 .tag {
2082 display: inline-flex;
2083 align-items: center;
2084 gap: 5px;
2085 padding: 2px 9px;
2086 border-radius: var(--r-full);
2087 font-size: 11px;
2088 font-weight: 500;
2089 background: var(--bg-tertiary);
2090 border: 1px solid var(--border);
2091 color: var(--text-muted);
2092 line-height: 1.5;
2093 font-family: var(--font-mono);
2094 letter-spacing: 0.01em;
2095 }
2096 .tag-accent {
2097 background: var(--accent-gradient-faint);
2098 border-color: rgba(140,109,255,0.30);
2099 color: var(--accent);
2100 }
2ce1d0bClaude2101
2102 /* Command palette polish */
2103 .cmdk-item { transition: background var(--t-fast) var(--ease); }
2104 .cmdk-item:hover { background: var(--bg-hover) !important; }
2105 .cmdk-active { background: var(--accent-gradient-faint) !important; border-left: 2px solid var(--accent) !important; }
2106
e1db10eClaude2107 /* ============================================================ */
2108 /* Error pages (404 / 500) */
2109 /* ============================================================ */
2110 .error-page {
2111 text-align: center;
2112 padding: 96px 24px 80px;
2113 max-width: 720px;
2114 margin: 0 auto;
2115 position: relative;
2116 }
2117 .error-page::before {
2118 content: '';
2119 position: absolute;
2120 top: 0; left: 50%;
2121 transform: translateX(-50%);
2122 width: 80%; height: 60%;
2123 background: radial-gradient(ellipse at center, rgba(140,109,255,0.10), transparent 65%);
2124 z-index: -1;
2125 pointer-events: none;
2126 }
2127 .error-page-code {
2128 font-family: var(--font-display);
2129 font-size: clamp(80px, 14vw, 160px);
2130 font-weight: 700;
2131 line-height: 0.95;
2132 letter-spacing: -0.05em;
2133 background: linear-gradient(180deg, var(--text) 0%, var(--text-faint) 100%);
2134 -webkit-background-clip: text;
2135 background-clip: text;
2136 -webkit-text-fill-color: transparent;
2137 margin-bottom: var(--s-4);
2138 opacity: 0.85;
2139 }
2140 .error-page-code-err {
2141 background: linear-gradient(180deg, var(--red) 0%, rgba(248,113,113,0.4) 100%);
2142 -webkit-background-clip: text;
2143 background-clip: text;
2144 -webkit-text-fill-color: transparent;
2145 }
2146 .error-page .eyebrow { justify-content: center; margin: 0 auto var(--s-3); }
2147 .error-page-title {
2148 font-size: clamp(28px, 4.5vw, 48px);
2149 line-height: 1.05;
2150 letter-spacing: -0.03em;
2151 margin-bottom: var(--s-4);
2152 }
2153 .error-page-sub {
2154 color: var(--text-muted);
2155 font-size: var(--t-md);
2156 line-height: 1.55;
2157 max-width: 480px;
2158 margin: 0 auto var(--s-8);
2159 }
2160 .error-page-actions {
2161 display: flex;
2162 gap: 12px;
2163 justify-content: center;
2164 flex-wrap: wrap;
2165 margin-bottom: var(--s-7);
2166 }
2167 .error-page-meta {
2168 color: var(--text-faint);
2169 font-size: 11px;
2170 }
2171 .error-page-trace {
2172 margin-top: var(--s-5);
2173 padding: 16px 20px;
2174 background: var(--bg-secondary);
2175 border: 1px solid rgba(248,113,113,0.30);
2176 border-radius: var(--r-md);
2177 font-family: var(--font-mono);
2178 font-size: 12px;
2179 color: var(--red);
2180 text-align: left;
2181 overflow-x: auto;
2182 white-space: pre-wrap;
2183 word-break: break-all;
2184 }
2185
2186 /* Animated underline on inline content links inside markdown / prose */
2187 .prose a, .markdown-body a {
2188 position: relative;
2189 transition: color var(--t-fast) var(--ease);
2190 }
2191 .prose a::after, .markdown-body a::after {
2192 content: '';
2193 position: absolute;
2194 left: 0; right: 0; bottom: -1px;
2195 height: 1px;
2196 background: currentColor;
2197 opacity: 0.35;
2198 transform-origin: left;
2199 transition: opacity var(--t-fast) var(--ease), transform var(--t-base) var(--ease);
2200 }
2201 .prose a:hover::after, .markdown-body a:hover::after {
2202 opacity: 1;
2203 transform: scaleX(1.02);
2204 }
2205
2206 /* Print: keep it readable */
2207 @media print {
2208 body::before, body::after { display: none; }
2209 header, footer, .prelaunch-banner, .repo-nav, .repo-header-actions,
2210 .nav-search, .nav-right, .btn { display: none !important; }
2211 body { background: #fff; color: #000; }
2212 a { color: #000; text-decoration: underline; }
2213 main { max-width: 100%; padding: 0; }
2214 }
2215
2ce1d0bClaude2216 /* Reduced motion preference */
2217 @media (prefers-reduced-motion: reduce) {
2218 *, *::before, *::after {
2219 animation-duration: 0.01ms !important;
2220 animation-iteration-count: 1 !important;
2221 transition-duration: 0.01ms !important;
2222 }
2223 }
2224
2225 /* Tablet + below */
2226 @media (max-width: 768px) {
2227 main { padding: 20px 16px 40px; }
2228 header { padding: 0 16px; }
2229 .nav-search { display: none; }
2230 .repo-header { font-size: var(--t-md); }
2231 .card-grid { grid-template-columns: 1fr; }
2232 .auth-container { margin: 32px 16px; padding: 24px; }
2233 .visibility-options { flex-direction: column; }
2234 }
2235
2236 /* Scrollbar styling — subtle, themed */
2237 ::-webkit-scrollbar { width: 10px; height: 10px; }
2238 ::-webkit-scrollbar-track { background: transparent; }
2239 ::-webkit-scrollbar-thumb {
2240 background: var(--bg-surface);
2241 border: 2px solid var(--bg);
2242 border-radius: var(--r-full);
2243 }
2244 ::-webkit-scrollbar-thumb:hover { background: var(--border-strong); }
fc1817aClaude2245`;