Files
resolutionflow/docs/plans/2026-03-03-aesthetic-redesign-impl.md
chihlasm 4d2c4930fd feat: Slate & Ice Modern aesthetic redesign (#94)
* chore: update Google Fonts to Bricolage Grotesque, IBM Plex Sans, JetBrains Mono

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: update Tailwind config to Slate & Ice theme colors and fonts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: update CSS variables and glass-card utilities for Slate & Ice theme

- Replace all color variables with Slate & Ice palette
- Add glass system vars (--glass-bg, --glass-blur, --shadow-float)
- Replace legacy glass-card with new variable-driven glass classes
- Add breatheGlow, bellWobble, slideDown, fadeInRight keyframes
- Update font references to IBM Plex Sans and Bricolage Grotesque

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: recolor BrandLogo to cyan gradient, split BrandWordmark for gradient Flow text

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: update TopBar with glassmorphism backdrop and cyan accent styling

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: update Sidebar with glassmorphism backdrop

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add ambient atmosphere gradient orbs behind app shell

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: update QuickStats and SessionsPanel with glass-card styling

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add WeeklyCalendar, QuickActions, OpenSessions, RecentActivity dashboard components

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: redesign dashboard layout with calendar, open sessions, and glass-card panels

New layout: greeting → calendar+actions → sessions+stats → activity
Replaces old QuickStats and SessionsPanel with new dashboard components

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: replace remaining purple hex references with ice-cyan accent

Sweep of hardcoded purple hex values (#818cf8, #6366f1) replaced with
new cyan accent (#06b6d4) in QuickActions, RecentActivity, QuickLaunch,
and SVG brand assets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: update CLAUDE.md branding and design system for Slate & Ice Modern

Updated Last Updated date, branding section (fonts, colors, glass
utilities, atmosphere orbs), component styling rules, and Design System
section to reflect the new ice-cyan glassmorphism theme.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add Slate & Ice Modern design doc and implementation plan

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: redesign login page with Slate & Ice Modern design system

Apply glassmorphism styling, atmosphere orbs, branded wordmark, and
consistent design tokens to match the updated app shell aesthetic.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: raise TopBar z-index so profile dropdown renders above main content

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add AI assistant with in-session copilot and standalone chat with RAG

Implements three-phase AI assistant feature:
- Phase 0: RAG infrastructure with pgvector embeddings, Voyage AI integration,
  tree chunking service, and semantic search over team's flow library
- Phase 1: In-session copilot panel during flow navigation with contextual
  AI help, current step awareness, and suggested related flows
- Phase 2: Standalone AI chat page with persistent conversation history,
  pin/delete, and configurable retention policies (account-level)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add account management, email verification, AI fixes, and user guides

- Profile settings, account transfer, delete/leave account flows
- Email verification with JWT tokens and Resend integration
- AI assistant/copilot fixes: markdown rendering, shared RAG helpers,
  token tracking, input refocus, model_validate usage
- User guides hub + detail pages with 13 topic guides
- Sidebar and top bar navigation for guides

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: prevent stale chunk errors after deployments

- Set Cache-Control no-cache on index.html in nginx so browsers always
  fetch fresh chunk references after a deploy
- Auto-reload on chunk load failures (stale deploy detection) with
  loop prevention via sessionStorage
- Show friendly "App Updated" message if auto-reload doesn't resolve it

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add email verification toggle to admin settings

Adds platform-level toggle to enable/disable email verification.
When disabled, the verification banner is hidden and the send
endpoint returns 403.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 20:44:25 -05:00

46 KiB

Aesthetic Redesign Implementation Plan

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: Replace the current purple gradient theme with the approved Slate & Ice Modern design — glassmorphism, ice-cyan accent, new fonts, orchestrated animations, and a redesigned dashboard layout.

Architecture: Token-based theme swap via CSS variables + Tailwind config, followed by component-level updates. The design system tokens (colors, fonts, gradients, shadows) change in 3 files. Components then adopt new glass-card utilities and animation classes. The dashboard gets new panels (calendar, open sessions). No backend changes required.

Tech Stack: React 19, Tailwind CSS v3, CSS custom properties, Google Fonts (Bricolage Grotesque, IBM Plex Sans, JetBrains Mono)

Design Doc: docs/plans/2026-03-03-aesthetic-redesign-design.md Reference Mockup: /tmp/mockup-j-slate-ice-modern.html


Task 1: Update Google Fonts in index.html

Files:

  • Modify: frontend/index.html:10-13

Step 1: Replace the Google Fonts import

Change the font families from Plus Jakarta Sans / Inter / Outfit to Bricolage Grotesque / IBM Plex Sans / JetBrains Mono.

<!-- Replace line 13 -->
<!-- OLD -->
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=Inter:wght@400;500;600&family=Outfit:wght@400;500;600;700&display=swap" rel="stylesheet">

<!-- NEW -->
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:wght@400;600;700;800&family=IBM+Plex+Sans:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">

Also update the theme-color meta tag from #09090b to #101114:

<meta name="theme-color" content="#101114" />

Step 2: Verify the file looks correct

Open frontend/index.html and confirm the font link and meta tag are updated.

Step 3: Run frontend build to verify no errors

Run: cd frontend && npm run build Expected: Build succeeds

Step 4: Commit

git add frontend/index.html
git commit -m "chore: update Google Fonts to Bricolage Grotesque, IBM Plex Sans, JetBrains Mono"

Task 2: Update Tailwind config (colors, fonts, gradients)

Files:

  • Modify: frontend/tailwind.config.js

Step 1: Replace the tailwind config

Update font families, brand colors, and gradient background images. The shadcn/ui color system stays the same (it references CSS variables). Only the brand object, fontFamily, and backgroundImage change.

// frontend/tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
  darkMode: ["class"],
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {
      colors: {
        // ResolutionFlow Brand Colors — Slate & Ice
        brand: {
          gradient: {
            from: '#06b6d4',
            to: '#22d3ee',
          },
          dark: {
            DEFAULT: '#101114',
            card: '#14161a',
            surface: '#14161a',
          },
          text: {
            primary: '#f8fafc',
            secondary: '#8891a0',
            muted: '#5a6170',
          },
          border: 'rgba(255, 255, 255, 0.06)',
        },
        // shadcn/ui color system (unchanged — references CSS vars)
        border: "hsl(var(--border))",
        input: "hsl(var(--input))",
        ring: "hsl(var(--ring))",
        background: "hsl(var(--background))",
        foreground: "hsl(var(--foreground))",
        primary: {
          DEFAULT: "hsl(var(--primary))",
          foreground: "hsl(var(--primary-foreground))",
        },
        secondary: {
          DEFAULT: "hsl(var(--secondary))",
          foreground: "hsl(var(--secondary-foreground))",
        },
        destructive: {
          DEFAULT: "hsl(var(--destructive))",
          foreground: "hsl(var(--destructive-foreground))",
        },
        muted: {
          DEFAULT: "hsl(var(--muted))",
          foreground: "hsl(var(--muted-foreground))",
        },
        accent: {
          DEFAULT: "hsl(var(--accent))",
          foreground: "hsl(var(--accent-foreground))",
        },
        popover: {
          DEFAULT: "hsl(var(--popover))",
          foreground: "hsl(var(--popover-foreground))",
        },
        card: {
          DEFAULT: "hsl(var(--card))",
          foreground: "hsl(var(--card-foreground))",
        },
      },
      borderRadius: {
        lg: "var(--radius)",
        md: "calc(var(--radius) - 2px)",
        sm: "calc(var(--radius) - 4px)",
      },
      fontFamily: {
        sans: ['IBM Plex Sans', 'system-ui', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'sans-serif'],
        heading: ['Bricolage Grotesque', 'system-ui', 'sans-serif'],
        label: ['JetBrains Mono', 'monospace'],
      },
      backgroundImage: {
        'gradient-brand': 'linear-gradient(135deg, #06b6d4 0%, #22d3ee 100%)',
        'gradient-brand-hover': 'linear-gradient(135deg, #0891b2 0%, #06b6d4 100%)',
      },
    },
  },
  plugins: [],
}

Key changes:

  • fontFamily.sans: InterIBM Plex Sans
  • fontFamily.heading: Plus Jakarta SansBricolage Grotesque
  • fontFamily.label: OutfitJetBrains Mono (with monospace fallback)
  • brand.gradient.from: #818cf8#06b6d4
  • brand.gradient.to: #a78bfa#22d3ee
  • backgroundImage.gradient-brand: purple → cyan, angle 90deg135deg
  • backgroundImage.gradient-brand-hover: darker purple → darker cyan

Step 2: Run frontend build

Run: cd frontend && npm run build Expected: Build succeeds

Step 3: Commit

git add frontend/tailwind.config.js
git commit -m "chore: update Tailwind config to Slate & Ice theme colors and fonts"

Task 3: Update CSS variables and utilities in index.css

Files:

  • Modify: frontend/src/index.css

Step 1: Update the :root CSS variables

Replace the existing :root block with Slate & Ice values. The key changes:

  • --background: darker, cooler charcoal
  • --primary: purple → cyan
  • --card: slightly transparent for glass effect
  • --border: uses lower opacity white
  • New glass and shadow custom properties
@layer base {
  :root {
    /* ResolutionFlow Dark Theme — Slate & Ice Modern */
    --background: 228 12% 7%;        /* #101114 */
    --foreground: 210 40% 98%;       /* #f8fafc */
    --card: 220 10% 10%;             /* #171a1e — fallback for non-glass contexts */
    --card-foreground: 210 40% 98%;
    --popover: 220 10% 10%;
    --popover-foreground: 210 40% 98%;
    --primary: 187 72% 43%;          /* #06b6d4 — cyan */
    --primary-foreground: 228 12% 7%; /* dark text on cyan buttons */
    --secondary: 220 8% 14%;
    --secondary-foreground: 210 40% 98%;
    --muted: 220 8% 14%;
    --muted-foreground: 215 10% 58%; /* #8891a0 */
    --accent: 220 8% 14%;
    --accent-foreground: 210 40% 98%;
    --destructive: 350 81% 55%;      /* #f43f5e — rose */
    --destructive-foreground: 210 40% 98%;
    --border: 220 8% 14%;
    --input: 220 8% 14%;
    --ring: 187 72% 43%;             /* cyan focus ring */
    --radius: 0.75rem;

    /* App Shell tokens */
    --sidebar-w: 260px;
    --sidebar-bg: 228 12% 6%;       /* slightly darker than background */
    --sidebar-hover: 220 8% 14%;
    --sidebar-active: 187 72% 43% / 0.10;  /* cyan with 10% opacity */
    --border-subtle: 220 8% 12%;
    --text-dimmed: 218 10% 39%;      /* #5a6170 */

    /* Glass system */
    --glass-bg: rgba(24, 26, 31, 0.55);
    --glass-bg-hover: rgba(24, 26, 31, 0.7);
    --glass-border: rgba(255, 255, 255, 0.06);
    --glass-border-hover: rgba(255, 255, 255, 0.12);
    --glass-blur: blur(16px);
    --glass-blur-strong: blur(20px);
    --glass-blur-light: blur(12px);

    /* Shadow system */
    --shadow-float: 0 8px 32px rgba(0, 0, 0, 0.3);
    --shadow-float-hover: 0 12px 40px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.08);
    --shadow-cyan-glow: 0 8px 32px rgba(6, 182, 212, 0.08);

    /* Easing */
    --ease-out-smooth: cubic-bezier(0.4, 0, 0.2, 1);
  }
}

