From 1811889ed92b123d05cce6885473768bf60b0734 Mon Sep 17 00:00:00 2001 From: chihlasm Date: Mon, 6 Apr 2026 20:17:47 +0000 Subject: [PATCH] chore: update docs and redesign landing page hero - CLAUDE.md: correct Docker container names, update migration format docs (hash IDs now default), fix Node path in Lesson 63, update design system values to electric blue accent, add retracted lessons note, add GitNexus section - .gitignore: add .gitnexus - Landing page: replace animated chat preview with ticket-comparison hero layout; remove backdrop-filter from scrolled nav (aligns with design system); clean up removed chat animation CSS Co-Authored-By: Claude Sonnet 4.6 --- .gitignore | 1 + CLAUDE.md | 156 ++++++++++--- frontend/src/pages/LandingPage.tsx | 51 ----- frontend/src/styles/landing.css | 346 ++++++++++++++++++----------- 4 files changed, 343 insertions(+), 211 deletions(-) diff --git a/.gitignore b/.gitignore index e6cfa118..758ce880 100644 --- a/.gitignore +++ b/.gitignore @@ -233,3 +233,4 @@ package.json package-lock.json .worktrees/ .gstack/ +.gitnexus diff --git a/CLAUDE.md b/CLAUDE.md index 3ebb8970..4ce6373a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,6 +1,6 @@ # CLAUDE.md - Patherly / ResolutionFlow Project Context -> **Last Updated:** March 27, 2026 +> **Last Updated:** April 6, 2026 --- @@ -16,7 +16,8 @@ | Context | Name Used | |---------|-----------| -| Repository / directory / database / Docker | `patherly` / `patherly_postgres` | +| Repository / directory / database | `patherly` (internal name) | +| Docker containers | `resolutionflow_postgres`, `resolutionflow_frontend`, `resolutionflow_backend` | | Backend, frontend UI, production URLs | **ResolutionFlow** | - **Design system:** [DESIGN-SYSTEM.md](DESIGN-SYSTEM.md) — THE source of truth for all design decisions @@ -44,7 +45,7 @@ - **Phase:** Go-to-Market Validation (Pre-PMF) - **Backend:** Complete (55+ API endpoints, 100+ integration tests) - **Frontend:** Core features complete, Tree Editor functional -- **Database:** PostgreSQL with Docker, 98 migrations +- **Database:** PostgreSQL with Docker, 101 migrations - **Detailed status:** [CURRENT-STATE.md](CURRENT-STATE.md) ### What's In Progress @@ -96,7 +97,7 @@ patherly/ │ │ ├── services/knowledge_flywheel.py # AI session analysis → flow proposals │ │ ├── services/knowledge_flywheel_scheduler.py # APScheduler job for batch analysis │ │ └── services/knowledge_gap_service.py # Weak options & escalation signal detection -│ ├── alembic/ # Database migrations (001-029+) +│ ├── alembic/ # Database migrations (001-070 sequential, then hash IDs) │ ├── scripts/ # seed_data.py, seed_trees.py │ └── tests/ # pytest integration tests ├── frontend/ @@ -188,8 +189,8 @@ Official ConnectWise developer guides live in `docs/connectwise/best-practices/` ## Development Commands ```powershell -# Start PostgreSQL -docker start patherly_postgres +# Start PostgreSQL (run from VPS SSH — docker not available inside code-server, see Lesson 103) +docker start resolutionflow_postgres # Backend (from backend/) source venv/bin/activate # Linux/Mac @@ -203,21 +204,19 @@ npm run dev pytest --override-ini="addopts=" # First time only: create test database -docker exec -it patherly_postgres psql -U postgres -c "CREATE DATABASE patherly_test;" +docker exec -it resolutionflow_postgres psql -U postgres -c "CREATE DATABASE resolutionflow_test;" # Frontend build (IMPORTANT: stricter than tsc --noEmit — always use as final check) cd frontend && npm run build # Database migrations cd backend && alembic upgrade head -alembic revision --autogenerate -m "Description" --rev-id=NNN # NNN = next sequential number -# IMPORTANT: Migrations use sequential 3-digit IDs (001, 002, ..., 068, 069). -# Check the latest: ls backend/alembic/versions/ | grep -E '^\d{3}_' | sort | tail -1 -# The revision ID and filename prefix MUST match (e.g., revision="068", file=068_description.py). -# down_revision MUST point to the previous sequential number. Never use hex hash IDs for new migrations. +alembic revision --autogenerate -m "Description" +# Sequential 3-digit IDs (001–070) were used historically. New migrations use Alembic's default hex hash IDs. +# Do NOT pass --rev-id — let Alembic generate the hash automatically. -# Access PostgreSQL -docker exec -it patherly_postgres psql -U postgres -d patherly +# Access PostgreSQL (run from VPS SSH — docker not available inside code-server, see Lesson 103) +docker exec -it resolutionflow_postgres psql -U postgres -d resolutionflow # Seed data cd backend && pip install httpx && python -m scripts.seed_trees @@ -292,7 +291,7 @@ gh run view --json jobs --jq '.jobs[] | {name: .name, conclusion: .conclusi **62. Playwright strict mode — scope selectors to avoid ambiguity:** Step titles appear in both the sidebar checklist and main content heading. Use `getByRole('heading', { name })` for the main content, or scope with `page.locator('.animate-scale-in')` for command palette items. `getByText()` frequently matches multiple elements due to the sidebar + main content layout. -**63. Node 20 required for frontend builds:** Vite 7+ requires Node 20.19+. The system Node may be v18; use nvm: `export NVM_DIR="$HOME/.nvm" && source "$NVM_DIR/nvm.sh" && nvm use 20`. For direct binary access without nvm sourcing: `PATH="/home/michaelchihlas/.nvm/versions/node/v20.19.0/bin:$PATH"`. +**63. Node 20 required for frontend builds:** Vite 7+ requires Node 20.19+. The system Node may be v18; use nvm: `export NVM_DIR="$HOME/.nvm" && source "$NVM_DIR/nvm.sh" && nvm use 20`. For direct binary access without nvm sourcing: `PATH="$HOME/.nvm/versions/node/v20.19.0/bin:$PATH"`. **64. PostHog product analytics:** Initialized via `PostHogProvider` in `main.tsx` with explicit `posthog.init()` + `client` prop pattern. Event helpers in `lib/analytics.ts` — use `analytics.eventName(props)` to track. `identifyUser()` called in `authStore.fetchUser()`, `resetAnalytics()` on logout. Env vars: `VITE_PUBLIC_POSTHOG_KEY`, `VITE_PUBLIC_POSTHOG_HOST`. Autocapture enabled. @@ -332,7 +331,7 @@ gh run view --json jobs --jq '.jobs[] | {name: .name, conclusion: .conclusi **82. `bun` requires PATH setup on devserver01:** `export BUN_INSTALL="$HOME/.bun" && export PATH="$BUN_INSTALL/bin:$PATH"`. The gstack browse binary and Playwright need this. Chromium system deps: `libatk1.0-0 libatk-bridge2.0-0 libcups2 libxkbcommon0 libatspi2.0-0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libasound2`. -**83. FlowPilot ActionBar is `position: fixed; bottom: 0`:** Any UI element placed in normal document flow below the session content will be hidden behind it. New fixed-position elements (like the message bar) must use `bottom: 68px` (action bar height) and the same `left: var(--sidebar-w)` pattern. The conversation column uses `pb-32` for clearance. +**83. ~~FlowPilot ActionBar fixed bottom~~ (Superseded by Lesson 93):** Actions moved to the page header. `FlowPilotActionBar` component exists but is no longer used in the main session flow. The only fixed-bottom element is the message input. **84. AI session `abandoned` status is fully wired:** `POST /ai-sessions/{id}/abandon` sets status to `abandoned` with optional `reason` param. Frontend: `aiSessionsApi.abandonSession()`, `useFlowPilotSession().abandonSession()`, "Close" button in `FlowPilotActionBar`. Redirects to `/sessions` after closing. @@ -344,6 +343,7 @@ gh run view --json jobs --jq '.jobs[] | {name: .name, conclusion: .conclusi **88. Charcoal palette — sidebar-darkest approach:** Sidebar `#0e1016`, page `#16181f`, cards `#1e2028`, borders `#2a2e3a`. This gives more contrast range than true-dark. All colors via CSS variables in `index.css` `@theme` block. Accent is electric blue (#60a5fa), not orange or cyan. +*(Lessons 89–91 were retracted.)* **92. `tsc -b` in Dockerfile is stricter than `npx tsc --noEmit`:** The production build (`tsc -b && vite build`) enforces `noUnusedLocals` and `noUnusedParameters` as hard errors. After any refactor that moves logic between components or removes features, trace every import and destructured prop to remove orphans. IDE warnings (yellow squiggles) flag these — check them before pushing. @@ -353,7 +353,7 @@ gh run view --json jobs --jq '.jobs[] | {name: .name, conclusion: .conclusi **95. Image upload → AI vision pipeline:** Paste/attach images → upload to Railway S3 bucket via `uploadsApi.upload()` → send `upload_ids` with chat message → backend fetches from S3 via `storage_service.download_file()` → resized via `storage_service.resize_image_for_vision()` (Pillow, 1568px max, PNG→JPEG) → base64-encoded → sent as Claude multimodal content blocks. Max 3 images/message. Images are NOT stored in conversation history (text-only). Vision helpers live in `storage_service.py`. -**96. `bg-accent` is ember orange — never use for code/kbd elements:** In Tailwind v4, `bg-accent` maps to `--color-accent: #f97316`. Use `bg-code` for code blocks, `bg-white/[0.12] border border-white/[0.06]` for inline code/badges, `bg-white/[0.08]` for kbd shortcuts. Orange is reserved for interactive elements only (buttons, active nav, links). +**96. `bg-accent` is electric blue — never use for code/kbd elements:** In Tailwind v4, `bg-accent` maps to `--color-accent: #60a5fa` (dark) / `#2563eb` (light). Use `bg-code` for code blocks, `bg-white/[0.12] border border-white/[0.06]` for inline code/badges, `bg-white/[0.08]` for kbd shortcuts. Blue accent is reserved for interactive elements only (buttons, active nav, links). Ember orange (#f97316) is deprecated — do not use. **97. Railway Object Storage (S3 bucket) is provisioned:** Bucket `resolutionflow-uploads` on Railway canvas. Variables: `STORAGE_ENDPOINT`, `STORAGE_ACCESS_KEY`, `STORAGE_SECRET_KEY`, `STORAGE_BUCKET_NAME`, `STORAGE_REGION` — mapped via variable references on the `patherly` backend service. Accessed via boto3 in `storage_service.py`. Pillow (`Pillow>=10.0.0`) + `libjpeg-dev`/`zlib1g-dev` in Dockerfile for image resize. @@ -390,16 +390,16 @@ gh run view --json jobs --jq '.jobs[] | {name: .name, conclusion: .conclusi **Source of truth:** [DESIGN-SYSTEM.md](DESIGN-SYSTEM.md) — always read this before making visual or UI decisions. -- **Theme:** Flat, high-contrast dark theme (Sentry/PostHog-inspired). No glass morphism, no backdrop blur, no ambient orbs, no gradient backgrounds on surfaces. Light mode planned. -- **Backgrounds:** `bg-page` (`#1a1c23`), `bg-sidebar` (`#10121a`), `bg-card` (`#22252e`), `bg-elevated` (`#2e3140`) -- **Cards:** `bg-card` with 1px `border-default` (`#2e3240`), 8px radius. No shadows, no blur, no gradients. Hover: `border-hover` (`#3d4252`) -- **Buttons:** Primary: solid `accent` (#f97316), white text, 5px radius. Ghost: transparent + 1px border, hover `bg-elevated` -- **Inputs:** `bg-input` (`#282b35`) with 1px `border-default`, 5px radius. Focus: `border-color: accent` + `box-shadow: 0 0 0 2px accent-dim` -- **Text:** `text-heading` (`#f0f2f5`) → `text-primary` (`#e2e5eb`) → `text-muted-foreground` (`#848b9b`) → `text-muted` (`#4f5666`). NEVER use `text-secondary` — in Tailwind v4 it maps to a surface color (#2e3140), not a text color. -- **Borders:** `border-default` (`#2e3240`), `border-hover` (`#3d4252`) -- **Functional colors:** `#34d399` (success), `#eab308` (warning), `#f87171` (danger) — each with `-dim` variant at 10% opacity -- **Accent:** Ember orange `#f97316` — used sparingly (≤5% of UI). `accent-dim` = `rgba(249,115,22,0.10)`, `accent-text` = `#fdba74` -- **Deprecated:** Do NOT use `glass-card`, `glass-stat`, `bg-gradient-brand`, `text-gradient-brand`, `backdrop-filter: blur()`, ambient orbs, purple gradients, or cyan accent (`#22d3ee`) +- **Theme:** Flat, high-contrast dark theme (Sentry/PostHog-inspired). No glass morphism, no backdrop blur, no ambient orbs, no gradient backgrounds on surfaces. Light mode fully specified (v6). +- **Backgrounds:** `bg-page` (`#16181f`), `bg-sidebar` (`#0e1016`), `bg-card` (`#1e2028`), `bg-elevated` (`#2a2d38`) +- **Cards:** `bg-card` with 1px `border-default` (`#2a2e3a`), 8px radius. No shadows, no blur, no gradients. Hover: `border-hover` (`#3d4252`) +- **Buttons:** Primary: solid `accent` (#60a5fa dark / #2563eb light), white text, 5px radius. Ghost: transparent + 1px border, hover `bg-elevated` +- **Inputs:** `bg-input` (`#252830`) with 1px `border-default`, 5px radius. Focus: `border-color: accent` + `box-shadow: 0 0 0 2px accent-dim` +- **Text:** `text-heading` (`#f0f2f5`) → `text-primary` (`#e2e5eb`) → `text-muted-foreground` (`#848b9b`) → `text-muted` (`#4f5666`). NEVER use `text-secondary` — in Tailwind v4 it maps to a surface color, not a text color. +- **Borders:** `border-default` (`#2a2e3a`), `border-hover` (`#3d4252`) +- **Functional colors:** `#34d399` (success), `#fbbf24` (warning/amber), `#f87171` (danger), `#67e8f9` (info/cyan) — each with `-dim` variant at 10% opacity +- **Accent:** Electric blue `#60a5fa` (dark) / `#2563eb` (light) — used sparingly (≤5% of UI). `accent-dim` = `rgba(96,165,250,0.10)`, `accent-text` = `#93c5fd` +- **Deprecated:** Do NOT use `glass-card`, `glass-stat`, `bg-gradient-brand`, `text-gradient-brand`, `backdrop-filter: blur()`, ambient orbs, purple gradients, ember orange (`#f97316`), or cyan (`#22d3ee`) as accent — cyan is now the info color only --- @@ -518,3 +518,105 @@ When a feature, fix, or significant piece of work is finished and merged/committ | Bugs & Fixes | CLAUDE.md → Critical Lessons Learned section | | Design System | [DESIGN-SYSTEM.md](DESIGN-SYSTEM.md) | | Dev Environment | [DEV-ENV.md](DEV-ENV.md) — 46.202.92.250 setup, Docker, CORS, networking | + + +# GitNexus — Code Intelligence + +This project is indexed by GitNexus as **resolutionflow** (14787 symbols, 31366 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely. + +> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first. + +## Always Do + +- **MUST run impact analysis before editing any symbol.** Before modifying a function, class, or method, run `gitnexus_impact({target: "symbolName", direction: "upstream"})` and report the blast radius (direct callers, affected processes, risk level) to the user. +- **MUST run `gitnexus_detect_changes()` before committing** to verify your changes only affect expected symbols and execution flows. +- **MUST warn the user** if impact analysis returns HIGH or CRITICAL risk before proceeding with edits. +- When exploring unfamiliar code, use `gitnexus_query({query: "concept"})` to find execution flows instead of grepping. It returns process-grouped results ranked by relevance. +- When you need full context on a specific symbol — callers, callees, which execution flows it participates in — use `gitnexus_context({name: "symbolName"})`. + +## When Debugging + +1. `gitnexus_query({query: ""})` — find execution flows related to the issue +2. `gitnexus_context({name: ""})` — see all callers, callees, and process participation +3. `READ gitnexus://repo/resolutionflow/process/{processName}` — trace the full execution flow step by step +4. For regressions: `gitnexus_detect_changes({scope: "compare", base_ref: "main"})` — see what your branch changed + +## When Refactoring + +- **Renaming**: MUST use `gitnexus_rename({symbol_name: "old", new_name: "new", dry_run: true})` first. Review the preview — graph edits are safe, text_search edits need manual review. Then run with `dry_run: false`. +- **Extracting/Splitting**: MUST run `gitnexus_context({name: "target"})` to see all incoming/outgoing refs, then `gitnexus_impact({target: "target", direction: "upstream"})` to find all external callers before moving code. +- After any refactor: run `gitnexus_detect_changes({scope: "all"})` to verify only expected files changed. + +## Never Do + +- NEVER edit a function, class, or method without first running `gitnexus_impact` on it. +- NEVER ignore HIGH or CRITICAL risk warnings from impact analysis. +- NEVER rename symbols with find-and-replace — use `gitnexus_rename` which understands the call graph. +- NEVER commit changes without running `gitnexus_detect_changes()` to check affected scope. + +## Tools Quick Reference + +| Tool | When to use | Command | +|------|-------------|---------| +| `query` | Find code by concept | `gitnexus_query({query: "auth validation"})` | +| `context` | 360-degree view of one symbol | `gitnexus_context({name: "validateUser"})` | +| `impact` | Blast radius before editing | `gitnexus_impact({target: "X", direction: "upstream"})` | +| `detect_changes` | Pre-commit scope check | `gitnexus_detect_changes({scope: "staged"})` | +| `rename` | Safe multi-file rename | `gitnexus_rename({symbol_name: "old", new_name: "new", dry_run: true})` | +| `cypher` | Custom graph queries | `gitnexus_cypher({query: "MATCH ..."})` | + +## Impact Risk Levels + +| Depth | Meaning | Action | +|-------|---------|--------| +| d=1 | WILL BREAK — direct callers/importers | MUST update these | +| d=2 | LIKELY AFFECTED — indirect deps | Should test | +| d=3 | MAY NEED TESTING — transitive | Test if critical path | + +## Resources + +| Resource | Use for | +|----------|---------| +| `gitnexus://repo/resolutionflow/context` | Codebase overview, check index freshness | +| `gitnexus://repo/resolutionflow/clusters` | All functional areas | +| `gitnexus://repo/resolutionflow/processes` | All execution flows | +| `gitnexus://repo/resolutionflow/process/{name}` | Step-by-step execution trace | + +## Self-Check Before Finishing + +Before completing any code modification task, verify: +1. `gitnexus_impact` was run for all modified symbols +2. No HIGH/CRITICAL risk warnings were ignored +3. `gitnexus_detect_changes()` confirms changes match expected scope +4. All d=1 (WILL BREAK) dependents were updated + +## Keeping the Index Fresh + +After committing code changes, the GitNexus index becomes stale. Re-run analyze to update it: + +```bash +npx gitnexus analyze +``` + +If the index previously included embeddings, preserve them by adding `--embeddings`: + +```bash +npx gitnexus analyze --embeddings +``` + +To check whether embeddings exist, inspect `.gitnexus/meta.json` — the `stats.embeddings` field shows the count (0 means no embeddings). **Running analyze without `--embeddings` will delete any previously generated embeddings.** + +> Claude Code users: A PostToolUse hook handles this automatically after `git commit` and `git merge`. + +## CLI + +| Task | Read this skill file | +|------|---------------------| +| Understand architecture / "How does X work?" | `.claude/skills/gitnexus/gitnexus-exploring/SKILL.md` | +| Blast radius / "What breaks if I change X?" | `.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md` | +| Trace bugs / "Why is X failing?" | `.claude/skills/gitnexus/gitnexus-debugging/SKILL.md` | +| Rename / extract / split / refactor | `.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md` | +| Tools, resources, schema reference | `.claude/skills/gitnexus/gitnexus-guide/SKILL.md` | +| Index, status, clean, wiki CLI commands | `.claude/skills/gitnexus/gitnexus-cli/SKILL.md` | + + diff --git a/frontend/src/pages/LandingPage.tsx b/frontend/src/pages/LandingPage.tsx index ba49969e..aaff9d10 100644 --- a/frontend/src/pages/LandingPage.tsx +++ b/frontend/src/pages/LandingPage.tsx @@ -180,57 +180,6 @@ export default function LandingPage() { Built by a 15-year MSP veteran who got tired of empty ticket notes.

