devdank commited on
Commit
ce53bc1
Β·
verified Β·
1 Parent(s): bec2aac

## πŸ“£ Product Pitch: **Moot** β€” The Offline-First AI Media Intelligence Suite

Browse files

### πŸš€ What is Moot?

**Moot** is a production-grade, offline-first AI media intelligence suite that transforms local audio, video, image, and document content into structured, searchable artifacts β€” entirely without internet connectivity.

Designed for secure environments and privacy-focused workflows, Moot combines GPU-accelerated AI pipelines, real-time monitoring, a customizable dashboard, and a modular CLI. It uniquely supports **NSFW-friendly use cases** by offering **local-only tagging models**, schema-driven customization, and careful metadata handling β€” making it ideal for adult content archiving, moderation, and research.

---

### πŸ” Built for Privacy, Built for Trust

* **Offline-first with controlled download support**: No cloud APIs, CDNs, or telemetry at runtime. Models, datasets, and tools may be downloaded one-way during setup using verified scripts or HuggingFace snapshot tools.
* **All models are local**: Manually hashed and stored under `/models/`.
* **Structured sandboxing**: All temp files, logs, and data are hashed, locked, and stored under controlled paths.
* **Custom tagging schemas**: Define your own tag vocabularies and categories via editable YAML/JSON configs.
* **Training-ready metadata**: Outputs include clean datasets for custom model finetuning or classifier building.
* **NSFW-safe defaults**: Moot makes **no assumptions about user content**, and provides:

* Discrete folder labeling.
* Optional encrypted archives.
* UI-level content warnings.

---

### 🧐 Core Capabilities

#### πŸ“ Transcription: Faster-Whisper Pro Integration

Moot supports an offline, high-performance transcription engine using a **standalone Windows executable** of **Faster-Whisper Pro** (by Purfview). This binary is treated as a trusted external plugin:

* **Offline-only Execution**: Stored under `/vendor/bin/faster-whisper.exe`.
* **Triggered by Plugin Layer**: Called via a Python wrapper, which handles input/output orchestration.
* **Cross-Platform Use**: Supports Wine-based execution or Windows sidecar machine integration.
* **Model Path Control**: Models loaded from `/models/transcription/` by hash/version.
* **Configurable via MCP**: Switchable in real time using the Model Control Panel (e.g., `fw-open` vs `fw-pro`).

This integration ensures that Pro-level transcription features remain offline, GPU-capable (via Windows), and compatible with Moot’s artifact and job framework.

---

#### 🎯 Primary Feature: Face Recognition + Tagging

Moot's central capability is the ability to detect, crop, recognize, and tag faces across video and image media. This is achieved through:

* **Face Detection & Recognition**: Powered by InsightFace with vector matching against a local gallery.
* **Embedding + Metadata Fusion**: Detected faces are embedded (CLIP) and matched with existing person records.
* **Schema-Based Tagging**: Tagging schemas allow faces to be annotated with custom labels (e.g., performer, role, context).
* **Merged Artifacts**: Face crops, embeddings, and tagging are merged into searchable artifacts and datasets.

This pipeline is pluggable, verifiable, and usable offline β€” with performance tuned for both CPU and GPU environments.

---

#### πŸ”„ Modular Media Pipeline

* **Transcription** (Faster-Whisper, CUDA w/ CPU fallback).
* **Subtitle Burn-in** (FFmpeg NVENC).
* **OCR** (Qwen2-VL/Qwen3-VL or Tesseract).
* **Vision Captioning** (BLIP-2).
* **Image & Face Embeddings** (CLIP, InsightFace).
* **HuggingFace Integration**:

* Load models from local HuggingFace format via `/models/{task}/{model_id}/`.
* Use HuggingFace Datasets for local tagging workflows and finetuning.
* Optional HuggingFace Spaces-compatible interface for visual demos (offline).
* Integrate with **MCP** (Model Control Panel) for managing weights, schema linkage, and version pinning.
* **Artifacts**: Subtitles, OCR, embeddings, face crops, captions, hardsubbed videos.
* **Exports**: Stream JSONL/CSV exports, with per-artifact manifests and checksums.

---

### 🧰 Plugin Toolkit: Python-First Swiss-Army Extensions

Moot includes a preloaded, modular plugin system built primarily in Python for maximal portability, auditability, and offline usability. Each plugin is a self-contained task unit, callable from CLI, API, or dashboard.

#### πŸ”§ Core Python-First Plugins

* **Metadata Extraction**: Uses `hachoir` or `pyexiftool` to extract EXIF/XMP/MP4 metadata.
* **Subtitle Manipulation**: Handled via `pysubs2` for merging, splitting, or translating `.srt`, `.ass`, `.vtt` files.
* **Audio Tools**: Leverages `pydub` and `ffmpeg-python` for normalization and waveform trimming.
* **PDF Processing**: Uses `PyMuPDF` or `pdfplumber` to split/merge/annotate PDFs.
* **Scene Detection**: Built with `scenedetect` for frame-accurate shot detection.
* **Image Deduplication**: Uses `imagehash` for perceptual similarity and quarantine logic.
* **Face Recognition**: Wraps `insightface` for local detection, cropping, and gallery matching.

#### 🧩 Plugin Integration Format

* All plugins are stored under `/plugins/{domain}/`.
* Each exports a `run(config)` Python entrypoint.
* Plugins return structured JSON or JSONL.
* Callable from: `aimp plugin <name>` or API UI.