Step 2: Update the body and heading font rules

@layer base {
  /* ... scrollbar rules stay the same ... */

  body {
    @apply bg-background text-foreground;
    font-family: 'IBM Plex Sans', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  }

  h1, h2, h3, h4, h5, h6 {
    font-family: 'Bricolage Grotesque', system-ui, sans-serif;
    font-weight: 700;
    letter-spacing: -0.02em;
  }
}

Step 3: Replace legacy glass-card utilities with the new glass system

Remove the old legacy glass utilities and replace with the approved glass-card system:

@layer utilities {
  /* ... keep animate-* and btn-press utilities unchanged ... */

  /* Brand gradient text */
  .text-gradient-brand {
    @apply bg-gradient-brand bg-clip-text text-transparent;
  }

  /* Glass card — interactive with hover lift */
  .glass-card {
    background: var(--glass-bg);
    backdrop-filter: var(--glass-blur);
    -webkit-backdrop-filter: var(--glass-blur);
    border: 1px solid var(--glass-border);
    border-radius: 16px;
    box-shadow: var(--shadow-float);
    transition: transform 200ms var(--ease-out-smooth),
                border-color 200ms var(--ease-out-smooth),
                box-shadow 200ms var(--ease-out-smooth);
  }
  .glass-card:hover {
    transform: scale(1.02);
    border-color: var(--glass-border-hover);
    box-shadow: var(--shadow-float-hover);
  }

  /* Glass card — static, no hover transform */
  .glass-card-static {
    background: var(--glass-bg);
    backdrop-filter: var(--glass-blur);
    -webkit-backdrop-filter: var(--glass-blur);
    border: 1px solid var(--glass-border);
    border-radius: 16px;
    box-shadow: var(--shadow-float);
  }
}

