Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
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.tsxBlame2241 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" />
fc1817aClaude25 <title>{title ? `${title} — gluecron` : "gluecron"}</title>
fa880f2Claude26 <script dangerouslySetInnerHTML={{ __html: themeInitScript }} />
27 <style dangerouslySetInnerHTML={{ __html: css }} />
28 <style dangerouslySetInnerHTML={{ __html: hljsThemeCss }} />
fc1817aClaude29 </head>
30 <body>
4a52a98Claude31 <div class="prelaunch-banner" role="status" aria-live="polite">
32 Pre-launch &mdash; Gluecron is in final validation. Public signups
33 and git hosting for non-owner users open after launch review.
34 </div>
fc1817aClaude35 <header>
36 <nav>
37 <a href="/" class="logo">
38 gluecron
39 </a>
3ef4c9dClaude40 <div class="nav-search">
001af43Claude41 <form method="get" action="/search">
3ef4c9dClaude42 <input
43 type="search"
44 name="q"
45 placeholder="Search (press /)"
46 aria-label="Search"
47 />
48 </form>
49 </div>
06d5ffeClaude50 <div class="nav-right">
6fc53bdClaude51 <a
52 href="/theme/toggle"
53 class="nav-link nav-theme"
54 title="Toggle theme"
55 aria-label="Toggle theme"
56 >
57 <span class="theme-icon-dark">{"\u263E"}</span>
58 <span class="theme-icon-light">{"\u2600"}</span>
59 </a>
c81ab7aClaude60 <a href="/explore" class="nav-link">
61 Explore
62 </a>
06d5ffeClaude63 {user ? (
64 <>
f1ab587Claude65 <a href="/dashboard" class="nav-link" style="font-weight: 600">
66 Dashboard
67 </a>
bdbd0deClaude68 <a href="/import" class="nav-link">
69 Import
70 </a>
06d5ffeClaude71 <a href="/new" class="btn btn-sm btn-primary">
72 + New
73 </a>
74 <a href={`/${user.username}`} class="nav-user">
75 {user.displayName || user.username}
76 </a>
77 <a href="/settings" class="nav-link">
78 Settings
79 </a>
80 <a href="/logout" class="nav-link">
81 Sign out
82 </a>
83 </>
84 ) : (
85 <>
86 <a href="/login" class="nav-link">
87 Sign in
88 </a>
89 <a href="/register" class="btn btn-sm btn-primary">
90 Register
91 </a>
92 </>
93 )}
94 </div>
fc1817aClaude95 </nav>
96 </header>
45e31d0Claude97 <main id="main-content">{children}</main>
fc1817aClaude98 <footer>
958d26aClaude99 <div class="footer-inner">
100 <div class="footer-brand">
101 <a href="/" class="logo">gluecron</a>
102 <p class="footer-tag">
103 AI-native code intelligence. Self-hosted git, automated CI,
104 push-time gates. Software that ships itself.
105 </p>
106 </div>
107 <div class="footer-links">
108 <div class="footer-col">
109 <div class="footer-col-title">Product</div>
b0148e9Claude110 <a href="/features">Features</a>
111 <a href="/pricing">Pricing</a>
958d26aClaude112 <a href="/explore">Explore</a>
113 <a href="/marketplace">Marketplace</a>
114 </div>
115 <div class="footer-col">
116 <div class="footer-col-title">Platform</div>
b0148e9Claude117 <a href="/help">Quickstart</a>
958d26aClaude118 <a href="/status">Status</a>
119 <a href="/api/graphql">GraphQL</a>
120 <a href="/mcp">MCP server</a>
121 </div>
122 <div class="footer-col">
b0148e9Claude123 <div class="footer-col-title">Company</div>
124 <a href="/about">About</a>
958d26aClaude125 <a href="/terms">Terms</a>
126 <a href="/privacy">Privacy</a>
127 <a href="/acceptable-use">Acceptable use</a>
128 </div>
129 </div>
130 </div>
131 <div class="footer-bottom">
132 <span>&copy; {new Date().getFullYear()} gluecron</span>
05cdb85Claude133 <span class="footer-build" title={`commit ${build.shaFull}\nbuilt ${build.builtAt}`}>
134 <span class="footer-build-dot" aria-hidden="true" />
135 {build.sha} · {build.branch}
136 </span>
36b4cbdClaude137 </div>
fc1817aClaude138 </footer>
05cdb85Claude139 {/* Live update poller — checks /api/version every 15s, prompts
140 reload when the running sha changes. Pure progressive-
141 enhancement; degrades to nothing if JS is off. */}
142 <div
143 id="version-banner"
144 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"
145 >
146 <span style="display:inline-flex;align-items:center;gap:8px">
147 <span style="width:8px;height:8px;border-radius:50%;background:#34d399;box-shadow:0 0 10px rgba(52,211,153,0.6)" />
148 <span>New version available</span>
149 </span>
150 <button
151 type="button"
152 id="version-banner-reload"
153 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"
154 >
155 Reload
156 </button>
157 </div>
fa880f2Claude158 <script dangerouslySetInnerHTML={{ __html: versionPollerScript }} />
699e5c7Claude159 {/* Block I4 — Command palette shell (hidden by default) */}
160 <div
161 id="cmdk-backdrop"
162 style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:9998"
163 />
164 <div
165 id="cmdk-panel"
166 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"
167 >
168 <input
169 id="cmdk-input"
170 type="text"
171 placeholder="Type a command..."
172 aria-label="Command palette"
173 style="width:100%;padding:12px 16px;background:transparent;color:var(--text);border:0;border-bottom:1px solid var(--border);outline:none;font-size:14px"
174 />
175 <div id="cmdk-list" style="max-height:60vh;overflow-y:auto" />
176 </div>
fa880f2Claude177 <script dangerouslySetInnerHTML={{ __html: clientJs }} />
178 <script dangerouslySetInnerHTML={{ __html: pwaRegisterScript }} />
179 <script dangerouslySetInnerHTML={{ __html: navScript }} />
fc1817aClaude180 </body>
181 </html>
182 );
183};
184
05cdb85Claude185// Live version poller. Checks /api/version every 15s; if the sha differs
186// from the one we booted with, reveal the floating 'New version' pill so
187// the user can reload onto the new code without manually refreshing.
188const versionPollerScript = `
189 (function(){
190 var loadedSha = null;
191 var banner, btn;
192 function poll(){
193 fetch('/api/version', { cache: 'no-store' })
194 .then(function(r){ return r.ok ? r.json() : null; })
195 .then(function(j){
196 if (!j || !j.sha) return;
197 if (loadedSha === null) { loadedSha = j.sha; return; }
198 if (j.sha !== loadedSha && banner) {
199 banner.style.display = 'inline-flex';
200 }
201 })
202 .catch(function(){});
203 }
204 function init(){
205 banner = document.getElementById('version-banner');
206 btn = document.getElementById('version-banner-reload');
207 if (btn) btn.addEventListener('click', function(){ window.location.reload(); });
208 poll();
209 setInterval(poll, 15000);
210 }
211 if (document.readyState === 'loading') {
212 document.addEventListener('DOMContentLoaded', init);
213 } else {
214 init();
215 }
216 })();
217`;
218
6fc53bdClaude219// Runs before paint — reads the theme cookie and flips data-theme so there's
220// no dark-to-light flash on load. SSR default is dark.
221const themeInitScript = `
222 (function(){
223 try {
224 var m = document.cookie.match(/(?:^|; )theme=([^;]+)/);
225 var t = m ? decodeURIComponent(m[1]) : 'dark';
226 if (t !== 'light' && t !== 'dark') t = 'dark';
227 document.documentElement.setAttribute('data-theme', t);
228 } catch(_){}
229 })();
230`;
231
eae38d1Claude232// Block G1 — register service worker for offline / install support.
233// Kept inline (and tiny) so we don't block first paint.
234const pwaRegisterScript = `
235 if ('serviceWorker' in navigator) {
236 window.addEventListener('load', function(){
237 navigator.serviceWorker.register('/sw.js').catch(function(){});
238 });
239 }
240`;
241
3ef4c9dClaude242const navScript = `
243 (function(){
244 var chord = null;
245 var chordTimer = null;
246 function isTyping(t){
247 t = t || {};
248 var tag = (t.tagName || '').toLowerCase();
249 return tag === 'input' || tag === 'textarea' || t.isContentEditable;
250 }
71cd5ecClaude251
252 // ---------- Block I4 — Command palette ----------
253 var COMMANDS = [
254 { label: 'Go to Dashboard', href: '/dashboard', kw: 'home' },
255 { label: 'Go to Explore', href: '/explore', kw: 'browse discover' },
256 { label: 'Go to Notifications', href: '/notifications', kw: 'inbox' },
257 { label: 'Go to Ask AI', href: '/ask', kw: 'chat assistant' },
258 { label: 'Create new repository', href: '/new', kw: 'add create' },
259 { label: 'Marketplace', href: '/marketplace', kw: 'apps store' },
260 { label: 'Installed apps', href: '/settings/apps', kw: 'my apps' },
261 { label: 'Register new app', href: '/developer/apps-new', kw: 'developer create' },
262 { label: 'Keyboard shortcuts', href: '/shortcuts', kw: 'help keys' },
263 { label: 'Settings (profile)', href: '/settings', kw: 'account' },
264 { label: '2FA settings', href: '/settings/2fa', kw: 'two factor security' },
265 { label: 'Passkeys settings', href: '/settings/passkeys', kw: 'webauthn' },
266 { label: 'Personal access tokens', href: '/settings/tokens', kw: 'pat api' },
267 { label: 'Billing + quotas', href: '/settings/billing', kw: 'plans money' },
268 { label: 'Audit log (personal)', href: '/settings/audit', kw: 'history' },
269 { label: 'Gists', href: '/gists', kw: 'snippets' },
270 { label: 'GraphQL explorer', href: '/api/graphql', kw: 'api query' },
271 { label: 'Admin dashboard', href: '/admin', kw: 'superuser' },
272 { label: 'Toggle theme', href: '/theme/toggle', kw: 'dark light mode' }
273 ];
274
275 function fuzzyMatch(item, q){
276 if (!q) return true;
277 var hay = (item.label + ' ' + (item.kw||'') + ' ' + item.href).toLowerCase();
278 q = q.toLowerCase();
279 var qi = 0;
280 for (var i = 0; i < hay.length && qi < q.length; i++) {
281 if (hay[i] === q[qi]) qi++;
282 }
283 return qi === q.length;
284 }
285
286 var backdrop, panel, input, list, selected = 0, filtered = COMMANDS.slice();
287
288 function render(){
289 if (!list) return;
290 var html = '';
291 for (var i = 0; i < filtered.length; i++) {
292 var item = filtered[i];
293 var cls = i === selected ? 'cmdk-item cmdk-active' : 'cmdk-item';
294 var bg = i === selected ? 'background:var(--bg);' : '';
ea52715copilot-swe-agent[bot]295 html += '<div class="' + cls + '" data-idx="' + i + '" data-url="' + item.href + '"' +
71cd5ecClaude296 ' style="padding:10px 16px;cursor:pointer;border-bottom:1px solid var(--border);' + bg + '">' +
297 '<div>' + item.label + '</div>' +
298 '<div style="font-size:11px;color:var(--text-muted)">' + item.href + '</div>' +
299 '</div>';
300 }
301 if (filtered.length === 0) {
302 html = '<div style="padding:16px;color:var(--text-muted);text-align:center">No matches.</div>';
303 }
304 list.innerHTML = html;
305 }
306
307 function openPalette(){
308 backdrop = document.getElementById('cmdk-backdrop');
309 panel = document.getElementById('cmdk-panel');
310 input = document.getElementById('cmdk-input');
311 list = document.getElementById('cmdk-list');
312 if (!backdrop || !panel) return;
313 backdrop.style.display = 'block';
314 panel.style.display = 'block';
315 input.value = '';
316 selected = 0;
317 filtered = COMMANDS.slice();
318 render();
319 input.focus();
320 }
321 function closePalette(){
322 if (backdrop) backdrop.style.display = 'none';
323 if (panel) panel.style.display = 'none';
324 }
325 function go(href){ closePalette(); window.location.href = href; }
326
327 document.addEventListener('click', function(e){
328 var t = e.target;
329 if (t && t.id === 'cmdk-backdrop') { closePalette(); return; }
330 var item = t && t.closest && t.closest('.cmdk-item');
ea52715copilot-swe-agent[bot]331 if (item) { go(item.getAttribute('data-url')); }
71cd5ecClaude332 });
333
334 document.addEventListener('input', function(e){
335 if (e.target && e.target.id === 'cmdk-input') {
336 var q = e.target.value;
337 filtered = COMMANDS.filter(function(c){ return fuzzyMatch(c, q); });
338 selected = 0;
339 render();
340 }
341 });
342
3ef4c9dClaude343 document.addEventListener('keydown', function(e){
71cd5ecClaude344 // Palette-scoped keys take priority when open
345 if (panel && panel.style.display === 'block') {
346 if (e.key === 'Escape') { e.preventDefault(); closePalette(); return; }
347 if (e.key === 'ArrowDown') {
348 e.preventDefault();
349 selected = Math.min(filtered.length - 1, selected + 1);
350 render();
351 return;
352 }
353 if (e.key === 'ArrowUp') {
354 e.preventDefault();
355 selected = Math.max(0, selected - 1);
356 render();
357 return;
358 }
359 if (e.key === 'Enter') {
360 e.preventDefault();
361 var item = filtered[selected];
362 if (item) go(item.href);
363 return;
364 }
365 return;
366 }
367
3ef4c9dClaude368 if (isTyping(e.target)) return;
369 // Single key shortcuts
370 if (e.key === '/') {
371 var el = document.querySelector('.nav-search input');
372 if (el) { e.preventDefault(); el.focus(); return; }
373 }
374 if ((e.metaKey||e.ctrlKey) && e.key.toLowerCase() === 'k') {
71cd5ecClaude375 e.preventDefault();
376 openPalette();
377 return;
3ef4c9dClaude378 }
379 if (e.key === '?' && !e.ctrlKey && !e.metaKey) {
380 e.preventDefault(); window.location.href = '/shortcuts'; return;
381 }
382 if (e.key === 'n' && !e.ctrlKey && !e.metaKey) {
383 e.preventDefault(); window.location.href = '/new'; return;
384 }
385 // "g" chord
386 if (e.key === 'g' && !e.ctrlKey && !e.metaKey) {
387 chord = 'g';
388 clearTimeout(chordTimer);
389 chordTimer = setTimeout(function(){ chord = null; }, 1200);
390 return;
391 }
392 if (chord === 'g') {
393 if (e.key === 'd') { e.preventDefault(); window.location.href = '/dashboard'; }
394 else if (e.key === 'n') { e.preventDefault(); window.location.href = '/notifications'; }
395 else if (e.key === 'e') { e.preventDefault(); window.location.href = '/explore'; }
396 else if (e.key === 'a') { e.preventDefault(); window.location.href = '/ask'; }
397 chord = null;
398 }
399 });
400 })();
401`;
402
fc1817aClaude403const css = `
2ce1d0bClaude404 /* ================================================================
958d26aClaude405 * Gluecron design system — 2026.05 "Editorial-Technical"
406 * Slate-noir base · refined violet signature · hairline geometry ·
407 * mono-as-feature · cinematic motion · Inter Tight + JetBrains Mono.
408 * All class names preserved for back-compat across 50+ route views.
2ce1d0bClaude409 * ============================================================== */
6fc53bdClaude410 :root, :root[data-theme='dark'] {
958d26aClaude411 /* Surfaces — slate, not black. More depth, less crush. */
412 --bg: #08090f;
413 --bg-secondary: #0c0d14;
414 --bg-tertiary: #11131c;
415 --bg-elevated: #0f111a;
416 --bg-surface: #161826;
417 --bg-hover: rgba(255,255,255,0.04);
418 --bg-active: rgba(255,255,255,0.08);
419 --bg-inset: rgba(0,0,0,0.30);
420
421 /* Borders — three weights, used deliberately */
422 --border: rgba(255,255,255,0.06);
423 --border-subtle: rgba(255,255,255,0.035);
424 --border-strong: rgba(255,255,255,0.13);
425 --border-focus: rgba(140,109,255,0.55);
426
427 /* Text */
428 --text: #ededf2;
429 --text-strong: #f7f7fb;
430 --text-muted: #8b8c9c;
431 --text-faint: #555665;
432 --text-link: #b69dff;
433
434 /* Accent — refined violet (less candy), warm amber as secondary signal */
435 --accent: #8c6dff;
436 --accent-2: #36c5d6;
437 --accent-warm: #ffb45e;
438 --accent-hover: #a48bff;
439 --accent-pressed:#7559e8;
440 --accent-gradient: linear-gradient(135deg, #8c6dff 0%, #36c5d6 100%);
441 --accent-gradient-soft: linear-gradient(135deg, rgba(140,109,255,0.18) 0%, rgba(54,197,214,0.18) 100%);
442 --accent-gradient-faint: linear-gradient(135deg, rgba(140,109,255,0.07) 0%, rgba(54,197,214,0.07) 100%);
443 --accent-glow: 0 0 24px rgba(140,109,255,0.28);
444
445 /* Semantic */
446 --green: #34d399;
447 --red: #f87171;
448 --yellow: #fbbf24;
449 --amber: #fbbf24;
450 --blue: #60a5fa;
451
fb71554Claude452 /* Type — system fonts FIRST so we never depend on Google Fonts loading.
453 Segoe UI (Win), -apple-system / SF (Mac), Roboto (Android), Inter as
454 optional upgrade if the user already has it. NEVER falls back to serif. */
455 --font-mono: ui-monospace, 'SF Mono', 'Cascadia Code', 'Cascadia Mono', Menlo, Consolas, 'Courier New', monospace;
456 --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI Variable', 'Segoe UI', system-ui, Roboto, 'Helvetica Neue', Arial, 'Inter', sans-serif;
457 --font-display: -apple-system, BlinkMacSystemFont, 'Segoe UI Variable', 'Segoe UI', system-ui, Roboto, 'Helvetica Neue', Arial, 'Inter Tight', 'Inter', sans-serif;
958d26aClaude458 --mono-feat: 'calt', 'liga', 'ss01';
459
460 /* Radius — sharper than before */
461 --r-sm: 5px;
462 --r: 7px;
463 --r-md: 9px;
464 --r-lg: 12px;
465 --r-xl: 16px;
466 --r-2xl: 22px;
467 --r-full: 9999px;
468 --radius: 7px;
469
470 /* Type scale — bigger display sizes for editorial feel */
471 --t-xs: 11px;
472 --t-sm: 13px;
473 --t-base: 14px;
474 --t-md: 16px;
475 --t-lg: 20px;
476 --t-xl: 28px;
477 --t-2xl: 40px;
478 --t-3xl: 56px;
479 --t-display: 72px;
480 --t-display-lg:96px;
481
482 /* Spacing — 4px base */
2ce1d0bClaude483 --s-0: 0;
958d26aClaude484 --s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px;
485 --s-5: 20px; --s-6: 24px; --s-7: 28px; --s-8: 32px;
486 --s-10:40px; --s-12:48px; --s-14:56px; --s-16:64px;
487 --s-20:80px; --s-24:96px; --s-32:128px;
488
489 /* Elevation — softer + more layered */
490 --elev-0: 0 0 0 1px var(--border);
491 --elev-1: 0 1px 2px rgba(0,0,0,0.50), 0 0 0 1px var(--border);
492 --elev-2: 0 8px 24px -8px rgba(0,0,0,0.60), 0 0 0 1px var(--border);
493 --elev-3: 0 20px 48px -12px rgba(0,0,0,0.70), 0 0 0 1px var(--border-strong);
494 --elev-glow: 0 0 0 1px rgba(140,109,255,0.40), 0 0 32px -4px rgba(140,109,255,0.30);
495 --ring: 0 0 0 3px rgba(140,109,255,0.28);
496 --ring-warn: 0 0 0 3px rgba(251,191,36,0.28);
497 --ring-err: 0 0 0 3px rgba(248,113,113,0.28);
498
499 /* Motion */
500 --ease: cubic-bezier(0.16, 1, 0.3, 1);
501 --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
502 --ease-out-expo: cubic-bezier(0.19, 1, 0.22, 1);
503 --ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
504 --t-fast: 120ms;
505 --t-base: 200ms;
506 --t-slow: 360ms;
507 --t-slower:560ms;
508
509 --header-h: 60px;
fc1817aClaude510 }
511
6fc53bdClaude512 :root[data-theme='light'] {
958d26aClaude513 --bg: #fbfbfc;
4c47454Claude514 --bg-secondary: #ffffff;
958d26aClaude515 --bg-tertiary: #f3f3f6;
516 --bg-elevated: #ffffff;
517 --bg-surface: #f6f6f9;
518 --bg-hover: rgba(0,0,0,0.035);
519 --bg-active: rgba(0,0,0,0.07);
520 --bg-inset: rgba(0,0,0,0.04);
521
522 --border: rgba(15,16,28,0.08);
523 --border-subtle: rgba(15,16,28,0.04);
524 --border-strong: rgba(15,16,28,0.16);
525
526 --text: #0e1020;
527 --text-strong: #050617;
528 --text-muted: #5a5b70;
529 --text-faint: #8a8b9e;
530 --text-link: #6d4dff;
531
532 --accent: #6d4dff;
533 --accent-2: #0891b2;
534 --accent-hover: #5a3df0;
535 --accent-pressed:#4a30d6;
536 --accent-glow: 0 0 24px rgba(109,77,255,0.18);
537
538 --green: #059669;
539 --red: #dc2626;
4c47454Claude540 --yellow: #d97706;
958d26aClaude541
542 --elev-1: 0 1px 2px rgba(15,16,28,0.06), 0 0 0 1px var(--border);
543 --elev-2: 0 8px 24px -10px rgba(15,16,28,0.10), 0 0 0 1px var(--border);
544 --elev-3: 0 20px 48px -16px rgba(15,16,28,0.14), 0 0 0 1px var(--border-strong);
6fc53bdClaude545 }
546
547 /* Theme toggle — show the icon for the *opposite* theme so users see what they'll switch to. */
958d26aClaude548 .nav-theme { display: inline-flex; align-items: center; font-size: 15px; line-height: 1; opacity: 0.85; }
549 .nav-theme:hover { opacity: 1; }
6fc53bdClaude550 :root[data-theme='dark'] .theme-icon-dark { display: none; }
551 :root[data-theme='light'] .theme-icon-light { display: none; }
552
fc1817aClaude553 * { margin: 0; padding: 0; box-sizing: border-box; }
958d26aClaude554 *::selection { background: rgba(140,109,255,0.32); color: var(--text-strong); }
2ce1d0bClaude555
958d26aClaude556 html { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-rendering: optimizeLegibility; }
fc1817aClaude557
558 body {
559 font-family: var(--font-sans);
560 background: var(--bg);
561 color: var(--text);
2ce1d0bClaude562 line-height: 1.55;
958d26aClaude563 letter-spacing: -0.011em;
fc1817aClaude564 min-height: 100vh;
565 display: flex;
566 flex-direction: column;
958d26aClaude567 font-feature-settings: 'cv11', 'ss01', 'ss03', 'calt';
2ce1d0bClaude568 }
569
958d26aClaude570 /* Whole-page atmosphere: very subtle gradient + dot-grid layered behind everything.
571 Keeps every page feeling like part of the same product without competing with hero art. */
2ce1d0bClaude572 body::before {
573 content: '';
574 position: fixed;
575 inset: 0;
576 pointer-events: none;
958d26aClaude577 z-index: -2;
2ce1d0bClaude578 background:
958d26aClaude579 radial-gradient(70% 55% at 85% -20%, rgba(140,109,255,0.07), transparent 65%),
580 radial-gradient(55% 45% at -10% 115%, rgba(54,197,214,0.05), transparent 65%);
581 }
582 body::after {
583 content: '';
584 position: fixed;
585 inset: 0;
586 pointer-events: none;
587 z-index: -1;
588 background-image: radial-gradient(rgba(255,255,255,0.025) 1px, transparent 1px);
589 background-size: 28px 28px;
590 background-position: 0 0;
591 opacity: 0.55;
592 mask-image: radial-gradient(ellipse at 50% 0%, #000 0%, transparent 70%);
593 -webkit-mask-image: radial-gradient(ellipse at 50% 0%, #000 0%, transparent 70%);
594 }
595 :root[data-theme='light'] body::before { opacity: 0.55; }
596 :root[data-theme='light'] body::after {
597 background-image: radial-gradient(rgba(15,16,28,0.06) 1px, transparent 1px);
598 opacity: 0.4;
fc1817aClaude599 }
2ce1d0bClaude600
601 a { color: var(--text-link); text-decoration: none; transition: color var(--t-fast) var(--ease); }
602 a:hover { color: var(--accent-hover); text-decoration: none; }
fc1817aClaude603
958d26aClaude604 /* Heading scale — confident, editorial, tight tracking */
605 h1, h2, h3, h4, h5, h6 {
606 font-family: var(--font-display);
2ce1d0bClaude607 font-weight: 600;
958d26aClaude608 letter-spacing: -0.022em;
609 line-height: 1.18;
610 color: var(--text-strong);
611 }
612 h1 { font-size: var(--t-xl); letter-spacing: -0.028em; }
613 h2 { font-size: var(--t-lg); letter-spacing: -0.022em; }
614 h3 { font-size: var(--t-md); font-weight: 600; letter-spacing: -0.015em; }
615 h4 { font-size: var(--t-base); font-weight: 600; letter-spacing: -0.01em; }
616 h5, h6 { font-size: var(--t-sm); font-weight: 600; letter-spacing: -0.005em; }
617
618 /* Editorial display heading utility — used by landing + marketing pages */
619 .display {
620 font-family: var(--font-display);
621 font-size: clamp(40px, 7.5vw, 96px);
622 line-height: 0.98;
623 letter-spacing: -0.04em;
624 font-weight: 600;
625 color: var(--text-strong);
2ce1d0bClaude626 }
fc1817aClaude627
958d26aClaude628 /* Eyebrow — uppercase mono label that sits above section headings */
629 .eyebrow {
630 display: inline-flex;
631 align-items: center;
632 gap: 8px;
633 font-family: var(--font-mono);
634 font-size: 11px;
635 font-weight: 500;
636 letter-spacing: 0.14em;
637 text-transform: uppercase;
638 color: var(--accent);
639 margin-bottom: var(--s-3);
640 }
641 .eyebrow::before {
642 content: '';
643 width: 18px;
644 height: 1px;
645 background: currentColor;
646 opacity: 0.6;
647 }
648
649 /* Section header — paired eyebrow + title + lede */
650 .section-header { max-width: 720px; margin: 0 auto var(--s-10); text-align: center; }
651 .section-header.left { text-align: left; margin-left: 0; margin-right: auto; }
652 .section-header h2 {
653 font-size: clamp(28px, 4vw, 44px);
654 line-height: 1.05;
655 letter-spacing: -0.028em;
656 margin-bottom: var(--s-3);
657 }
658 .section-header p {
659 color: var(--text-muted);
660 font-size: var(--t-md);
661 line-height: 1.6;
662 max-width: 580px;
663 margin: 0 auto;
664 }
665 .section-header.left p { margin-left: 0; }
666
667 code, kbd, samp {
2ce1d0bClaude668 font-family: var(--font-mono);
958d26aClaude669 font-feature-settings: var(--mono-feat);
670 }
671 code {
672 font-size: 0.9em;
2ce1d0bClaude673 background: var(--bg-tertiary);
958d26aClaude674 border: 1px solid var(--border-subtle);
2ce1d0bClaude675 padding: 1px 6px;
676 border-radius: var(--r-sm);
677 color: var(--text);
678 }
958d26aClaude679 kbd, .kbd {
680 display: inline-flex;
681 align-items: center;
682 padding: 1px 6px;
683 font-family: var(--font-mono);
684 font-size: 11px;
685 background: var(--bg-elevated);
686 border: 1px solid var(--border);
687 border-bottom-width: 2px;
688 border-radius: 4px;
689 color: var(--text);
690 line-height: 1.5;
691 vertical-align: middle;
692 }
2ce1d0bClaude693
958d26aClaude694 /* Mono utility for technical chrome (paths, IDs, dates) */
695 .mono { font-family: var(--font-mono); font-feature-settings: var(--mono-feat); font-size: 0.96em; }
696 .meta-mono { font-family: var(--font-mono); font-size: var(--t-xs); color: var(--text-muted); letter-spacing: 0; }
697
698 /* Pre-launch banner — slim, refined, mono caption */
4a52a98Claude699 .prelaunch-banner {
958d26aClaude700 position: relative;
2ce1d0bClaude701 background:
958d26aClaude702 linear-gradient(180deg, rgba(251,191,36,0.10), rgba(251,191,36,0.03)),
2ce1d0bClaude703 var(--bg);
958d26aClaude704 border-bottom: 1px solid rgba(251,191,36,0.28);
4a52a98Claude705 color: var(--yellow);
958d26aClaude706 padding: 7px 24px;
707 font-family: var(--font-mono);
708 font-size: 11px;
4a52a98Claude709 font-weight: 500;
710 text-align: center;
2ce1d0bClaude711 line-height: 1.5;
958d26aClaude712 letter-spacing: 0.04em;
713 text-transform: uppercase;
714 }
715 .prelaunch-banner::before {
716 content: '◆';
717 margin-right: 8px;
718 font-size: 9px;
719 opacity: 0.7;
720 vertical-align: 1px;
4a52a98Claude721 }
722
958d26aClaude723 /* Header — sticky, blurred, hairline border, taller for breathing room */
fc1817aClaude724 header {
2ce1d0bClaude725 position: sticky;
726 top: 0;
727 z-index: 100;
fc1817aClaude728 border-bottom: 1px solid var(--border);
2ce1d0bClaude729 padding: 0 24px;
730 height: var(--header-h);
958d26aClaude731 background: rgba(8,9,15,0.72);
732 backdrop-filter: saturate(180%) blur(18px);
733 -webkit-backdrop-filter: saturate(180%) blur(18px);
fc1817aClaude734 }
958d26aClaude735 :root[data-theme='light'] header { background: rgba(251,251,252,0.78); }
fc1817aClaude736
06d5ffeClaude737 header nav {
738 display: flex;
739 align-items: center;
958d26aClaude740 gap: 18px;
741 max-width: 1240px;
06d5ffeClaude742 margin: 0 auto;
2ce1d0bClaude743 height: 100%;
744 }
745 .logo {
958d26aClaude746 font-family: var(--font-display);
747 font-size: 16px;
2ce1d0bClaude748 font-weight: 700;
958d26aClaude749 letter-spacing: -0.025em;
750 color: var(--text-strong);
2ce1d0bClaude751 display: inline-flex;
752 align-items: center;
958d26aClaude753 gap: 9px;
754 transition: opacity var(--t-fast) var(--ease);
06d5ffeClaude755 }
2ce1d0bClaude756 .logo::before {
757 content: '';
958d26aClaude758 width: 20px; height: 20px;
759 border-radius: 6px;
2ce1d0bClaude760 background: var(--accent-gradient);
958d26aClaude761 box-shadow:
762 inset 0 1px 0 rgba(255,255,255,0.25),
763 0 0 0 1px rgba(140,109,255,0.45),
764 0 0 20px rgba(140,109,255,0.30);
2ce1d0bClaude765 flex-shrink: 0;
958d26aClaude766 transition: transform var(--t-base) var(--ease-spring), box-shadow var(--t-base) var(--ease);
767 }
768 .logo:hover { text-decoration: none; color: var(--text-strong); }
769 .logo:hover::before {
770 transform: rotate(8deg) scale(1.05);
771 box-shadow:
772 inset 0 1px 0 rgba(255,255,255,0.30),
773 0 0 0 1px rgba(140,109,255,0.55),
774 0 0 28px rgba(140,109,255,0.45);
2ce1d0bClaude775 }
fc1817aClaude776
2ce1d0bClaude777 .nav-search {
778 flex: 1;
958d26aClaude779 max-width: 360px;
780 margin: 0 4px 0 8px;
781 position: relative;
2ce1d0bClaude782 }
783 .nav-search input {
784 width: 100%;
958d26aClaude785 padding: 7px 12px 7px 32px;
2ce1d0bClaude786 background: var(--bg-tertiary);
787 border: 1px solid var(--border);
788 border-radius: var(--r-sm);
789 color: var(--text);
790 font-family: var(--font-sans);
791 font-size: var(--t-sm);
958d26aClaude792 transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
793 }
794 .nav-search::before {
795 content: '';
796 position: absolute;
797 left: 11px; top: 50%;
798 transform: translateY(-50%);
799 width: 12px; height: 12px;
800 border: 1.5px solid var(--text-faint);
801 border-radius: 50%;
802 pointer-events: none;
803 }
804 .nav-search::after {
805 content: '';
806 position: absolute;
807 left: 19px; top: calc(50% + 4px);
808 width: 5px; height: 1.5px;
809 background: var(--text-faint);
810 transform: rotate(45deg);
811 pointer-events: none;
2ce1d0bClaude812 }
813 .nav-search input::placeholder { color: var(--text-faint); }
814 .nav-search input:focus {
815 outline: none;
816 background: var(--bg-secondary);
958d26aClaude817 border-color: var(--border-focus);
818 box-shadow: var(--ring);
2ce1d0bClaude819 }
06d5ffeClaude820
958d26aClaude821 .nav-right { display: flex; align-items: center; gap: 2px; margin-left: auto; }
2ce1d0bClaude822 .nav-link {
958d26aClaude823 position: relative;
2ce1d0bClaude824 color: var(--text-muted);
825 font-size: var(--t-sm);
826 font-weight: 500;
958d26aClaude827 padding: 7px 11px;
2ce1d0bClaude828 border-radius: var(--r-sm);
958d26aClaude829 transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
2ce1d0bClaude830 }
831 .nav-link:hover {
958d26aClaude832 color: var(--text-strong);
2ce1d0bClaude833 background: var(--bg-hover);
834 text-decoration: none;
835 }
958d26aClaude836 .nav-link.active { color: var(--text-strong); }
837 .nav-link.active::after {
838 content: '';
839 position: absolute;
840 left: 11px; right: 11px;
841 bottom: -1px;
842 height: 2px;
843 background: var(--accent-gradient);
844 border-radius: 2px;
845 }
2ce1d0bClaude846 .nav-user {
958d26aClaude847 color: var(--text-strong);
2ce1d0bClaude848 font-weight: 600;
849 font-size: var(--t-sm);
850 padding: 6px 10px;
851 border-radius: var(--r-sm);
958d26aClaude852 margin-left: 6px;
2ce1d0bClaude853 transition: background var(--t-fast) var(--ease);
854 }
958d26aClaude855 .nav-user::before {
856 content: '';
857 display: inline-block;
858 width: 8px; height: 8px;
859 background: var(--green);
860 border-radius: 50%;
861 margin-right: 7px;
862 box-shadow: 0 0 8px rgba(52,211,153,0.5);
863 vertical-align: 1px;
864 }
2ce1d0bClaude865 .nav-user:hover { background: var(--bg-hover); text-decoration: none; }
866
867 main {
958d26aClaude868 max-width: 1240px;
2ce1d0bClaude869 margin: 0 auto;
958d26aClaude870 padding: 36px 24px 80px;
2ce1d0bClaude871 flex: 1;
872 width: 100%;
873 }
fc1817aClaude874
958d26aClaude875 /* Editorial footer: link grid + tagline row */
fc1817aClaude876 footer {
877 border-top: 1px solid var(--border);
958d26aClaude878 padding: 56px 24px 40px;
879 color: var(--text-muted);
880 font-size: var(--t-sm);
881 background:
882 linear-gradient(180deg, transparent 0%, rgba(140,109,255,0.025) 100%),
883 var(--bg);
884 }
885 footer .footer-inner {
886 max-width: 1240px;
887 margin: 0 auto;
888 display: grid;
889 grid-template-columns: 1fr auto;
890 gap: 48px;
891 align-items: start;
892 }
893 footer .footer-brand .logo { margin-bottom: var(--s-3); }
894 footer .footer-tag {
895 color: var(--text-muted);
896 font-size: var(--t-sm);
897 max-width: 320px;
898 line-height: 1.55;
899 }
900 footer .footer-links {
901 display: grid;
902 grid-template-columns: repeat(3, minmax(120px, auto));
903 gap: 0 56px;
904 }
905 footer .footer-col-title {
906 font-family: var(--font-mono);
907 font-size: 11px;
908 text-transform: uppercase;
909 letter-spacing: 0.14em;
910 color: var(--text-faint);
911 margin-bottom: var(--s-3);
912 }
913 footer .footer-col a {
914 display: block;
915 color: var(--text-muted);
916 font-size: var(--t-sm);
917 padding: 5px 0;
918 transition: color var(--t-fast) var(--ease);
919 }
920 footer .footer-col a:hover { color: var(--text-strong); text-decoration: none; }
921 footer .footer-bottom {
922 max-width: 1240px;
923 margin: 40px auto 0;
924 padding-top: 24px;
925 border-top: 1px solid var(--border-subtle);
926 display: flex;
927 justify-content: space-between;
928 align-items: center;
2ce1d0bClaude929 color: var(--text-faint);
930 font-size: var(--t-xs);
958d26aClaude931 font-family: var(--font-mono);
932 letter-spacing: 0.02em;
933 }
934 footer .footer-bottom a { color: var(--text-faint); }
935 footer .footer-bottom a:hover { color: var(--text-muted); text-decoration: none; }
05cdb85Claude936 footer .footer-build {
937 display: inline-flex;
938 align-items: center;
939 gap: 6px;
940 color: var(--text-faint);
941 font-family: var(--font-mono);
942 font-size: 11px;
943 cursor: help;
944 }
945 footer .footer-build-dot {
946 width: 6px; height: 6px;
947 border-radius: 50%;
948 background: var(--green);
949 box-shadow: 0 0 6px rgba(52,211,153,0.55);
950 animation: footer-build-pulse 2.4s ease-in-out infinite;
951 }
952 @keyframes footer-build-pulse {
953 0%, 100% { opacity: 0.6; }
954 50% { opacity: 1; }
955 }
958d26aClaude956 @media (max-width: 768px) {
957 footer .footer-inner { grid-template-columns: 1fr; gap: 32px; }
958 footer .footer-links { grid-template-columns: repeat(2, 1fr); gap: 24px 32px; }
959 footer .footer-bottom { flex-direction: column; gap: 8px; text-align: center; }
fc1817aClaude960 }
961
2ce1d0bClaude962 /* ============================================================ */
963 /* Buttons */
964 /* ============================================================ */
06d5ffeClaude965 .btn {
966 display: inline-flex;
967 align-items: center;
2ce1d0bClaude968 justify-content: center;
958d26aClaude969 gap: 7px;
2ce1d0bClaude970 padding: 7px 14px;
971 border-radius: var(--r-sm);
958d26aClaude972 font-family: var(--font-sans);
2ce1d0bClaude973 font-size: var(--t-sm);
06d5ffeClaude974 font-weight: 500;
975 border: 1px solid var(--border);
2ce1d0bClaude976 background: var(--bg-elevated);
06d5ffeClaude977 color: var(--text);
978 cursor: pointer;
979 text-decoration: none;
958d26aClaude980 line-height: 1.25;
981 letter-spacing: -0.008em;
2ce1d0bClaude982 transition:
983 background var(--t-fast) var(--ease),
984 border-color var(--t-fast) var(--ease),
985 transform var(--t-fast) var(--ease),
958d26aClaude986 box-shadow var(--t-fast) var(--ease),
987 color var(--t-fast) var(--ease);
2ce1d0bClaude988 user-select: none;
989 white-space: nowrap;
958d26aClaude990 position: relative;
06d5ffeClaude991 }
2ce1d0bClaude992 .btn:hover {
993 background: var(--bg-surface);
994 border-color: var(--border-strong);
958d26aClaude995 color: var(--text-strong);
2ce1d0bClaude996 text-decoration: none;
997 }
958d26aClaude998 .btn:active { transform: translateY(1px); }
2ce1d0bClaude999 .btn:focus-visible { outline: none; box-shadow: var(--ring); }
1000
1001 .btn-primary {
1002 background: var(--accent-gradient);
1003 border-color: transparent;
1004 color: #fff;
1005 font-weight: 600;
958d26aClaude1006 text-shadow: 0 1px 0 rgba(0,0,0,0.15);
2ce1d0bClaude1007 box-shadow:
958d26aClaude1008 inset 0 1px 0 rgba(255,255,255,0.22),
1009 inset 0 -1px 0 rgba(0,0,0,0.10),
1010 0 1px 2px rgba(0,0,0,0.40),
1011 0 0 0 1px rgba(140,109,255,0.30);
1012 }
1013 .btn-primary::before {
1014 content: '';
1015 position: absolute;
1016 inset: 0;
1017 border-radius: inherit;
1018 background: linear-gradient(180deg, rgba(255,255,255,0.18), transparent 60%);
1019 opacity: 0;
1020 transition: opacity var(--t-fast) var(--ease);
1021 pointer-events: none;
2ce1d0bClaude1022 }
1023 .btn-primary:hover {
958d26aClaude1024 color: #fff;
2ce1d0bClaude1025 background: var(--accent-gradient);
958d26aClaude1026 border-color: transparent;
2ce1d0bClaude1027 box-shadow:
958d26aClaude1028 inset 0 1px 0 rgba(255,255,255,0.30),
1029 inset 0 -1px 0 rgba(0,0,0,0.10),
1030 0 6px 18px -4px rgba(140,109,255,0.45),
1031 0 0 0 1px rgba(140,109,255,0.45);
2ce1d0bClaude1032 }
958d26aClaude1033 .btn-primary:hover::before { opacity: 1; }
2ce1d0bClaude1034
1035 .btn-danger {
1036 background: transparent;
958d26aClaude1037 border-color: rgba(248,113,113,0.40);
2ce1d0bClaude1038 color: var(--red);
1039 }
1040 .btn-danger:hover {
958d26aClaude1041 background: rgba(248,113,113,0.08);
2ce1d0bClaude1042 border-color: var(--red);
958d26aClaude1043 color: var(--red);
2ce1d0bClaude1044 }
958d26aClaude1045 .btn-danger:focus-visible { box-shadow: var(--ring-err); }
2ce1d0bClaude1046
1047 .btn-ghost {
1048 background: transparent;
1049 border-color: transparent;
1050 color: var(--text-muted);
1051 }
1052 .btn-ghost:hover {
1053 background: var(--bg-hover);
958d26aClaude1054 color: var(--text-strong);
2ce1d0bClaude1055 border-color: var(--border);
1056 }
1057
958d26aClaude1058 .btn-secondary {
1059 background: var(--bg-elevated);
1060 border-color: var(--border-strong);
1061 color: var(--text-strong);
1062 }
1063 .btn-secondary:hover {
1064 background: var(--bg-surface);
1065 border-color: var(--border-strong);
1066 }
1067
1068 .btn-sm { padding: 4px 10px; font-size: var(--t-xs); border-radius: var(--r-sm); gap: 5px; }
1069 .btn-lg { padding: 11px 22px; font-size: var(--t-base); border-radius: var(--r); }
1070 .btn-xl { padding: 14px 28px; font-size: var(--t-md); border-radius: var(--r); font-weight: 600; }
1071 .btn-block { width: 100%; }
2ce1d0bClaude1072
1073 .btn:disabled, .btn[aria-disabled='true'] {
958d26aClaude1074 opacity: 0.45;
2ce1d0bClaude1075 cursor: not-allowed;
1076 pointer-events: none;
1077 }
1078
1079 /* ============================================================ */
1080 /* Forms */
1081 /* ============================================================ */
1082 .form-group { margin-bottom: 20px; }
1083 .form-group label {
1084 display: block;
1085 font-size: var(--t-sm);
1086 font-weight: 500;
1087 margin-bottom: 6px;
1088 color: var(--text);
1089 letter-spacing: -0.005em;
1090 }
1091 .form-group input,
1092 .form-group textarea,
1093 .form-group select,
1094 input[type='text'], input[type='email'], input[type='password'],
1095 input[type='url'], input[type='search'], input[type='number'],
1096 textarea, select {
06d5ffeClaude1097 width: 100%;
2ce1d0bClaude1098 padding: 9px 12px;
1099 background: var(--bg-secondary);
06d5ffeClaude1100 border: 1px solid var(--border);
2ce1d0bClaude1101 border-radius: var(--r-sm);
06d5ffeClaude1102 color: var(--text);
2ce1d0bClaude1103 font-size: var(--t-sm);
06d5ffeClaude1104 font-family: var(--font-sans);
2ce1d0bClaude1105 transition:
1106 border-color var(--t-fast) var(--ease),
1107 background var(--t-fast) var(--ease),
1108 box-shadow var(--t-fast) var(--ease);
1109 }
1110 .form-group input::placeholder, textarea::placeholder, input::placeholder {
1111 color: var(--text-faint);
06d5ffeClaude1112 }
2ce1d0bClaude1113 .form-group input:hover, textarea:hover, select:hover,
1114 input[type='text']:hover, input[type='email']:hover, input[type='password']:hover {
1115 border-color: var(--border-strong);
1116 }
1117 .form-group input:focus, .form-group textarea:focus, .form-group select:focus,
1118 input:focus, textarea:focus, select:focus {
06d5ffeClaude1119 outline: none;
2ce1d0bClaude1120 background: var(--bg);
1121 border-color: var(--border-focus);
1122 box-shadow: var(--ring);
06d5ffeClaude1123 }
2ce1d0bClaude1124 textarea { font-family: var(--font-mono); font-size: var(--t-sm); line-height: 1.55; }
06d5ffeClaude1125 .input-disabled { opacity: 0.5; cursor: not-allowed; }
1126
2ce1d0bClaude1127 /* ============================================================ */
1128 /* Auth (register / login / verify) */
1129 /* ============================================================ */
1130 .auth-container {
1131 max-width: 420px;
1132 margin: 64px auto;
1133 padding: 32px;
1134 background: var(--bg-elevated);
1135 border: 1px solid var(--border);
1136 border-radius: var(--r-lg);
1137 box-shadow: var(--elev-2);
1138 }
1139 .auth-container h2 {
1140 margin-bottom: 6px;
1141 font-size: var(--t-lg);
1142 letter-spacing: -0.02em;
1143 }
1144 .auth-container > p {
1145 color: var(--text-muted);
1146 font-size: var(--t-sm);
1147 margin-bottom: 24px;
1148 }
1149 .auth-container .btn-primary { width: 100%; padding: 10px 16px; }
06d5ffeClaude1150 .auth-error {
958d26aClaude1151 background: rgba(248,113,113,0.08);
1152 border: 1px solid rgba(248,113,113,0.35);
06d5ffeClaude1153 color: var(--red);
2ce1d0bClaude1154 padding: 10px 14px;
1155 border-radius: var(--r-sm);
06d5ffeClaude1156 margin-bottom: 16px;
2ce1d0bClaude1157 font-size: var(--t-sm);
06d5ffeClaude1158 }
1159 .auth-success {
958d26aClaude1160 background: rgba(52,211,153,0.08);
1161 border: 1px solid rgba(52,211,153,0.35);
06d5ffeClaude1162 color: var(--green);
2ce1d0bClaude1163 padding: 10px 14px;
1164 border-radius: var(--r-sm);
06d5ffeClaude1165 margin-bottom: 16px;
2ce1d0bClaude1166 font-size: var(--t-sm);
1167 }
1168 .auth-switch {
1169 margin-top: 20px;
1170 font-size: var(--t-sm);
1171 color: var(--text-muted);
1172 text-align: center;
1173 }
1174 .banner {
1175 background: var(--accent-gradient-faint);
958d26aClaude1176 border: 1px solid rgba(140,109,255,0.35);
2ce1d0bClaude1177 color: var(--text);
1178 padding: 10px 14px;
1179 border-radius: var(--r-sm);
1180 font-size: var(--t-sm);
06d5ffeClaude1181 }
1182
2ce1d0bClaude1183 /* ============================================================ */
1184 /* Settings */
1185 /* ============================================================ */
1186 .settings-container { max-width: 720px; }
1187 .settings-container h2 { margin-bottom: 8px; font-size: var(--t-xl); letter-spacing: -0.02em; }
1188 .settings-container > h2 + p { color: var(--text-muted); font-size: var(--t-sm); margin-bottom: 24px; }
1189 .settings-container h3 { font-size: var(--t-md); margin-bottom: 12px; margin-top: 28px; }
1190 .settings-container h3:first-of-type { margin-top: 0; }
06d5ffeClaude1191 .ssh-keys-list { margin-bottom: 24px; }
1192 .ssh-key-item {
1193 display: flex;
1194 justify-content: space-between;
1195 align-items: center;
2ce1d0bClaude1196 padding: 14px 16px;
06d5ffeClaude1197 border: 1px solid var(--border);
2ce1d0bClaude1198 border-radius: var(--r-md);
06d5ffeClaude1199 margin-bottom: 8px;
2ce1d0bClaude1200 background: var(--bg-elevated);
1201 transition: border-color var(--t-fast) var(--ease);
06d5ffeClaude1202 }
2ce1d0bClaude1203 .ssh-key-item:hover { border-color: var(--border-strong); }
1204 .ssh-key-meta { font-size: var(--t-xs); color: var(--text-muted); margin-top: 4px; }
1205 .ssh-key-meta code { font-size: var(--t-xs); background: var(--bg-tertiary); padding: 1px 6px; border-radius: 3px; margin-right: 8px; }
06d5ffeClaude1206
2ce1d0bClaude1207 /* ============================================================ */
1208 /* Repo header + nav */
1209 /* ============================================================ */
fc1817aClaude1210 .repo-header {
1211 display: flex;
1212 align-items: center;
debcf27Claude1213 gap: 12px;
1214 margin-bottom: 22px;
1215 }
1216 .repo-header-title {
1217 display: flex;
1218 align-items: center;
1219 gap: 10px;
1220 font-family: var(--font-display);
1221 font-size: 24px;
1222 letter-spacing: -0.025em;
1223 flex-wrap: wrap;
1224 }
1225 .repo-header .owner {
1226 color: var(--text-muted);
1227 font-weight: 500;
1228 transition: color var(--t-fast) var(--ease);
1229 }
1230 .repo-header .owner:hover { color: var(--text-link); text-decoration: none; }
1231 .repo-header .separator { color: var(--text-faint); font-weight: 300; }
1232 .repo-header .name {
1233 color: var(--text-strong);
1234 font-weight: 700;
1235 letter-spacing: -0.028em;
fc1817aClaude1236 }
2ce1d0bClaude1237 .repo-header .name:hover { color: var(--text-link); text-decoration: none; }
debcf27Claude1238 .repo-header-fork {
1239 font-family: var(--font-mono);
1240 font-size: 11px;
1241 color: var(--text-muted);
1242 margin-top: 4px;
1243 letter-spacing: 0.01em;
1244 }
1245 .repo-header-fork a { color: var(--text-muted); }
1246 .repo-header-fork a:hover { color: var(--accent); }
1247 .repo-header-pill {
1248 display: inline-flex;
1249 align-items: center;
1250 padding: 2px 10px;
1251 border-radius: var(--r-full);
1252 font-family: var(--font-mono);
1253 font-size: 10px;
1254 font-weight: 600;
1255 letter-spacing: 0.12em;
1256 text-transform: uppercase;
1257 line-height: 1.6;
1258 vertical-align: 4px;
1259 }
1260 .repo-header-pill-archived {
1261 background: rgba(251,191,36,0.10);
1262 color: var(--yellow);
1263 border: 1px solid rgba(251,191,36,0.30);
1264 }
1265 .repo-header-pill-template {
1266 background: var(--accent-gradient-faint);
1267 color: var(--accent);
1268 border: 1px solid rgba(140,109,255,0.30);
1269 }
06d5ffeClaude1270 .repo-header-actions { margin-left: auto; display: flex; gap: 8px; align-items: center; }
fc1817aClaude1271
1272 .repo-nav {
1273 display: flex;
debcf27Claude1274 gap: 1px;
fc1817aClaude1275 border-bottom: 1px solid var(--border);
debcf27Claude1276 margin-bottom: 28px;
2ce1d0bClaude1277 overflow-x: auto;
1278 scrollbar-width: thin;
fc1817aClaude1279 }
2ce1d0bClaude1280 .repo-nav::-webkit-scrollbar { height: 0; }
fc1817aClaude1281 .repo-nav a {
debcf27Claude1282 position: relative;
1283 padding: 11px 14px;
fc1817aClaude1284 color: var(--text-muted);
1285 border-bottom: 2px solid transparent;
2ce1d0bClaude1286 font-size: var(--t-sm);
1287 font-weight: 500;
1288 margin-bottom: -1px;
debcf27Claude1289 transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
2ce1d0bClaude1290 white-space: nowrap;
1291 }
debcf27Claude1292 .repo-nav a:hover { text-decoration: none; color: var(--text-strong); background: var(--bg-hover); }
2ce1d0bClaude1293 .repo-nav a.active {
debcf27Claude1294 color: var(--text-strong);
1295 font-weight: 600;
1296 }
1297 .repo-nav a.active::after {
1298 content: '';
1299 position: absolute;
1300 left: 14px;
1301 right: 14px;
1302 bottom: -1px;
1303 height: 2px;
1304 background: var(--accent-gradient);
1305 border-radius: 2px;
1306 }
1307 /* AI links in the right-side cluster — sparkle accent */
1308 .repo-nav-ai {
1309 color: var(--accent) !important;
1310 font-weight: 500;
1311 }
1312 .repo-nav-ai:hover {
1313 color: var(--accent-hover) !important;
1314 background: var(--accent-gradient-faint) !important;
1315 }
1316 .repo-nav-ai.active {
1317 color: var(--accent-hover) !important;
2ce1d0bClaude1318 font-weight: 600;
fc1817aClaude1319 }
1320
2ce1d0bClaude1321 .breadcrumb {
1322 display: flex;
debcf27Claude1323 gap: 6px;
2ce1d0bClaude1324 align-items: center;
debcf27Claude1325 margin-bottom: 18px;
2ce1d0bClaude1326 color: var(--text-muted);
1327 font-size: var(--t-sm);
1328 font-family: var(--font-mono);
debcf27Claude1329 font-feature-settings: var(--mono-feat);
2ce1d0bClaude1330 }
1331 .breadcrumb a { color: var(--text-link); font-weight: 500; }
1332 .breadcrumb a:hover { color: var(--accent-hover); }
debcf27Claude1333 .breadcrumb strong {
1334 color: var(--text-strong);
1335 font-weight: 600;
1336 }
1337
1338 /* Page header — eyebrow + title + optional actions row.
1339 Use on dashboard, settings, admin, any "section landing" page. */
1340 .page-header {
1341 display: flex;
1342 align-items: flex-end;
1343 justify-content: space-between;
1344 gap: 16px;
1345 margin-bottom: 28px;
1346 padding-bottom: 20px;
1347 border-bottom: 1px solid var(--border-subtle);
1348 flex-wrap: wrap;
1349 }
1350 .page-header-text { flex: 1; min-width: 280px; }
1351 .page-header .eyebrow { margin-bottom: var(--s-2); }
1352 .page-header h1 {
1353 font-family: var(--font-display);
1354 font-size: clamp(24px, 3vw, 36px);
1355 line-height: 1.1;
1356 letter-spacing: -0.028em;
1357 margin-bottom: 6px;
1358 }
1359 .page-header p {
1360 color: var(--text-muted);
1361 font-size: var(--t-sm);
1362 line-height: 1.55;
1363 max-width: 640px;
1364 }
1365 .page-header-actions { display: flex; gap: 8px; align-items: center; }
fc1817aClaude1366
2ce1d0bClaude1367 /* ============================================================ */
1368 /* File browser table */
1369 /* ============================================================ */
1370 .file-table {
1371 width: 100%;
1372 border: 1px solid var(--border);
1373 border-radius: var(--r-md);
1374 overflow: hidden;
1375 background: var(--bg-elevated);
debcf27Claude1376 border-collapse: collapse;
2ce1d0bClaude1377 }
debcf27Claude1378 .file-table tr { border-bottom: 1px solid var(--border-subtle); transition: background var(--t-fast) var(--ease); }
fc1817aClaude1379 .file-table tr:last-child { border-bottom: none; }
debcf27Claude1380 .file-table td {
1381 padding: 9px 16px;
1382 font-size: var(--t-sm);
1383 font-family: var(--font-mono);
1384 font-feature-settings: var(--mono-feat);
1385 }
2ce1d0bClaude1386 .file-table tr:hover { background: var(--bg-hover); }
debcf27Claude1387 .file-icon {
1388 width: 22px;
1389 color: var(--text-faint);
1390 font-size: 13px;
1391 text-align: center;
1392 }
1393 .file-name a {
1394 color: var(--text);
1395 font-weight: 500;
1396 transition: color var(--t-fast) var(--ease);
1397 }
1398 .file-name a:hover { color: var(--accent); text-decoration: none; }
fc1817aClaude1399
2ce1d0bClaude1400 /* ============================================================ */
1401 /* Blob view */
1402 /* ============================================================ */
fc1817aClaude1403 .blob-view {
1404 border: 1px solid var(--border);
2ce1d0bClaude1405 border-radius: var(--r-md);
fc1817aClaude1406 overflow: hidden;
2ce1d0bClaude1407 background: var(--bg-elevated);
fc1817aClaude1408 }
1409 .blob-header {
1410 background: var(--bg-secondary);
2ce1d0bClaude1411 padding: 10px 16px;
fc1817aClaude1412 border-bottom: 1px solid var(--border);
2ce1d0bClaude1413 font-size: var(--t-sm);
fc1817aClaude1414 color: var(--text-muted);
06d5ffeClaude1415 display: flex;
1416 justify-content: space-between;
1417 align-items: center;
fc1817aClaude1418 }
1419 .blob-code {
1420 overflow-x: auto;
1421 font-family: var(--font-mono);
2ce1d0bClaude1422 font-size: var(--t-sm);
1423 line-height: 1.65;
fc1817aClaude1424 }
1425 .blob-code table { width: 100%; border-collapse: collapse; }
1426 .blob-code .line-num {
1427 width: 1%;
2ce1d0bClaude1428 min-width: 56px;
1429 padding: 0 14px;
fc1817aClaude1430 text-align: right;
2ce1d0bClaude1431 color: var(--text-faint);
fc1817aClaude1432 user-select: none;
1433 white-space: nowrap;
1434 border-right: 1px solid var(--border);
1435 }
2ce1d0bClaude1436 .blob-code .line-content { padding: 0 16px; white-space: pre; }
1437 .blob-code tr:hover { background: var(--bg-hover); }
fc1817aClaude1438
2ce1d0bClaude1439 /* ============================================================ */
1440 /* Commits + diffs */
1441 /* ============================================================ */
1442 .commit-list {
1443 border: 1px solid var(--border);
1444 border-radius: var(--r-md);
1445 overflow: hidden;
1446 background: var(--bg-elevated);
1447 }
fc1817aClaude1448 .commit-item {
1449 display: flex;
1450 justify-content: space-between;
1451 align-items: center;
debcf27Claude1452 padding: 14px 18px;
1453 border-bottom: 1px solid var(--border-subtle);
2ce1d0bClaude1454 transition: background var(--t-fast) var(--ease);
fc1817aClaude1455 }
1456 .commit-item:last-child { border-bottom: none; }
2ce1d0bClaude1457 .commit-item:hover { background: var(--bg-hover); }
debcf27Claude1458 .commit-message {
1459 font-size: var(--t-sm);
1460 font-weight: 500;
1461 line-height: 1.45;
1462 color: var(--text-strong);
1463 letter-spacing: -0.005em;
1464 }
1465 .commit-meta {
1466 font-family: var(--font-mono);
1467 font-size: 11px;
1468 color: var(--text-muted);
1469 margin-top: 5px;
1470 letter-spacing: 0.01em;
1471 }
fc1817aClaude1472 .commit-sha {
1473 font-family: var(--font-mono);
debcf27Claude1474 font-feature-settings: var(--mono-feat);
1475 font-size: 11px;
1476 padding: 4px 9px;
fc1817aClaude1477 background: var(--bg-tertiary);
1478 border: 1px solid var(--border);
2ce1d0bClaude1479 border-radius: var(--r-sm);
debcf27Claude1480 color: var(--accent);
1481 font-weight: 600;
1482 letter-spacing: 0.02em;
2ce1d0bClaude1483 transition: all var(--t-fast) var(--ease);
fc1817aClaude1484 }
debcf27Claude1485 .commit-sha:hover {
1486 border-color: rgba(140,109,255,0.40);
1487 background: var(--accent-gradient-faint);
1488 color: var(--accent-hover);
1489 text-decoration: none;
1490 }
fc1817aClaude1491
1492 .diff-view { margin-top: 16px; }
1493 .diff-file {
1494 border: 1px solid var(--border);
2ce1d0bClaude1495 border-radius: var(--r-md);
fc1817aClaude1496 margin-bottom: 16px;
1497 overflow: hidden;
2ce1d0bClaude1498 background: var(--bg-elevated);
fc1817aClaude1499 }
1500 .diff-file-header {
1501 background: var(--bg-secondary);
2ce1d0bClaude1502 padding: 10px 16px;
fc1817aClaude1503 border-bottom: 1px solid var(--border);
1504 font-family: var(--font-mono);
2ce1d0bClaude1505 font-size: var(--t-sm);
1506 font-weight: 500;
fc1817aClaude1507 }
1508 .diff-content {
1509 overflow-x: auto;
1510 font-family: var(--font-mono);
2ce1d0bClaude1511 font-size: var(--t-sm);
1512 line-height: 1.65;
fc1817aClaude1513 }
958d26aClaude1514 .diff-content .line-add { background: rgba(52,211,153,0.10); color: var(--green); }
1515 .diff-content .line-del { background: rgba(248,113,113,0.08); color: var(--red); }
1516 .diff-content .line-hunk { background: rgba(140,109,255,0.06); color: var(--text-link); }
2ce1d0bClaude1517 .diff-content .line { padding: 0 16px; white-space: pre; display: block; }
fc1817aClaude1518
1519 .stat-add { color: var(--green); font-weight: 600; }
1520 .stat-del { color: var(--red); font-weight: 600; }
1521
2ce1d0bClaude1522 /* ============================================================ */
1523 /* Empty state */
1524 /* ============================================================ */
fc1817aClaude1525 .empty-state {
1526 text-align: center;
958d26aClaude1527 padding: 96px 24px;
fc1817aClaude1528 color: var(--text-muted);
2ce1d0bClaude1529 border: 1px dashed var(--border);
1530 border-radius: var(--r-lg);
958d26aClaude1531 background:
1532 radial-gradient(60% 60% at 50% 0%, rgba(140,109,255,0.05), transparent 70%),
1533 var(--bg-elevated);
1534 position: relative;
1535 overflow: hidden;
1536 }
1537 .empty-state::before {
1538 content: '';
1539 position: absolute;
1540 inset: 0;
1541 background-image: radial-gradient(rgba(255,255,255,0.025) 1px, transparent 1px);
1542 background-size: 24px 24px;
1543 opacity: 0.5;
1544 pointer-events: none;
1545 mask-image: radial-gradient(ellipse at center, #000 30%, transparent 70%);
1546 -webkit-mask-image: radial-gradient(ellipse at center, #000 30%, transparent 70%);
1547 }
1548 :root[data-theme='light'] .empty-state::before {
1549 background-image: radial-gradient(rgba(15,16,28,0.08) 1px, transparent 1px);
fc1817aClaude1550 }
958d26aClaude1551 .empty-state > * { position: relative; z-index: 1; }
2ce1d0bClaude1552 .empty-state h2 {
958d26aClaude1553 font-size: var(--t-xl);
2ce1d0bClaude1554 margin-bottom: 8px;
958d26aClaude1555 color: var(--text-strong);
1556 letter-spacing: -0.022em;
2ce1d0bClaude1557 }
958d26aClaude1558 .empty-state p { font-size: var(--t-md); max-width: 480px; margin: 0 auto; line-height: 1.55; }
fc1817aClaude1559 .empty-state pre {
1560 text-align: left;
1561 display: inline-block;
1562 background: var(--bg-secondary);
958d26aClaude1563 padding: 18px 24px;
1564 border-radius: var(--r-md);
fc1817aClaude1565 border: 1px solid var(--border);
1566 font-family: var(--font-mono);
958d26aClaude1567 font-feature-settings: var(--mono-feat);
2ce1d0bClaude1568 font-size: var(--t-sm);
958d26aClaude1569 margin-top: 24px;
fc1817aClaude1570 line-height: 1.8;
2ce1d0bClaude1571 color: var(--text);
958d26aClaude1572 box-shadow: var(--elev-1);
fc1817aClaude1573 }
1574
2ce1d0bClaude1575 /* ============================================================ */
1576 /* Badges */
1577 /* ============================================================ */
fc1817aClaude1578 .badge {
2ce1d0bClaude1579 display: inline-flex;
1580 align-items: center;
1581 gap: 4px;
1582 padding: 2px 9px;
1583 border-radius: var(--r-full);
1584 font-size: var(--t-xs);
fc1817aClaude1585 font-weight: 500;
1586 background: var(--bg-tertiary);
1587 border: 1px solid var(--border);
1588 color: var(--text-muted);
2ce1d0bClaude1589 line-height: 1.5;
fc1817aClaude1590 }
1591
2ce1d0bClaude1592 /* ============================================================ */
1593 /* Branch dropdown */
1594 /* ============================================================ */
fc1817aClaude1595 .branch-selector {
1596 display: inline-flex;
1597 align-items: center;
2ce1d0bClaude1598 gap: 6px;
1599 padding: 6px 12px;
1600 background: var(--bg-elevated);
fc1817aClaude1601 border: 1px solid var(--border);
2ce1d0bClaude1602 border-radius: var(--r-sm);
1603 font-size: var(--t-sm);
fc1817aClaude1604 color: var(--text);
1605 margin-bottom: 12px;
2ce1d0bClaude1606 transition: border-color var(--t-fast) var(--ease);
fc1817aClaude1607 }
2ce1d0bClaude1608 .branch-selector:hover { border-color: var(--border-strong); }
fc1817aClaude1609
06d5ffeClaude1610 .branch-dropdown {
1611 position: relative;
1612 display: inline-block;
1613 margin-bottom: 12px;
1614 }
1615 .branch-dropdown-content {
1616 display: none;
1617 position: absolute;
2ce1d0bClaude1618 top: calc(100% + 4px);
06d5ffeClaude1619 left: 0;
1620 z-index: 10;
2ce1d0bClaude1621 min-width: 220px;
1622 background: var(--bg-elevated);
1623 border: 1px solid var(--border-strong);
1624 border-radius: var(--r-md);
1625 overflow: hidden;
1626 box-shadow: var(--elev-3);
06d5ffeClaude1627 }
1628 .branch-dropdown:hover .branch-dropdown-content,
1629 .branch-dropdown:focus-within .branch-dropdown-content { display: block; }
1630 .branch-dropdown-content a {
1631 display: block;
2ce1d0bClaude1632 padding: 9px 14px;
1633 font-size: var(--t-sm);
06d5ffeClaude1634 color: var(--text);
1635 border-bottom: 1px solid var(--border);
2ce1d0bClaude1636 transition: background var(--t-fast) var(--ease);
06d5ffeClaude1637 }
1638 .branch-dropdown-content a:last-child { border-bottom: none; }
2ce1d0bClaude1639 .branch-dropdown-content a:hover { background: var(--bg-hover); text-decoration: none; }
1640 .branch-dropdown-content a.active-branch { color: var(--text-link); font-weight: 600; background: var(--accent-gradient-faint); }
06d5ffeClaude1641
2ce1d0bClaude1642 /* ============================================================ */
1643 /* Card grid */
1644 /* ============================================================ */
1645 .card-grid {
1646 display: grid;
1647 grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
1648 gap: 16px;
1649 }
fc1817aClaude1650 .card {
1651 border: 1px solid var(--border);
2ce1d0bClaude1652 border-radius: var(--r-md);
958d26aClaude1653 padding: 20px;
2ce1d0bClaude1654 background: var(--bg-elevated);
1655 transition:
958d26aClaude1656 border-color var(--t-base) var(--ease),
1657 transform var(--t-base) var(--ease-out-quart),
2ce1d0bClaude1658 box-shadow var(--t-base) var(--ease);
1659 position: relative;
1660 overflow: hidden;
958d26aClaude1661 isolation: isolate;
1662 }
1663 .card::before {
1664 content: '';
1665 position: absolute;
1666 inset: 0;
1667 background: linear-gradient(135deg, rgba(140,109,255,0.06), transparent 50%);
1668 opacity: 0;
1669 transition: opacity var(--t-base) var(--ease);
1670 pointer-events: none;
1671 z-index: -1;
2ce1d0bClaude1672 }
1673 .card:hover {
1674 border-color: var(--border-strong);
1675 box-shadow: var(--elev-2);
958d26aClaude1676 transform: translateY(-2px);
2ce1d0bClaude1677 }
958d26aClaude1678 .card:hover::before { opacity: 1; }
1679 .card h3 { font-size: var(--t-md); margin-bottom: 6px; letter-spacing: -0.012em; }
2ce1d0bClaude1680 .card h3 a { color: var(--text); font-weight: 600; }
1681 .card h3 a:hover { color: var(--text-link); }
1682 .card p { font-size: var(--t-sm); color: var(--text-muted); line-height: 1.5; }
1683 .card-meta {
1684 display: flex;
1685 gap: 14px;
1686 margin-top: 14px;
1687 padding-top: 14px;
1688 border-top: 1px solid var(--border);
1689 font-size: var(--t-xs);
1690 color: var(--text-muted);
1691 }
1692 .card-meta span { display: flex; align-items: center; gap: 5px; }
1693
1694 /* ============================================================ */
1695 /* Stat card / box */
1696 /* ============================================================ */
1697 .stat-card {
1698 background: var(--bg-elevated);
1699 border: 1px solid var(--border);
1700 border-radius: var(--r-md);
fc1817aClaude1701 padding: 16px;
2ce1d0bClaude1702 transition: border-color var(--t-fast) var(--ease);
1703 }
1704 .stat-card:hover { border-color: var(--border-strong); }
1705 .stat-label {
1706 font-size: var(--t-xs);
1707 color: var(--text-muted);
1708 text-transform: uppercase;
1709 letter-spacing: 0.06em;
1710 font-weight: 500;
1711 }
1712 .stat-value {
1713 font-size: var(--t-xl);
1714 font-weight: 700;
1715 margin-top: 4px;
1716 letter-spacing: -0.025em;
1717 color: var(--text);
1718 font-feature-settings: 'tnum';
fc1817aClaude1719 }
06d5ffeClaude1720
2ce1d0bClaude1721 /* ============================================================ */
1722 /* Star button */
1723 /* ============================================================ */
06d5ffeClaude1724 .star-btn {
1725 display: inline-flex;
1726 align-items: center;
1727 gap: 6px;
2ce1d0bClaude1728 padding: 5px 12px;
1729 background: var(--bg-elevated);
06d5ffeClaude1730 border: 1px solid var(--border);
2ce1d0bClaude1731 border-radius: var(--r-sm);
06d5ffeClaude1732 color: var(--text);
2ce1d0bClaude1733 font-size: var(--t-sm);
1734 font-weight: 500;
06d5ffeClaude1735 cursor: pointer;
2ce1d0bClaude1736 transition: all var(--t-fast) var(--ease);
1737 }
1738 .star-btn:hover { background: var(--bg-surface); border-color: var(--border-strong); text-decoration: none; }
1739 .star-btn.starred {
1740 color: var(--yellow);
958d26aClaude1741 border-color: rgba(251,191,36,0.4);
1742 background: rgba(251,191,36,0.08);
06d5ffeClaude1743 }
1744
2ce1d0bClaude1745 /* ============================================================ */
1746 /* User profile */
1747 /* ============================================================ */
06d5ffeClaude1748 .user-profile {
1749 display: flex;
1750 gap: 32px;
1751 margin-bottom: 32px;
2ce1d0bClaude1752 padding: 24px;
1753 background: var(--bg-elevated);
1754 border: 1px solid var(--border);
1755 border-radius: var(--r-lg);
06d5ffeClaude1756 }
1757 .user-avatar {
1758 width: 96px;
1759 height: 96px;
2ce1d0bClaude1760 border-radius: var(--r-full);
1761 background: var(--accent-gradient-soft);
1762 border: 1px solid var(--border-strong);
06d5ffeClaude1763 display: flex;
1764 align-items: center;
1765 justify-content: center;
2ce1d0bClaude1766 font-size: 36px;
1767 font-weight: 600;
1768 color: var(--text);
06d5ffeClaude1769 flex-shrink: 0;
2ce1d0bClaude1770 letter-spacing: -0.02em;
06d5ffeClaude1771 }
2ce1d0bClaude1772 .user-info h2 { font-size: var(--t-xl); margin-bottom: 2px; letter-spacing: -0.025em; }
1773 .user-info .username { font-size: var(--t-md); color: var(--text-muted); }
1774 .user-info .bio { font-size: var(--t-sm); color: var(--text-muted); margin-top: 10px; line-height: 1.55; }
06d5ffeClaude1775
2ce1d0bClaude1776 /* ============================================================ */
1777 /* New repo form */
1778 /* ============================================================ */
1779 .new-repo-form { max-width: 640px; }
1780 .new-repo-form h2 { margin-bottom: 24px; font-size: var(--t-xl); letter-spacing: -0.025em; }
1781 .visibility-options { display: flex; gap: 12px; margin-bottom: 20px; }
06d5ffeClaude1782 .visibility-option {
1783 flex: 1;
2ce1d0bClaude1784 padding: 16px;
06d5ffeClaude1785 border: 1px solid var(--border);
2ce1d0bClaude1786 border-radius: var(--r-md);
1787 background: var(--bg-elevated);
06d5ffeClaude1788 cursor: pointer;
2ce1d0bClaude1789 text-align: left;
1790 transition: all var(--t-fast) var(--ease);
1791 }
1792 .visibility-option:hover { border-color: var(--border-strong); background: var(--bg-surface); }
1793 .visibility-option:has(input:checked) {
1794 border-color: var(--accent);
1795 background: var(--accent-gradient-faint);
1796 box-shadow: 0 0 0 1px var(--accent);
06d5ffeClaude1797 }
1798 .visibility-option input { display: none; }
2ce1d0bClaude1799 .visibility-option .vis-label { font-size: var(--t-sm); font-weight: 600; margin-bottom: 4px; }
1800 .visibility-option .vis-desc { font-size: var(--t-xs); color: var(--text-muted); }
79136bbClaude1801
2ce1d0bClaude1802 /* ============================================================ */
1803 /* Issues */
1804 /* ============================================================ */
1805 .issue-tabs { display: flex; gap: 4px; }
1806 .issue-tabs a {
1807 color: var(--text-muted);
1808 font-size: var(--t-sm);
1809 font-weight: 500;
1810 padding: 6px 12px;
1811 border-radius: var(--r-sm);
1812 transition: all var(--t-fast) var(--ease);
1813 }
1814 .issue-tabs a:hover { color: var(--text); background: var(--bg-hover); text-decoration: none; }
1815 .issue-tabs a.active { color: var(--text); background: var(--bg-elevated); }
79136bbClaude1816
2ce1d0bClaude1817 .issue-list {
1818 border: 1px solid var(--border);
1819 border-radius: var(--r-md);
1820 overflow: hidden;
1821 background: var(--bg-elevated);
1822 }
79136bbClaude1823 .issue-item {
1824 display: flex;
2ce1d0bClaude1825 gap: 14px;
79136bbClaude1826 align-items: flex-start;
2ce1d0bClaude1827 padding: 14px 16px;
79136bbClaude1828 border-bottom: 1px solid var(--border);
2ce1d0bClaude1829 transition: background var(--t-fast) var(--ease);
79136bbClaude1830 }
1831 .issue-item:last-child { border-bottom: none; }
2ce1d0bClaude1832 .issue-item:hover { background: var(--bg-hover); }
1833 .issue-state-icon {
1834 font-size: 14px;
1835 padding-top: 2px;
1836 width: 18px;
1837 height: 18px;
1838 display: inline-flex;
1839 align-items: center;
1840 justify-content: center;
1841 border-radius: var(--r-full);
1842 flex-shrink: 0;
1843 }
79136bbClaude1844 .state-open { color: var(--green); }
958d26aClaude1845 .state-closed { color: #b69dff; }
2ce1d0bClaude1846 .issue-title {
debcf27Claude1847 font-family: var(--font-display);
1848 font-size: var(--t-md);
2ce1d0bClaude1849 font-weight: 600;
debcf27Claude1850 line-height: 1.35;
1851 letter-spacing: -0.012em;
1852 }
1853 .issue-title a { color: var(--text-strong); transition: color var(--t-fast) var(--ease); }
1854 .issue-title a:hover { color: var(--accent); text-decoration: none; }
1855 .issue-meta {
1856 font-family: var(--font-mono);
1857 font-size: 11px;
1858 color: var(--text-muted);
1859 margin-top: 5px;
1860 letter-spacing: 0.01em;
2ce1d0bClaude1861 }
79136bbClaude1862
1863 .issue-badge {
1864 display: inline-flex;
1865 align-items: center;
2ce1d0bClaude1866 gap: 6px;
79136bbClaude1867 padding: 4px 12px;
2ce1d0bClaude1868 border-radius: var(--r-full);
1869 font-size: var(--t-sm);
79136bbClaude1870 font-weight: 500;
2ce1d0bClaude1871 line-height: 1.4;
79136bbClaude1872 }
958d26aClaude1873 .badge-open { background: rgba(52,211,153,0.10); color: var(--green); border: 1px solid rgba(52,211,153,0.35); }
1874 .badge-closed { background: rgba(182,157,255,0.10); color: #b69dff; border: 1px solid rgba(182,157,255,0.35); }
1875 .badge-merged { background: rgba(140,109,255,0.10); color: var(--accent); border: 1px solid rgba(140,109,255,0.35); }
2ce1d0bClaude1876 .state-merged { color: var(--accent); }
958d26aClaude1877 .ai-review { border-color: var(--accent); box-shadow: 0 0 0 1px rgba(140,109,255,0.3); }
79136bbClaude1878
2ce1d0bClaude1879 .issue-detail { max-width: 920px; }
79136bbClaude1880 .issue-comment-box {
1881 border: 1px solid var(--border);
2ce1d0bClaude1882 border-radius: var(--r-md);
79136bbClaude1883 margin-bottom: 16px;
1884 overflow: hidden;
2ce1d0bClaude1885 background: var(--bg-elevated);
79136bbClaude1886 }
1887 .comment-header {
1888 background: var(--bg-secondary);
2ce1d0bClaude1889 padding: 10px 16px;
1890 border-bottom: 1px solid var(--border);
1891 font-size: var(--t-sm);
1892 color: var(--text-muted);
1893 }
1894
1895 /* ============================================================ */
1896 /* Panel — flexible container used across many pages */
1897 /* ============================================================ */
1898 .panel {
1899 background: var(--bg-elevated);
1900 border: 1px solid var(--border);
1901 border-radius: var(--r-md);
1902 overflow: hidden;
1903 }
1904 .panel-item {
1905 display: flex;
1906 align-items: center;
1907 gap: 12px;
1908 padding: 12px 16px;
79136bbClaude1909 border-bottom: 1px solid var(--border);
2ce1d0bClaude1910 transition: background var(--t-fast) var(--ease);
1911 }
1912 .panel-item:last-child { border-bottom: none; }
1913 .panel-item:hover { background: var(--bg-hover); }
1914 .panel-empty {
1915 padding: 24px;
1916 text-align: center;
79136bbClaude1917 color: var(--text-muted);
2ce1d0bClaude1918 font-size: var(--t-sm);
79136bbClaude1919 }
1920
2ce1d0bClaude1921 /* ============================================================ */
1922 /* Search */
1923 /* ============================================================ */
79136bbClaude1924 .search-results .diff-file { margin-bottom: 12px; }
16b325cClaude1925
2ce1d0bClaude1926 /* ============================================================ */
1927 /* Timeline */
1928 /* ============================================================ */
1929 .timeline { position: relative; padding-left: 28px; }
16b325cClaude1930 .timeline::before {
1931 content: '';
1932 position: absolute;
1933 left: 4px;
1934 top: 8px;
1935 bottom: 8px;
1936 width: 2px;
2ce1d0bClaude1937 background: linear-gradient(180deg, var(--border) 0%, transparent 100%);
16b325cClaude1938 }
2ce1d0bClaude1939 .timeline-item { position: relative; padding-bottom: 16px; }
16b325cClaude1940 .timeline-dot {
1941 position: absolute;
2ce1d0bClaude1942 left: -28px;
1943 top: 8px;
1944 width: 12px;
1945 height: 12px;
1946 border-radius: var(--r-full);
1947 background: var(--accent-gradient);
16b325cClaude1948 border: 2px solid var(--bg);
2ce1d0bClaude1949 box-shadow: 0 0 0 1px var(--border-strong);
16b325cClaude1950 }
1951 .timeline-content {
2ce1d0bClaude1952 background: var(--bg-elevated);
16b325cClaude1953 border: 1px solid var(--border);
2ce1d0bClaude1954 border-radius: var(--r-md);
1955 padding: 14px 16px;
16b325cClaude1956 }
f1ab587Claude1957
2ce1d0bClaude1958 /* ============================================================ */
1959 /* Toggle switch */
1960 /* ============================================================ */
f1ab587Claude1961 .toggle-switch {
1962 position: relative;
1963 display: inline-block;
2ce1d0bClaude1964 width: 40px;
1965 height: 22px;
f1ab587Claude1966 flex-shrink: 0;
1967 margin-left: 16px;
1968 }
1969 .toggle-switch input { opacity: 0; width: 0; height: 0; }
1970 .toggle-slider {
1971 position: absolute;
1972 cursor: pointer;
1973 top: 0; left: 0; right: 0; bottom: 0;
1974 background: var(--bg-tertiary);
1975 border: 1px solid var(--border);
2ce1d0bClaude1976 border-radius: var(--r-full);
1977 transition: all var(--t-base) var(--ease);
f1ab587Claude1978 }
1979 .toggle-slider::before {
1980 content: '';
1981 position: absolute;
2ce1d0bClaude1982 height: 16px;
1983 width: 16px;
f1ab587Claude1984 left: 2px;
1985 bottom: 2px;
1986 background: var(--text-muted);
2ce1d0bClaude1987 border-radius: var(--r-full);
1988 transition: all var(--t-base) var(--ease);
f1ab587Claude1989 }
1990 .toggle-switch input:checked + .toggle-slider {
2ce1d0bClaude1991 background: var(--accent-gradient);
1992 border-color: transparent;
958d26aClaude1993 box-shadow: 0 0 0 1px rgba(140,109,255,0.4);
f1ab587Claude1994 }
1995 .toggle-switch input:checked + .toggle-slider::before {
2ce1d0bClaude1996 transform: translateX(18px);
f1ab587Claude1997 background: #fff;
1998 }
2ce1d0bClaude1999
2000 /* ============================================================ */
958d26aClaude2001 /* Utilities — gradient text, surfaces, dot-grid, skeleton */
2ce1d0bClaude2002 /* ============================================================ */
2003 .gradient-text {
2004 background: var(--accent-gradient);
2005 -webkit-background-clip: text;
2006 background-clip: text;
2007 -webkit-text-fill-color: transparent;
958d26aClaude2008 color: transparent;
2ce1d0bClaude2009 }
2010 .surface { background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--r-md); }
2011 .surface-elevated { background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--r-md); box-shadow: var(--elev-1); }
958d26aClaude2012 .surface-glow {
2013 background: var(--bg-elevated);
2014 border: 1px solid var(--border-strong);
2015 border-radius: var(--r-lg);
2016 box-shadow: var(--elev-2), var(--accent-glow);
2017 }
2018
2019 /* Dot-grid background utility — for hero surfaces, empty states, terminal blocks */
2020 .dot-grid {
2021 background-image: radial-gradient(rgba(255,255,255,0.04) 1px, transparent 1px);
2022 background-size: 22px 22px;
2023 }
2024 :root[data-theme='light'] .dot-grid {
2025 background-image: radial-gradient(rgba(15,16,28,0.06) 1px, transparent 1px);
2026 }
2027
2028 /* Hairline-grid background utility */
2029 .grid-lines {
2030 background-image:
2031 linear-gradient(to right, var(--border-subtle) 1px, transparent 1px),
2032 linear-gradient(to bottom, var(--border-subtle) 1px, transparent 1px);
2033 background-size: 56px 56px;
2034 }
2035
2036 /* Skeleton loader */
2037 .skeleton {
2038 background: linear-gradient(90deg, var(--bg-tertiary) 0%, var(--bg-surface) 50%, var(--bg-tertiary) 100%);
2039 background-size: 200% 100%;
2040 animation: skel 1.4s ease-in-out infinite;
2041 border-radius: var(--r-sm);
2042 }
2043 @keyframes skel { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
2044
2045 /* Inline divider */
2046 .divider {
2047 border: 0;
2048 border-top: 1px solid var(--border);
2049 margin: var(--s-6) 0;
2050 }
2051 .divider-vert {
2052 width: 1px;
2053 align-self: stretch;
2054 background: var(--border);
2055 margin: 0 var(--s-3);
2056 }
2057
2058 /* Stagger fade-in helper — apply to a parent, animate children */
2059 .stagger > * {
2060 opacity: 0;
2061 transform: translateY(10px);
2062 animation: stagger-in 600ms var(--ease-out-expo) forwards;
2063 }
2064 .stagger > *:nth-child(1) { animation-delay: 0ms; }
2065 .stagger > *:nth-child(2) { animation-delay: 60ms; }
2066 .stagger > *:nth-child(3) { animation-delay: 120ms; }
2067 .stagger > *:nth-child(4) { animation-delay: 180ms; }
2068 .stagger > *:nth-child(5) { animation-delay: 240ms; }
2069 .stagger > *:nth-child(6) { animation-delay: 300ms; }
2070 .stagger > *:nth-child(7) { animation-delay: 360ms; }
2071 .stagger > *:nth-child(8) { animation-delay: 420ms; }
2072 @keyframes stagger-in {
2073 to { opacity: 1; transform: translateY(0); }
2074 }
2075
2076 /* Tag pill — used for labels, topics */
2077 .tag {
2078 display: inline-flex;
2079 align-items: center;
2080 gap: 5px;
2081 padding: 2px 9px;
2082 border-radius: var(--r-full);
2083 font-size: 11px;
2084 font-weight: 500;
2085 background: var(--bg-tertiary);
2086 border: 1px solid var(--border);
2087 color: var(--text-muted);
2088 line-height: 1.5;
2089 font-family: var(--font-mono);
2090 letter-spacing: 0.01em;
2091 }
2092 .tag-accent {
2093 background: var(--accent-gradient-faint);
2094 border-color: rgba(140,109,255,0.30);
2095 color: var(--accent);
2096 }
2ce1d0bClaude2097
2098 /* Command palette polish */
2099 .cmdk-item { transition: background var(--t-fast) var(--ease); }
2100 .cmdk-item:hover { background: var(--bg-hover) !important; }
2101 .cmdk-active { background: var(--accent-gradient-faint) !important; border-left: 2px solid var(--accent) !important; }
2102
e1db10eClaude2103 /* ============================================================ */
2104 /* Error pages (404 / 500) */
2105 /* ============================================================ */
2106 .error-page {
2107 text-align: center;
2108 padding: 96px 24px 80px;
2109 max-width: 720px;
2110 margin: 0 auto;
2111 position: relative;
2112 }
2113 .error-page::before {
2114 content: '';
2115 position: absolute;
2116 top: 0; left: 50%;
2117 transform: translateX(-50%);
2118 width: 80%; height: 60%;
2119 background: radial-gradient(ellipse at center, rgba(140,109,255,0.10), transparent 65%);
2120 z-index: -1;
2121 pointer-events: none;
2122 }
2123 .error-page-code {
2124 font-family: var(--font-display);
2125 font-size: clamp(80px, 14vw, 160px);
2126 font-weight: 700;
2127 line-height: 0.95;
2128 letter-spacing: -0.05em;
2129 background: linear-gradient(180deg, var(--text) 0%, var(--text-faint) 100%);
2130 -webkit-background-clip: text;
2131 background-clip: text;
2132 -webkit-text-fill-color: transparent;
2133 margin-bottom: var(--s-4);
2134 opacity: 0.85;
2135 }
2136 .error-page-code-err {
2137 background: linear-gradient(180deg, var(--red) 0%, rgba(248,113,113,0.4) 100%);
2138 -webkit-background-clip: text;
2139 background-clip: text;
2140 -webkit-text-fill-color: transparent;
2141 }
2142 .error-page .eyebrow { justify-content: center; margin: 0 auto var(--s-3); }
2143 .error-page-title {
2144 font-size: clamp(28px, 4.5vw, 48px);
2145 line-height: 1.05;
2146 letter-spacing: -0.03em;
2147 margin-bottom: var(--s-4);
2148 }
2149 .error-page-sub {
2150 color: var(--text-muted);
2151 font-size: var(--t-md);
2152 line-height: 1.55;
2153 max-width: 480px;
2154 margin: 0 auto var(--s-8);
2155 }
2156 .error-page-actions {
2157 display: flex;
2158 gap: 12px;
2159 justify-content: center;
2160 flex-wrap: wrap;
2161 margin-bottom: var(--s-7);
2162 }
2163 .error-page-meta {
2164 color: var(--text-faint);
2165 font-size: 11px;
2166 }
2167 .error-page-trace {
2168 margin-top: var(--s-5);
2169 padding: 16px 20px;
2170 background: var(--bg-secondary);
2171 border: 1px solid rgba(248,113,113,0.30);
2172 border-radius: var(--r-md);
2173 font-family: var(--font-mono);
2174 font-size: 12px;
2175 color: var(--red);
2176 text-align: left;
2177 overflow-x: auto;
2178 white-space: pre-wrap;
2179 word-break: break-all;
2180 }
2181
2182 /* Animated underline on inline content links inside markdown / prose */
2183 .prose a, .markdown-body a {
2184 position: relative;
2185 transition: color var(--t-fast) var(--ease);
2186 }
2187 .prose a::after, .markdown-body a::after {
2188 content: '';
2189 position: absolute;
2190 left: 0; right: 0; bottom: -1px;
2191 height: 1px;
2192 background: currentColor;
2193 opacity: 0.35;
2194 transform-origin: left;
2195 transition: opacity var(--t-fast) var(--ease), transform var(--t-base) var(--ease);
2196 }
2197 .prose a:hover::after, .markdown-body a:hover::after {
2198 opacity: 1;
2199 transform: scaleX(1.02);
2200 }
2201
2202 /* Print: keep it readable */
2203 @media print {
2204 body::before, body::after { display: none; }
2205 header, footer, .prelaunch-banner, .repo-nav, .repo-header-actions,
2206 .nav-search, .nav-right, .btn { display: none !important; }
2207 body { background: #fff; color: #000; }
2208 a { color: #000; text-decoration: underline; }
2209 main { max-width: 100%; padding: 0; }
2210 }
2211
2ce1d0bClaude2212 /* Reduced motion preference */
2213 @media (prefers-reduced-motion: reduce) {
2214 *, *::before, *::after {
2215 animation-duration: 0.01ms !important;
2216 animation-iteration-count: 1 !important;
2217 transition-duration: 0.01ms !important;
2218 }
2219 }
2220
2221 /* Tablet + below */
2222 @media (max-width: 768px) {
2223 main { padding: 20px 16px 40px; }
2224 header { padding: 0 16px; }
2225 .nav-search { display: none; }
2226 .repo-header { font-size: var(--t-md); }
2227 .card-grid { grid-template-columns: 1fr; }
2228 .auth-container { margin: 32px 16px; padding: 24px; }
2229 .visibility-options { flex-direction: column; }
2230 }
2231
2232 /* Scrollbar styling — subtle, themed */
2233 ::-webkit-scrollbar { width: 10px; height: 10px; }
2234 ::-webkit-scrollbar-track { background: transparent; }
2235 ::-webkit-scrollbar-thumb {
2236 background: var(--bg-surface);
2237 border: 2px solid var(--bg);
2238 border-radius: var(--r-full);
2239 }
2240 ::-webkit-scrollbar-thumb:hover { background: var(--border-strong); }
fc1817aClaude2241`;