This unified toolkit allows media manipulation, AI inference, tagging, and preparation workflows without relying on shell tools or GUI-based external apps.

---

### πŸ’» Interface-First UX

* **Dashboard**: Built with **Next.js 14**, Tailwind, shadcn/ui.

* Scan, enqueue, job queue, plugin tools, and logs.
* Preview artifacts and export content.
* **StashApp Fork**:

* Full-featured adult media browser integrated as a tab.
* Tagging, scene previews, model-assisted sorting.
* UI hardening + privacy toggles.
* **CLI (`aimp`)**:

* Run full workflows, automate tagging, or execute plugins via terminal.

---

### πŸ“¦ Architecture Overview

* **Backend**: FastAPI, Python 3.12, SQLAlchemy, Pydantic, asyncio, Redis.
* **Frontend**: Next.js 14, SWR, Tailwind.
* **Database**: SQLite (default), Postgres (optional).
* **Deployment**: Offline Docker builds, systemd units, tarball exports.

---

### πŸ“± Monitoring & Operations

* Real-time WebSocket logs with correlation IDs and progress percentages.

* Prometheus labels include `job_kind`, `media_type`, `gpu_present`, `queue_name`.

* `/healthz` fast checks, `/readyz` dependency-aware checks (Redis/DB/models).

* WebSocket logs and status.

* `/metrics` for Prometheus (queue depth, job time, GPU usage, NVENC stats).

* Health checks: `/healthz`, `/readyz`.

* Model/version fingerprinting for reproducibility.

---

### 🦾 Data Model Summary

```plaintext
media(id, path, type, hash, ...)
job(id, media_id, kind, status, ...)
artifact(id, media_id, type, uri, payload JSON)
person(id, name, vector, meta)
tag_schema(id, name, structure, is_custom)
```

---

### 🌟 Performance Targets

* Process 10-min 1080p video (transcription + OCR + hardsubs) under *N* minutes on RTX 4070 Ti.
* Support 100,000+ media files, with resumable and deduplicated pipelines.

---

### πŸ—‚οΈ Organizer & Archiver

* Rule engine on mime/ext/metadata/EXIF/duration/people/language.
* Structured output tree: `/archive/{date}/{type}/{hash}/…` with dedup via SHA256.
* Move/rename hooks, quarantine on failure, retention policies.

---

### πŸ”— API Surface (MVP)

* `POST /api/media/scan` – discover, hash, extract basic media info.
* `POST /api/jobs/enqueue` – create processing jobs (transcribe/ocr/burnin/faces/embed).
* `GET /api/jobs/{id}` – status, progress, logs tail, artifacts.
* `GET /api/media/{id}/artifacts` – filter by type.
* `GET /ws/jobs/{id}` – WebSocket live events.
* `GET /api/export/{format}` – JSONL/CSV stream.
* `GET /api/system/gpu` & `/api/system/watcher` – diagnostics.

---

### 🧰 Ideal Users & Use Cases

* **Adult content researchers** needing structured, local analysis with zero cloud reliance.
* **Archive digitizers** organizing massive offline libraries.
* **Media teams in air-gapped or confidential environments** (e.g., legal, intelligence, journalism).
* **Researchers building datasets** for custom vision/language classifiers.

---

### πŸ“Œ Summary

**Moot** is the first offline-first media AI platform engineered for **trust, flexibility, and performance**. Whether you’re organizing personal archives, building secure pipelines, or processing sensitive NSFW datasets, Moot delivers a complete, modular stack β€” with control, privacy, and verifiability at its core.

No cloud. No compromise.

---

Files changed (7) hide show
  1. README.md +8 -5
  2. components/footer.js +121 -0
  3. components/navbar.js +120 -0
  4. dashboard.html +219 -0
  5. index.html +163 -19
  6. script.js +197 -0
  7. style.css +65 -19
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Mootvision Ai Media Intelligence Suite
3
- emoji: 🐠
4
- colorFrom: green
5
- colorTo: blue
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
1
  ---