Step 4: Add new animation keyframes

Add these after the existing keyframe definitions (keep existing ones, add new):

@keyframes slideDown {
  from { transform: translateY(-100%); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

@keyframes slideInLeft {
  from { transform: translateX(-100%); opacity: 0; }
  to { transform: translateX(0); opacity: 1; }
}

@keyframes fadeInRight {
  from { transform: translateX(30px); opacity: 0; }
  to { transform: translateX(0); opacity: 1; }
}

@keyframes breatheGlow {
  from { box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), 0 0 20px rgba(6, 182, 212, 0.04); }
  to { box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), 0 0 30px rgba(6, 182, 212, 0.12); }
}

@keyframes bellWobble {
  0% { transform: rotate(0deg); }
  20% { transform: rotate(8deg); }
  40% { transform: rotate(-6deg); }
  60% { transform: rotate(4deg); }
  80% { transform: rotate(-2deg); }
  100% { transform: rotate(0deg); }
}

Step 5: Update Sonner toast font reference

In the [data-sonner-toast] rules, update font-family from 'Inter' to 'IBM Plex Sans':

[data-sonner-toast] {
  /* ... */
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
}
[data-sonner-toast] [data-title] {
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  /* ... */
}

Step 6: Run frontend build

Run: cd frontend && npm run build Expected: Build succeeds

Step 7: Commit

git add frontend/src/index.css
git commit -m "feat: update CSS variables and glass-card utilities for Slate & Ice theme"

Task 4: Update BrandLogo and BrandWordmark

Files:

  • Modify: frontend/src/components/common/BrandLogo.tsx
  • Modify: frontend/src/components/common/BrandWordmark.tsx

Step 1: Recolor BrandLogo SVG to use cyan gradient

The structure stays the same, but colors change from white to cyan gradient. Add a <defs> block with a linear gradient and reference it.

In BrandLogo.tsx, update the SVG to use cyan gradient fills instead of plain white. Change all fill="white" to fill="url(#logoGrad)" and add the gradient definition:

import { cn } from '@/lib/utils'

interface BrandLogoProps {
  size?: 'sm' | 'lg'
  className?: string
}

export function BrandLogo({ size = 'sm', className }: BrandLogoProps) {
  const sizeClasses = size === 'sm' ? 'h-8 w-8' : 'h-20 w-20'

  const strokeBase = size === 'sm' ? 1 : 2
  const strokeThick = size === 'sm' ? 1.25 : 2.5
  const dashArray = size === 'sm' ? '1 1.5' : '2 3'
  const nodeR = size === 'sm' ? { outer: 2.5, inner: 2.75 } : { outer: 5, inner: 5.5 }
  const hubR = size === 'sm' ? { glow: 5, solid: 3.5 } : { glow: 10, solid: 7 }

  const vb = size === 'sm' ? '0 0 40 40' : '0 0 80 80'
  const s = size === 'sm' ? 1 : 2
  const gradId = size === 'sm' ? 'logoGradSm' : 'logoGradLg'

  return (
    <svg viewBox={vb} fill="none" className={cn(sizeClasses, className)}>
      <defs>
        <linearGradient id={gradId} x1="0" y1="0" x2={String(40 * (size === 'sm' ? 1 : 2))} y2={String(40 * (size === 'sm' ? 1 : 2))} gradientUnits="userSpaceOnUse">
          <stop offset="0%" stopColor="#06b6d4" />
          <stop offset="100%" stopColor="#22d3ee" />
        </linearGradient>
      </defs>

      {/* Input nodes */}
      <circle cx={5 * s} cy={7 * s} r={nodeR.outer} fill={`url(#${gradId})`} opacity="0.5" />
      <circle cx={5 * s} cy={15 * s} r={nodeR.inner} fill={`url(#${gradId})`} opacity="0.7" />
      <circle cx={5 * s} cy={25 * s} r={nodeR.inner} fill={`url(#${gradId})`} opacity="0.7" />
      <circle cx={5 * s} cy={33 * s} r={nodeR.outer} fill={`url(#${gradId})`} opacity="0.5" />

      {/* Connecting lines */}
      <path d={`M${7.5 * s} ${7 * s}L${14 * s} ${17 * s}`} stroke={`url(#${gradId})`} strokeWidth={strokeBase} strokeLinecap="round" strokeDasharray={dashArray} opacity="0.4" />
      <path d={`M${7.75 * s} ${15 * s}L${14 * s} ${19 * s}`} stroke={`url(#${gradId})`} strokeWidth={strokeBase} strokeLinecap="round" opacity="0.5" />
      <path d={`M${7.75 * s} ${25 * s}L${14 * s} ${21 * s}`} stroke={`url(#${gradId})`} strokeWidth={strokeBase} strokeLinecap="round" opacity="0.5" />
      <path d={`M${7.5 * s} ${33 * s}L${14 * s} ${23 * s}`} stroke={`url(#${gradId})`} strokeWidth={strokeBase} strokeLinecap="round" strokeDasharray={dashArray} opacity="0.4" />

      {/* Central hub */}
      <circle cx={18 * s} cy={20 * s} r={hubR.glow} fill={`url(#${gradId})`} opacity="0.15" />
      <circle cx={18 * s} cy={20 * s} r={hubR.solid} fill={`url(#${gradId})`} opacity="0.9" />

      {/* Output arrow */}
      <path d={`M${21.5 * s} ${20 * s}H${35 * s}M${35 * s} ${20 * s}L${30 * s} ${15 * s}M${35 * s} ${20 * s}L${30 * s} ${25 * s}`} stroke={`url(#${gradId})`} strokeWidth={strokeThick} strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  )
}

