diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 6d147b1..d8ea0fd 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -47,6 +47,7 @@ {"id":"ts-ast-parser-eval-5xj","title":"Fix misc code quality errors","description":"Includes: nested template literals, nested ternary, dead stores, no-case-declarations, prefer-read-only-props, no-array-index-key, dangerouslySetInnerHTML, no-await-in-loop, no-unnecessary-condition, react-refresh warnings","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-12-19T12:41:55.908368Z","updated_at":"2025-12-19T16:02:24.299207Z","closed_at":"2025-12-19T16:02:24.299207Z","close_reason":"Fixed all misc errors: nested ternaries, array-index-key, dangerouslySetInnerHTML, react-refresh"} {"id":"ts-ast-parser-eval-63y","title":"Fix prefer-regexp-exec in callStack.ts","description":"Use RegExp.exec() instead of String.match() at line 46","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-19T12:47:47.385612Z","updated_at":"2025-12-19T14:42:23.252456Z","closed_at":"2025-12-19T14:42:23.252456Z","close_reason":"Validated - no errors remain","dependencies":[{"issue_id":"ts-ast-parser-eval-63y","depends_on_id":"ts-ast-parser-eval-5pa","type":"parent-child","created_at":"2025-12-19T12:48:04.547044Z","created_by":"daemon"}]} {"id":"ts-ast-parser-eval-664","title":"Fix react-hooks/exhaustive-deps in App.tsx","description":"Add missing dependency playback.currentStep to useMemo at line 83","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-19T12:48:30.096961Z","updated_at":"2025-12-19T15:04:53.976433Z","closed_at":"2025-12-19T15:04:53.976433Z","close_reason":"Added playback.currentStep to deps","dependencies":[{"issue_id":"ts-ast-parser-eval-664","depends_on_id":"ts-ast-parser-eval-6u6","type":"parent-child","created_at":"2025-12-19T12:48:50.40874Z","created_by":"daemon"}]} +{"id":"ts-ast-parser-eval-66k","title":"Find and consolidate duplicate CSS color declarations","description":"Scan styles.css for duplicate color hex values that can be replaced with existing CSS variables","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-30T18:16:53.148872Z","updated_at":"2025-12-30T18:24:06.188791Z","closed_at":"2025-12-30T18:24:06.188791Z","close_reason":"All duplicate hardcoded rgba values consolidated to CSS variables"} {"id":"ts-ast-parser-eval-68y","title":"Fix StepDetailsPanel.tsx hasResult logic bug - line 121 inverted condition","description":"**File:** src/web/components/StepDetailsPanel.tsx:121-122\n\n**Problem:** The `hasResult` condition is inverted. Current logic:\n```typescript\nconst hasResult = step.result !== undefined \u0026\u0026 !step.result;\n```\nThis shows the result bar only when `result` is falsy (empty string, 0, false), which is backwards.\n\n**Expected:** Should show result bar when `step.result` exists and is truthy.\n\n**Fix options:**\n1. `const hasResult = step.result !== undefined \u0026\u0026 step.result !== null;` (show when defined)\n2. `const hasResult = !!step.result;` (show when truthy)\n3. `const hasResult = step.result !== undefined;` (show when not undefined)\n\n**Test failures:**\n- StepDetailsPanel.integration.test.tsx:708 - `expect(screen.getByText(/finalResult/)).toBeDefined()` fails because result bar isn't rendered\n- Related screenshot tests fail due to missing result bar","acceptance_criteria":"- [ ] Result bar displays when step.result has a value\n- [ ] Test `shows Result bar at bottom when result exists` passes\n- [ ] Test `handles union stepping with full data flow` passes\n- [ ] Screenshot tests match expected output","status":"closed","priority":1,"issue_type":"bug","assignee":"claude","created_at":"2025-12-19T16:07:46.785117Z","updated_at":"2025-12-19T16:10:57.849309Z","closed_at":"2025-12-19T16:10:57.849309Z","close_reason":"Fixed hasResult logic on line 121. Also fixed test regex for CallStackSection (`:5` -\u003e `: 5`). All 158 tests now passing."} {"id":"ts-ast-parser-eval-6b7","title":"Fix @typescript-eslint/await-thenable errors","description":"9 unnecessary awaits on non-Promise values.","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-12-19T12:41:36.374309Z","updated_at":"2025-12-19T14:50:18.227252Z","closed_at":"2025-12-19T14:50:18.227252Z","close_reason":"Removed 9 unnecessary awaits - validated lint passes"} {"id":"ts-ast-parser-eval-6ip","title":"Fix jsx-a11y in Toast.tsx","description":"Fix click-events-have-key-events and no-static-element-interactions at line 37","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-19T12:48:29.360676Z","updated_at":"2025-12-19T15:51:06.051816Z","closed_at":"2025-12-19T15:51:06.051816Z","close_reason":"Converted div to button with reset styles","dependencies":[{"issue_id":"ts-ast-parser-eval-6ip","depends_on_id":"ts-ast-parser-eval-d7z","type":"parent-child","created_at":"2025-12-19T12:48:50.084274Z","created_by":"daemon"}]} @@ -92,6 +93,7 @@ {"id":"ts-ast-parser-eval-d17","title":"Highlight selected example on landing page","description":"When user clicks an example button on the landing page, visually highlight which example is currently selected","design":"Track selected example in state, apply CSS class to selected button","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-23T19:41:36.943968Z","updated_at":"2025-12-23T19:44:48.467987Z","closed_at":"2025-12-23T19:44:48.467987Z","close_reason":"Added selectedExample state and .selected CSS class to highlight active example button"} {"id":"ts-ast-parser-eval-d7z","title":"Fix jsx-a11y accessibility errors","description":"5 accessibility issues - missing keyboard listeners and interactive element roles.","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-12-19T12:41:36.477804Z","updated_at":"2025-12-19T15:51:05.562816Z","closed_at":"2025-12-19T15:51:05.562816Z","close_reason":"Fixed 5 a11y errors: semantic buttons + role=separator"} {"id":"ts-ast-parser-eval-deu","title":"Fix @eslint-react/dom/no-missing-button-type errors","description":"8 buttons missing type attribute. Need to add type=\"button\".","design":"Add type=\\\"button\\\" to all non-submit buttons","status":"closed","priority":2,"issue_type":"epic","created_at":"2025-12-19T12:41:36.175215Z","updated_at":"2025-12-19T14:35:13.347946Z","closed_at":"2025-12-19T14:35:13.347946Z","close_reason":"All 7 no-missing-button-type errors fixed"} +{"id":"ts-ast-parser-eval-dfw","title":"Commit CSS variable consolidation changes","description":"Commit the CSS changes that consolidated hardcoded values into CSS variables","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-30T18:16:53.011456Z","updated_at":"2025-12-30T18:17:46.180412Z","closed_at":"2025-12-30T18:17:46.180412Z","close_reason":"Committed CSS variable consolidation changes (263a998)"} {"id":"ts-ast-parser-eval-e0h","title":"Exclude lib-bundle.ts from max-len rule","description":"Generated file has 12 lines over 400 chars. Add eslint-disable or update config to ignore.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-19T12:49:11.848848Z","updated_at":"2025-12-23T10:56:21.878107Z","closed_at":"2025-12-23T10:56:21.878107Z","close_reason":"Completed","dependencies":[{"issue_id":"ts-ast-parser-eval-e0h","depends_on_id":"ts-ast-parser-eval-idu","type":"parent-child","created_at":"2025-12-19T12:49:26.629599Z","created_by":"daemon"}]} {"id":"ts-ast-parser-eval-e7g","title":"Fix slow-regex in traceProcessor.ts","description":"Fix regex vulnerable to super-linear runtime at line 322","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-19T12:47:14.344472Z","updated_at":"2025-12-19T14:28:47.461299Z","closed_at":"2025-12-19T14:28:47.461299Z","close_reason":"Skipped per user request","dependencies":[{"issue_id":"ts-ast-parser-eval-e7g","depends_on_id":"ts-ast-parser-eval-1c7","type":"parent-child","created_at":"2025-12-19T12:47:27.480309Z","created_by":"daemon"}]} {"id":"ts-ast-parser-eval-efh","title":"Fix jsx-no-bind: PlaybackControls.test.tsx:9-11","description":"Move arrow functions to variables at lines 9,10,11","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T17:16:06.55211Z","updated_at":"2025-12-19T17:35:04.724203Z","closed_at":"2025-12-19T17:35:04.724203Z","close_reason":"Fixed","dependencies":[{"issue_id":"ts-ast-parser-eval-efh","depends_on_id":"ts-ast-parser-eval-4i7","type":"parent-child","created_at":"2025-12-19T17:16:23.783374Z","created_by":"daemon"}]} diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 3ef25b4..568cfad 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -53,7 +53,10 @@ "mcp__plugin_beads_beads__set_context", "mcp__plugin_beads_beads__create", "mcp__plugin_beads_beads__update", - "mcp__plugin_beads_beads__close" + "mcp__plugin_beads_beads__close", + "Bash(gh pr view:*)", + "Bash(gh pr diff:*)", + "Bash(gh api:*)" ], "deny": [], "ask": [] diff --git a/src/web/components/LandingPage.tsx b/src/web/components/LandingPage.tsx index 695cda7..fde7968 100644 --- a/src/web/components/LandingPage.tsx +++ b/src/web/components/LandingPage.tsx @@ -1,5 +1,5 @@ import { Editor } from "@monaco-editor/react"; -import React, { useState, useCallback, useRef } from "react"; +import React, { useState, useCallback, useRef, useEffect } from "react"; import { useTheme } from "../hooks/useThemeHook.ts"; import { ThemeDropdown } from "./ThemeDropdown.tsx"; @@ -120,6 +120,21 @@ export const LandingPage: React.FC = ({ onTryIt }) => { setInputCode(value ?? ""); }, []); + // Scroll-to-top button visibility + const [ showScrollTop, setShowScrollTop ] = useState(false); + + useEffect(() => { + const handleScroll = () => { + setShowScrollTop(window.scrollY > 200); + }; + window.addEventListener("scroll", handleScroll); + return () => window.removeEventListener("scroll", handleScroll); + }, []); + + const scrollToTry = useCallback(() => { + document.getElementById("try")?.scrollIntoView({ behavior: "smooth" }); + }, []); + return (
{/* HERO */} @@ -263,24 +278,12 @@ export const LandingPage: React.FC = ({ onTryIt }) => {

    +
  • {"See how types actually evaluate, step by step"}
  • - - {"See how types actually evaluate, step by step"} -
  • -
  • - - - {"Understand "}{"extends"}{", "}{"infer"}{", and mapped types visually"} - -
  • -
  • - - {"Debug type errors without trial-and-error"} -
  • -
  • - - {"Learn advanced TypeScript faster"} + {"Understand "}{"extends"}{", "}{"infer"}{", and mapped types visually"}
  • +
  • {"Debug type errors without trial-and-error"}
  • +
  • {"Learn advanced TypeScript faster"}

@@ -304,9 +307,6 @@ export const LandingPage: React.FC = ({ onTryIt }) => { {"A quick walkthrough showing how a complex type turns into a clear, step-by-step explanation."}

- - {"Back to Try It"} - {/* Demo Video */} @@ -419,6 +419,28 @@ export const LandingPage: React.FC = ({ onTryIt }) => { + + {/* Scroll to Try It button */} + {showScrollTop && ( + + )} ); }; diff --git a/src/web/styles.css b/src/web/styles.css index c3f1fab..1184b84 100644 --- a/src/web/styles.css +++ b/src/web/styles.css @@ -23,6 +23,15 @@ --border-subtle: rgba(255, 255, 255, 0.1); --border-medium: rgba(255, 255, 255, 0.2); + /* Glass effects */ + --glass-5: rgba(255, 255, 255, 0.05); + --glass-10: rgba(255, 255, 255, 0.1); + --glass-card: rgba(15, 23, 42, 0.6); /* slate-900/60 */ + --glass-card-alt: rgba(15, 23, 42, 0.4); /* slate-900/40 */ + --glass-input: rgba(2, 6, 23, 0.8); /* slate-950/80 */ + --glass-menu: rgba(15, 23, 42, 0.95); /* slate-900/95 */ + --glass-features: rgba(30, 27, 75, 0.35); /* indigo-950/35 */ + /* Accent colors - Indigo palette */ --accent-primary: #6366f1; /* indigo-500 */ --accent-primary-alt: #818cf8; /* indigo-400 */ @@ -41,7 +50,20 @@ --red: #ef4444; /* red-500 */ --yellow: #fde047; /* yellow-300 */ --indigo: #818cf8; /* indigo-400 */ - --indigo-light: #c7d2fe; /* indigo-200 */ + --indigo-light: #c7d2fe; /* indigo-200 */ + --indigo-lighter: #e0e7ff; /* indigo-100 */ + --indigo-dark: #1e1b4b; /* indigo-950 */ + + /* Extended text colors */ + --text-white: #ffffff; + --text-light: #e2e8f0; /* slate-200 */ + --text-muted: #cbd5e1; /* slate-300 */ + + /* Focus ring */ + --focus-ring: rgba(99, 102, 241, 0.3); + + /* Hero gradient */ + --landing-hero-gradient: linear-gradient(to bottom right, var(--bg), var(--bg-secondary), var(--indigo-dark)); /* Syntax highlighting */ --syntax-keyword: #f472b6; /* pink-400 */ @@ -117,9 +139,20 @@ --transition-fast: all 0.15s ease; --transition-normal: all 0.3s ease; + /* Shadow colors */ + --shadow-color-light: rgba(0, 0, 0, 0.2); + --shadow-color-medium: rgba(0, 0, 0, 0.3); + --shadow-subtle-light: rgba(255, 255, 255, 0.04); + + /* Glass overlays */ + --glass-overlay-dark: rgba(30, 41, 59, 0.8); /* slate-800/80 */ + --glass-accent-90: rgba(99, 102, 241, 0.9); /* indigo-500/90 */ + /* Shadows - dark theme uses minimal shadows */ --shadow-sm: none; --shadow-md: none; + --shadow-dropdown: 0 4px 12px var(--shadow-color-medium); + --shadow-thumb: 0 2px 4px var(--shadow-color-light); --shadow-glow-green: 0 0 8px var(--green); --shadow-glow-purple: 0 0 8px var(--purple); @@ -220,6 +253,28 @@ body.theme-light { --step-indexed-access-result: #16a34a; --step-type-alias-start: #64748b; + /* Glass effects - light theme uses semi-transparent with actual color values */ + --glass-5: rgba(0, 0, 0, 0.03); + --glass-10: rgba(0, 0, 0, 0.06); + --glass-card: rgba(255, 255, 255, 0.8); + --glass-card-alt: rgba(255, 255, 255, 0.6); + --glass-input: rgba(255, 255, 255, 0.9); + --glass-menu: rgba(255, 255, 255, 0.98); + --glass-features: rgba(224, 231, 255, 0.4); /* indigo-100/40 */ + + /* Extended text colors - light theme */ + --text-white: #0f172a; /* inverted for light theme - slate-900 */ + --text-light: #334155; /* slate-700 */ + --text-muted: #475569; /* slate-600 */ + --indigo-lighter: #c7d2fe; /* indigo-200 */ + --indigo-dark: #312e81; /* indigo-900 for light gradient */ + + /* Focus ring - light theme */ + --focus-ring: rgba(79, 70, 229, 0.25); + + /* Hero gradient - light theme */ + --landing-hero-gradient: linear-gradient(to bottom right, var(--bg), var(--bg-secondary), rgba(199, 210, 254, 0.5)); + /* Shadows - light theme uses subtle shadows */ --shadow-sm: 0 1px 3px rgba(15, 23, 42, 0.08); --shadow-md: 0 2px 6px rgba(15, 23, 42, 0.1); @@ -270,7 +325,7 @@ input[type='range']::-webkit-slider-thumb { border-radius: 50%; background: var(--accent-highlight); cursor: pointer; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); + box-shadow: var(--shadow-thumb); margin-top: -5px; } @@ -281,7 +336,7 @@ input[type='range']::-moz-range-thumb { background: var(--accent-highlight); cursor: pointer; border: none; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); + box-shadow: var(--shadow-thumb); margin-top: -5px; } @@ -376,10 +431,10 @@ input[type='range']::-moz-range-progress { font-family: var(--font-sans); } -/* Hero section */ +/* Hero section - diagonal gradient with indigo tint */ .landing-hero { position: relative; - background: var(--bg); + background: var(--landing-hero-gradient); border-color: var(--border); } @@ -446,6 +501,7 @@ input[type='range']::-moz-range-progress { display: flex; flex-wrap: wrap; gap: var(--spacing-sm); + margin-left: auto; } .landing-input-row { @@ -532,14 +588,14 @@ input[type='range']::-moz-range-progress { border-radius: var(--radius-full); font-size: var(--font-size-xs); line-height: 1rem; - background: var(--bg-highlight); - color: var(--text-secondary); + background: var(--glass-5); + color: var(--text-light); border: 1px solid var(--border); } /* Title styling */ .landing-title { - color: var(--foreground); + color: var(--text-white); font-size: 2.25rem; line-height: 2.5rem; font-weight: 800; @@ -548,12 +604,12 @@ input[type='range']::-moz-range-progress { } .landing-title-accent { - color: var(--accent-highlight); + color: var(--indigo-light); } /* Subtitle */ .landing-subtitle { - color: var(--text-secondary); + color: var(--text-light); font-size: 1.125rem; line-height: 1.75rem; margin-top: var(--spacing-md); @@ -561,7 +617,7 @@ input[type='range']::-moz-range-progress { /* Headings */ .landing-heading { - color: var(--foreground); + color: var(--text-white); } .landing-heading-lg { @@ -578,28 +634,27 @@ input[type='range']::-moz-range-progress { /* Text */ .landing-text { - color: var(--text-secondary); + color: var(--text-light); } .landing-text-muted { - color: var(--text-tertiary); + color: var(--text-muted); } /* Labels */ .landing-label { - color: var(--text-secondary); + color: var(--text-light); font-size: var(--font-size-sm); } /* Links */ .landing-link { - color: var(--accent-highlight); - text-decoration: underline; - text-underline-offset: 4px; + color: var(--indigo-light); + text-decoration: none; } .landing-link:hover { - color: var(--accent-primary-alt); + color: var(--indigo-lighter); } /* Buttons */ @@ -607,15 +662,16 @@ input[type='range']::-moz-range-progress { display: inline-flex; align-items: center; justify-content: center; - padding: var(--spacing-md) var(--spacing-lg); + padding: var(--spacing-md) var(--spacing-xxl); background: var(--accent-primary); - color: var(--btn-accent-text); + color: var(--text-white); border: none; border-radius: var(--radius-lg); font-weight: 600; font-size: var(--font-size-md); cursor: pointer; transition: var(--transition-fast); + text-decoration: none; } .landing-btn-primary:hover { @@ -627,24 +683,25 @@ input[type='range']::-moz-range-progress { align-items: center; justify-content: center; padding: var(--spacing-md) var(--spacing-lg); - background: var(--bg-highlight); + background: var(--glass-5); color: var(--foreground); border: 1px solid var(--border-medium); border-radius: var(--radius-lg); font-size: var(--font-size-md); cursor: pointer; transition: var(--transition-fast); + text-decoration: none; } .landing-btn-secondary:hover { - background: var(--bg-active); + background: var(--glass-10); } .landing-btn-outline { display: inline-flex; align-items: center; justify-content: center; - padding: var(--spacing-md) var(--spacing-lg); + padding: var(--spacing-md) var(--spacing-xxl); background: transparent; color: var(--foreground); border: 1px solid var(--border-medium); @@ -652,44 +709,46 @@ input[type='range']::-moz-range-progress { font-size: var(--font-size-md); cursor: pointer; transition: var(--transition-fast); + text-decoration: none; } .landing-btn-outline:hover { - background: var(--bg-highlight); + background: var(--glass-5); } /* Cards */ .landing-card { - background: var(--bg-secondary); + background: var(--glass-card); border: 1px solid var(--border); border-radius: 1rem; padding: var(--spacing-xxl); + box-shadow: 0 0 0 1px var(--shadow-subtle-light); } .landing-card-alt { - background: var(--bg-secondary); + background: var(--glass-card-alt); border: 1px solid var(--border); border-radius: 1rem; padding: var(--spacing-xxl); } .landing-card-inner { - background: var(--bg-highlight); + background: var(--glass-5); border: 1px solid var(--border); border-radius: 0.75rem; padding: var(--spacing-xxl); } -/* Features section */ +/* Features section - with indigo tint */ .landing-features-card { - background: var(--bg-secondary); + background: var(--glass-features); border: 1px solid var(--border); border-radius: 1rem; padding: var(--spacing-xxl); } .landing-feature-card { - background: var(--bg-highlight); + background: var(--glass-5); border: 1px solid var(--border); border-radius: 0.75rem; padding: var(--spacing-lg); @@ -697,8 +756,8 @@ input[type='range']::-moz-range-progress { /* Code styling */ .landing-code { - background: var(--bg-highlight); - color: var(--text-secondary); + background: var(--glass-10); + color: var(--text-light); font-family: var(--font-mono); padding: 0.125rem 0.375rem; border-radius: var(--radius-sm); @@ -707,7 +766,7 @@ input[type='range']::-moz-range-progress { /* Input fields */ .landing-input { - background: var(--bg); + background: var(--glass-input); color: var(--foreground); border: 1px solid var(--border); border-radius: var(--radius-lg); @@ -719,7 +778,7 @@ input[type='range']::-moz-range-progress { .landing-input:focus { border-color: var(--accent-primary); outline: none; - box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.3); + box-shadow: 0 0 0 2px var(--focus-ring); } .landing-input::placeholder { @@ -728,7 +787,7 @@ input[type='range']::-moz-range-progress { /* Textarea */ .landing-textarea { - background: var(--bg); + background: var(--glass-input); color: var(--foreground); border: 1px solid var(--border); } @@ -736,7 +795,7 @@ input[type='range']::-moz-range-progress { .landing-textarea:focus { border-color: var(--accent-primary); outline: none; - box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.3); + box-shadow: 0 0 0 2px var(--focus-ring); } .landing-textarea::placeholder { @@ -745,7 +804,7 @@ input[type='range']::-moz-range-progress { /* Output area */ .landing-output { - background: var(--bg); + background: var(--glass-input); color: var(--foreground); border: 1px solid var(--border); font-family: var(--font-mono); @@ -759,7 +818,7 @@ input[type='range']::-moz-range-progress { /* Video container */ .landing-video-container { position: relative; - background: var(--bg); + background: var(--glass-input); border: 1px solid var(--border); border-radius: 0.75rem; overflow: hidden; @@ -773,7 +832,7 @@ input[type='range']::-moz-range-progress { display: flex; align-items: center; justify-content: center; - background: var(--bg-highlight) url('/ts-debugger-poster.jpg') center/contain no-repeat; + background: var(--glass-overlay-dark) url('/ts-debugger-poster.jpg') center/contain no-repeat; cursor: pointer; border: none; z-index: 1; @@ -789,7 +848,7 @@ input[type='range']::-moz-range-progress { /* Video placeholder (legacy) */ .landing-video-placeholder { - background: var(--bg); + background: var(--glass-input); border: 1px solid var(--border); border-radius: 0.75rem; overflow: hidden; @@ -819,7 +878,7 @@ input[type='range']::-moz-range-progress { height: 3.5rem; border-radius: 9999px; margin: 0 auto; - background: var(--bg-highlight); + background: var(--glass-5); border: 1px solid var(--border); color: var(--foreground); font-size: 1.5rem; @@ -852,7 +911,7 @@ body.theme-light .landing-card { width: 2.25rem; height: 2.25rem; border-radius: var(--radius-lg); - background: var(--bg-highlight); + background: var(--glass-5); border: 1px solid var(--border); color: var(--foreground); font-size: 1.125rem; @@ -861,7 +920,7 @@ body.theme-light .landing-card { } .landing-theme-btn:hover { - background: var(--bg-active); + background: var(--glass-10); } .landing-theme-menu { @@ -873,9 +932,9 @@ body.theme-light .landing-card { border-radius: var(--radius-lg); overflow: hidden; z-index: var(--z-dropdown); - background: var(--bg-secondary); + background: var(--glass-menu); border: 1px solid var(--border); - box-shadow: var(--shadow-md); + box-shadow: var(--shadow-dropdown); } .landing-theme-option { @@ -894,11 +953,11 @@ body.theme-light .landing-card { } .landing-theme-option:hover { - background: var(--bg-highlight); + background: var(--glass-5); } .landing-theme-option.selected { - background: var(--bg-active); + background: var(--glass-10); color: var(--accent-highlight); } @@ -919,26 +978,50 @@ body.theme-light .landing-card { } .landing-example-btn:hover { - background: var(--bg-highlight); + background: var(--glass-5); border-color: var(--accent-primary); } .landing-example-btn.selected { - background: var(--bg-active); + background: var(--glass-10); border-color: var(--accent-primary); color: var(--accent-highlight); } /* Why list */ .landing-why-list { - list-style: none; - padding-left: 0; + list-style: disc; + padding-left: 1.75rem; + margin-top: var(--spacing-md); } .landing-why-list li { + margin-top: var(--spacing-sm); +} + +/* Scroll to top button */ +.landing-scroll-top { + position: fixed; + bottom: 2rem; + right: 2rem; display: flex; - gap: var(--spacing-sm); - margin-top: var(--spacing-md); + align-items: center; + justify-content: center; + width: 3rem; + height: 3rem; + border-radius: 9999px; + background: var(--glass-accent-90); + border: 1px solid var(--border-medium); + color: var(--text-white); + cursor: pointer; + transition: var(--transition-fast); + box-shadow: var(--shadow-dropdown); + z-index: var(--z-fixed); +} + +.landing-scroll-top:hover { + background: var(--accent-primary-alt); + transform: translateY(-2px); } /* GitHub link for landing page */ @@ -949,14 +1032,14 @@ body.theme-light .landing-card { width: 2.25rem; height: 2.25rem; border-radius: var(--radius-lg); - background: var(--bg-highlight); + background: var(--glass-5); border: 1px solid var(--border); color: var(--text-secondary); transition: var(--transition-fast); } .landing-github-link:hover { - background: var(--bg-active); + background: var(--glass-10); color: var(--foreground); }