2
+ title: MootVision AI - Media Intelligence Suite πŸš€
3
+ colorFrom: purple
4
+ colorTo: purple
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://huggingface.co/deepsite).
components/footer.js ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CustomFooter extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ :host {
7
+ display: block;
8
+ width: 100%;
9
+ }
10
+ .footer-link {
11
+ transition: color 0.2s ease;
12
+ }
13
+ .footer-link:hover {
14
+ color: #3B82F6;
15
+ }
16
+ </style>
17
+ <footer class="bg-white">
18
+ <div class="max-w-7xl mx-auto py-12 px-4 sm:px-6 lg:py-16 lg:px-8">
19
+ <div class="xl:grid xl:grid-cols-3 xl:gap-8">
20
+ <div class="space-y-8 xl:col-span-1">
21
+ <div class="flex items-center">
22
+ <i data-feather="cpu" class="h-8 w-8 text-primary"></i>
23
+ <span class="ml-2 text-xl font-bold text-gray-900">MootVision AI</span>
24
+ </div>
25
+ <p class="text-gray-500 text-base">
26
+ The offline-first AI media intelligence suite. Transform local media into structured, searchable artifacts with complete privacy.
27
+ </p>
28
+ <div class="flex space-x-6">
29
+ <a href="#" class="footer-link text-gray-400 hover:text-gray-500">
30
+ <i data-feather="github"></i>
31
+ </a>
32
+ <a href="#" class="footer-link text-gray-400 hover:text-gray-500">
33
+ <i data-feather="twitter"></i>
34
+ </a>
35
+ <a href="#" class="footer-link text-gray-400 hover:text-gray-500">
36
+ <i data-feather="mail"></i>
37
+ </a>
38
+ </div>
39
+ </div>
40
+ <div class="mt-12 grid grid-cols-2 gap-8 xl:mt-0 xl:col-span-2">
41
+ <div class="md:grid md:grid-cols-2 md:gap-8">
42
+ <div>
43
+ <h3 class="text-sm font-semibold text-gray-400 tracking-wider uppercase">
44
+ Solutions
45
+ </h3>
46
+ <ul class="mt-4 space-y-4">
47
+ <li>
48
+ <a href="dashboard.html" class="footer-link text-base text-gray-500 hover:text-gray-900">
49
+ Media Processing
50
+ </a>
51
+ </li>
52
+ <li>
53
+ <a href="features.html" class="footer-link text-base text-gray-500 hover:text-gray-900">
54
+ AI Features
55
+ </a>
56
+ </li>
57
+ <li>
58
+ <a href="docs.html" class="footer-link text-base text-gray-500 hover:text-gray-900">
59
+ Documentation
60
+ </a>
61
+ </li>
62
+ </ul>
63
+ </div>
64
+ <div>
65
+ <h3 class="text-sm font-semibold text-gray-400 tracking-wider uppercase">
66
+ Support
67
+ </h3>
68
+ <ul class="mt-4 space-y-4">
69
+ <li>
70
+ <a href="about.html" class="footer-link text-base text-gray-500 hover:text-gray-900">
71
+ About
72
+ </a>
73
+ </li>
74
+ <li>
75
+ <a href="#" class="footer-link text-base text-gray-500 hover:text-gray-900">
76
+ Contact
77
+ </a>
78
+ </li>
79
+ <li>
80
+ <a href="#" class="footer-link text-base text-gray-500 hover:text-gray-900">
81
+ Privacy
82
+ </a>
83
+ </li>
84
+ </ul>
85
+ </div>
86
+ </div>
87
+ </div>
88
+ </div>
89
+ <div class="mt-12 border-t border-gray-200 pt-8">
90
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
91
+ <div class="md:flex md:justify-between">
92
+ <div class="flex space-x-6 md:order-2">
93
+ <a href="#" class="footer-link text-gray-400 hover:text-gray-500">
94
+ Terms
95
+ </a>
96
+ <a href="#" class="footer-link text-gray-400 hover:text-gray-500">
97
+ Privacy
98
+ </a>
99
+ <a href="#" class="footer-link text-gray-400 hover:text-gray-500">
100
+ License
101
+ </a>
102
+ </div>
103
+ <p class="mt-8 text-base text-gray-400 md:mt-0 md:order-1">
104
+ &copy; 2024 MootVision AI. All rights reserved.
105
+ </p>
106
+ </div>
107
+ </div>
108
+ </div>
109
+ </div>
110
+ `;
111
+
112
+ // Initialize Feather icons in shadow DOM
113
+ setTimeout(() => {
114
+ if (typeof feather !== 'undefined') {
115
+ feather.replace();
116
+ }
117
+ }, 100);
118
+ }
119
+ }
120
+
121
+ customElements.define('custom-footer', CustomFooter);
components/navbar.js ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CustomNavbar extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ :host {
7
+ display: block;
8
+ width: 100%;
9
+ position: sticky;
10
+ top: 0;
11
+ z-index: 50;
12
+ }
13
+ nav {
14
+ background: rgba(255, 255, 255, 0.95);
15
+ backdrop-filter: blur(8px);
16
+ border-bottom: 1px solid #e5e7eb;
17
+ }
18
+ .nav-link {
19
+ transition: color 0.2s ease;
20
+ }
21
+ .nav-link:hover {
22
+ color: #3B82F6;
23
+ }
24
+ .mobile-menu {
25
+ transition: all 0.3s ease;
26
+ }
27
+ </style>
28
+ <nav class="bg-white shadow-sm">
29
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
30
+ <div class="flex justify-between h-16">
31
+ <div class="flex items-center">
32
+ <a href="index.html" class="flex-shrink-0 flex items-center">
33
+ <i data-feather="cpu" class="h-8 w-8 text-primary"></i>
34
+ <span class="ml-2 text-xl font-bold text-gray-900">MootVision AI</span>
35
+ </a>
36
+ <div class="hidden md:ml-6 md:flex md:space-x-8">
37
+ <a href="index.html" class="nav-link border-primary text-gray-900 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium">
38
+ Home
39
+ </a>
40
+ <a href="dashboard.html" class="nav-link border-transparent text-gray-500 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium">
41
+ Dashboard
42
+ </a>
43
+ <a href="features.html" class="nav-link border-transparent text-gray-500 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium">
44
+ Features
45
+ </a>
46
+ <a href="about.html" class="nav-link border-transparent text-gray-500 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium">
47
+ About
48
+ </a>
49
+ </div>
50
+ </div>
51
+ <div class="hidden md:flex items-center space-x-4">
52
+ <a href="docs.html" class="text-gray-500 hover:text-gray-700">
53
+ <i data-feather="book"></i>
54
+ </a>
55
+ <button id="theme-toggle" class="text-gray-500 hover:text-gray-700">
56
+ <i data-feather="moon"></i>
57
+ </button>
58
+ </div>
59
+ <div class="md:hidden flex items-center">
60
+ <button id="mobile-menu-button" class="text-gray-500 hover:text-gray-700">
61
+ <i data-feather="menu"></i>
62
+ </button>
63
+ </div>
64
+ </div>
65
+ </div>
66
+
67
+ <!-- Mobile menu -->
68
+ <div id="mobile-menu" class="mobile-menu hidden md:hidden">
69
+ <div class="px-2 pt-2 pb-3 space-y-1">
70
+ <a href="index.html" class="nav-link block px-3 py-2 text-base font-medium text-gray-900 bg-gray-50">
71
+ Home
72
+ </a>
73
+ <a href="dashboard.html" class="nav-link block px-3 py-2 text-base font-medium text-gray-500 hover:text-gray-700 hover:bg-gray-50">
74
+ Dashboard
75
+ </a>
76
+ <a href="features.html" class="nav-link block px-3 py-2 text-base font-medium text-gray-500 hover:text-gray-700 hover:bg-gray-50">
77
+ Features
78
+ </a>
79
+ <a href="about.html" class="nav-link block px-3 py-2 text-base font-medium text-gray-500 hover:text-gray-700 hover:bg-gray-50">
80
+ About
81
+ </a>
82
+ </div>
83
+ </div>
84
+ </nav>
85
+ `;
86
+
87
+ this.initializeEventListeners();
88
+ }
89
+
90
+ initializeEventListeners() {
91
+ // Mobile menu toggle
92
+ const mobileMenuButton = this.shadowRoot.getElementById('mobile-menu-button');
93
+ const mobileMenu = this.shadowRoot.getElementById('mobile-menu');
94
+
95
+ if (mobileMenuButton && mobileMenu) {
96
+ mobileMenuButton.addEventListener('click', () => {
97
+ mobileMenu.classList.toggle('hidden');
98
+ });
99
+ }
100
+
101
+ // Theme toggle
102
+ const themeToggle = this.shadowRoot.getElementById('theme-toggle');
103
+ if (themeToggle) {
104
+ themeToggle.addEventListener('click', () => {
105
+ if (window.themeManager) {
106
+ window.themeManager.toggleTheme();
107
+ }
108
+ });
109
+ }
110
+
111
+ // Initialize Feather icons in shadow DOM
112
+ setTimeout(() => {
113
+ if (typeof feather !== 'undefined') {
114
+ feather.replace();
115
+ }
116
+ }, 100);
117
+ }
118
+ }
119
+
120
+ customElements.define('custom-navbar', CustomNavbar);
dashboard.html ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Dashboard - MootVision AI</title>
7
+ <link rel="icon" type="image/x-icon" href="/static/favicon.ico">
8
+ <link rel="stylesheet" href="style.css">
9
+ <script src="https://cdn.tailwindcss.com"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
11
+ <script src="https://unpkg.com/feather-icons"></script>
12
+ <script>
13
+ tailwind.config = {
14
+ theme: {
15
+ extend: {
16
+ colors: {
17
+ primary: '#3B82F6',
18
+ secondary: '#10B981'
19
+ }
20
+ }
21
+ }
22
+ }
23
+ </script>
24
+ </head>
25
+ <body class="bg-gray-50">
26
+ <custom-navbar></custom-navbar>
27
+
28
+ <main class="min-h-screen">
29
+ <div class="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
30
+ <!-- Page header -->
31
+ <div class="md:flex md:items-center md:justify-between">
32
+ <div class="flex-1 min-w-0">
33
+ <h2 class="text-2xl font-bold leading-7 text-gray-900 sm:text-3xl sm:truncate">
34
+ Dashboard
35
+ </h2>
36
+ </div>
37
+ <div class="mt-4 flex md:mt-0 md:ml-4">
38
+ <button type="button" class="ml-3 inline-flex items-center px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-primary hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary">
39
+ <i data-feather="plus" class="mr-2"></i>
40
+ New Job
41
+ </button>
42
+ </div>
43
+ </div>
44
+ </div>
45
+
46
+ <!-- Stats grid -->
47
+ <div class="mt-8 grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-4">
48
+ <!-- Total Media -->
49
+ <div class="bg-white overflow-hidden shadow rounded-lg">
50
+ <div class="p-5">
51
+ <div class="flex items-center">
52
+ <div class="flex-shrink-0">
53
+ <i data-feather="film" class="h-6 w-6 text-gray-400"></i>
54
+ </div>
55
+ <div class="ml-5 w-0 flex-1">
56
+ <dl>
57
+ <dt class="text-sm font-medium text-gray-500 truncate">
58
+ Total Media
59
+ </dt>
60
+ <dd class="flex items-baseline">
61
+ <div class="text-2xl font-semibold text-gray-900">1,248</div>
62
+ </dd>
63
+ </dl>
64
+ </div>
65
+ </div>
66
+ </div>
67
+ </div>
68
+
69
+ <!-- Processing Jobs -->
70
+ <div class="bg-white overflow-hidden shadow rounded-lg">
71
+ <div class="p-5">
72
+ <div class="flex items-center">
73
+ <div class="flex-shrink-0">
74
+ <i data-feather="cpu" class="h-6 w-6 text-gray-400"></i>
75
+ </div>
76
+ <div class="ml-5 w-0 flex-1">
77
+ <dl>
78
+ <dt class="text-sm font-medium text-gray-500 truncate">
79
+ Active Jobs
80
+ </dt>
81
+ <dd class="flex items-baseline">
82
+ <div class="text-2xl font-semibold text-gray-900">3</div>
83
+ </dd>
84
+ </dl>
85
+ </div>
86
+ </div>
87
+ </div>
88
+ </div>
89
+
90
+ <!-- Storage Used -->
91
+ <div class="bg-white overflow-hidden shadow rounded-lg">
92
+ <div class="p-5">
93
+ <div class="flex items-center">
94
+ <div class="flex-shrink-0">
95
+ <i data-feather="hard-drive" class="h-6 w-6 text-gray-400"></i>
96
+ </div>
97
+ <div class="ml-5 w-0 flex-1">
98
+ <dl>
99
+ <dt class="text-sm font-medium text-gray-500 truncate">
100
+ Storage Used
101
+ </dt>
102
+ <dd class="flex items-baseline">
103
+ <div class="text-2xl font-semibold text-gray-900">2.4 TB</div>
104
+ </dd>
105
+ </dl>
106
+ </div>
107
+ </div>
108
+ </div>
109
+ </div>
110
+
111
+ <!-- GPU Status -->
112
+ <div class="bg-white overflow-hidden shadow rounded-lg">
113
+ <div class="p-5">
114
+ <div class="flex items-center">
115
+ <div class="flex-shrink-0">
116
+ <i data-feather="activity" class="h-6 w-6 text-gray-400"></i>
117
+ </div>
118
+ <div class="ml-5 w-0 flex-1">
119
+ <dl>
120
+ <dt class="text-sm font-medium text-gray-500 truncate">
121
+ GPU Status
122
+ </dt>
123
+ <dd class="flex items-baseline">
124
+ <div class="text-2xl font-semibold text-gray-900">Active</div>
125
+ </dd>
126
+ </dl>
127
+ </div>
128
+ </div>
129
+ </div>
130
+ </div>
131
+ </div>
132
+
133
+ <!-- Main content area -->
134
+ <div class="mt-8 grid grid-cols-1 gap-6 lg:grid-cols-3">
135
+ <!-- Job Queue -->
136
+ <div class="lg:col-span-2">
137
+ <div class="bg-white shadow rounded-lg">
138
+ <div class="px-4 py-5 sm:p-6">
139
+ <h3 class="text-lg leading-6 font-medium text-gray-900">
140
+ Active Job Queue
141
+ </h3>
142
+ <div class="mt-5">
143
+ <div class="space-y-4">
144
+ <!-- Job 1 -->
145
+ <div class="bg-gray-50 rounded-lg p-4">
146
+ <div class="flex items-center justify-between">
147
+ <div>
148
+ <h4 class="text-sm font-medium text-gray-900">
149
+ Video Transcription - sample_video.mp4
150
+ </h4>
151
+ <div class="mt-2">
152
+ <div class="flex items-center text-sm text-gray-500">
153
+ <i data-feather="clock" class="mr-1 h-4 w-4"></i>
154
+ <span>Started 5 minutes ago</span>
155
+ </div>
156
+ </div>
157
+ <div class="mt-4">
158
+ <div class="w-full bg-gray-200 rounded-full h-2">
159
+ <div class="bg-primary h-2 rounded-full" style="width: 65%"></div>
160
+ </div>
161
+ </div>
162
+
163
+ <!-- Job 2 -->
164
+ <div class="bg-gray-50 rounded-lg p-4">
165
+ <div class="flex items-center justify-between">
166
+ <div>
167
+ <h4 class="text-sm font-medium text-gray-900">
168
+ Face Recognition - image_gallery
169
+ </h4>
170
+ <div class="mt-2">
171
+ <div class="flex items-center text-sm text-gray-500">
172
+ <i data-feather="clock" class="mr-1 h-4 w-4"></i>
173
+ <span>Started 2 minutes ago</span>
174
+ </div>
175
+ </div>
176
+ <div class="mt-4">
177
+ <div class="w-full bg-gray-200 rounded-full h-2">
178
+ <div class="bg-secondary h-2 rounded-full" style="width: 30%"></div>
179
+ </div>
180
+ </div>
181
+ </div>
182
+ </div>
183
+ </div>
184
+ </div>
185
+
186
+ <!-- Quick Actions -->
187
+ <div class="lg:col-span-1">
188
+ <div class="bg-white shadow rounded-lg">
189
+ <div class="px-4 py-5 sm:p-6">
190
+ <h3 class="text-lg leading-6 font-medium text-gray-900">
191
+ Quick Actions
192
+ </h3>
193
+ <div class="mt-5 space-y-3">
194
+ <button class="w-full inline-flex items-center justify-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-primary hover:bg-blue-700">
195
+ <i data-feather="folder-plus" class="mr-2"></i>
196
+ Scan Media
197
+ </button>
198
+ <button class="w-full inline-flex items-center justify-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-primary bg-white border-primary hover:bg-gray-50">
199
+ <i data-feather="settings" class="mr-2"></i>
200
+ Settings
201
+ </button>
202
+ <button class="w-full inline-flex items-center justify-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-secondary hover:bg-green-600">
203
+ <i data-feather="download" class="mr-2"></i>
204
+ Export Data
205
+ </button>
206
+ </div>
207
+ </div>
208
+ </div>
209
+ </div>
210
+ </main>
211
+
212
+ <custom-footer></custom-footer>
213
+
214
+ <script src="components/navbar.js"></script>
215
+ <script src="components/footer.js"></script>
216
+ <script src="script.js"></script>
217
+ <script>feather.replace();</script>
218
+ </body>
219
+ </html>
index.html CHANGED
@@ -1,19 +1,163 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>MootVision AI - Media Intelligence Suite</title>
7
+ <link rel="icon" type="image/x-icon" href="/static/favicon.ico">
8
+ <link rel="stylesheet" href="style.css">
9
+ <script src="https://cdn.tailwindcss.com"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
11
+ <script src="https://unpkg.com/feather-icons"></script>
12
+ <script>
13
+ tailwind.config = {
14
+ theme: {
15
+ extend: {
16
+ colors: {
17
+ primary: '#3B82F6',
18
+ secondary: '#10B981'
19
+ }
20
+ }
21
+ }
22
+ }
23
+ </script>
24
+ </head>
25
+ <body class="bg-gray-50">
26
+ <custom-navbar></custom-navbar>
27
+
28
+ <main class="min-h-screen">
29
+ <!-- Hero Section -->
30
+ <section class="relative bg-white overflow-hidden">
31
+ <div class="max-w-7xl mx-auto">
32
+ <div class="relative z-10 pb-8 bg-white sm:pb-16 md:pb-20 lg:max-w-2xl lg:w-full lg:pb-28 xl:pb-32">
33
+ <div class="pt-10 mx-auto max-w-7xl px-4 sm:pt-12 sm:px-6 md:pt-16 lg:pt-20 lg:px-8 xl:pt-28">
34
+ <div class="sm:text-center lg:text-left">
35
+ <h1 class="text-4xl tracking-tight font-extrabold text-gray-900 sm:text-5xl md:text-6xl">
36
+ <span class="block">MootVision AI</span>
37
+ <span class="block text-primary">Media Intelligence</span>
38
+ <span class="block text-secondary">Suite</span>
39
+ </h1>
40
+ <p class="mt-3 text-base text-gray-500 sm:mt-5 sm:text-lg sm:max-w-xl sm:mx-auto md:mt-5 md:text-xl lg:mx-0">
41
+ Transform your local media into structured, searchable artifacts with our offline-first AI platform. Privacy-focused, GPU-accelerated, and completely cloud-free.
42
+ </p>
43
+ <div class="mt-5 sm:mt-8 sm:flex sm:justify-center lg:justify-start">
44
+ <div class="rounded-md shadow">
45
+ <a href="dashboard.html" class="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base font-medium rounded-md text-white bg-primary hover:bg-blue-700 md:py-4 md:text-lg md:px-10">
46
+ Launch Dashboard
47
+ </a>
48
+ </div>
49
+ <div class="mt-3 sm:mt-0 sm:ml-3">
50
+ <a href="features.html" class="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base font-medium rounded-md text-primary bg-white hover:bg-gray-50 md:py-4 md:text-lg md:px-10">
51
+ Explore Features
52
+ </a>
53
+ </div>
54
+ </div>
55
+ </div>
56
+ </div>
57
+ </div>
58
+ </div>
59
+ <div class="lg:absolute lg:inset-y-0 lg:right-0 lg:w-1/2">
60
+ <img class="h-56 w-full object-cover sm:h-72 md:h-96 lg:w-full lg:h-full" src="http://static.photos/technology/1200x630/1" alt="AI Media Processing">
61
+ </div>
62
+ </section>
63
+
64
+ <!-- Features Grid -->
65
+ <section class="py-12 bg-white">
66
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
67
+ <div class="lg:text-center">
68
+ <h2 class="text-base text-primary font-semibold tracking-wide uppercase">Core Capabilities</h2>
69
+ <p class="mt-2 text-3xl leading-8 font-extrabold tracking-tight text-gray-900 sm:text-4xl">
70
+ Powerful AI Media Processing
71
+ </p>
72
+ </div>
73
+
74
+ <div class="mt-10">
75
+ <div class="space-y-10 md:space-y-0 md:grid md:grid-cols-2 md:gap-x-8 md:gap-y-10">
76
+ <!-- Feature 1 -->
77
+ <div class="relative">
78
+ <div class="absolute flex items-center justify-center h-12 w-12 rounded-md bg-primary text-white">
79
+ <i data-feather="mic"></i>
80
+ </div>
81
+ <div class="ml-16">
82
+ <h3 class="text-lg leading-6 font-medium text-gray-900">Advanced Transcription</h3>
83
+ <p class="mt-2 text-base text-gray-500">
84
+ Offline Faster-Whisper Pro integration with GPU acceleration and multi-language support.
85
+ </p>
86
+ </div>
87
+ </div>
88
+
89
+ <!-- Feature 2 -->
90
+ <div class="relative">
91
+ <div class="absolute flex items-center justify-center h-12 w-12 rounded-md bg-primary text-white">
92
+ <i data-feather="user"></i>
93
+ </div>
94
+ <div class="ml-16">
95
+ <h3 class="text-lg leading-6 font-medium text-gray-900">Face Recognition</h3>
96
+ <p class="mt-2 text-base text-gray-500">
97
+ InsightFace-powered detection, cropping, and tagging with local gallery matching.
98
+ </p>
99
+ </div>
100
+ </div>
101
+
102
+ <!-- Feature 3 -->
103
+ <div class="relative">
104
+ <div class="absolute flex items-center justify-center h-12 w-12 rounded-md bg-primary text-white">
105
+ <i data-feather="eye"></i>
106
+ </div>
107
+ <div class="ml-16">
108
+ <h3 class="text-lg leading-6 font-medium text-gray-900">Vision Analysis</h3>
109
+ <p class="mt-2 text-base text-gray-500">
110
+ CLIP embeddings, BLIP-2 captioning, and scene detection for comprehensive media understanding.
111
+ </p>
112
+ </div>
113
+ </div>
114
+
115
+ <!-- Feature 4 -->
116
+ <div class="relative">
117
+ <div class="absolute flex items-center justify-center h-12 w-12 rounded-md bg-primary text-white">
118
+ <i data-feather="shield"></i>
119
+ </div>
120
+ <div class="ml-16">
121
+ <h3 class="text-lg leading-6 font-medium text-gray-900">Privacy First</h3>
122
+ <p class="mt-2 text-base text-gray-500">
123
+ All processing happens locally with no cloud dependencies or data leaks.
124
+ </p>
125
+ </div>
126
+ </div>
127
+ </div>
128
+ </div>
129
+ </div>
130
+ </section>
131
+
132
+ <!-- CTA Section -->
133
+ <section class="bg-primary">
134
+ <div class="max-w-7xl mx-auto py-12 px-4 sm:px-6 lg:py-16 lg:px-8">
135
+ <div class="lg:flex lg:items-center lg:justify-between">
136
+ <div class="flex-1 min-w-0">
137
+ <h2 class="text-3xl font-extrabold tracking-tight text-white sm:text-4xl">
138
+ <span class="block">Ready to transform your media?</span>
139
+ <span class="block text-blue-200">Start processing offline today.</span>
140
+ </h2>
141
+ </div>
142
+ <div class="mt-8 flex lg:mt-0 lg:flex-shrink-0">
143
+ <div class="inline-flex rounded-md shadow">
144
+ <a href="dashboard.html" class="inline-flex items-center justify-center px-5 py-3 border border-transparent text-base font-medium rounded-md text-primary bg-white hover:bg-gray-50">
145
+ Get Started
146
+ <i data-feather="arrow-right" class="ml-2"></i>
147
+ </a>
148
+ </div>
149
+ </div>
150
+ </div>
151
+ </div>
152
+ </section>
153
+ </main>
154
+
155
+ <custom-footer></custom-footer>
156
+
157
+ <script src="components/navbar.js"></script>
158
+ <script src="components/footer.js"></script>
159
+ <script src="script.js"></script>
160
+ <script>feather.replace();</script>
161
+ <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
162
+ </body>
163
+ </html>
script.js ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Global JavaScript for MootVision AI
2
+
3
+ // Initialize Feather Icons
4
+ document.addEventListener('DOMContentLoaded', function() {
5
+ if (typeof feather !== 'undefined') {
6
+ feather.replace();
7
+ }
8
+ });
9
+
10
+ // Theme management
11
+ class ThemeManager {
12
+ constructor() {
13
+ this.currentTheme = 'light';
14
+ this.init();
15
+ }
16
+
17
+ init() {
18
+ // Check for saved theme preference or default to light
19
+ const savedTheme = localStorage.getItem('mootvision-theme');
20
+ if (savedTheme) {
21
+ this.setTheme(savedTheme);
22
+ }
23
+ }
24
+
25
+ setTheme(theme) {
26
+ this.currentTheme = theme;
27
+ document.documentElement.setAttribute('data-theme', theme);
28
+ localStorage.setItem('mootvision-theme', theme);
29
+ }
30
+
31
+ toggleTheme() {
32
+ const newTheme = this.currentTheme === 'light' ? 'dark' : 'light';
33
+ this.setTheme(newTheme);
34
+ }
35
+ }
36
+
37
+ // Initialize theme manager
38
+ const themeManager = new ThemeManager();
39
+
40
+ // API integration utilities
41
+ class API {
42
+ static baseURL = '/api';
43
+
44
+ static async get(endpoint) {
45
+ try {
46
+ const response = await fetch(`${this.baseURL}${endpoint}`);
47
+ return await response.json();
48
+ } catch (error) {
49
+ console.error('API Error:', error);
50
+ throw error;
51
+ }
52
+ }
53
+
54
+ static async post(endpoint, data) {
55
+ try {
56
+ const response = await fetch(`${this.baseURL}${endpoint}`, {
57
+ method: 'POST',
58
+ headers: {
59
+ 'Content-Type': 'application/json',
60
+ },
61
+ body: JSON.stringify(data)
62
+ });
63
+ return await response.json();
64
+ } catch (error) {
65
+ console.error('API Error:', error);
66
+ throw error;
67
+ }
68
+ }
69
+ }
70
+
71
+ // Job progress tracking
72
+ class JobTracker {
73
+ constructor(jobId) {
74
+ this.jobId = jobId;
75
+ this.ws = null;
76
+ this.connect();
77
+ }
78
+
79
+ connect() {
80
+ this.ws = new WebSocket(`ws://localhost/api/ws/jobs/${this.jobId}`);
81
+
82
+ this.ws.onopen = () => {
83
+ console.log(`WebSocket connected for job ${this.jobId}`);
84
+ this.updateUI('connected');
85
+ };
86
+
87
+ this.ws.onmessage = (event) => {
88
+ const data = JSON.parse(event.data);
89
+ this.handleMessage(data);
90
+ };
91
+
92
+ this.ws.onclose = () => {
93
+ console.log(`WebSocket disconnected for job ${this.jobId}`);
94
+ setTimeout(() => this.connect(), 5000); // Reconnect after 5 seconds
95
+ };
96
+ }
97
+
98
+ handleMessage(data) {
99
+ switch (data.type) {
100
+ case 'progress':
101
+ this.updateProgress(data.progress);
102
+ break;
103
+ case 'log':
104
+ this.appendLog(data.message);
105
+ break;
106
+ case 'completed':
107
+ this.jobCompleted(data.results);
108
+ break;
109
+ case 'error':
110
+ this.jobError(data.error);
111
+ break;
112
+ }
113
+ }
114
+
115
+ updateProgress(progress) {
116
+ const progressBar = document.getElementById(`progress-${this.jobId}`);
117
+ const progressText = document.getElementById(`progress-text-${this.jobId}`);
118
+
119
+ if (progressBar) {
120
+ progressBar.style.width = `${progress}%`;
121
+ }
122
+
123
+ if (progressText) {
124
+ progressText.textContent = `${progress}%`;
125
+ }
126
+ }
127
+
128
+ appendLog(message) {
129
+ const logContainer = document.getElementById(`logs-${this.jobId}`);
130
+ if (logContainer) {
131
+ const logEntry = document.createElement('div');
132
+ logEntry.className = 'text-sm text-gray-600';
133
+ logEntry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
134
+ logContainer.appendChild(logEntry);
135
+ logContainer.scrollTop = logContainer.scrollHeight;
136
+ }
137
+ }
138
+
139
+ jobCompleted(results) {
140
+ this.updateUI('completed');
141
+ if (typeof window.jobCompletedCallback === 'function') {
142
+ window.jobCompletedCallback(results);
143
+ }
144
+ }
145
+
146
+ jobError(error) {
147
+ this.updateUI('error');
148
+ console.error('Job error:', error);
149
+ }
150
+
151
+ updateUI(status) {
152
+ // Update UI based on job status
153
+ const jobElement = document.getElementById(`job-${this.jobId}`);
154
+ if (jobElement) {
155
+ jobElement.setAttribute('data-status', status);
156
+ }
157
+ }
158
+ }
159
+
160
+ // Utility functions
161
+ const Utils = {
162
+ formatFileSize(bytes) {
163
+ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
164
+ if (bytes === 0) return '0 Bytes';
165
+ const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
166
+ return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i];
167
+ },
168
+
169
+ formatDuration(seconds) {
170
+ const hours = Math.floor(seconds / 3600);
171
+ const minutes = Math.floor((seconds % 3600) / 60);
172
+ const secs = Math.floor(seconds % 60);
173
+ return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
174
+ },
175
+
176
+ debounce(func, wait) {
177
+ let timeout;
178
+ return function executedFunction(...args) {
179
+ const later = () => {
180
+ clearTimeout(timeout);
181
+ func(...args);
182
+ };
183
+ clearTimeout(timeout);
184
+ timeout = setTimeout(later, wait);
185
+ };
186
+ },
187
+
188
+ generateId() {
189
+ return Date.now().toString(36) + Math.random().toString(36).substr(2);
190
+ }
191
+ };
192
+
193
+ // Export for use in other modules
194
+ window.API = API;
195
+ window.JobTracker = JobTracker;
196
+ window.Utils = Utils;
197
+ window.themeManager = themeManager;
style.css CHANGED
@@ -1,28 +1,74 @@
1
- body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  }
5
 