Step 2: Update BrandWordmark to use cyan gradient for "Flow"

In BrandWordmark.tsx, split the text so "Resolution" is white and "Flow" uses the gradient text:

import { cn } from '@/lib/utils'

interface BrandWordmarkProps {
  size?: 'sm' | 'lg'
  className?: string
}

export function BrandWordmark({ size = 'sm', className }: BrandWordmarkProps) {
  return (
    <span
      className={cn(
        'font-heading font-bold tracking-tight',
        size === 'sm' ? 'text-xl' : 'text-3xl',
        className
      )}
    >
      <span className="text-foreground">Resolution</span>
      <span className="text-gradient-brand">Flow</span>
    </span>
  )
}

Step 3: Run frontend build

Run: cd frontend && npm run build Expected: Build succeeds

Step 4: Commit

git add frontend/src/components/common/BrandLogo.tsx frontend/src/components/common/BrandWordmark.tsx
git commit -m "feat: recolor BrandLogo to cyan gradient, split BrandWordmark for gradient Flow text"

Task 5: Update TopBar with glassmorphism and new styles

Files:

  • Modify: frontend/src/components/layout/TopBar.tsx

Step 1: Update the TopBar component

Key changes:

  • Remove bg-gradient-brand wrapper from logo icon (logo icon is now standalone with gradient fill)
  • Avatar: change from rounded-full to rounded-[10px] (rounded square)
  • Add subtle cyan bottom glow line via after: pseudo-element (handled in CSS, not JSX)
  • Update topbar class for glassmorphism: replace bg-background with glass styling

In TopBar.tsx, update the header element's className:

// Line 57 — replace the header className:
<header className="topbar flex items-center gap-4 border-b px-4"
  style={{
    background: 'rgba(16, 17, 20, 0.6)',
    backdropFilter: 'var(--glass-blur-strong)',
    WebkitBackdropFilter: 'var(--glass-blur-strong)',
    borderColor: 'var(--glass-border)',
  }}
>

Update the logo area (lines 59-70). Remove the gradient wrapper div, show icon directly:

<Link
  to="/"
  className="flex items-center gap-2.5 pr-4 transition-all duration-200"
>
  <BrandLogo size="sm" className="h-7 w-7 shrink-0" />
  <span className="text-sm font-heading font-bold tracking-tight whitespace-nowrap">
    <span className="text-foreground">Resolution</span>
    <span className="text-gradient-brand">Flow</span>
  </span>
</Link>

Update the avatar button (line 107-109). Change from rounded-full to rounded-[10px]:

<button
  onClick={() => setUserMenuOpen(!userMenuOpen)}
  className="flex h-8 w-8 items-center justify-center rounded-[10px] bg-gradient-brand text-xs font-heading font-bold text-primary-foreground hover:opacity-90 transition-opacity"
  title={user?.name || user?.email || 'User'}
>

Step 2: Run frontend build

Run: cd frontend && npm run build Expected: Build succeeds

Step 3: Commit

git add frontend/src/components/layout/TopBar.tsx
git commit -m "feat: update TopBar with glassmorphism backdrop and cyan accent styling"

Task 6: Update Sidebar and NavItem with glassmorphism

Files:

  • Modify: frontend/src/components/layout/Sidebar.tsx
  • Modify: frontend/src/components/layout/NavItem.tsx

Step 1: Update Sidebar background

In Sidebar.tsx, line 66, update the nav element to use glass background:

<nav
  className="sidebar flex flex-col border-r"
  style={{
    background: 'rgba(16, 17, 20, 0.5)',
    backdropFilter: 'var(--glass-blur-light)',
    WebkitBackdropFilter: 'var(--glass-blur-light)',
    borderColor: 'var(--glass-border)',
  }}
  onWheel={handleSidebarWheel}
>

Also update the divider borders from border-[hsl(var(--border-subtle))] to use glass border:

<div style={{ borderColor: 'var(--glass-border)' }} className="border-b" />

Step 2: Update NavItem active indicator

In NavItem.tsx, the active indicator bar (line 48 collapsed, line 75 expanded) uses bg-gradient-brand which will automatically pick up the new cyan gradient from Tailwind config. No code changes needed for the gradient bar itself.

However, update the --sidebar-active background. Since we already changed the CSS variable in Task 3 to use cyan (187 72% 43% / 0.10), the bg-[hsl(var(--sidebar-active))] references will automatically update. No further changes needed in NavItem.tsx.

Step 3: Run frontend build

Run: cd frontend && npm run build Expected: Build succeeds

Step 4: Commit

git add frontend/src/components/layout/Sidebar.tsx frontend/src/components/layout/NavItem.tsx
git commit -m "feat: update Sidebar with glassmorphism backdrop"

Task 7: Add atmosphere orbs to AppLayout

Files:

  • Modify: frontend/src/components/layout/AppLayout.tsx

Step 1: Add the two ambient gradient orbs

In AppLayout.tsx, add two fixed-position gradient orbs before the app-shell div. These create subtle ambient light effects behind the glass cards.

Find the return statement and add the orbs right before or inside the app-shell wrapper:

{/* Atmosphere orbs — ambient light behind glass */}
<div
  className="pointer-events-none fixed z-0"
  style={{
    top: '-120px',
    right: '-80px',
    width: '600px',
    height: '600px',
    borderRadius: '50%',
    background: 'radial-gradient(circle, rgba(6, 182, 212, 0.15) 0%, rgba(6, 182, 212, 0.04) 40%, transparent 70%)',
    filter: 'blur(60px)',
  }}
/>
<div
  className="pointer-events-none fixed z-0"
  style={{
    bottom: '-100px',
    left: '-60px',
    width: '500px',
    height: '500px',
    borderRadius: '50%',
    background: 'radial-gradient(circle, rgba(99, 102, 241, 0.08) 0%, rgba(99, 102, 241, 0.02) 40%, transparent 70%)',
    filter: 'blur(50px)',
  }}
/>

Make sure the app-shell div has position: relative; z-index: 1; so content sits above the orbs (add relative z-[1] to the app-shell class if not already).

