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.tsxBlame1479 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";
fc1817aClaude5
06d5ffeClaude6export const Layout: FC<
3ef4c9dClaude7 PropsWithChildren<{
8 title?: string;
9 user?: User | null;
10 notificationCount?: number;
6fc53bdClaude11 theme?: "dark" | "light";
3ef4c9dClaude12 }>
6fc53bdClaude13> = ({ children, title, user, notificationCount, theme }) => {
14 const initialTheme = theme === "light" ? "light" : "dark";
fc1817aClaude15 return (
6fc53bdClaude16 <html lang="en" data-theme={initialTheme}>
fc1817aClaude17 <head>
18 <meta charset="UTF-8" />
19 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
eae38d1Claude20 <meta name="theme-color" content="#0d1117" />
21 <link rel="manifest" href="/manifest.webmanifest" />
22 <link rel="icon" type="image/svg+xml" href="/icon.svg" />
4c47454Claude23 <link rel="preconnect" href="https://fonts.googleapis.com" />
24 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="" />
25 <link
26 rel="stylesheet"
27 href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap"
28 />
fc1817aClaude29 <title>{title ? `${title} — gluecron` : "gluecron"}</title>
6fc53bdClaude30 <script>{themeInitScript}</script>
fc1817aClaude31 <style>{css}</style>
06d5ffeClaude32 <style>{hljsThemeCss}</style>
fc1817aClaude33 </head>
34 <body>
4a52a98Claude35 <div class="prelaunch-banner" role="status" aria-live="polite">
36 Pre-launch &mdash; Gluecron is in final validation. Public signups
37 and git hosting for non-owner users open after launch review.
38 </div>
fc1817aClaude39 <header>
40 <nav>
41 <a href="/" class="logo">
42 gluecron
43 </a>
3ef4c9dClaude44 <div class="nav-search">
001af43Claude45 <form method="get" action="/search">
3ef4c9dClaude46 <input
47 type="search"
48 name="q"
49 placeholder="Search (press /)"
50 aria-label="Search"
51 />
52 </form>
53 </div>
06d5ffeClaude54 <div class="nav-right">
6fc53bdClaude55 <a
56 href="/theme/toggle"
57 class="nav-link nav-theme"
58 title="Toggle theme"
59 aria-label="Toggle theme"
60 >
61 <span class="theme-icon-dark">{"\u263E"}</span>
62 <span class="theme-icon-light">{"\u2600"}</span>
63 </a>
c81ab7aClaude64 <a href="/explore" class="nav-link">
65 Explore
66 </a>
06d5ffeClaude67 {user ? (
68 <>
f1ab587Claude69 <a href="/dashboard" class="nav-link" style="font-weight: 600">
70 Dashboard
71 </a>
bdbd0deClaude72 <a href="/import" class="nav-link">
73 Import
74 </a>
06d5ffeClaude75 <a href="/new" class="btn btn-sm btn-primary">
76 + New
77 </a>
78 <a href={`/${user.username}`} class="nav-user">
79 {user.displayName || user.username}
80 </a>
81 <a href="/settings" class="nav-link">
82 Settings
83 </a>
84 <a href="/logout" class="nav-link">
85 Sign out
86 </a>
87 </>
88 ) : (
89 <>
90 <a href="/login" class="nav-link">
91 Sign in
92 </a>
93 <a href="/register" class="btn btn-sm btn-primary">
94 Register
95 </a>
96 </>
97 )}
98 </div>
fc1817aClaude99 </nav>
100 </header>
45e31d0Claude101 <main id="main-content">{children}</main>
fc1817aClaude102 <footer>
36b4cbdClaude103 <span>
104 &copy; {new Date().getFullYear()} gluecron — AI-native code intelligence
105 </span>
106 <div style="margin-top: 6px; display: flex; gap: 16px; justify-content: center; font-size: 12px">
107 <a href="/terms" style="color: var(--text-muted)">Terms</a>
108 <a href="/privacy" style="color: var(--text-muted)">Privacy</a>
109 <a href="/acceptable-use" style="color: var(--text-muted)">Acceptable Use</a>
110 </div>
fc1817aClaude111 </footer>
699e5c7Claude112 {/* Block I4 — Command palette shell (hidden by default) */}
113 <div
114 id="cmdk-backdrop"
115 style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:9998"
116 />
117 <div
118 id="cmdk-panel"
119 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"
120 >
121 <input
122 id="cmdk-input"
123 type="text"
124 placeholder="Type a command..."
125 aria-label="Command palette"
126 style="width:100%;padding:12px 16px;background:transparent;color:var(--text);border:0;border-bottom:1px solid var(--border);outline:none;font-size:14px"
127 />
128 <div id="cmdk-list" style="max-height:60vh;overflow-y:auto" />
129 </div>
45e31d0Claude130 <script>{clientJs}</script>
699e5c7Claude131 <script>{pwaRegisterScript}</script>
132 <script>{navScript}</script>
fc1817aClaude133 </body>
134 </html>
135 );
136};
137
6fc53bdClaude138// Runs before paint — reads the theme cookie and flips data-theme so there's
139// no dark-to-light flash on load. SSR default is dark.
140const themeInitScript = `
141 (function(){
142 try {
143 var m = document.cookie.match(/(?:^|; )theme=([^;]+)/);
144 var t = m ? decodeURIComponent(m[1]) : 'dark';
145 if (t !== 'light' && t !== 'dark') t = 'dark';
146 document.documentElement.setAttribute('data-theme', t);
147 } catch(_){}
148 })();
149`;
150
eae38d1Claude151// Block G1 — register service worker for offline / install support.
152// Kept inline (and tiny) so we don't block first paint.
153const pwaRegisterScript = `
154 if ('serviceWorker' in navigator) {
155 window.addEventListener('load', function(){
156 navigator.serviceWorker.register('/sw.js').catch(function(){});
157 });
158 }
159`;
160
3ef4c9dClaude161const navScript = `
162 (function(){
163 var chord = null;
164 var chordTimer = null;
165 function isTyping(t){
166 t = t || {};
167 var tag = (t.tagName || '').toLowerCase();
168 return tag === 'input' || tag === 'textarea' || t.isContentEditable;
169 }
71cd5ecClaude170
171 // ---------- Block I4 — Command palette ----------
172 var COMMANDS = [
173 { label: 'Go to Dashboard', href: '/dashboard', kw: 'home' },
174 { label: 'Go to Explore', href: '/explore', kw: 'browse discover' },
175 { label: 'Go to Notifications', href: '/notifications', kw: 'inbox' },
176 { label: 'Go to Ask AI', href: '/ask', kw: 'chat assistant' },
177 { label: 'Create new repository', href: '/new', kw: 'add create' },
178 { label: 'Marketplace', href: '/marketplace', kw: 'apps store' },
179 { label: 'Installed apps', href: '/settings/apps', kw: 'my apps' },
180 { label: 'Register new app', href: '/developer/apps-new', kw: 'developer create' },
181 { label: 'Keyboard shortcuts', href: '/shortcuts', kw: 'help keys' },
182 { label: 'Settings (profile)', href: '/settings', kw: 'account' },
183 { label: '2FA settings', href: '/settings/2fa', kw: 'two factor security' },
184 { label: 'Passkeys settings', href: '/settings/passkeys', kw: 'webauthn' },
185 { label: 'Personal access tokens', href: '/settings/tokens', kw: 'pat api' },
186 { label: 'Billing + quotas', href: '/settings/billing', kw: 'plans money' },
187 { label: 'Audit log (personal)', href: '/settings/audit', kw: 'history' },
188 { label: 'Gists', href: '/gists', kw: 'snippets' },
189 { label: 'GraphQL explorer', href: '/api/graphql', kw: 'api query' },
190 { label: 'Admin dashboard', href: '/admin', kw: 'superuser' },
191 { label: 'Toggle theme', href: '/theme/toggle', kw: 'dark light mode' }
192 ];
193
194 function fuzzyMatch(item, q){
195 if (!q) return true;
196 var hay = (item.label + ' ' + (item.kw||'') + ' ' + item.href).toLowerCase();
197 q = q.toLowerCase();
198 var qi = 0;
199 for (var i = 0; i < hay.length && qi < q.length; i++) {
200 if (hay[i] === q[qi]) qi++;
201 }
202 return qi === q.length;
203 }
204
205 var backdrop, panel, input, list, selected = 0, filtered = COMMANDS.slice();
206
207 function render(){
208 if (!list) return;
209 var html = '';
210 for (var i = 0; i < filtered.length; i++) {
211 var item = filtered[i];
212 var cls = i === selected ? 'cmdk-item cmdk-active' : 'cmdk-item';
213 var bg = i === selected ? 'background:var(--bg);' : '';
ea52715copilot-swe-agent[bot]214 html += '<div class="' + cls + '" data-idx="' + i + '" data-url="' + item.href + '"' +
71cd5ecClaude215 ' style="padding:10px 16px;cursor:pointer;border-bottom:1px solid var(--border);' + bg + '">' +
216 '<div>' + item.label + '</div>' +
217 '<div style="font-size:11px;color:var(--text-muted)">' + item.href + '</div>' +
218 '</div>';
219 }
220 if (filtered.length === 0) {
221 html = '<div style="padding:16px;color:var(--text-muted);text-align:center">No matches.</div>';
222 }
223 list.innerHTML = html;
224 }
225
226 function openPalette(){
227 backdrop = document.getElementById('cmdk-backdrop');
228 panel = document.getElementById('cmdk-panel');
229 input = document.getElementById('cmdk-input');
230 list = document.getElementById('cmdk-list');
231 if (!backdrop || !panel) return;
232 backdrop.style.display = 'block';
233 panel.style.display = 'block';
234 input.value = '';
235 selected = 0;
236 filtered = COMMANDS.slice();
237 render();
238 input.focus();
239 }
240 function closePalette(){
241 if (backdrop) backdrop.style.display = 'none';
242 if (panel) panel.style.display = 'none';
243 }
244 function go(href){ closePalette(); window.location.href = href; }
245
246 document.addEventListener('click', function(e){
247 var t = e.target;
248 if (t && t.id === 'cmdk-backdrop') { closePalette(); return; }
249 var item = t && t.closest && t.closest('.cmdk-item');
ea52715copilot-swe-agent[bot]250 if (item) { go(item.getAttribute('data-url')); }
71cd5ecClaude251 });
252
253 document.addEventListener('input', function(e){
254 if (e.target && e.target.id === 'cmdk-input') {
255 var q = e.target.value;
256 filtered = COMMANDS.filter(function(c){ return fuzzyMatch(c, q); });
257 selected = 0;
258 render();
259 }
260 });
261
3ef4c9dClaude262 document.addEventListener('keydown', function(e){
71cd5ecClaude263 // Palette-scoped keys take priority when open
264 if (panel && panel.style.display === 'block') {
265 if (e.key === 'Escape') { e.preventDefault(); closePalette(); return; }
266 if (e.key === 'ArrowDown') {
267 e.preventDefault();
268 selected = Math.min(filtered.length - 1, selected + 1);
269 render();
270 return;
271 }
272 if (e.key === 'ArrowUp') {
273 e.preventDefault();
274 selected = Math.max(0, selected - 1);
275 render();
276 return;
277 }
278 if (e.key === 'Enter') {
279 e.preventDefault();
280 var item = filtered[selected];
281 if (item) go(item.href);
282 return;
283 }
284 return;
285 }
286
3ef4c9dClaude287 if (isTyping(e.target)) return;
288 // Single key shortcuts
289 if (e.key === '/') {
290 var el = document.querySelector('.nav-search input');
291 if (el) { e.preventDefault(); el.focus(); return; }
292 }
293 if ((e.metaKey||e.ctrlKey) && e.key.toLowerCase() === 'k') {
71cd5ecClaude294 e.preventDefault();
295 openPalette();
296 return;
3ef4c9dClaude297 }
298 if (e.key === '?' && !e.ctrlKey && !e.metaKey) {
299 e.preventDefault(); window.location.href = '/shortcuts'; return;
300 }
301 if (e.key === 'n' && !e.ctrlKey && !e.metaKey) {
302 e.preventDefault(); window.location.href = '/new'; return;
303 }
304 // "g" chord
305 if (e.key === 'g' && !e.ctrlKey && !e.metaKey) {
306 chord = 'g';
307 clearTimeout(chordTimer);
308 chordTimer = setTimeout(function(){ chord = null; }, 1200);
309 return;
310 }
311 if (chord === 'g') {
312 if (e.key === 'd') { e.preventDefault(); window.location.href = '/dashboard'; }
313 else if (e.key === 'n') { e.preventDefault(); window.location.href = '/notifications'; }
314 else if (e.key === 'e') { e.preventDefault(); window.location.href = '/explore'; }
315 else if (e.key === 'a') { e.preventDefault(); window.location.href = '/ask'; }
316 chord = null;
317 }
318 });
319 })();
320`;
321
fc1817aClaude322const css = `
2ce1d0bClaude323 /* ================================================================
324 * Design system — 2026
325 * Warm-dark base · violet→cyan accent · hairline borders ·
326 * spring motion · Inter / JetBrains Mono.
327 * Token-first: every component reads from these vars.
328 * ============================================================== */
6fc53bdClaude329 :root, :root[data-theme='dark'] {
2ce1d0bClaude330 --bg: #07070b;
331 --bg-secondary: #0e0e16;
332 --bg-tertiary: #15151f;
333 --bg-elevated: #11111a;
334 --bg-surface: #181822;
335 --bg-hover: rgba(255,255,255,0.035);
336 --bg-active: rgba(255,255,255,0.07);
337 --border: rgba(255,255,255,0.07);
338 --border-strong: rgba(255,255,255,0.12);
339 --border-focus: rgba(168,85,247,0.55);
340 --text: #ececf3;
341 --text-muted: #8a8a9e;
342 --text-faint: #555568;
343 --text-link: #c084fc;
4c47454Claude344 --accent: #a855f7;
345 --accent-2: #06b6d4;
2ce1d0bClaude346 --accent-hover: #b873f8;
4c47454Claude347 --accent-gradient: linear-gradient(135deg, #a855f7 0%, #06b6d4 100%);
2ce1d0bClaude348 --accent-gradient-soft: linear-gradient(135deg, rgba(168,85,247,0.18) 0%, rgba(6,182,212,0.18) 100%);
349 --accent-gradient-faint: linear-gradient(135deg, rgba(168,85,247,0.08) 0%, rgba(6,182,212,0.08) 100%);
4c47454Claude350 --green: #10b981;
351 --red: #ef4444;
352 --yellow: #f59e0b;
353 --amber: #f59e0b;
354 --blue: #3b82f6;
355 --font-mono: 'JetBrains Mono', 'SF Mono', 'Cascadia Code', 'Fira Code', ui-monospace, monospace;
356 --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
357 --radius: 8px;
358 --r-sm: 6px;
359 --r: 8px;
2ce1d0bClaude360 --r-md: 10px;
4c47454Claude361 --r-lg: 12px;
362 --r-xl: 16px;
2ce1d0bClaude363 --r-2xl: 20px;
4c47454Claude364 --r-full: 9999px;
365 --t-xs: 11px;
366 --t-sm: 13px;
367 --t-base: 14px;
368 --t-md: 16px;
369 --t-lg: 20px;
370 --t-xl: 28px;
371 --t-2xl: 40px;
372 --t-3xl: 56px;
2ce1d0bClaude373 --s-0: 0;
4c47454Claude374 --s-1: 4px;
375 --s-2: 8px;
376 --s-3: 12px;
377 --s-4: 16px;
378 --s-5: 20px;
379 --s-6: 24px;
2ce1d0bClaude380 --s-7: 28px;
4c47454Claude381 --s-8: 32px;
382 --s-10: 40px;
383 --s-12: 48px;
384 --s-16: 64px;
2ce1d0bClaude385 --s-20: 80px;
4c47454Claude386 --elev-0: 0 0 0 1px var(--border);
2ce1d0bClaude387 --elev-1: 0 1px 2px rgba(0,0,0,0.4), 0 0 0 1px var(--border);
388 --elev-2: 0 4px 12px rgba(0,0,0,0.35), 0 0 0 1px var(--border);
389 --elev-3: 0 12px 32px rgba(0,0,0,0.45), 0 0 0 1px var(--border-strong);
390 --elev-glow: 0 0 0 1px rgba(168,85,247,0.35), 0 0 28px rgba(168,85,247,0.18);
391 --ring: 0 0 0 3px rgba(168,85,247,0.25);
4c47454Claude392 --ease: cubic-bezier(0.16, 1, 0.3, 1);
393 --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
394 --t-fast: 120ms;
2ce1d0bClaude395 --t-base: 200ms;
396 --t-slow: 360ms;
397 --header-h: 56px;
fc1817aClaude398 }
399
6fc53bdClaude400 :root[data-theme='light'] {
4c47454Claude401 --bg: #fafafa;
402 --bg-secondary: #ffffff;
403 --bg-tertiary: #f4f4f7;
404 --bg-elevated: #ffffff;
405 --bg-surface: #f4f4f7;
2ce1d0bClaude406 --bg-hover: rgba(0,0,0,0.035);
407 --bg-active: rgba(0,0,0,0.07);
4c47454Claude408 --border: rgba(0,0,0,0.08);
409 --border-strong: rgba(0,0,0,0.14);
410 --text: #0a0a0f;
411 --text-muted: #5a5a70;
412 --text-faint: #8b8ba0;
413 --text-link: #7c3aed;
414 --accent: #7c3aed;
415 --accent-2: #0891b2;
416 --accent-hover: #6d28d9;
417 --green: #059669;
418 --red: #dc2626;
419 --yellow: #d97706;
2ce1d0bClaude420 --elev-1: 0 1px 2px rgba(0,0,0,0.06), 0 0 0 1px var(--border);
421 --elev-2: 0 4px 12px rgba(0,0,0,0.08), 0 0 0 1px var(--border);
422 --elev-3: 0 12px 32px rgba(0,0,0,0.12), 0 0 0 1px var(--border-strong);
6fc53bdClaude423 }
424
425 /* Theme toggle — show the icon for the *opposite* theme so users see what they'll switch to. */
426 .nav-theme { display: inline-flex; align-items: center; font-size: 16px; line-height: 1; }
427 :root[data-theme='dark'] .theme-icon-dark { display: none; }
428 :root[data-theme='light'] .theme-icon-light { display: none; }
429
fc1817aClaude430 * { margin: 0; padding: 0; box-sizing: border-box; }
2ce1d0bClaude431 *::selection { background: rgba(168,85,247,0.35); color: var(--text); }
432
433 html { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
fc1817aClaude434
435 body {
436 font-family: var(--font-sans);
437 background: var(--bg);
438 color: var(--text);
2ce1d0bClaude439 line-height: 1.55;
440 letter-spacing: -0.005em;
fc1817aClaude441 min-height: 100vh;
442 display: flex;
443 flex-direction: column;
2ce1d0bClaude444 font-feature-settings: 'cv11', 'ss01', 'ss03';
445 }
446
447 /* Subtle radial backdrop — gives every page a hint of depth without
448 fighting the landing-page hero blob. */
449 body::before {
450 content: '';
451 position: fixed;
452 inset: 0;
453 pointer-events: none;
454 z-index: -1;
455 background:
456 radial-gradient(60% 50% at 80% -10%, rgba(168,85,247,0.05), transparent 60%),
457 radial-gradient(50% 40% at 0% 110%, rgba(6,182,212,0.04), transparent 60%);
fc1817aClaude458 }
2ce1d0bClaude459 :root[data-theme='light'] body::before { display: none; }
460
461 a { color: var(--text-link); text-decoration: none; transition: color var(--t-fast) var(--ease); }
462 a:hover { color: var(--accent-hover); text-decoration: none; }
fc1817aClaude463
2ce1d0bClaude464 h1, h2, h3, h4 {
465 font-weight: 600;
466 letter-spacing: -0.02em;
467 line-height: 1.2;
468 color: var(--text);
469 }
470 h1 { font-size: var(--t-xl); }
471 h2 { font-size: var(--t-lg); }
472 h3 { font-size: var(--t-md); font-weight: 600; }
473 h4 { font-size: var(--t-base); font-weight: 600; }
fc1817aClaude474
2ce1d0bClaude475 code {
476 font-family: var(--font-mono);
477 font-size: 0.92em;
478 background: var(--bg-tertiary);
479 border: 1px solid var(--border);
480 padding: 1px 6px;
481 border-radius: var(--r-sm);
482 color: var(--text);
483 }
484
485 /* Pre-launch banner — slim, refined, gradient hairline */
4a52a98Claude486 .prelaunch-banner {
2ce1d0bClaude487 background:
488 linear-gradient(180deg, rgba(245,158,11,0.10), rgba(245,158,11,0.04)),
489 var(--bg);
490 border-bottom: 1px solid rgba(245,158,11,0.30);
4a52a98Claude491 color: var(--yellow);
492 padding: 8px 24px;
2ce1d0bClaude493 font-size: var(--t-xs);
4a52a98Claude494 font-weight: 500;
495 text-align: center;
2ce1d0bClaude496 line-height: 1.5;
497 letter-spacing: 0.01em;
4a52a98Claude498 }
499
2ce1d0bClaude500 /* Header — sticky, backdrop-blur, hairline border */
fc1817aClaude501 header {
2ce1d0bClaude502 position: sticky;
503 top: 0;
504 z-index: 100;
fc1817aClaude505 border-bottom: 1px solid var(--border);
2ce1d0bClaude506 padding: 0 24px;
507 height: var(--header-h);
508 background: rgba(7,7,11,0.78);
509 backdrop-filter: saturate(150%) blur(14px);
510 -webkit-backdrop-filter: saturate(150%) blur(14px);
fc1817aClaude511 }
2ce1d0bClaude512 :root[data-theme='light'] header { background: rgba(255,255,255,0.78); }
fc1817aClaude513
06d5ffeClaude514 header nav {
515 display: flex;
516 align-items: center;
2ce1d0bClaude517 gap: 24px;
06d5ffeClaude518 max-width: 1200px;
519 margin: 0 auto;
2ce1d0bClaude520 height: 100%;
521 }
522 .logo {
523 font-size: 17px;
524 font-weight: 700;
525 letter-spacing: -0.02em;
526 color: var(--text);
527 display: inline-flex;
528 align-items: center;
529 gap: 8px;
06d5ffeClaude530 }
2ce1d0bClaude531 .logo::before {
532 content: '';
533 width: 18px; height: 18px;
534 border-radius: 5px;
535 background: var(--accent-gradient);
536 box-shadow: 0 0 14px rgba(168,85,247,0.35);
537 flex-shrink: 0;
538 }
539 .logo:hover { text-decoration: none; color: var(--text); }
fc1817aClaude540
2ce1d0bClaude541 .nav-search {
542 flex: 1;
543 max-width: 320px;
544 margin: 0 8px 0 12px;
545 }
546 .nav-search input {
547 width: 100%;
548 padding: 6px 12px;
549 background: var(--bg-tertiary);
550 border: 1px solid var(--border);
551 border-radius: var(--r-sm);
552 color: var(--text);
553 font-family: var(--font-sans);
554 font-size: var(--t-sm);
555 transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
556 }
557 .nav-search input::placeholder { color: var(--text-faint); }
558 .nav-search input:focus {
559 outline: none;
560 background: var(--bg-secondary);
561 border-color: var(--border-strong);
562 }
06d5ffeClaude563
2ce1d0bClaude564 .nav-right { display: flex; align-items: center; gap: 4px; margin-left: auto; }
565 .nav-link {
566 color: var(--text-muted);
567 font-size: var(--t-sm);
568 font-weight: 500;
569 padding: 6px 10px;
570 border-radius: var(--r-sm);
571 transition: all var(--t-fast) var(--ease);
572 }
573 .nav-link:hover {
574 color: var(--text);
575 background: var(--bg-hover);
576 text-decoration: none;
577 }
578 .nav-user {
579 color: var(--text);
580 font-weight: 600;
581 font-size: var(--t-sm);
582 padding: 6px 10px;
583 border-radius: var(--r-sm);
584 transition: background var(--t-fast) var(--ease);
585 }
586 .nav-user:hover { background: var(--bg-hover); text-decoration: none; }
587
588 main {
589 max-width: 1200px;
590 margin: 0 auto;
591 padding: 32px 24px 56px;
592 flex: 1;
593 width: 100%;
594 }
fc1817aClaude595
596 footer {
597 border-top: 1px solid var(--border);
2ce1d0bClaude598 padding: 28px 24px 32px;
fc1817aClaude599 text-align: center;
2ce1d0bClaude600 color: var(--text-faint);
601 font-size: var(--t-xs);
602 background: var(--bg);
fc1817aClaude603 }
2ce1d0bClaude604 footer a { color: var(--text-faint); transition: color var(--t-fast) var(--ease); }
605 footer a:hover { color: var(--text-muted); text-decoration: none; }
fc1817aClaude606
2ce1d0bClaude607 /* ============================================================ */
608 /* Buttons */
609 /* ============================================================ */
06d5ffeClaude610 .btn {
611 display: inline-flex;
612 align-items: center;
2ce1d0bClaude613 justify-content: center;
06d5ffeClaude614 gap: 6px;
2ce1d0bClaude615 padding: 7px 14px;
616 border-radius: var(--r-sm);
617 font-size: var(--t-sm);
06d5ffeClaude618 font-weight: 500;
619 border: 1px solid var(--border);
2ce1d0bClaude620 background: var(--bg-elevated);
06d5ffeClaude621 color: var(--text);
622 cursor: pointer;
623 text-decoration: none;
2ce1d0bClaude624 line-height: 1.3;
625 letter-spacing: -0.005em;
626 transition:
627 background var(--t-fast) var(--ease),
628 border-color var(--t-fast) var(--ease),
629 transform var(--t-fast) var(--ease),
630 box-shadow var(--t-fast) var(--ease);
631 user-select: none;
632 white-space: nowrap;
06d5ffeClaude633 }
2ce1d0bClaude634 .btn:hover {
635 background: var(--bg-surface);
636 border-color: var(--border-strong);
637 text-decoration: none;
638 }
639 .btn:active { transform: scale(0.98); }
640 .btn:focus-visible { outline: none; box-shadow: var(--ring); }
641
642 .btn-primary {
643 background: var(--accent-gradient);
644 border-color: transparent;
645 color: #fff;
646 font-weight: 600;
647 box-shadow:
648 inset 0 1px 0 rgba(255,255,255,0.2),
649 0 1px 3px rgba(168,85,247,0.30),
650 0 0 0 1px rgba(168,85,247,0.4);
651 }
652 .btn-primary:hover {
653 background: var(--accent-gradient);
654 filter: brightness(1.08);
655 box-shadow:
656 inset 0 1px 0 rgba(255,255,255,0.25),
657 0 4px 14px rgba(168,85,247,0.40),
658 0 0 0 1px rgba(168,85,247,0.5);
659 }
660
661 .btn-danger {
662 background: transparent;
663 border-color: rgba(239,68,68,0.40);
664 color: var(--red);
665 }
666 .btn-danger:hover {
667 background: rgba(239,68,68,0.10);
668 border-color: var(--red);
669 }
670
671 .btn-ghost {
672 background: transparent;
673 border-color: transparent;
674 color: var(--text-muted);
675 }
676 .btn-ghost:hover {
677 background: var(--bg-hover);
678 color: var(--text);
679 border-color: var(--border);
680 }
681
682 .btn-sm { padding: 4px 10px; font-size: var(--t-xs); border-radius: var(--r-sm); }
683 .btn-lg { padding: 11px 22px; font-size: var(--t-base); border-radius: var(--r); }
684
685 .btn:disabled, .btn[aria-disabled='true'] {
686 opacity: 0.5;
687 cursor: not-allowed;
688 pointer-events: none;
689 }
690
691 /* ============================================================ */
692 /* Forms */
693 /* ============================================================ */
694 .form-group { margin-bottom: 20px; }
695 .form-group label {
696 display: block;
697 font-size: var(--t-sm);
698 font-weight: 500;
699 margin-bottom: 6px;
700 color: var(--text);
701 letter-spacing: -0.005em;
702 }
703 .form-group input,
704 .form-group textarea,
705 .form-group select,
706 input[type='text'], input[type='email'], input[type='password'],
707 input[type='url'], input[type='search'], input[type='number'],
708 textarea, select {
06d5ffeClaude709 width: 100%;
2ce1d0bClaude710 padding: 9px 12px;
711 background: var(--bg-secondary);
06d5ffeClaude712 border: 1px solid var(--border);
2ce1d0bClaude713 border-radius: var(--r-sm);
06d5ffeClaude714 color: var(--text);
2ce1d0bClaude715 font-size: var(--t-sm);
06d5ffeClaude716 font-family: var(--font-sans);
2ce1d0bClaude717 transition:
718 border-color var(--t-fast) var(--ease),
719 background var(--t-fast) var(--ease),
720 box-shadow var(--t-fast) var(--ease);
721 }
722 .form-group input::placeholder, textarea::placeholder, input::placeholder {
723 color: var(--text-faint);
06d5ffeClaude724 }
2ce1d0bClaude725 .form-group input:hover, textarea:hover, select:hover,
726 input[type='text']:hover, input[type='email']:hover, input[type='password']:hover {
727 border-color: var(--border-strong);
728 }
729 .form-group input:focus, .form-group textarea:focus, .form-group select:focus,
730 input:focus, textarea:focus, select:focus {
06d5ffeClaude731 outline: none;
2ce1d0bClaude732 background: var(--bg);
733 border-color: var(--border-focus);
734 box-shadow: var(--ring);
06d5ffeClaude735 }
2ce1d0bClaude736 textarea { font-family: var(--font-mono); font-size: var(--t-sm); line-height: 1.55; }
06d5ffeClaude737 .input-disabled { opacity: 0.5; cursor: not-allowed; }
738
2ce1d0bClaude739 /* ============================================================ */
740 /* Auth (register / login / verify) */
741 /* ============================================================ */
742 .auth-container {
743 max-width: 420px;
744 margin: 64px auto;
745 padding: 32px;
746 background: var(--bg-elevated);
747 border: 1px solid var(--border);
748 border-radius: var(--r-lg);
749 box-shadow: var(--elev-2);
750 }
751 .auth-container h2 {
752 margin-bottom: 6px;
753 font-size: var(--t-lg);
754 letter-spacing: -0.02em;
755 }
756 .auth-container > p {
757 color: var(--text-muted);
758 font-size: var(--t-sm);
759 margin-bottom: 24px;
760 }
761 .auth-container .btn-primary { width: 100%; padding: 10px 16px; }
06d5ffeClaude762 .auth-error {
2ce1d0bClaude763 background: rgba(239,68,68,0.08);
764 border: 1px solid rgba(239,68,68,0.35);
06d5ffeClaude765 color: var(--red);
2ce1d0bClaude766 padding: 10px 14px;
767 border-radius: var(--r-sm);
06d5ffeClaude768 margin-bottom: 16px;
2ce1d0bClaude769 font-size: var(--t-sm);
06d5ffeClaude770 }
771 .auth-success {
2ce1d0bClaude772 background: rgba(16,185,129,0.08);
773 border: 1px solid rgba(16,185,129,0.35);
06d5ffeClaude774 color: var(--green);
2ce1d0bClaude775 padding: 10px 14px;
776 border-radius: var(--r-sm);
06d5ffeClaude777 margin-bottom: 16px;
2ce1d0bClaude778 font-size: var(--t-sm);
779 }
780 .auth-switch {
781 margin-top: 20px;
782 font-size: var(--t-sm);
783 color: var(--text-muted);
784 text-align: center;
785 }
786 .banner {
787 background: var(--accent-gradient-faint);
788 border: 1px solid rgba(168,85,247,0.35);
789 color: var(--text);
790 padding: 10px 14px;
791 border-radius: var(--r-sm);
792 font-size: var(--t-sm);
06d5ffeClaude793 }
794
2ce1d0bClaude795 /* ============================================================ */
796 /* Settings */
797 /* ============================================================ */
798 .settings-container { max-width: 720px; }
799 .settings-container h2 { margin-bottom: 8px; font-size: var(--t-xl); letter-spacing: -0.02em; }
800 .settings-container > h2 + p { color: var(--text-muted); font-size: var(--t-sm); margin-bottom: 24px; }
801 .settings-container h3 { font-size: var(--t-md); margin-bottom: 12px; margin-top: 28px; }
802 .settings-container h3:first-of-type { margin-top: 0; }
06d5ffeClaude803 .ssh-keys-list { margin-bottom: 24px; }
804 .ssh-key-item {
805 display: flex;
806 justify-content: space-between;
807 align-items: center;
2ce1d0bClaude808 padding: 14px 16px;
06d5ffeClaude809 border: 1px solid var(--border);
2ce1d0bClaude810 border-radius: var(--r-md);
06d5ffeClaude811 margin-bottom: 8px;
2ce1d0bClaude812 background: var(--bg-elevated);
813 transition: border-color var(--t-fast) var(--ease);
06d5ffeClaude814 }
2ce1d0bClaude815 .ssh-key-item:hover { border-color: var(--border-strong); }
816 .ssh-key-meta { font-size: var(--t-xs); color: var(--text-muted); margin-top: 4px; }
817 .ssh-key-meta code { font-size: var(--t-xs); background: var(--bg-tertiary); padding: 1px 6px; border-radius: 3px; margin-right: 8px; }
06d5ffeClaude818
2ce1d0bClaude819 /* ============================================================ */
820 /* Repo header + nav */
821 /* ============================================================ */
fc1817aClaude822 .repo-header {
823 display: flex;
824 align-items: center;
825 gap: 8px;
2ce1d0bClaude826 margin-bottom: 18px;
827 font-size: var(--t-lg);
828 letter-spacing: -0.015em;
fc1817aClaude829 }
2ce1d0bClaude830 .repo-header .owner { color: var(--text-link); font-weight: 500; }
831 .repo-header .separator { color: var(--text-faint); }
832 .repo-header .name { color: var(--text); font-weight: 700; }
833 .repo-header .name:hover { color: var(--text-link); text-decoration: none; }
06d5ffeClaude834 .repo-header-actions { margin-left: auto; display: flex; gap: 8px; align-items: center; }
fc1817aClaude835
836 .repo-nav {
837 display: flex;
2ce1d0bClaude838 gap: 2px;
fc1817aClaude839 border-bottom: 1px solid var(--border);
2ce1d0bClaude840 margin-bottom: 24px;
841 overflow-x: auto;
842 scrollbar-width: thin;
fc1817aClaude843 }
2ce1d0bClaude844 .repo-nav::-webkit-scrollbar { height: 0; }
fc1817aClaude845 .repo-nav a {
2ce1d0bClaude846 padding: 10px 14px;
fc1817aClaude847 color: var(--text-muted);
848 border-bottom: 2px solid transparent;
2ce1d0bClaude849 font-size: var(--t-sm);
850 font-weight: 500;
851 margin-bottom: -1px;
852 transition: all var(--t-fast) var(--ease);
853 white-space: nowrap;
854 }
855 .repo-nav a:hover { text-decoration: none; color: var(--text); background: var(--bg-hover); }
856 .repo-nav a.active {
857 color: var(--text);
858 border-bottom-color: var(--accent);
859 font-weight: 600;
fc1817aClaude860 }
861
2ce1d0bClaude862 .breadcrumb {
863 display: flex;
864 gap: 4px;
865 align-items: center;
866 margin-bottom: 16px;
867 color: var(--text-muted);
868 font-size: var(--t-sm);
869 font-family: var(--font-mono);
870 }
871 .breadcrumb a { color: var(--text-link); font-weight: 500; }
872 .breadcrumb a:hover { color: var(--accent-hover); }
fc1817aClaude873
2ce1d0bClaude874 /* ============================================================ */
875 /* File browser table */
876 /* ============================================================ */
877 .file-table {
878 width: 100%;
879 border: 1px solid var(--border);
880 border-radius: var(--r-md);
881 overflow: hidden;
882 background: var(--bg-elevated);
883 }
fc1817aClaude884 .file-table tr { border-bottom: 1px solid var(--border); }
885 .file-table tr:last-child { border-bottom: none; }
2ce1d0bClaude886 .file-table td { padding: 10px 16px; font-size: var(--t-sm); }
887 .file-table tr:hover { background: var(--bg-hover); }
888 .file-icon { width: 22px; color: var(--text-faint); font-family: var(--font-mono); font-size: var(--t-sm); }
889 .file-name a { color: var(--text); font-weight: 500; }
890 .file-name a:hover { color: var(--text-link); text-decoration: none; }
fc1817aClaude891
2ce1d0bClaude892 /* ============================================================ */
893 /* Blob view */
894 /* ============================================================ */
fc1817aClaude895 .blob-view {
896 border: 1px solid var(--border);
2ce1d0bClaude897 border-radius: var(--r-md);
fc1817aClaude898 overflow: hidden;
2ce1d0bClaude899 background: var(--bg-elevated);
fc1817aClaude900 }
901 .blob-header {
902 background: var(--bg-secondary);
2ce1d0bClaude903 padding: 10px 16px;
fc1817aClaude904 border-bottom: 1px solid var(--border);
2ce1d0bClaude905 font-size: var(--t-sm);
fc1817aClaude906 color: var(--text-muted);
06d5ffeClaude907 display: flex;
908 justify-content: space-between;
909 align-items: center;
fc1817aClaude910 }
911 .blob-code {
912 overflow-x: auto;
913 font-family: var(--font-mono);
2ce1d0bClaude914 font-size: var(--t-sm);
915 line-height: 1.65;
fc1817aClaude916 }
917 .blob-code table { width: 100%; border-collapse: collapse; }
918 .blob-code .line-num {
919 width: 1%;
2ce1d0bClaude920 min-width: 56px;
921 padding: 0 14px;
fc1817aClaude922 text-align: right;
2ce1d0bClaude923 color: var(--text-faint);
fc1817aClaude924 user-select: none;
925 white-space: nowrap;
926 border-right: 1px solid var(--border);
927 }
2ce1d0bClaude928 .blob-code .line-content { padding: 0 16px; white-space: pre; }
929 .blob-code tr:hover { background: var(--bg-hover); }
fc1817aClaude930
2ce1d0bClaude931 /* ============================================================ */
932 /* Commits + diffs */
933 /* ============================================================ */
934 .commit-list {
935 border: 1px solid var(--border);
936 border-radius: var(--r-md);
937 overflow: hidden;
938 background: var(--bg-elevated);
939 }
fc1817aClaude940 .commit-item {
941 display: flex;
942 justify-content: space-between;
943 align-items: center;
2ce1d0bClaude944 padding: 14px 16px;
fc1817aClaude945 border-bottom: 1px solid var(--border);
2ce1d0bClaude946 transition: background var(--t-fast) var(--ease);
fc1817aClaude947 }
948 .commit-item:last-child { border-bottom: none; }
2ce1d0bClaude949 .commit-item:hover { background: var(--bg-hover); }
950 .commit-message { font-size: var(--t-sm); font-weight: 500; line-height: 1.45; }
951 .commit-meta { font-size: var(--t-xs); color: var(--text-muted); margin-top: 4px; }
fc1817aClaude952 .commit-sha {
953 font-family: var(--font-mono);
2ce1d0bClaude954 font-size: var(--t-xs);
955 padding: 3px 8px;
fc1817aClaude956 background: var(--bg-tertiary);
957 border: 1px solid var(--border);
2ce1d0bClaude958 border-radius: var(--r-sm);
fc1817aClaude959 color: var(--text-link);
2ce1d0bClaude960 font-weight: 500;
961 transition: all var(--t-fast) var(--ease);
fc1817aClaude962 }
2ce1d0bClaude963 .commit-sha:hover { border-color: var(--border-strong); color: var(--accent-hover); }
fc1817aClaude964
965 .diff-view { margin-top: 16px; }
966 .diff-file {
967 border: 1px solid var(--border);
2ce1d0bClaude968 border-radius: var(--r-md);
fc1817aClaude969 margin-bottom: 16px;
970 overflow: hidden;
2ce1d0bClaude971 background: var(--bg-elevated);
fc1817aClaude972 }
973 .diff-file-header {
974 background: var(--bg-secondary);
2ce1d0bClaude975 padding: 10px 16px;
fc1817aClaude976 border-bottom: 1px solid var(--border);
977 font-family: var(--font-mono);
2ce1d0bClaude978 font-size: var(--t-sm);
979 font-weight: 500;
fc1817aClaude980 }
981 .diff-content {
982 overflow-x: auto;
983 font-family: var(--font-mono);
2ce1d0bClaude984 font-size: var(--t-sm);
985 line-height: 1.65;
fc1817aClaude986 }
2ce1d0bClaude987 .diff-content .line-add { background: rgba(16,185,129,0.10); color: var(--green); }
988 .diff-content .line-del { background: rgba(239,68,68,0.08); color: var(--red); }
989 .diff-content .line-hunk { background: rgba(168,85,247,0.06); color: var(--text-link); }
990 .diff-content .line { padding: 0 16px; white-space: pre; display: block; }
fc1817aClaude991
992 .stat-add { color: var(--green); font-weight: 600; }
993 .stat-del { color: var(--red); font-weight: 600; }
994
2ce1d0bClaude995 /* ============================================================ */
996 /* Empty state */
997 /* ============================================================ */
fc1817aClaude998 .empty-state {
999 text-align: center;
2ce1d0bClaude1000 padding: 80px 20px;
fc1817aClaude1001 color: var(--text-muted);
2ce1d0bClaude1002 border: 1px dashed var(--border);
1003 border-radius: var(--r-lg);
1004 background: var(--bg);
fc1817aClaude1005 }
2ce1d0bClaude1006 .empty-state h2 {
1007 font-size: var(--t-lg);
1008 margin-bottom: 8px;
1009 color: var(--text);
1010 letter-spacing: -0.015em;
1011 }
1012 .empty-state p { font-size: var(--t-sm); }
fc1817aClaude1013 .empty-state pre {
1014 text-align: left;
1015 display: inline-block;
1016 background: var(--bg-secondary);
2ce1d0bClaude1017 padding: 16px 22px;
1018 border-radius: var(--r-sm);
fc1817aClaude1019 border: 1px solid var(--border);
1020 font-family: var(--font-mono);
2ce1d0bClaude1021 font-size: var(--t-sm);
1022 margin-top: 20px;
fc1817aClaude1023 line-height: 1.8;
2ce1d0bClaude1024 color: var(--text);
fc1817aClaude1025 }
1026
2ce1d0bClaude1027 /* ============================================================ */
1028 /* Badges */
1029 /* ============================================================ */
fc1817aClaude1030 .badge {
2ce1d0bClaude1031 display: inline-flex;
1032 align-items: center;
1033 gap: 4px;
1034 padding: 2px 9px;
1035 border-radius: var(--r-full);
1036 font-size: var(--t-xs);
fc1817aClaude1037 font-weight: 500;
1038 background: var(--bg-tertiary);
1039 border: 1px solid var(--border);
1040 color: var(--text-muted);
2ce1d0bClaude1041 line-height: 1.5;
fc1817aClaude1042 }
1043
2ce1d0bClaude1044 /* ============================================================ */
1045 /* Branch dropdown */
1046 /* ============================================================ */
fc1817aClaude1047 .branch-selector {
1048 display: inline-flex;
1049 align-items: center;
2ce1d0bClaude1050 gap: 6px;
1051 padding: 6px 12px;
1052 background: var(--bg-elevated);
fc1817aClaude1053 border: 1px solid var(--border);
2ce1d0bClaude1054 border-radius: var(--r-sm);
1055 font-size: var(--t-sm);
fc1817aClaude1056 color: var(--text);
1057 margin-bottom: 12px;
2ce1d0bClaude1058 transition: border-color var(--t-fast) var(--ease);
fc1817aClaude1059 }
2ce1d0bClaude1060 .branch-selector:hover { border-color: var(--border-strong); }
fc1817aClaude1061
06d5ffeClaude1062 .branch-dropdown {
1063 position: relative;
1064 display: inline-block;
1065 margin-bottom: 12px;
1066 }
1067 .branch-dropdown-content {
1068 display: none;
1069 position: absolute;
2ce1d0bClaude1070 top: calc(100% + 4px);
06d5ffeClaude1071 left: 0;
1072 z-index: 10;
2ce1d0bClaude1073 min-width: 220px;
1074 background: var(--bg-elevated);
1075 border: 1px solid var(--border-strong);
1076 border-radius: var(--r-md);
1077 overflow: hidden;
1078 box-shadow: var(--elev-3);
06d5ffeClaude1079 }
1080 .branch-dropdown:hover .branch-dropdown-content,
1081 .branch-dropdown:focus-within .branch-dropdown-content { display: block; }
1082 .branch-dropdown-content a {
1083 display: block;
2ce1d0bClaude1084 padding: 9px 14px;
1085 font-size: var(--t-sm);
06d5ffeClaude1086 color: var(--text);
1087 border-bottom: 1px solid var(--border);
2ce1d0bClaude1088 transition: background var(--t-fast) var(--ease);
06d5ffeClaude1089 }
1090 .branch-dropdown-content a:last-child { border-bottom: none; }
2ce1d0bClaude1091 .branch-dropdown-content a:hover { background: var(--bg-hover); text-decoration: none; }
1092 .branch-dropdown-content a.active-branch { color: var(--text-link); font-weight: 600; background: var(--accent-gradient-faint); }
06d5ffeClaude1093
2ce1d0bClaude1094 /* ============================================================ */
1095 /* Card grid */
1096 /* ============================================================ */
1097 .card-grid {
1098 display: grid;
1099 grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
1100 gap: 16px;
1101 }
fc1817aClaude1102 .card {
1103 border: 1px solid var(--border);
2ce1d0bClaude1104 border-radius: var(--r-md);
1105 padding: 18px;
1106 background: var(--bg-elevated);
1107 transition:
1108 border-color var(--t-fast) var(--ease),
1109 transform var(--t-fast) var(--ease),
1110 box-shadow var(--t-base) var(--ease);
1111 position: relative;
1112 overflow: hidden;
1113 }
1114 .card:hover {
1115 border-color: var(--border-strong);
1116 box-shadow: var(--elev-2);
1117 transform: translateY(-1px);
1118 }
1119 .card h3 { font-size: var(--t-md); margin-bottom: 6px; letter-spacing: -0.01em; }
1120 .card h3 a { color: var(--text); font-weight: 600; }
1121 .card h3 a:hover { color: var(--text-link); }
1122 .card p { font-size: var(--t-sm); color: var(--text-muted); line-height: 1.5; }
1123 .card-meta {
1124 display: flex;
1125 gap: 14px;
1126 margin-top: 14px;
1127 padding-top: 14px;
1128 border-top: 1px solid var(--border);
1129 font-size: var(--t-xs);
1130 color: var(--text-muted);
1131 }
1132 .card-meta span { display: flex; align-items: center; gap: 5px; }
1133
1134 /* ============================================================ */
1135 /* Stat card / box */
1136 /* ============================================================ */
1137 .stat-card {
1138 background: var(--bg-elevated);
1139 border: 1px solid var(--border);
1140 border-radius: var(--r-md);
fc1817aClaude1141 padding: 16px;
2ce1d0bClaude1142 transition: border-color var(--t-fast) var(--ease);
1143 }
1144 .stat-card:hover { border-color: var(--border-strong); }
1145 .stat-label {
1146 font-size: var(--t-xs);
1147 color: var(--text-muted);
1148 text-transform: uppercase;
1149 letter-spacing: 0.06em;
1150 font-weight: 500;
1151 }
1152 .stat-value {
1153 font-size: var(--t-xl);
1154 font-weight: 700;
1155 margin-top: 4px;
1156 letter-spacing: -0.025em;
1157 color: var(--text);
1158 font-feature-settings: 'tnum';
fc1817aClaude1159 }
06d5ffeClaude1160
2ce1d0bClaude1161 /* ============================================================ */
1162 /* Star button */
1163 /* ============================================================ */
06d5ffeClaude1164 .star-btn {
1165 display: inline-flex;
1166 align-items: center;
1167 gap: 6px;
2ce1d0bClaude1168 padding: 5px 12px;
1169 background: var(--bg-elevated);
06d5ffeClaude1170 border: 1px solid var(--border);
2ce1d0bClaude1171 border-radius: var(--r-sm);
06d5ffeClaude1172 color: var(--text);
2ce1d0bClaude1173 font-size: var(--t-sm);
1174 font-weight: 500;
06d5ffeClaude1175 cursor: pointer;
2ce1d0bClaude1176 transition: all var(--t-fast) var(--ease);
1177 }
1178 .star-btn:hover { background: var(--bg-surface); border-color: var(--border-strong); text-decoration: none; }
1179 .star-btn.starred {
1180 color: var(--yellow);
1181 border-color: rgba(245,158,11,0.4);
1182 background: rgba(245,158,11,0.08);
06d5ffeClaude1183 }
1184
2ce1d0bClaude1185 /* ============================================================ */
1186 /* User profile */
1187 /* ============================================================ */
06d5ffeClaude1188 .user-profile {
1189 display: flex;
1190 gap: 32px;
1191 margin-bottom: 32px;
2ce1d0bClaude1192 padding: 24px;
1193 background: var(--bg-elevated);
1194 border: 1px solid var(--border);
1195 border-radius: var(--r-lg);
06d5ffeClaude1196 }
1197 .user-avatar {
1198 width: 96px;
1199 height: 96px;
2ce1d0bClaude1200 border-radius: var(--r-full);
1201 background: var(--accent-gradient-soft);
1202 border: 1px solid var(--border-strong);
06d5ffeClaude1203 display: flex;
1204 align-items: center;
1205 justify-content: center;
2ce1d0bClaude1206 font-size: 36px;
1207 font-weight: 600;
1208 color: var(--text);
06d5ffeClaude1209 flex-shrink: 0;
2ce1d0bClaude1210 letter-spacing: -0.02em;
06d5ffeClaude1211 }
2ce1d0bClaude1212 .user-info h2 { font-size: var(--t-xl); margin-bottom: 2px; letter-spacing: -0.025em; }
1213 .user-info .username { font-size: var(--t-md); color: var(--text-muted); }
1214 .user-info .bio { font-size: var(--t-sm); color: var(--text-muted); margin-top: 10px; line-height: 1.55; }
06d5ffeClaude1215
2ce1d0bClaude1216 /* ============================================================ */
1217 /* New repo form */
1218 /* ============================================================ */
1219 .new-repo-form { max-width: 640px; }
1220 .new-repo-form h2 { margin-bottom: 24px; font-size: var(--t-xl); letter-spacing: -0.025em; }
1221 .visibility-options { display: flex; gap: 12px; margin-bottom: 20px; }
06d5ffeClaude1222 .visibility-option {
1223 flex: 1;
2ce1d0bClaude1224 padding: 16px;
06d5ffeClaude1225 border: 1px solid var(--border);
2ce1d0bClaude1226 border-radius: var(--r-md);
1227 background: var(--bg-elevated);
06d5ffeClaude1228 cursor: pointer;
2ce1d0bClaude1229 text-align: left;
1230 transition: all var(--t-fast) var(--ease);
1231 }
1232 .visibility-option:hover { border-color: var(--border-strong); background: var(--bg-surface); }
1233 .visibility-option:has(input:checked) {
1234 border-color: var(--accent);
1235 background: var(--accent-gradient-faint);
1236 box-shadow: 0 0 0 1px var(--accent);
06d5ffeClaude1237 }
1238 .visibility-option input { display: none; }
2ce1d0bClaude1239 .visibility-option .vis-label { font-size: var(--t-sm); font-weight: 600; margin-bottom: 4px; }
1240 .visibility-option .vis-desc { font-size: var(--t-xs); color: var(--text-muted); }
79136bbClaude1241
2ce1d0bClaude1242 /* ============================================================ */
1243 /* Issues */
1244 /* ============================================================ */
1245 .issue-tabs { display: flex; gap: 4px; }
1246 .issue-tabs a {
1247 color: var(--text-muted);
1248 font-size: var(--t-sm);
1249 font-weight: 500;
1250 padding: 6px 12px;
1251 border-radius: var(--r-sm);
1252 transition: all var(--t-fast) var(--ease);
1253 }
1254 .issue-tabs a:hover { color: var(--text); background: var(--bg-hover); text-decoration: none; }
1255 .issue-tabs a.active { color: var(--text); background: var(--bg-elevated); }
79136bbClaude1256
2ce1d0bClaude1257 .issue-list {
1258 border: 1px solid var(--border);
1259 border-radius: var(--r-md);
1260 overflow: hidden;
1261 background: var(--bg-elevated);
1262 }
79136bbClaude1263 .issue-item {
1264 display: flex;
2ce1d0bClaude1265 gap: 14px;
79136bbClaude1266 align-items: flex-start;
2ce1d0bClaude1267 padding: 14px 16px;
79136bbClaude1268 border-bottom: 1px solid var(--border);
2ce1d0bClaude1269 transition: background var(--t-fast) var(--ease);
79136bbClaude1270 }
1271 .issue-item:last-child { border-bottom: none; }
2ce1d0bClaude1272 .issue-item:hover { background: var(--bg-hover); }
1273 .issue-state-icon {
1274 font-size: 14px;
1275 padding-top: 2px;
1276 width: 18px;
1277 height: 18px;
1278 display: inline-flex;
1279 align-items: center;
1280 justify-content: center;
1281 border-radius: var(--r-full);
1282 flex-shrink: 0;
1283 }
79136bbClaude1284 .state-open { color: var(--green); }
2ce1d0bClaude1285 .state-closed { color: #c084fc; }
1286 .issue-title {
1287 font-size: var(--t-base);
1288 font-weight: 600;
1289 line-height: 1.4;
1290 letter-spacing: -0.005em;
1291 }
79136bbClaude1292 .issue-title a { color: var(--text); }
2ce1d0bClaude1293 .issue-title a:hover { color: var(--text-link); text-decoration: none; }
1294 .issue-meta { font-size: var(--t-xs); color: var(--text-muted); margin-top: 4px; }
79136bbClaude1295
1296 .issue-badge {
1297 display: inline-flex;
1298 align-items: center;
2ce1d0bClaude1299 gap: 6px;
79136bbClaude1300 padding: 4px 12px;
2ce1d0bClaude1301 border-radius: var(--r-full);
1302 font-size: var(--t-sm);
79136bbClaude1303 font-weight: 500;
2ce1d0bClaude1304 line-height: 1.4;
79136bbClaude1305 }
2ce1d0bClaude1306 .badge-open { background: rgba(16,185,129,0.10); color: var(--green); border: 1px solid rgba(16,185,129,0.35); }
1307 .badge-closed { background: rgba(192,132,252,0.10); color: #c084fc; border: 1px solid rgba(192,132,252,0.35); }
1308 .badge-merged { background: rgba(168,85,247,0.10); color: var(--accent); border: 1px solid rgba(168,85,247,0.35); }
1309 .state-merged { color: var(--accent); }
1310 .ai-review { border-color: var(--accent); box-shadow: 0 0 0 1px rgba(168,85,247,0.3); }
79136bbClaude1311
2ce1d0bClaude1312 .issue-detail { max-width: 920px; }
79136bbClaude1313 .issue-comment-box {
1314 border: 1px solid var(--border);
2ce1d0bClaude1315 border-radius: var(--r-md);
79136bbClaude1316 margin-bottom: 16px;
1317 overflow: hidden;
2ce1d0bClaude1318 background: var(--bg-elevated);
79136bbClaude1319 }
1320 .comment-header {
1321 background: var(--bg-secondary);
2ce1d0bClaude1322 padding: 10px 16px;
1323 border-bottom: 1px solid var(--border);
1324 font-size: var(--t-sm);
1325 color: var(--text-muted);
1326 }
1327
1328 /* ============================================================ */
1329 /* Panel — flexible container used across many pages */
1330 /* ============================================================ */
1331 .panel {
1332 background: var(--bg-elevated);
1333 border: 1px solid var(--border);
1334 border-radius: var(--r-md);
1335 overflow: hidden;
1336 }
1337 .panel-item {
1338 display: flex;
1339 align-items: center;
1340 gap: 12px;
1341 padding: 12px 16px;
79136bbClaude1342 border-bottom: 1px solid var(--border);
2ce1d0bClaude1343 transition: background var(--t-fast) var(--ease);
1344 }
1345 .panel-item:last-child { border-bottom: none; }
1346 .panel-item:hover { background: var(--bg-hover); }
1347 .panel-empty {
1348 padding: 24px;
1349 text-align: center;
79136bbClaude1350 color: var(--text-muted);
2ce1d0bClaude1351 font-size: var(--t-sm);
79136bbClaude1352 }
1353
2ce1d0bClaude1354 /* ============================================================ */
1355 /* Search */
1356 /* ============================================================ */
79136bbClaude1357 .search-results .diff-file { margin-bottom: 12px; }
16b325cClaude1358
2ce1d0bClaude1359 /* ============================================================ */
1360 /* Timeline */
1361 /* ============================================================ */
1362 .timeline { position: relative; padding-left: 28px; }
16b325cClaude1363 .timeline::before {
1364 content: '';
1365 position: absolute;
1366 left: 4px;
1367 top: 8px;
1368 bottom: 8px;
1369 width: 2px;
2ce1d0bClaude1370 background: linear-gradient(180deg, var(--border) 0%, transparent 100%);
16b325cClaude1371 }
2ce1d0bClaude1372 .timeline-item { position: relative; padding-bottom: 16px; }
16b325cClaude1373 .timeline-dot {
1374 position: absolute;
2ce1d0bClaude1375 left: -28px;
1376 top: 8px;
1377 width: 12px;
1378 height: 12px;
1379 border-radius: var(--r-full);
1380 background: var(--accent-gradient);
16b325cClaude1381 border: 2px solid var(--bg);
2ce1d0bClaude1382 box-shadow: 0 0 0 1px var(--border-strong);
16b325cClaude1383 }
1384 .timeline-content {
2ce1d0bClaude1385 background: var(--bg-elevated);
16b325cClaude1386 border: 1px solid var(--border);
2ce1d0bClaude1387 border-radius: var(--r-md);
1388 padding: 14px 16px;
16b325cClaude1389 }
f1ab587Claude1390
2ce1d0bClaude1391 /* ============================================================ */
1392 /* Toggle switch */
1393 /* ============================================================ */
f1ab587Claude1394 .toggle-switch {
1395 position: relative;
1396 display: inline-block;
2ce1d0bClaude1397 width: 40px;
1398 height: 22px;
f1ab587Claude1399 flex-shrink: 0;
1400 margin-left: 16px;
1401 }
1402 .toggle-switch input { opacity: 0; width: 0; height: 0; }
1403 .toggle-slider {
1404 position: absolute;
1405 cursor: pointer;
1406 top: 0; left: 0; right: 0; bottom: 0;
1407 background: var(--bg-tertiary);
1408 border: 1px solid var(--border);
2ce1d0bClaude1409 border-radius: var(--r-full);
1410 transition: all var(--t-base) var(--ease);
f1ab587Claude1411 }
1412 .toggle-slider::before {
1413 content: '';
1414 position: absolute;
2ce1d0bClaude1415 height: 16px;
1416 width: 16px;
f1ab587Claude1417 left: 2px;
1418 bottom: 2px;
1419 background: var(--text-muted);
2ce1d0bClaude1420 border-radius: var(--r-full);
1421 transition: all var(--t-base) var(--ease);
f1ab587Claude1422 }
1423 .toggle-switch input:checked + .toggle-slider {
2ce1d0bClaude1424 background: var(--accent-gradient);
1425 border-color: transparent;
1426 box-shadow: 0 0 0 1px rgba(168,85,247,0.4);
f1ab587Claude1427 }
1428 .toggle-switch input:checked + .toggle-slider::before {
2ce1d0bClaude1429 transform: translateX(18px);
f1ab587Claude1430 background: #fff;
1431 }
2ce1d0bClaude1432
1433 /* ============================================================ */
1434 /* Utility — gradient text + soft surfaces */
1435 /* ============================================================ */
1436 .gradient-text {
1437 background: var(--accent-gradient);
1438 -webkit-background-clip: text;
1439 background-clip: text;
1440 -webkit-text-fill-color: transparent;
1441 }
1442 .surface { background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--r-md); }
1443 .surface-elevated { background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--r-md); box-shadow: var(--elev-1); }
1444
1445 /* Command palette polish */
1446 .cmdk-item { transition: background var(--t-fast) var(--ease); }
1447 .cmdk-item:hover { background: var(--bg-hover) !important; }
1448 .cmdk-active { background: var(--accent-gradient-faint) !important; border-left: 2px solid var(--accent) !important; }
1449
1450 /* Reduced motion preference */
1451 @media (prefers-reduced-motion: reduce) {
1452 *, *::before, *::after {
1453 animation-duration: 0.01ms !important;
1454 animation-iteration-count: 1 !important;
1455 transition-duration: 0.01ms !important;
1456 }
1457 }
1458
1459 /* Tablet + below */
1460 @media (max-width: 768px) {
1461 main { padding: 20px 16px 40px; }
1462 header { padding: 0 16px; }
1463 .nav-search { display: none; }
1464 .repo-header { font-size: var(--t-md); }
1465 .card-grid { grid-template-columns: 1fr; }
1466 .auth-container { margin: 32px 16px; padding: 24px; }
1467 .visibility-options { flex-direction: column; }
1468 }
1469
1470 /* Scrollbar styling — subtle, themed */
1471 ::-webkit-scrollbar { width: 10px; height: 10px; }
1472 ::-webkit-scrollbar-track { background: transparent; }
1473 ::-webkit-scrollbar-thumb {
1474 background: var(--bg-surface);
1475 border: 2px solid var(--bg);
1476 border-radius: var(--r-full);
1477 }
1478 ::-webkit-scrollbar-thumb:hover { background: var(--border-strong); }
fc1817aClaude1479`;