-
-
-
-
-
- 🔒 - app.resolutionflow.com/pilot -
-
-
-
-
-
- You - User can't access shared drive after password reset -
-
-
-
- - FlowPilot is thinking… -
-
-
-
- FlowPilot - Likely a cached credential issue. Let's check: -
-
-
-
- FlowPilot - 1. Run klist purge to clear Kerberos tickets -
-
-
-
- FlowPilot - 2. Credential Manager → remove saved share entries -
-
-
-
- Auto-doc - 3 steps captured ✓ -
-
-
-
-
-
diff --git a/frontend/src/styles/landing.css b/frontend/src/styles/landing.css index 56f36fc1..313b4d95 100644 --- a/frontend/src/styles/landing.css +++ b/frontend/src/styles/landing.css @@ -74,9 +74,8 @@ } .landing-nav.scrolled { - background: rgba(20, 22, 29, 0.95); + background: #0d0f15; border-bottom: 1px solid var(--lp-border); - backdrop-filter: blur(8px); } .landing-nav-inner { @@ -230,19 +229,44 @@ /* ---- HERO ---- */ .landing-hero { - padding: 9rem 2rem 5rem; + padding: 10rem 2rem 8rem; + position: relative; + overflow: hidden; + min-height: 580px; +} + +/* Full-bleed image layer — positioned lower so terrain fills, hub upper-right */ +.landing-hero::before { + content: ''; + position: absolute; + inset: 0; + background: url('/images/hero_001.jpg') 58% 38% / cover no-repeat; + opacity: 0.72; + z-index: 0; +} + +/* Left-to-right bleed: solid dark where text lives, dissolves into raw image on the right */ +.landing-hero::after { + content: ''; + position: absolute; + inset: 0; + background: + linear-gradient(to right, #14161d 22%, rgba(20, 22, 29, 0.80) 38%, rgba(20, 22, 29, 0.20) 58%, transparent 78%), + linear-gradient(to top, #14161d 0%, rgba(20, 22, 29, 0) 16%); + z-index: 1; } .landing-hero-inner { max-width: 1200px; margin: 0 auto; - display: grid; - grid-template-columns: 1fr 1fr; - gap: 4rem; - align-items: center; + display: flex; + align-items: flex-start; + position: relative; + z-index: 2; } .landing-hero-content { + max-width: 520px; animation: landingFadeInUp 0.8s ease-out; } @@ -286,7 +310,7 @@ } .landing-hero-accent { - color: var(--lp-accent-text); + color: var(--lp-accent); } .landing-hero-sub { @@ -359,72 +383,205 @@ animation: landingPreviewEntrance 1s cubic-bezier(0.22, 1, 0.36, 1) 0.3s both; } -/* ---- PREVIEW WINDOW ---- */ -.landing-preview-window { +/* ---- TICKET COMPARISON (hero visual) ---- */ +.landing-ticket-comparison { + display: flex; + align-items: stretch; + gap: 0; + width: 100%; +} + +.landing-tc-col { + flex: 1; + display: flex; + flex-direction: column; + gap: 0.5rem; + min-width: 0; +} + +.landing-tc-label { + font-size: 0.6rem; + font-weight: 700; + letter-spacing: 0.1em; + text-transform: uppercase; + padding: 0 0.25rem; +} + +.landing-tc-label.before-label { + color: var(--lp-text-dim); +} + +.landing-tc-label.after-label { + color: var(--lp-accent); +} + +.landing-tc-card { border-radius: 8px; border: 1px solid var(--lp-border); background: var(--lp-card); - overflow: hidden; - box-shadow: 0 24px 80px rgba(0, 0, 0, 0.5); + padding: 0.875rem; + display: flex; + flex-direction: column; + gap: 0.5rem; + flex: 1; } -.landing-preview-titlebar { +.landing-tc-card.before-card { + opacity: 0.55; +} + +.landing-tc-card.after-card { + border-color: rgba(96, 165, 250, 0.28); + box-shadow: 0 0 36px rgba(96, 165, 250, 0.10), 0 16px 48px rgba(0, 0, 0, 0.55); +} + +.landing-tc-header { display: flex; align-items: center; - gap: 12px; - padding: 10px 14px; - background: rgba(255, 255, 255, 0.02); + justify-content: space-between; + padding-bottom: 0.5rem; border-bottom: 1px solid var(--lp-border); } -.landing-preview-dots { - display: flex; - gap: 6px; +.tc-ticket-id { + font-size: 0.65rem; + font-weight: 700; + color: var(--lp-text-secondary); + font-family: 'IBM Plex Sans', sans-serif; } -.landing-preview-dots span { - width: 10px; - height: 10px; - border-radius: 50%; - background: var(--lp-elevated); +.tc-status { + font-size: 0.58rem; + font-weight: 600; + padding: 2px 7px; + border-radius: 100px; + letter-spacing: 0.02em; } -.landing-preview-dots span:first-child { - background: #ef4444; +.tc-status.open { + background: rgba(248, 113, 113, 0.1); + color: #f87171; + border: 1px solid rgba(248, 113, 113, 0.2); } -.landing-preview-dots span:nth-child(2) { - background: #eab308; -} - -.landing-preview-dots span:last-child { - background: #22c55e; -} - -.landing-preview-url { - display: flex; - align-items: center; - gap: 6px; - padding: 3px 10px; - border-radius: 6px; - background: rgba(255, 255, 255, 0.03); - border: 1px solid var(--lp-border); - font-size: 0.6rem; - color: var(--lp-text-dim); - flex: 1; - max-width: 260px; -} - -.landing-lock-icon { +.tc-status.resolved { + background: rgba(52, 211, 153, 0.1); color: var(--lp-success); - font-size: 0.55rem; + border: 1px solid rgba(52, 211, 153, 0.2); } -.landing-preview-body { - padding: 1.25rem; - min-height: 260px; +.landing-tc-subject { + font-size: 0.7rem; + font-weight: 600; + color: var(--lp-text-heading); + line-height: 1.4; +} + +.landing-tc-notes-heading { + font-size: 0.58rem; + font-weight: 600; + color: var(--lp-text-dim); + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.landing-tc-notes { + display: flex; + flex-direction: column; + gap: 0.3rem; + flex: 1; +} + +.landing-tc-notes.before-notes { + padding: 0.6rem 0.75rem; + border-radius: 5px; + background: rgba(255, 255, 255, 0.02); + border: 1px dashed rgba(255, 255, 255, 0.06); + font-size: 0.65rem; + color: var(--lp-text-dim); + font-style: italic; + min-height: 80px; + align-items: flex-start; + justify-content: flex-start; +} + +.tc-note { + display: flex; + align-items: baseline; + gap: 5px; + font-size: 0.62rem; + color: var(--lp-text-secondary); + line-height: 1.5; + animation: tcNoteIn 0.4s cubic-bezier(0.22, 1, 0.36, 1) both; + animation-delay: calc(1.2s + var(--note-i, 0) * 0.55s); + opacity: 0; +} + +@keyframes tcNoteIn { + from { opacity: 0; transform: translateY(5px); } + to { opacity: 1; transform: translateY(0); } +} + +.tc-note.resolution-note { + margin-top: 0.15rem; + padding-top: 0.35rem; + border-top: 1px solid var(--lp-border); +} + +.tc-time { + font-size: 0.55rem; + color: var(--lp-text-dim); + font-family: 'JetBrains Mono', monospace; + flex-shrink: 0; + min-width: 28px; +} + +.tc-check { + color: var(--lp-success); + flex-shrink: 0; + font-size: 0.6rem; +} + +.tc-resolution-tag { + font-size: 0.52rem; + font-weight: 700; + padding: 1px 5px; + border-radius: 3px; + background: rgba(96, 165, 250, 0.12); + color: var(--lp-accent-text); + flex-shrink: 0; + letter-spacing: 0.02em; +} + +.landing-tc-footer { + font-size: 0.58rem; + padding-top: 0.4rem; + border-top: 1px solid var(--lp-border); + line-height: 1.4; +} + +.landing-tc-footer.before-footer { + color: var(--lp-text-dim); +} + +.landing-tc-footer.after-footer { + color: var(--lp-accent-text); + font-weight: 500; +} + +.landing-tc-divider { display: flex; align-items: center; + justify-content: center; + flex-shrink: 0; + width: 32px; + padding-top: 1.4rem; + color: var(--lp-text-dim); +} + +.landing-tc-divider svg { + width: 14px; + height: 14px; } /* ---- MOCK ELEMENTS ---- */ @@ -1255,79 +1412,6 @@ to { opacity: 1; transform: translateY(0) scale(1); } } -/* ---- CHAT ANIMATION ---- */ -.landing-chat-animated { - opacity: 0; - transform: translateX(-16px); - animation: landingChatSlideIn 0.5s cubic-bezier(0.22, 1, 0.36, 1) both; - animation-delay: calc(1.5s + var(--chat-index, 0) * 1.2s); -} - -.landing-chat-animated:nth-child(2) { - animation: landingTypingLifecycle 3s ease both; - animation-delay: 2.7s; -} - -.landing-chat-animated:nth-child(3) { animation-delay: 5.7s; } -.landing-chat-animated:nth-child(4) { animation-delay: 6.7s; } -.landing-chat-animated:nth-child(5) { animation-delay: 7.7s; } -.landing-chat-animated:nth-child(6) { animation-delay: 9s; } - -@keyframes landingChatSlideIn { - from { opacity: 0; transform: translateX(-16px); } - to { opacity: 1; transform: translateX(0); } -} - -@keyframes landingTypingLifecycle { - 0% { opacity: 0; transform: translateX(-16px); } - 10% { opacity: 1; transform: translateX(0); } - 75% { opacity: 1; transform: translateX(0); } - 90% { opacity: 0; transform: translateX(0); } - 100% { opacity: 0; height: 0; padding: 0; margin: 0; overflow: hidden; } -} - -.landing-typing-indicator { - display: flex; - align-items: center; - gap: 5px; - padding: 6px 10px; - border-radius: 6px; - background: var(--lp-accent-soft); - border: 1px solid rgba(96, 165, 250, 0.1); - width: fit-content; -} - -.landing-typing-indicator span { - display: block; - width: 5px; - height: 5px; - border-radius: 50%; - background: var(--lp-accent); - opacity: 0.5; - animation: landingTypingBounce 1s ease-in-out infinite; -} - -.landing-typing-indicator span:nth-child(2) { animation-delay: 0.15s; } -.landing-typing-indicator span:nth-child(3) { animation-delay: 0.3s; } - -.landing-typing-label { - font-size: 0.6rem; - color: var(--lp-accent); - font-weight: 500; - white-space: nowrap; - /* Override dot styles */ - width: auto !important; - height: auto !important; - border-radius: 0 !important; - background: transparent !important; - opacity: 1 !important; - animation: none !important; -} - -@keyframes landingTypingBounce { - 0%, 60%, 100% { transform: translateY(0); opacity: 0.4; } - 30% { transform: translateY(-4px); opacity: 1; } -} /* ---- SCROLL REVEAL ---- */ .landing-reveal { @@ -1617,7 +1701,6 @@ /* ---- REDUCED MOTION ---- */ @media (prefers-reduced-motion: reduce) { - .landing-chat-animated, .landing-hero-visual, .landing-hero-content { opacity: 1; @@ -1625,13 +1708,10 @@ animation: none; } - .landing-typing-indicator span { + .tc-note { + opacity: 1; + transform: none; animation: none; - opacity: 0.6; - } - - .landing-chat-animated:nth-child(2) { - display: none; } .landing-reveal {