Step 2: Run frontend build

Run: cd frontend && npm run build Expected: Build succeeds

Step 3: Commit

git add frontend/src/components/layout/AppLayout.tsx
git commit -m "feat: add ambient atmosphere gradient orbs behind app shell"

Task 8: Update QuickStats component with glass-card styling

Files:

  • Modify: frontend/src/components/dashboard/QuickStats.tsx

Step 1: Update stat card styling

Replace the flat bg-card border border-border with the new glass-card class:

export function QuickStats({ stats }: QuickStatsProps) {
  return (
    <div className="grid grid-cols-2 gap-3 sm:grid-cols-4">
      {stats.map((stat, i) => (
        <div
          key={stat.label}
          className={cn(
            'glass-card p-4 fade-in',
            i === 0 && 'active-glow'
          )}
          style={{ animationDelay: `${50 + i * 30}ms` }}
        >
          <p className="font-label text-[0.625rem] font-medium uppercase tracking-[0.1em] text-muted-foreground">
            {stat.label}
          </p>
          <p
            className={cn(
              'mt-1 font-heading text-2xl font-extrabold tracking-tight',
              stat.gradient && 'text-gradient-brand',
              stat.color
            )}
            style={stat.color && !stat.color.startsWith('text-') ? { color: stat.color } : undefined}
          >
            {stat.value}
          </p>
          {stat.meta && (
            <p className="mt-0.5 text-[0.6875rem] text-[hsl(var(--text-dimmed))]">{stat.meta}</p>
          )}
        </div>
      ))}
    </div>
  )
}

Also add the active-glow keyframe class to index.css if not already present (the breatheGlow keyframe was added in Task 3). Add this utility:

/* In index.css @layer utilities */
.active-glow {
  animation: breatheGlow 3s ease-in-out infinite alternate;
}

Step 2: Run frontend build

Run: cd frontend && npm run build Expected: Build succeeds

Step 3: Commit

git add frontend/src/components/dashboard/QuickStats.tsx frontend/src/index.css
git commit -m "feat: update QuickStats with glass-card styling and breathe glow animation"

Task 9: Update SessionsPanel with glass-card styling

Files:

  • Modify: frontend/src/components/dashboard/SessionsPanel.tsx

Step 1: Update panel styling

Replace the flat card with glass-card-static (no hover scale for the full panel, but individual rows can highlight):

<div className="glass-card-static fade-in" style={{ animationDelay: `${delay}ms` }}>

Update the header border to use glass-border:

<div className="flex items-center justify-between px-4 py-3" style={{ borderBottom: '1px solid var(--glass-border)' }}>

Update the dividers: replace divide-y divide-border with inline style or a wrapper approach.

Step 2: Run frontend build

Run: cd frontend && npm run build Expected: Build succeeds

Step 3: Commit

git add frontend/src/components/dashboard/SessionsPanel.tsx
git commit -m "feat: update SessionsPanel with glass-card-static styling"

Task 10: Build WeeklyCalendar dashboard component

Files:

  • Create: frontend/src/components/dashboard/WeeklyCalendar.tsx

Step 1: Create the WeeklyCalendar component

This component shows a 5-day (Mon-Fri) calendar with tall day columns. Today is highlighted with a cyan top bar. Events appear inline within their day column.

import { useMemo } from 'react'
import { Calendar } from 'lucide-react'

interface CalendarEvent {
  id: string
  title: string
  time: string
  type: 'default' | 'maintenance'
}

interface WeeklyCalendarProps {
  events?: Record<string, CalendarEvent[]>  // keyed by ISO date string (YYYY-MM-DD)
}

const DAY_NAMES = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri']

function getWeekDays(): { label: string; date: Date; dateStr: string; isToday: boolean }[] {
  const now = new Date()
  const day = now.getDay()
  // Monday = 1, so offset = day - 1 (handle Sunday = 0 as 6)
  const mondayOffset = day === 0 ? 6 : day - 1
  const monday = new Date(now)
  monday.setDate(now.getDate() - mondayOffset)

  return DAY_NAMES.map((label, i) => {
    const d = new Date(monday)
    d.setDate(monday.getDate() + i)
    const dateStr = d.toISOString().split('T')[0]
    const isToday = d.toDateString() === now.toDateString()
    return { label, date: d, dateStr, isToday }
  })
}

export function WeeklyCalendar({ events = {} }: WeeklyCalendarProps) {
  const days = useMemo(() => getWeekDays(), [])

  return (
    <div className="glass-card-static flex flex-col h-full">
      {/* Header */}
      <div className="flex items-center gap-2 px-5 py-3" style={{ borderBottom: '1px solid var(--glass-border)' }}>
        <Calendar size={16} className="text-muted-foreground" />
        <h3 className="font-heading text-sm font-bold text-foreground">This Week</h3>
      </div>

      {/* Day columns */}
      <div className="flex flex-1 min-h-0">
        {days.map((day, i) => {
          const dayEvents = events[day.dateStr] || []
          return (
            <div
              key={day.dateStr}
              className="flex-1 flex flex-col min-h-0"
              style={{
                borderRight: i < 4 ? '1px solid var(--glass-border)' : undefined,
              }}
            >
              {/* Day header */}
              <div
                className="px-2 py-2 text-center"
                style={{
                  borderBottom: day.isToday
                    ? '2px solid transparent'
                    : '1px solid var(--glass-border)',
                  backgroundImage: day.isToday
                    ? 'linear-gradient(var(--glass-bg), var(--glass-bg)), linear-gradient(90deg, #06b6d4, #22d3ee)'
                    : undefined,
                  backgroundOrigin: 'border-box',
                  backgroundClip: day.isToday ? 'padding-box, border-box' : undefined,
                  borderBottomColor: day.isToday ? 'transparent' : undefined,
                }}
              >
                <span className={`font-label text-[0.625rem] uppercase tracking-[0.1em] ${day.isToday ? 'text-cyan-400' : 'text-muted-foreground'}`}>
                  {day.label}
                </span>
                <div className={`text-sm font-heading font-bold ${day.isToday ? 'text-foreground' : 'text-muted-foreground'}`}>
                  {day.date.getDate()}
                </div>
              </div>

              {/* Events */}
              <div className="flex-1 overflow-y-auto p-1.5 space-y-1">
                {dayEvents.length === 0 ? (
                  <p className="text-[0.625rem] text-[hsl(var(--text-dimmed))] text-center py-2">No events</p>
                ) : (
                  dayEvents.map(event => (
                    <div
                      key={event.id}
                      className="rounded-md px-2 py-1.5 text-[0.6875rem] cursor-pointer hover:bg-accent/30 transition-colors"
                      style={{
                        borderLeft: `3px solid ${event.type === 'maintenance' ? '#fbbf24' : '#06b6d4'}`,
                        background: 'rgba(255, 255, 255, 0.02)',
                      }}
                    >
                      <div className="font-medium text-foreground truncate">{event.title}</div>
                      <div className="font-label text-[0.5625rem] text-muted-foreground">{event.time}</div>
                    </div>
                  ))
                )}
              </div>
            </div>
          )
        })}
      </div>
    </div>
  )
}

