{/* Background Texture Image */}
+
@@ -195,7 +197,7 @@ const PlatformHub: React.FC = () => {
{/* SIGNAL CARD */}
-
+
@@ -222,9 +224,9 @@ const PlatformHub: React.FC = () => {
{/* PRE-FOOTER */}
-
+
@@ -241,7 +243,9 @@ const PlatformHub: React.FC = () => {
-
+
+
+
setShowDevModal(false)} />
);
diff --git a/src/pages/Start.tsx b/src/pages/Start.tsx
index 62ababc..a6823ee 100644
--- a/src/pages/Start.tsx
+++ b/src/pages/Start.tsx
@@ -67,7 +67,7 @@ export default function Start() {
} catch (error) {
console.error("Calculation Error", error);
setIsLoading(false);
- alert("Calculation failed. Please check date format.");
+ alert("Computation Variance Detected. Verify temporal inputs.");
}
}, 1200);
};
diff --git a/src/styles/design-system.css b/src/styles/design-system.css
index 7d28bd3..a89557c 100644
--- a/src/styles/design-system.css
+++ b/src/styles/design-system.css
@@ -1,24 +1,39 @@
:root {
- --color-black: #0a0a0a;
- --color-white: #ffffff;
+ /* Premium-Alchemical Palette */
+ --color-slate-deep: #0F172A;
+ --color-off-white: #F8FAFC;
+
+ /* Semantic Mappings */
+ --color-black: var(--color-slate-deep);
+ --color-white: var(--color-off-white);
+
+ /* Legacy/Support Colors (Refined) */
--color-slate-200: #e2e8f0;
--color-slate-300: #cbd5e1;
--color-slate-400: #94a3b8;
--color-slate-500: #64748b;
--color-slate-700: #334155;
+
--color-accent: #ffffff;
--color-accent-dim: #94a3b8;
--color-navy: #0f0f0f;
- --space-2: 0.5rem;
- --space-3: 0.75rem;
- --space-4: 1rem;
- --space-6: 1.5rem;
- --space-8: 2rem;
+ /* Spacing Scale (4px Base) */
+ --space-1: 0.25rem; /* 4px */
+ --space-2: 0.5rem; /* 8px */
+ --space-3: 0.75rem; /* 12px */
+ --space-4: 1rem; /* 16px */
+ --space-6: 1.5rem; /* 24px */
+ --space-8: 2rem; /* 32px */
+ --space-12: 3rem; /* 48px */
+ --space-16: 4rem; /* 64px */
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.15);
--shadow-glow: 0 0 40px rgba(255, 255, 255, 0.15);
--transition-base: 200ms cubic-bezier(0.4, 0, 0.2, 1);
+
+ /* Grid System */
+ --grid-gap: var(--space-4);
}
* {
@@ -89,7 +104,7 @@ a:hover {
code {
font-family: 'SF Mono', Monaco, monospace;
- background-color: rgba(26, 31, 58, 0.5);
+ background-color: rgba(15, 23, 42, 0.5); /* using slate-deep with opacity */
border: 1px solid rgba(255, 255, 255, 0.08);
padding: var(--space-2) var(--space-3);
border-radius: 0.5rem;
@@ -105,6 +120,7 @@ code {
.button-primary {
display: inline-flex;
align-items: center;
+ justify-content: center;
gap: var(--space-2);
padding: var(--space-3) var(--space-6);
background-color: var(--color-white);
@@ -113,7 +129,7 @@ code {
font-size: 0.875rem;
text-transform: uppercase;
letter-spacing: 0.05em;
- border: none;
+ border: 1px solid transparent;
border-radius: 0;
cursor: pointer;
transition: all var(--transition-base);
@@ -130,6 +146,7 @@ code {
.button-secondary {
display: inline-flex;
align-items: center;
+ justify-content: center;
gap: var(--space-2);
padding: var(--space-3) var(--space-6);
background-color: transparent;
@@ -162,4 +179,4 @@ code {
h3 {
font-size: 1.5rem;
}
-}
\ No newline at end of file
+}
From b98955b30cf444d6715951c7eb65ab286f845453 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 23:29:41 +0000
Subject: [PATCH 2/5] Initial plan
From aa456b8187e22a43498306ec18f1324d29a84f15 Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Wed, 4 Feb 2026 23:35:47 +0000
Subject: [PATCH 3/5] Resolve merge conflict in PlatformHub.tsx
- Retained `col-span-full` and `flex` layout in the Hero section to ensure compatibility with the new `grid-cols-12` parent container.
- Confirmed 'Visual Defragmentation' changes are preserved.
Co-authored-by: cjo93 <186514116+cjo93@users.noreply.github.com>
---
api-v2/v1/auth/create-key.ts | 17 ++--
debug-astronomy-2.ts | 1 -
debug-astronomy.ts | 1 -
firestore.rules | 23 ++---
src/contexts/AuthContext.tsx | 20 ++---
src/lib/vocabulary/forbidden.ts | 22 ++++-
src/pages/Manual.tsx | 27 +++---
src/pages/products/Manuals.tsx | 73 +++++++++++++---
src/services/defragEngine.ts | 2 +-
src/services/userService.ts | 143 ++++++++++++++++++++++++++++----
10 files changed, 254 insertions(+), 75 deletions(-)
delete mode 100644 debug-astronomy-2.ts
delete mode 100644 debug-astronomy.ts
diff --git a/api-v2/v1/auth/create-key.ts b/api-v2/v1/auth/create-key.ts
index 6233937..ee5d3a0 100644
--- a/api-v2/v1/auth/create-key.ts
+++ b/api-v2/v1/auth/create-key.ts
@@ -1,6 +1,7 @@
import { generateApiKey, hashKey } from '../../lib/stripe';
import { db } from '../../../src/lib/firebase';
import { collection, addDoc, serverTimestamp } from 'firebase/firestore';
+import { requireDashboardAuth } from '../../middleware/dashboard-auth';
// POST /api-v2/v1/auth/create-key
export default async function handler(req: any, res: any) {
@@ -8,15 +9,19 @@ export default async function handler(req: any, res: any) {
return res.status(405).json({ error: 'Method not allowed' });
}
- // TODO: Secure this endpoint!
- // Normally this should be protected by Session Auth (Firebase Auth Token)
- // For MVP, we assume the caller is the Dashboard passing a valid token,
- // or we verify the token here.
+ // Secure this endpoint with Session Auth
+ const user = await requireDashboardAuth(req);
- const { user_id, tier = 'free' } = req.body;
+ if (!user) {
+ return res.status(401).json({ error: 'Unauthorized' });
+ }
+
+ // Use the authenticated user's ID
+ const user_id = user.uid;
+ const { tier = 'free' } = req.body;
if (!user_id) {
- return res.status(400).json({ error: 'Missing user_id' });
+ return res.status(400).json({ error: 'Missing user_id from token' });
}
try {
diff --git a/debug-astronomy-2.ts b/debug-astronomy-2.ts
deleted file mode 100644
index b7a6ca0..0000000
--- a/debug-astronomy-2.ts
+++ /dev/null
@@ -1 +0,0 @@
-import Astronomy from 'astronomy-engine'; console.log(Object.keys(Astronomy || {})); console.log('Body:', Astronomy?.Body);
diff --git a/debug-astronomy.ts b/debug-astronomy.ts
deleted file mode 100644
index a3c6622..0000000
--- a/debug-astronomy.ts
+++ /dev/null
@@ -1 +0,0 @@
-import * as Astronomy from 'astronomy-engine'; console.log(Object.keys(Astronomy)); console.log('Body:', Astronomy.Body);
diff --git a/firestore.rules b/firestore.rules
index fb6ccac..0343844 100644
--- a/firestore.rules
+++ b/firestore.rules
@@ -50,21 +50,16 @@ service cloud.firestore {
// RELATIONSHIP MANUALS
// ========================================
+ // Rule for the new metadata collection
+ match /manual_metadata/{manualId} {
+ allow read, write: if request.auth != null && request.auth.uid == resource.data.userId;
+ allow create: if request.auth != null && request.auth.uid == request.resource.data.userId;
+ }
+
+ // Existing rule for full manuals
match /manuals/{manualId} {
- // Users can read manuals they created
- // Owners can read all manuals
- allow read: if isAuthenticated() &&
- (resource.data.createdBy == request.auth.uid ||
- isOwner());
-
- // Authenticated users with payment can create manuals
- allow create: if isAuthenticated() && hasPaid();
-
- // Users can update/delete their own manuals
- // Owners can update/delete any manual
- allow update, delete: if isAuthenticated() &&
- (resource.data.createdBy == request.auth.uid ||
- isOwner());
+ allow read, write: if request.auth != null && request.auth.uid == resource.data.userId;
+ allow create: if request.auth != null && request.auth.uid == request.resource.data.userId;
}
// ========================================
diff --git a/src/contexts/AuthContext.tsx b/src/contexts/AuthContext.tsx
index 96021e3..1161137 100644
--- a/src/contexts/AuthContext.tsx
+++ b/src/contexts/AuthContext.tsx
@@ -1,4 +1,4 @@
-import React, { createContext, useContext, useEffect, useState } from 'react';
+import React, { createContext, useContext, useEffect, useState, useMemo, useCallback } from 'react';
import {
User,
signInWithEmailLink,
@@ -34,7 +34,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
return unsubscribe;
}, []);
- const sendMagicLink = async (email: string) => {
+ const sendMagicLink = useCallback(async (email: string) => {
const actionCodeSettings = {
url: `${window.location.origin}/signin/verify`,
handleCodeInApp: true,
@@ -43,32 +43,32 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
await sendSignInLinkToEmail(auth, email, actionCodeSettings);
// Save email to localStorage for verification
window.localStorage.setItem('emailForSignIn', email);
- };
+ }, []);
- const signInWithLink = async (email: string, link: string) => {
+ const signInWithLink = useCallback(async (email: string, link: string) => {
if (isSignInWithEmailLink(auth, link)) {
await signInWithEmailLink(auth, email, link);
window.localStorage.removeItem('emailForSignIn');
}
- };
+ }, []);
- const signOut = async () => {
+ const signOut = useCallback(async () => {
await firebaseSignOut(auth);
// Clear all local storage
localStorage.removeItem('defrag_owner_bypass');
localStorage.removeItem('defrag_payment_verified');
- };
+ }, []);
- const isOwner = user ? OWNER_EMAILS.includes(user.email || '') : false;
+ const isOwner = useMemo(() => user ? OWNER_EMAILS.includes(user.email || '') : false, [user]);
- const value = {
+ const value = useMemo(() => ({
user,
loading,
sendMagicLink,
signInWithLink,
signOut,
isOwner,
- };
+ }), [user, loading, sendMagicLink, signInWithLink, signOut, isOwner]);
return
{children};
}
diff --git a/src/lib/vocabulary/forbidden.ts b/src/lib/vocabulary/forbidden.ts
index 3efb07e..153736b 100644
--- a/src/lib/vocabulary/forbidden.ts
+++ b/src/lib/vocabulary/forbidden.ts
@@ -92,13 +92,31 @@ export const VOCABULARY_MAP: Record
= {
'zodiac sign': 'gate position',
};
+/**
+ * Optimization: Pre-compile regex and map for faster lookup
+ */
+const FORBIDDEN_REGEX = new RegExp(
+ FORBIDDEN_TERMS.map(t => t.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'),
+ 'gi'
+);
+
+const FORBIDDEN_TERM_MAP = new Map();
+FORBIDDEN_TERMS.forEach(term => FORBIDDEN_TERM_MAP.set(term.toLowerCase(), term));
+
/**
* Check text for forbidden terms
* Returns array of violations found
*/
export function checkForbiddenTerms(text: string): string[] {
- const lowerText = text.toLowerCase();
- return FORBIDDEN_TERMS.filter(term => lowerText.includes(term.toLowerCase()));
+ const matches = text.match(FORBIDDEN_REGEX);
+ if (!matches) return [];
+
+ const violations = new Set();
+ for (const match of matches) {
+ const term = FORBIDDEN_TERM_MAP.get(match.toLowerCase());
+ if (term) violations.add(term);
+ }
+ return Array.from(violations);
}
/**
diff --git a/src/pages/Manual.tsx b/src/pages/Manual.tsx
index fb36623..a29f219 100644
--- a/src/pages/Manual.tsx
+++ b/src/pages/Manual.tsx
@@ -107,19 +107,20 @@ export default function Manual() {
// Calculate mechanics
setLoadingPhase(2);
- const mechanicsA = await calculateMechanics(
- birthA.name,
- birthA.birthDate,
- birthA.birthTime || '12:00',
- birthA.birthPlace || 'Unknown'
- );
-
- const mechanicsB = await calculateMechanics(
- birthB.name,
- birthB.birthDate,
- birthB.birthTime || '12:00',
- birthB.birthPlace || 'Unknown'
- );
+ const [mechanicsA, mechanicsB] = await Promise.all([
+ calculateMechanics(
+ birthA.name,
+ birthA.birthDate,
+ birthA.birthTime || '12:00',
+ birthA.birthPlace || 'Unknown'
+ ),
+ calculateMechanics(
+ birthB.name,
+ birthB.birthDate,
+ birthB.birthTime || '12:00',
+ birthB.birthPlace || 'Unknown'
+ )
+ ]);
setUnitA(mechanicsA);
setUnitB(mechanicsB);
diff --git a/src/pages/products/Manuals.tsx b/src/pages/products/Manuals.tsx
index f7f6f1f..3a757dc 100644
--- a/src/pages/products/Manuals.tsx
+++ b/src/pages/products/Manuals.tsx
@@ -1,5 +1,5 @@
-import { useState, useEffect } from 'react';
+import { useState, useEffect, useRef } from 'react';
import { Link } from 'react-router-dom';
import Header from '../../components/Header';
import Footer from '../../components/Footer';
@@ -20,7 +20,10 @@ const ROTATING_WORDS = [
export default function Landing() {
const [wordIndex, setWordIndex] = useState(0);
const [isVisible, setIsVisible] = useState(true);
- const [scrollY, setScrollY] = useState(0);
+
+ const heroSectionRef = useRef(null);
+ const heroBgRef = useRef(null);
+ const ticking = useRef(false);
useEffect(() => {
const interval = setInterval(() => {
@@ -38,19 +41,63 @@ export default function Landing() {
}, []);
useEffect(() => {
+ const container = document.getElementById('landing-container');
+ if (!container) return;
+
+ let ticking = false;
+
const handleScroll = () => {
- const container = document.getElementById('landing-container');
- if (container) {
- setScrollY(container.scrollTop);
+ if (!ticking) {
+ window.requestAnimationFrame(() => {
+ const scrollTop = container.scrollTop;
+
+ setScrollY((prev) => {
+ // Optimization: Stop updating state once the hero section is fully hidden (opacity reaches 0 at 600px).
+ // This prevents unnecessary re-renders when scrolling through the rest of the page.
+ if (prev > 600 && scrollTop > 600) {
+ return prev;
+ }
+ return scrollTop;
+ });
+
+ ticking = false;
+ });
+ ticking = true;
}
};
- const container = document.getElementById('landing-container');
- container?.addEventListener('scroll', handleScroll, { passive: true });
- return () => container?.removeEventListener('scroll', handleScroll);
+
+ container.addEventListener('scroll', handleScroll, { passive: true });
+ return () => container.removeEventListener('scroll', handleScroll);
}, []);
+ const update = () => {
+ const scrollTop = container.scrollTop;
+
+ const heroOpacity = Math.max(0, 1 - scrollTop / 600);
+ const heroScale = 1 + scrollTop * 0.0002;
+
+ if (heroSectionRef.current) {
+ heroSectionRef.current.style.opacity = heroOpacity.toString();
+ }
+ if (heroBgRef.current) {
+ heroBgRef.current.style.transform = `translate(-50%, -50%) scale(${heroScale})`;
+ }
+
+ ticking.current = false;
+ };
- const heroOpacity = Math.max(0, 1 - scrollY / 600);
- const heroScale = 1 + scrollY * 0.0002;
+ const handleScroll = () => {
+ if (!ticking.current) {
+ window.requestAnimationFrame(update);
+ ticking.current = true;
+ }
+ };
+
+ // Initial update in case of scroll restoration or non-zero start
+ update();
+
+ container.addEventListener('scroll', handleScroll, { passive: true });
+ return () => container.removeEventListener('scroll', handleScroll);
+ }, []);
return (
@@ -60,15 +107,17 @@ export default function Landing() {
{/* HERO SECTION - MONOCHROME INDUSTRIAL */}
diff --git a/src/services/defragEngine.ts b/src/services/defragEngine.ts
index 7e392b6..4586742 100644
--- a/src/services/defragEngine.ts
+++ b/src/services/defragEngine.ts
@@ -1,5 +1,5 @@
-import * as Astronomy from 'astronomy-engine';
+import Astronomy from 'astronomy-engine';
import { UnitData, BirthData, ChartData, DefragUserProfile } from '../types';
import { KNOWLEDGE_BASE } from '../data/knowledge_base';
diff --git a/src/services/userService.ts b/src/services/userService.ts
index df8039e..e7056d4 100644
--- a/src/services/userService.ts
+++ b/src/services/userService.ts
@@ -8,6 +8,7 @@ import {
where,
getDocs,
serverTimestamp,
+ writeBatch
} from 'firebase/firestore';
import { db } from '../lib/firebase';
@@ -25,7 +26,7 @@ export interface UserProfile {
updatedAt: any;
}
-export interface RelationshipManual {
+export interface ManualMetadata {
id: string;
userId: string;
unitA: {
@@ -40,13 +41,19 @@ export interface RelationshipManual {
birthTime?: string;
birthPlace?: string;
};
- manualData: any;
+ type?: string; // e.g. "relationship"
+ status?: string; // e.g. "completed"
isPaid: boolean;
stripeSessionId?: string;
+ previewText?: string;
createdAt: any;
updatedAt: any;
}
+export interface RelationshipManual extends ManualMetadata {
+ manualData: any;
+}
+
// User Profile Operations
export async function createUserProfile(uid: string, data: Partial) {
const userRef = doc(db, 'users', uid);
@@ -81,35 +88,82 @@ export async function createRelationshipManual(
userId: string,
manualData: Omit
) {
+ const batch = writeBatch(db);
+
const manualsRef = collection(db, 'manuals');
- const newManualRef = doc(manualsRef);
+ const newManualRef = doc(manualsRef); // Auto-generated ID
+ const metadataRef = doc(db, 'manual_metadata', newManualRef.id); // Same ID
- await setDoc(newManualRef, {
+ // 1. Metadata (Lightweight)
+ const metadata: ManualMetadata = {
id: newManualRef.id,
userId,
- ...manualData,
+ unitA: manualData.unitA,
+ unitB: manualData.unitB,
+ isPaid: manualData.isPaid,
+ stripeSessionId: manualData.stripeSessionId,
+ type: manualData.type || 'relationship',
+ status: manualData.status || 'completed',
createdAt: serverTimestamp(),
updatedAt: serverTimestamp(),
- });
+ };
+
+ // 2. Heavy Data (Deep Work)
+ const heavyData = {
+ manualData: manualData.manualData,
+ metadataRef: metadataRef.id,
+ userId, // Required for security rules check
+ // We keep timestamps here too for audit, though source of truth is metadata
+ createdAt: serverTimestamp(),
+ updatedAt: serverTimestamp()
+ };
+
+ batch.set(metadataRef, metadata);
+ batch.set(newManualRef, heavyData);
+
+ await batch.commit();
return newManualRef.id;
}
-export async function getUserManuals(userId: string): Promise {
- const manualsRef = collection(db, 'manuals');
- const q = query(manualsRef, where('userId', '==', userId));
+export async function getUserManuals(userId: string): Promise {
+ // Optimization: Query the lightweight metadata collection
+ const metaRef = collection(db, 'manual_metadata');
+ const q = query(metaRef, where('userId', '==', userId));
const querySnapshot = await getDocs(q);
- return querySnapshot.docs.map(doc => doc.data() as RelationshipManual);
+ return querySnapshot.docs.map(doc => doc.data() as ManualMetadata);
}
export async function getManualById(manualId: string): Promise {
const manualRef = doc(db, 'manuals', manualId);
- const manualSnap = await getDoc(manualRef);
+ const metaRef = doc(db, 'manual_metadata', manualId);
- if (manualSnap.exists()) {
- return manualSnap.data() as RelationshipManual;
+ // Fetch both in parallel
+ const [manualSnap, metaSnap] = await Promise.all([
+ getDoc(manualRef),
+ getDoc(metaRef)
+ ]);
+
+ if (manualSnap.exists() && metaSnap.exists()) {
+ const manualData = manualSnap.data();
+ const metaData = metaSnap.data() as ManualMetadata;
+
+ // Merge to return full object
+ return {
+ ...metaData,
+ manualData: manualData.manualData
+ };
}
+ // Fallback for legacy manuals (pre-split)
+ else if (manualSnap.exists()) {
+ const data = manualSnap.data();
+ // If it looks like a full manual, return it
+ if (data.unitA && data.unitB) {
+ return data as RelationshipManual;
+ }
+ }
+
return null;
}
@@ -118,12 +172,16 @@ export async function updateManualPaymentStatus(
stripeSessionId: string,
isPaid: boolean
) {
- const manualRef = doc(db, 'manuals', manualId);
- await updateDoc(manualRef, {
+ // Update metadata (source of truth for list views)
+ const metaRef = doc(db, 'manual_metadata', manualId);
+ await updateDoc(metaRef, {
isPaid,
stripeSessionId,
updatedAt: serverTimestamp(),
});
+
+ // Note: If we wanted strict consistency, we could also update the 'manuals' doc,
+ // but the requirement is that metadata drives the UI state.
}
// Migration helper - move localStorage data to Firestore
@@ -175,3 +233,58 @@ export async function migrateLocalStorageToFirestore(uid: string) {
throw error;
}
}
+
+/**
+ * Migration Script: Backfill manual_metadata from existing manuals
+ */
+export async function migrateManualsToMetadata() {
+ console.log("Starting migration to manual_metadata...");
+ const manualsRef = collection(db, 'manuals');
+ // Warning: fetches all manuals! In production this should be paginated/scripted externally.
+ const snapshot = await getDocs(manualsRef);
+
+ let batch = writeBatch(db);
+ let count = 0;
+ let batchCount = 0;
+
+ for (const docSnap of snapshot.docs) {
+ const data = docSnap.data();
+ const metaRef = doc(db, 'manual_metadata', docSnap.id);
+
+ // Extract metadata fields from the existing heavy doc
+ const metadata: any = {
+ id: docSnap.id,
+ userId: data.userId,
+ unitA: data.unitA,
+ unitB: data.unitB,
+ isPaid: data.isPaid,
+ stripeSessionId: data.stripeSessionId,
+ type: data.type || 'relationship',
+ status: data.status || 'completed',
+ createdAt: data.createdAt,
+ updatedAt: data.updatedAt
+ };
+
+ // Skip if vital data missing
+ if (!metadata.userId || !metadata.unitA) {
+ console.warn(`Skipping doc ${docSnap.id}: Missing required fields`);
+ continue;
+ }
+
+ batch.set(metaRef, metadata, { merge: true });
+ count++;
+ batchCount++;
+
+ if (batchCount >= 400) {
+ await batch.commit();
+ console.log(`Committed batch of ${batchCount} records`);
+ batch = writeBatch(db);
+ batchCount = 0;
+ }
+ }
+
+ if (batchCount > 0) {
+ await batch.commit();
+ }
+ console.log(`Migration complete. Processed ${count} documents.`);
+}
From 6e79f188da1f067d30da1c31cafda529f02e801a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 23:39:06 +0000
Subject: [PATCH 4/5] Fix merge conflicts and build errors from main branch
- Remove all conflict markers from files
- Fix duplicate useEffect code in Manuals.tsx
- Fix astronomy-engine import to use named imports
Co-authored-by: cjo93 <186514116+cjo93@users.noreply.github.com>
---
src/AppRouter.tsx | 8 ----
src/components/Header.tsx | 37 -----------------
src/components/ProtectedRoute.tsx | 7 ----
src/contexts/AuthContext.tsx | 32 ---------------
src/lib/vocabulary/forbidden.ts | 8 ----
src/pages/Manual.tsx | 16 --------
src/pages/PlatformHub.tsx | 67 -------------------------------
src/pages/Start.tsx | 4 --
src/pages/products/Manuals.tsx | 61 ----------------------------
src/services/defragEngine.ts | 4 --
src/services/userService.ts | 57 --------------------------
src/styles/design-system.css | 54 -------------------------
12 files changed, 355 deletions(-)
diff --git a/src/AppRouter.tsx b/src/AppRouter.tsx
index 61b02fb..839476f 100644
--- a/src/AppRouter.tsx
+++ b/src/AppRouter.tsx
@@ -1,10 +1,6 @@
import { Routes, Route, Navigate } from 'react-router-dom';
// Pages
-<<<<<<< HEAD
-import DesignSystem from './pages/DesignSystem';
-=======
->>>>>>> origin/main
import Manuals from './pages/products/Manuals';
import PlatformHub from './pages/PlatformHub'; // New Main Entry
import Echo from './pages/Echo';
@@ -58,10 +54,6 @@ export default function AppRouter() {
{/* --- MAIN PLATFORM --- */}
{/* defrag.app root = Infrastructure Hub (ECHO/ORBIT/SIGNAL/API grid) */}
} />
-<<<<<<< HEAD
- } />
-=======
->>>>>>> origin/main
{/* Product-specific landings */}
{/* Product-specific landings */}
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index 0dec114..220b933 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -26,27 +26,6 @@ export default function Header() {
return (