diff --git a/assets/css/custom.css b/assets/css/custom.css
index 65a1626..35683d1 100644
--- a/assets/css/custom.css
+++ b/assets/css/custom.css
@@ -1,346 +1,111 @@
:root {
- --color-bg: #ffffff;
- --color-text: #1a1a1a;
- --color-primary: #2563EB; /* Vibrant Blue */
- --color-secondary: #000000;
- --color-accent: #A3E635; /* Lime Green */
- --color-surface: #f8f9fa;
- --font-heading: 'Space Grotesk', sans-serif;
- --font-body: 'Inter', sans-serif;
- --border-width: 2px;
- --shadow-hard: 5px 5px 0px #000;
- --shadow-hover: 8px 8px 0px #000;
- --radius-pill: 50rem;
- --radius-card: 1rem;
+ --primary: #0F172A;
+ --secondary: #64748B;
+ --success: #10B981;
+ --danger: #EF4444;
+ --warning: #F59E0B;
+ --info: #3B82F6;
+ --light: #F8FAFC;
+ --border: #E2E8F0;
+ --radius: 6px;
}
body {
- font-family: var(--font-body);
- background-color: var(--color-bg);
- color: var(--color-text);
- overflow-x: hidden;
+ font-family: 'Inter', system-ui, -apple-system, sans-serif;
+ background-color: var(--light);
+ color: var(--primary);
+ font-size: 14px;
+ line-height: 1.5;
}
-h1, h2, h3, h4, h5, h6, .navbar-brand {
- font-family: var(--font-heading);
- letter-spacing: -0.03em;
+.card {
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
}
-/* Utilities */
-.text-primary { color: var(--color-primary) !important; }
-.bg-black { background-color: #000 !important; }
-.text-white { color: #fff !important; }
-.shadow-hard { box-shadow: var(--shadow-hard); }
-.border-2-black { border: var(--border-width) solid #000; }
-.py-section { padding-top: 5rem; padding-bottom: 5rem; }
-
-/* Navbar */
-.navbar {
- background: rgba(255, 255, 255, 0.9);
- backdrop-filter: blur(10px);
- border-bottom: var(--border-width) solid transparent;
- transition: all 0.3s;
- padding-top: 1rem;
- padding-bottom: 1rem;
-}
-
-.navbar.scrolled {
- border-bottom-color: #000;
- padding-top: 0.5rem;
- padding-bottom: 0.5rem;
-}
-
-.brand-text {
- font-size: 1.5rem;
- font-weight: 800;
-}
-
-.nav-link {
- font-weight: 500;
- color: var(--color-text);
- margin-left: 1rem;
- position: relative;
-}
-
-.nav-link:hover, .nav-link.active {
- color: var(--color-primary);
-}
-
-/* Buttons */
.btn {
- font-weight: 700;
- font-family: var(--font-heading);
- padding: 0.8rem 2rem;
- border-radius: var(--radius-pill);
- border: var(--border-width) solid #000;
- transition: all 0.2s cubic-bezier(0.25, 1, 0.5, 1);
- box-shadow: var(--shadow-hard);
-}
-
-.btn:hover {
- transform: translate(-2px, -2px);
- box-shadow: var(--shadow-hover);
-}
-
-.btn:active {
- transform: translate(2px, 2px);
- box-shadow: 0 0 0 #000;
+ border-radius: var(--radius);
+ font-weight: 500;
+ padding: 0.5rem 1rem;
+ transition: all 0.2s;
}
.btn-primary {
- background-color: var(--color-primary);
- border-color: #000;
- color: #fff;
+ background-color: var(--primary);
+ border-color: var(--primary);
}
.btn-primary:hover {
- background-color: #1d4ed8;
- border-color: #000;
- color: #fff;
+ background-color: #1E293B;
+ border-color: #1E293B;
}
-.btn-outline-dark {
- background-color: #fff;
- color: #000;
-}
-
-.btn-cta {
- background-color: var(--color-accent);
- color: #000;
-}
-
-.btn-cta:hover {
- background-color: #8cc629;
- color: #000;
-}
-
-/* Hero Section */
-.hero-section {
- min-height: 100vh;
- padding-top: 80px;
-}
-
-.background-blob {
- position: absolute;
- border-radius: 50%;
- filter: blur(80px);
- opacity: 0.6;
- z-index: 1;
-}
-
-.blob-1 {
- top: -10%;
- right: -10%;
- width: 600px;
- height: 600px;
- background: radial-gradient(circle, var(--color-accent), transparent);
-}
-
-.blob-2 {
- bottom: 10%;
- left: -10%;
- width: 500px;
- height: 500px;
- background: radial-gradient(circle, var(--color-primary), transparent);
-}
-
-.highlight-text {
- background: linear-gradient(120deg, transparent 0%, transparent 40%, var(--color-accent) 40%, var(--color-accent) 100%);
- background-repeat: no-repeat;
- background-size: 100% 40%;
- background-position: 0 88%;
- padding: 0 5px;
-}
-
-.dot { color: var(--color-primary); }
-
-.badge-pill {
- display: inline-block;
- padding: 0.5rem 1rem;
- border: 2px solid #000;
- border-radius: 50px;
- font-weight: 700;
- background: #fff;
- box-shadow: 4px 4px 0 #000;
- font-family: var(--font-heading);
- font-size: 0.9rem;
-}
-
-/* Marquee */
-.marquee-container {
- overflow: hidden;
- white-space: nowrap;
- border-top: 2px solid #000;
- border-bottom: 2px solid #000;
-}
-
-.rotate-divider {
- transform: rotate(-2deg) scale(1.05);
- z-index: 10;
- position: relative;
- margin-top: -50px;
- margin-bottom: 30px;
-}
-
-.marquee-content {
- display: inline-block;
- animation: marquee 20s linear infinite;
- font-family: var(--font-heading);
- font-weight: 700;
- font-size: 1.5rem;
- letter-spacing: 2px;
-}
-
-@keyframes marquee {
- 0% { transform: translateX(0); }
- 100% { transform: translateX(-50%); }
-}
-
-/* Portfolio Cards */
-.project-card {
- border: 2px solid #000;
- border-radius: var(--radius-card);
- overflow: hidden;
- background: #fff;
- transition: transform 0.3s ease;
- box-shadow: var(--shadow-hard);
- height: 100%;
- display: flex;
- flex-direction: column;
-}
-
-.project-card:hover {
- transform: translateY(-10px);
- box-shadow: 8px 8px 0 #000;
-}
-
-.card-img-holder {
- height: 250px;
- display: flex;
- align-items: center;
- justify-content: center;
- border-bottom: 2px solid #000;
- position: relative;
- font-size: 4rem;
-}
-
-.placeholder-art {
- transition: transform 0.3s ease;
-}
-
-.project-card:hover .placeholder-art {
- transform: scale(1.2) rotate(10deg);
-}
-
-.bg-soft-blue { background-color: #e0f2fe; }
-.bg-soft-green { background-color: #dcfce7; }
-.bg-soft-purple { background-color: #f3e8ff; }
-.bg-soft-yellow { background-color: #fef9c3; }
-
-.category-tag {
- position: absolute;
- top: 15px;
- right: 15px;
- background: #000;
- color: #fff;
- padding: 5px 12px;
- border-radius: 20px;
- font-size: 0.75rem;
- font-weight: 700;
-}
-
-.card-body { padding: 1.5rem; }
-
-.link-arrow {
- text-decoration: none;
- color: #000;
- font-weight: 700;
- display: inline-flex;
- align-items: center;
- margin-top: auto;
-}
-
-.link-arrow i { transition: transform 0.2s; margin-left: 5px; }
-.link-arrow:hover i { transform: translateX(5px); }
-
-/* About */
-.about-image-stack {
- position: relative;
- height: 400px;
- width: 100%;
-}
-
-.stack-card {
- position: absolute;
- width: 80%;
- height: 100%;
- border-radius: var(--radius-card);
- border: 2px solid #000;
- box-shadow: var(--shadow-hard);
- left: 10%;
- transform: rotate(-3deg);
- background-size: cover;
-}
-
-/* Forms */
-.form-control {
- border: 2px solid #000;
- border-radius: 0.5rem;
- padding: 1rem;
- font-weight: 500;
- background: #f8f9fa;
+.form-control, .form-select {
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ padding: 0.5rem 0.75rem;
}
.form-control:focus {
- box-shadow: 4px 4px 0 var(--color-primary);
- border-color: #000;
- background: #fff;
+ border-color: var(--info);
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);
}
-/* Animations */
-.animate-up {
- opacity: 0;
- transform: translateY(30px);
- animation: fadeUp 0.8s ease forwards;
+.navbar {
+ border-bottom: 1px solid var(--border);
+ background-color: #fff;
}
-.delay-100 { animation-delay: 0.1s; }
-.delay-200 { animation-delay: 0.2s; }
-
-@keyframes fadeUp {
- to {
- opacity: 1;
- transform: translateY(0);
- }
+.nav-link {
+ color: var(--secondary);
+ font-weight: 500;
}
-/* Social */
-.social-links a {
- transition: transform 0.2s;
- display: inline-block;
-}
-.social-links a:hover {
- transform: scale(1.2) rotate(10deg);
- color: var(--color-accent) !important;
+.nav-link.active {
+ color: var(--primary);
}
-/* Responsive */
-@media (max-width: 991px) {
- .rotate-divider {
- transform: rotate(0);
- margin-top: 0;
- margin-bottom: 2rem;
- }
-
- .hero-section {
- padding-top: 120px;
- text-align: center;
- min-height: auto;
- padding-bottom: 100px;
- }
-
- .display-1 { font-size: 3.5rem; }
-
- .blob-1 { width: 300px; height: 300px; right: -20%; }
- .blob-2 { width: 300px; height: 300px; left: -20%; }
+.step-indicator {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 2rem;
+ position: relative;
}
+
+.step-indicator::before {
+ content: '';
+ position: absolute;
+ top: 50%;
+ left: 0;
+ right: 0;
+ height: 2px;
+ background: var(--border);
+ z-index: 1;
+ transform: translateY(-50%);
+}
+
+.step {
+ width: 32px;
+ height: 32px;
+ border-radius: 50%;
+ background: #fff;
+ border: 2px solid var(--border);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 2;
+ font-weight: bold;
+ color: var(--secondary);
+}
+
+.step.active {
+ border-color: var(--primary);
+ color: var(--primary);
+}
+
+.step.completed {
+ background: var(--primary);
+ border-color: var(--primary);
+ color: #fff;
+}
\ No newline at end of file
diff --git a/db/init.sql b/db/init.sql
new file mode 100644
index 0000000..9a02767
--- /dev/null
+++ b/db/init.sql
@@ -0,0 +1,41 @@
+CREATE TABLE IF NOT EXISTS companies (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ name VARCHAR(255) NOT NULL,
+ uprn_required BOOLEAN DEFAULT FALSE,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE TABLE IF NOT EXISTS job_statuses (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ company_id INT NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ is_default BOOLEAN DEFAULT FALSE,
+ sort_order INT DEFAULT 0,
+ FOREIGN KEY (company_id) REFERENCES companies(id) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS required_folders (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ company_id INT NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ FOREIGN KEY (company_id) REFERENCES companies(id) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS clients (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ company_id INT NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ is_active BOOLEAN DEFAULT TRUE,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ FOREIGN KEY (company_id) REFERENCES companies(id) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS users (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ company_id INT NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ email VARCHAR(255) NOT NULL UNIQUE,
+ password VARCHAR(255) NOT NULL,
+ role ENUM('admin', 'standard') DEFAULT 'standard',
+ FOREIGN KEY (company_id) REFERENCES companies(id) ON DELETE CASCADE
+);
diff --git a/index.php b/index.php
index 7205f3d..cac0d41 100644
--- a/index.php
+++ b/index.php
@@ -1,150 +1,69 @@
query("SELECT COUNT(*) FROM companies");
+$companyCount = $stmt->fetchColumn();
+
+if ($companyCount == 0) {
+ header('Location: setup.php');
+ exit;
+}
+
+$pageTitle = "Repairs Multi-Tenant App";
?>
-
+
-
-
- New Style
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ = $pageTitle ?> - Landing
+
+
+
-
-
-
Analyzing your requirements and generating your website…
-
- Loading…
-
-
= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.
-
This page will update automatically as the plan is implemented.
-
Runtime: PHP = htmlspecialchars($phpVersion) ?> — UTC = htmlspecialchars($now) ?>
-
-
-
+
+
+
+
+
+
Efficient Repair Management for Multi-Tenant Businesses
+
Isolated data, customizable workflows, and strict audit logging. Everything you need to scale your repair operations.
+
+
+
+
Isolated Data
+
Each company has its own private database silo for jobs, clients, and files.
+
+
+
+
+
Custom Workflows
+
Define your own job statuses and mandatory folder structures.
+
+
+
+
+
Audit Trail
+
Strict server-side logging for every action taken on any job.
+
+
+
+
+
+
+
+
-
+