Step 2: Run frontend build

Run: cd frontend && npm run build Expected: Build succeeds

Step 3: Commit

git add frontend/src/components/dashboard/WeeklyCalendar.tsx
git commit -m "feat: add WeeklyCalendar dashboard component with day columns and inline events"

Task 11: Build QuickActions dashboard component

Files:

  • Create: frontend/src/components/dashboard/QuickActions.tsx

Step 1: Create the QuickActions component

4 glass cards in a vertical stack with different accent colors:

import { useNavigate } from 'react-router-dom'
import { Plus, Play, BookOpen, UserPlus } from 'lucide-react'

const ACTIONS = [
  { icon: Plus, label: 'New Flow', description: 'Create a new flow', href: '/trees/new', color: '#06b6d4' },
  { icon: Play, label: 'Resume Session', description: 'Continue where you left off', href: '/sessions', color: '#34d399' },
  { icon: BookOpen, label: 'Browse Library', description: 'Explore step library', href: '/step-library', color: '#fbbf24' },
  { icon: UserPlus, label: 'Invite Team', description: 'Add team members', href: '/account', color: '#818cf8' },
] as const

export function QuickActions() {
  const navigate = useNavigate()

  return (
    <div className="glass-card-static flex flex-col h-full">
      <div className="px-5 py-3" style={{ borderBottom: '1px solid var(--glass-border)' }}>
        <h3 className="font-heading text-sm font-bold text-foreground">Quick Actions</h3>
      </div>
      <div className="flex-1 flex flex-col justify-between p-3 gap-2">
        {ACTIONS.map(({ icon: Icon, label, description, href, color }) => (
          <button
            key={label}
            onClick={() => navigate(href)}
            className="glass-card flex items-center gap-3 px-4 py-3 text-left"
          >
            <span
              className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg"
              style={{ background: `${color}15` }}
            >
              <Icon size={18} style={{ color }} />
            </span>
            <div className="min-w-0">
              <div className="text-sm font-medium text-foreground">{label}</div>
              <div className="text-[0.6875rem] text-muted-foreground truncate">{description}</div>
            </div>
          </button>
        ))}
      </div>
    </div>
  )
}

Step 2: Run frontend build

Run: cd frontend && npm run build Expected: Build succeeds

Step 3: Commit

git add frontend/src/components/dashboard/QuickActions.tsx
git commit -m "feat: add QuickActions dashboard component with 4 action cards"

Task 12: Build OpenSessions dashboard component

Files:

  • Create: frontend/src/components/dashboard/OpenSessions.tsx

Step 1: Create the OpenSessions component

Shows 3 oldest open sessions with Resume buttons:

import { Link } from 'react-router-dom'
import { getTreeNavigatePath } from '@/lib/routing'

interface OpenSession {
  id: string
  treeName: string
  treeId: string
  treeType?: string
  stepNumber?: number
  totalSteps?: number
  timeAgo: string
}

interface OpenSessionsProps {
  sessions: OpenSession[]
}

export function OpenSessions({ sessions }: OpenSessionsProps) {
  return (
    <div className="glass-card-static flex flex-col h-full">
      <div className="flex items-center justify-between px-5 py-3" style={{ borderBottom: '1px solid var(--glass-border)' }}>
        <h3 className="font-heading text-sm font-bold text-foreground">My Open Sessions</h3>
        <Link to="/sessions" className="text-[0.6875rem] text-muted-foreground hover:text-foreground transition-colors">
          View All
        </Link>
      </div>
      <div className="flex-1 flex flex-col">
        {sessions.length === 0 ? (
          <div className="flex-1 flex items-center justify-center">
            <p className="text-sm text-muted-foreground">No open sessions</p>
          </div>
        ) : (
          sessions.map((session, i) => (
            <div
              key={session.id}
              className="flex items-center gap-3 px-5 py-3"
              style={{
                borderBottom: i < sessions.length - 1 ? '1px solid var(--glass-border)' : undefined,
              }}
            >
              <span className="h-2 w-2 shrink-0 rounded-full bg-amber-400" />
              <div className="flex-1 min-w-0">
                <div className="text-sm text-foreground truncate">{session.treeName}</div>
                <div className="text-[0.6875rem] text-muted-foreground">
                  {session.stepNumber && session.totalSteps
                    ? `Step ${session.stepNumber} of ${session.totalSteps}`
                    : 'In progress'}
                  <span className="mx-1.5 text-[hsl(var(--text-dimmed))]">&middot;</span>
                  <span className="font-label text-[0.625rem]">{session.timeAgo}</span>
                </div>
              </div>
              <Link
                to={getTreeNavigatePath(session.treeId, session.treeType)}
                state={{ sessionId: session.id }}
                className="shrink-0 rounded-lg bg-gradient-brand px-3 py-1 text-[0.6875rem] font-medium text-primary-foreground hover:opacity-90 transition-opacity"
              >
                Resume
              </Link>
            </div>
          ))
        )}
      </div>
    </div>
  )
}

Step 2: Run frontend build

Run: cd frontend && npm run build Expected: Build succeeds

Step 3: Commit

git add frontend/src/components/dashboard/OpenSessions.tsx
git commit -m "feat: add OpenSessions dashboard component showing 3 oldest open sessions"

Task 13: Build RecentActivity dashboard component

Files:

  • Create: frontend/src/components/dashboard/RecentActivity.tsx