6
- h1 {
7
- font-size: 16px;
8
- margin-top: 0;
9
  }
10
 
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
16
  }
17
 
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
24
  }
25
 
26
- .card p:last-child {
27
- margin-bottom: 0;
 
 
 
28
  }
 
 
 
 
 
 
 
 
 
1
+ /* Custom styles for MootVision AI */
2
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
3
+
4
+ * {
5
+ font-family: 'Inter', sans-serif;
6
+ }
7
+
8
+ /* Smooth scrolling */
9
+ html {
10
+ scroll-behavior: smooth;
11
+ }
12
+
13
+ /* Custom gradient backgrounds */
14
+ .gradient-bg {
15
+ background: linear-gradient(135deg, #3B82F6 0%, #10B981 100%);
16
+ }
17
+
18
+ /* Card hover effects */
19
+ .feature-card {
20
+ transition: all 0.3s ease;
21
+ border: 1px solid #e5e7eb;
22
+ }
23
+
24
+ .feature-card:hover {
25
+ transform: translateY(-5px);
26
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
27
+ }
28
+
29
+ /* Loading animation */
30
+ @keyframes pulse {
31
+ 0%, 100% {
32
+ opacity: 1;
33
+ }
34
+ 50% {
35
+ opacity: 0.5;
36
+ }
37
+ }
38
+
39
+ .pulse {
40
+ animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
41
+ }
42
+
43
+ /* Custom scrollbar */
44
+ ::-webkit-scrollbar {
45
+ width: 6px;
46
  }
47
 
48
+ ::-webkit-scrollbar-track {
49
+ background: #f1f5f9;
 
50
  }
51
 
52
+ ::-webkit-scrollbar-thumb {
53
+ background: #cbd5e1;
54
+ border-radius: 3px;
 
 
55
  }
56
 
57
+ ::-webkit-scrollbar-thumb:hover {
58
+ background: #94a3b8;
 
 
 
 
59
  }
60
 
61
+ /* Focus states for accessibility */
62
+ button:focus,
63
+ a:focus {
64
+ outline: 2px solid #3B82F6;
65
+ outline-offset: 2px;
66
  }
67
+
68
+ /* Dark mode support (for future implementation) */
69
+ @media (prefers-color-scheme: dark) {
70
+ .dark-mode-support {
71
+ background-color: #1f2937;
72
+ color: #f9fafb;
73
+ }
74
+ }