Step 1: Create the RecentActivity component

Displays 5 recent activity items with icons and timestamps:

import type { LucideIcon } from 'lucide-react'
import { GitBranch, Play, CheckCircle, FileText, Edit } from 'lucide-react'

interface ActivityItem {
  id: string
  icon: LucideIcon
  iconColor: string
  iconBg: string
  description: string
  timestamp: string
}

interface RecentActivityProps {
  activities: ActivityItem[]
}

const DEFAULT_ACTIVITIES: ActivityItem[] = [
  { id: '1', icon: Play, iconColor: '#34d399', iconBg: 'rgba(52, 211, 153, 0.1)', description: 'Started VPN Connectivity Triage session', timestamp: '2 min ago' },
  { id: '2', icon: CheckCircle, iconColor: '#06b6d4', iconBg: 'rgba(6, 182, 212, 0.1)', description: 'Completed M365 License Provisioning', timestamp: '15 min ago' },
  { id: '3', icon: Edit, iconColor: '#fbbf24', iconBg: 'rgba(251, 191, 36, 0.1)', description: 'Updated Printer Troubleshooting flow', timestamp: '1 hr ago' },
  { id: '4', icon: GitBranch, iconColor: '#818cf8', iconBg: 'rgba(129, 140, 248, 0.1)', description: 'Created new DNS Resolution flow', timestamp: '3 hr ago' },
  { id: '5', icon: FileText, iconColor: '#8891a0', iconBg: 'rgba(136, 145, 160, 0.1)', description: 'Exported session report #TK-4821', timestamp: 'Yesterday' },
]

export function RecentActivity({ activities = DEFAULT_ACTIVITIES }: Partial<RecentActivityProps>) {
  return (
    <div className="glass-card-static">
      <div className="px-5 py-3" style={{ borderBottom: '1px solid var(--glass-border)' }}>
        <h3 className="font-heading text-sm font-bold text-foreground">Recent Activity</h3>
      </div>
      <div>
        {activities.map((item, i) => (
          <div
            key={item.id}
            className="flex items-start gap-3 px-5 py-3 fade-in"
            style={{
              animationDelay: `${750 + i * 40}ms`,
              borderBottom: i < activities.length - 1 ? '1px solid var(--glass-border)' : undefined,
            }}
          >
            <span
              className="flex h-9 w-9 shrink-0 items-center justify-center rounded-[10px]"
              style={{ background: item.iconBg }}
            >
              <item.icon size={16} style={{ color: item.iconColor }} />
            </span>
            <div className="flex-1 min-w-0 pt-0.5">
              <p className="text-sm text-foreground">{item.description}</p>
            </div>
            <span className="shrink-0 font-label text-[0.625rem] text-muted-foreground pt-1">
              {item.timestamp}
            </span>
          </div>
        ))}
      </div>
    </div>
  )
}

Step 2: Run frontend build

Run: cd frontend && npm run build Expected: Build succeeds

Step 3: Commit

git add frontend/src/components/dashboard/RecentActivity.tsx
git commit -m "feat: add RecentActivity dashboard component with staggered animations"

Task 14: Redesign the QuickStartPage dashboard layout

Files:

  • Modify: frontend/src/pages/QuickStartPage.tsx

Step 1: Import the new dashboard components

Add imports at the top of QuickStartPage.tsx:

import { WeeklyCalendar } from '@/components/dashboard/WeeklyCalendar'
import { QuickActions } from '@/components/dashboard/QuickActions'
import { OpenSessions } from '@/components/dashboard/OpenSessions'
import { RecentActivity } from '@/components/dashboard/RecentActivity'

Step 2: Prepare open sessions data

After the existing stats calculations (around line 212), add open sessions data:

// Open sessions for the new panel (3 oldest)
const openSessionItems = activeSessions
  .sort((a, b) => new Date(a.started_at).getTime() - new Date(b.started_at).getTime())
  .slice(0, 3)
  .map(s => ({
    id: s.id,
    treeName: s.tree_snapshot?.name || 'Unknown',
    treeId: s.tree_id,
    treeType: s.tree_snapshot?.tree_type,
    timeAgo: timeAgo(s.started_at),
  }))

Step 3: Restructure the dashboard layout

Replace the return JSX with the new layout order:

  1. Greeting + date (full width)
  2. Calendar + Quick Actions (same height row)
  3. Open Sessions + Stats 2x2 (same height row)
  4. Recent Activity (full width)
  5. (Keep existing: Search, Favorites, My Flows tabs — below the fold)

The new layout should be:

return (
  <div className="p-6 space-y-6">
    {/* Greeting */}
    <div className="fade-in" style={{ animationDelay: '400ms' }}>
      <h1 className="font-heading text-4xl font-extrabold tracking-tight text-foreground">
        Good {new Date().getHours() < 12 ? 'morning' : new Date().getHours() < 18 ? 'afternoon' : 'evening'}, {user?.name?.split(' ')[0] || 'there'}
      </h1>
      <p className="mt-1 text-sm text-muted-foreground">
        {new Date().toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' })}
      </p>
    </div>

    {/* Row 1: Calendar + Quick Actions */}
    <div className="flex gap-4" style={{ alignItems: 'stretch' }}>
      <div className="flex-1 min-w-0">
        <WeeklyCalendar />
      </div>
      <div className="w-72 shrink-0">
        <QuickActions />
      </div>
    </div>

    {/* Row 2: Open Sessions + Stats 2x2 */}
    <div className="flex gap-4" style={{ alignItems: 'stretch' }}>
      <div className="flex-1 min-w-0">
        <OpenSessions sessions={openSessionItems} />
      </div>
      <div className="w-72 shrink-0">
        <div className="grid grid-cols-2 gap-3 h-full">
          {/* 4 stat cards in 2x2 grid */}
          {[
            { label: 'Active Flows', value: myFlows.length, gradient: true, glow: true },
            { label: 'This Week', value: todaySessions },
            { label: 'Open Sessions', value: openSessions },
            { label: 'Favorites', value: pinnedItems.length },
          ].map((stat, i) => (
            <div
              key={stat.label}
              className={cn('glass-card p-4 flex flex-col justify-between fade-in', stat.glow && 'active-glow')}
              style={{ animationDelay: `${500 + i * 70}ms` }}
            >
              <p className="font-label text-[0.625rem] font-medium uppercase tracking-[0.1em] text-muted-foreground">
                {stat.label}
              </p>
              <p className={cn('font-heading text-2xl font-extrabold tracking-tight', stat.gradient && 'text-gradient-brand')}>
                {stat.value}
              </p>
            </div>
          ))}
        </div>
      </div>
    </div>

    {/* Row 3: Recent Activity */}
    <RecentActivity />

    {/* Divider before existing content */}
    <div style={{ borderTop: '1px solid var(--glass-border)' }} className="pt-6">
      {/* Keep existing: Search, Favorites, My Flows tabs below */}
    </div>

    {/* ... rest of existing code (search, favorites, my flows) stays below ... */}
  </div>
)

Keep the existing Search, Favorites, and My Flows sections below the new dashboard panels. Remove the old <QuickStats> component call since stats are now inline in the 2x2 grid.

Step 4: Run frontend build

Run: cd frontend && npm run build Expected: Build succeeds

Step 5: Manually verify in browser

Run: cd frontend && npm run dev Open http://localhost:5173 and verify:

  • Greeting with user's first name
  • Calendar + Quick Actions side by side, equal height
  • Open Sessions + Stats side by side, equal height
  • Recent Activity full width below
  • All glass-card effects working (backdrop blur, hover scale)
  • Cyan gradient accents throughout

Step 6: Commit

git add frontend/src/pages/QuickStartPage.tsx
git commit -m "feat: redesign dashboard layout with calendar, open sessions, and glass-card panels"

Task 15: Update login and register pages

Files:

  • Modify: frontend/src/pages/LoginPage.tsx
  • Modify: frontend/src/pages/RegisterPage.tsx

Step 1: Search for purple gradient references in auth pages

Run: Search both files for bg-gradient-brand, text-gradient-brand, font family references, and color hardcodes. These should already work with the new Tailwind config since they use design tokens, but verify:

  • bg-gradient-brand → now produces cyan (from tailwind.config.js)
  • text-gradient-brand → now produces cyan (from index.css utility)
  • font-heading → now maps to Bricolage Grotesque
  • font-label → now maps to JetBrains Mono
  • bg-card → now references the updated CSS variable

Most auth page styles should auto-update. Check for any hardcoded purple hex values.

Step 2: Run frontend build

Run: cd frontend && npm run build Expected: Build succeeds

Step 3: Commit (only if changes were needed)

git add frontend/src/pages/LoginPage.tsx frontend/src/pages/RegisterPage.tsx
git commit -m "fix: update auth pages for Slate & Ice theme consistency"

Task 16: Page-by-page sweep — find and fix remaining purple/old-font references

Files:

  • Multiple frontend files

Step 1: Search for hardcoded purple hex values

Run grep searches across the frontend for:

  • #818cf8 — old gradient-from
  • #a78bfa — old gradient-to
  • #6366f1 — old gradient-hover-from
  • #9333ea — old gradient-hover-to
  • Plus Jakarta Sans — old heading font
  • 'Inter' — old body font (note: not in font-stack, just standalone references)
  • 'Outfit' — old label font

These should only appear in tailwind.config.js (already updated) and index.css (already updated). If they appear elsewhere, update them.

Step 2: Check for shadow-primary/20 references

This shadow color depends on --primary, which is now cyan. Existing shadow-lg shadow-primary/20 will automatically become a cyan shadow, which is correct. No changes needed.

Step 3: Verify bg-primary references

bg-primary now renders as cyan instead of purple. Check all usages to ensure cyan makes sense in those contexts (badges, nav indicators). These should all be correct since purple and cyan serve the same accent role.

Step 4: Run full frontend build

Run: cd frontend && npm run build Expected: Build succeeds with no errors

Step 5: Commit any remaining fixes

git add -A
git commit -m "fix: sweep remaining hardcoded purple references across frontend"

Task 17: Update CLAUDE.md branding section

Files:

  • Modify: CLAUDE.md

Step 1: Update the Branding section in CLAUDE.md

Update the following in the Branding section:

  • Design description: Dark-first with purple gradient accents (#818cf8 → #a78bfa)Dark glassmorphism with ice-cyan accent (#06b6d4 → #22d3ee)
  • Fonts: Plus Jakarta Sans (font-heading)Bricolage Grotesque (font-heading), Inter (font-sans)IBM Plex Sans (font-sans), Outfit (font-label)JetBrains Mono (font-label)
  • CSS utilities: mention glass-card, glass-card-static as primary card patterns

Update the Component styling rules:

  • Primary buttons: bg-gradient-brand now produces cyan gradient
  • Cards: glass-card class replaces bg-card border border-border rounded-xl
  • Add: glassmorphism backdrop blur on sidebar and topbar

Update the Design System section:

  • Replace purple references with cyan
  • Add glass system description
  • Add animation descriptions

Step 2: Commit

git add CLAUDE.md
git commit -m "docs: update CLAUDE.md branding section for Slate & Ice theme"

Task 18: Final verification and build

Step 1: Run full frontend build

Run: cd frontend && npm run build Expected: Build succeeds with zero errors

Step 2: Run ESLint

Run: cd frontend && npx eslint src/ --quiet Expected: No errors (warnings OK)

Step 3: Start dev server and visual verification

Run: cd frontend && npm run dev

Verify in browser at http://localhost:5173:

  • Cyan gradient accent throughout (buttons, nav, logo "Flow" text)
  • Bricolage Grotesque headings (bold, distinctive)
  • IBM Plex Sans body text
  • JetBrains Mono labels and timestamps (monospace, uppercase)
  • Glass-card effects on all dashboard panels (backdrop blur visible)
  • Atmosphere orbs visible as subtle ambient glow
  • Sidebar has glass backdrop blur
  • Topbar has glass backdrop blur
  • Dashboard layout: Greeting → Calendar+Actions → Sessions+Stats → Activity
  • Weekly calendar with 5 day columns, today highlighted
  • Stat cards with hover scale(1.02)
  • First stat card has breathing glow
  • Login/register pages use new colors and fonts
  • No purple remnants anywhere

Step 4: Final commit if any fixes needed

git add -A
git commit -m "fix: final verification fixes for Slate & Ice redesign"