diff --git a/docs/PERFORMANCE_OPTIMIZATIONS.md b/docs/PERFORMANCE_OPTIMIZATIONS.md
new file mode 100644
index 0000000..9cf539a
--- /dev/null
+++ b/docs/PERFORMANCE_OPTIMIZATIONS.md
@@ -0,0 +1,314 @@
+# Performance Optimizations
+
+This document outlines the performance optimizations implemented for the Sensasiwangi.id web application.
+
+## Overview
+
+The application uses HTMX, vanilla JavaScript, and CSS with Supabase as the database. All optimizations focus on reducing bundle size, improving load times, and enhancing the user experience without compromising the tech stack.
+
+## Implemented Optimizations
+
+### 1. Asset Minification
+
+**Location**: `scripts/minify_assets.py`
+
+All CSS and JavaScript files are now minified for production use:
+
+- **CSS Reduction**: ~18-20% size reduction (128KB → ~105KB)
+- **JavaScript Reduction**: ~20-25% size reduction (30KB → ~24KB)
+
+**Files Minified**:
+- `base.css`: 47.5KB → 38.8KB (18.4% reduction)
+- `brand.css`: 15KB → 12KB (20.1% reduction)
+- `dashboard.css`: 12.3KB → 9.9KB (19.3% reduction)
+- All other CSS and JS files similarly optimized
+
+**Usage**:
+```bash
+python3 scripts/minify_assets.py
+```
+
+### 2. Resource Hints
+
+**Location**: `src/app/web/templates/base.html`
+
+Added DNS prefetch and preconnect hints for external resources:
+
+```html
+
+
+
+
+
+
+```
+
+**Benefits**: Reduces DNS lookup time and establishes early connections to external domains.
+
+### 3. Optimized Font Loading
+
+**Location**: `src/app/web/templates/base.html`
+
+Implemented non-blocking font loading strategy:
+
+```html
+
+```
+
+**Benefits**:
+- Prevents font loading from blocking page render
+- Uses `media="print"` trick for async loading
+- Includes `font-display: swap` in Google Fonts URL
+
+### 4. GZip Compression
+
+**Location**: `src/app/core/application.py`
+
+Added GZip compression middleware to compress responses:
+
+```python
+if settings.enable_compression:
+ app.add_middleware(GZipMiddleware, minimum_size=1000, compresslevel=6)
+```
+
+**Benefits**:
+- Typical 60-80% reduction in transfer size
+- Enabled by default (configurable via `ENABLE_COMPRESSION` env var)
+
+### 5. Aggressive Caching Headers
+
+**Location**: `src/app/core/static_files.py`
+
+Custom static file serving with optimized cache headers:
+
+```python
+class CachedStaticFiles(StaticFiles):
+ """Static files middleware with aggressive caching for immutable assets."""
+
+ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
+ # Add cache headers for static assets
+ headers[b"Cache-Control"] = b"public, max-age=31536000, immutable"
+ headers[b"Vary"] = b"Accept-Encoding"
+```
+
+**Benefits**:
+- 1-year cache for versioned static assets
+- Immutable flag tells browsers to never revalidate
+- Assets are versioned via query string (`?v=2024051901`)
+
+### 6. Deferred JavaScript Loading
+
+**Location**: All templates
+
+All JavaScript files load with `defer` attribute:
+
+```html
+
+```
+
+**Benefits**:
+- Scripts don't block HTML parsing
+- Scripts execute in order after DOM is ready
+- Better perceived page load time
+
+### 7. Conditional Minified Assets
+
+**Location**: `src/app/core/config.py`, `src/app/web/templates/__init__.py`
+
+Added configuration to toggle between development and production assets:
+
+```python
+# In config.py
+use_minified_assets: bool = False
+
+# In templates
+{{ url_for('static', path='css/base.min.css') if use_minified else url_for('static', path='css/base.css') }}
+```
+
+**Benefits**:
+- Easy switching between dev and prod builds
+- Maintains readable code in development
+- Optimized delivery in production
+
+### 8. Extracted Inline Scripts
+
+**Location**: `src/app/web/static/js/newsletter.js`
+
+Moved inline JavaScript to separate cacheable files:
+
+- Newsletter form handling → `newsletter.js`
+- Other inline scripts can be extracted similarly
+
+**Benefits**:
+- Better caching (inline scripts can't be cached)
+- Reduced HTML size
+- Easier maintenance and testing
+
+### 9. HTMX Optimization
+
+**Location**: `src/app/web/templates/base.html`
+
+Added module preload for HTMX:
+
+```html
+
+
+```
+
+**Benefits**:
+- Browser preloads HTMX while parsing HTML
+- HTMX executes after DOM is ready (defer)
+- Maintains full HTMX functionality
+
+## Performance Metrics
+
+### Before Optimizations
+- Total CSS: ~128KB uncompressed
+- Total JS: ~30KB uncompressed
+- No caching headers
+- No compression
+- Blocking font loading
+- Inline scripts
+
+### After Optimizations
+- Total CSS: ~105KB minified (~60KB gzipped)
+- Total JS: ~24KB minified (~14KB gzipped)
+- 1-year cache for static assets
+- GZip compression enabled
+- Non-blocking font loading
+- Extracted, cached scripts
+
+### Estimated Improvements
+- **Initial Load**: 30-40% faster (reduced payload + compression)
+- **Repeat Visits**: 70-80% faster (aggressive caching)
+- **Time to Interactive**: 20-30% improvement (deferred scripts)
+- **Largest Contentful Paint**: 15-25% improvement (font optimization)
+
+## Configuration
+
+### Environment Variables
+
+```bash
+# Enable minified assets (production)
+USE_MINIFIED_ASSETS=true
+
+# Enable GZip compression (default: true)
+ENABLE_COMPRESSION=true
+
+# Static asset version (for cache busting)
+STATIC_ASSET_VERSION=2024051901
+```
+
+### Production Deployment
+
+1. Minify assets:
+ ```bash
+ python3 scripts/minify_assets.py
+ ```
+
+2. Set environment variables:
+ ```bash
+ export USE_MINIFIED_ASSETS=true
+ export ENABLE_COMPRESSION=true
+ ```
+
+3. Deploy application
+
+### Development Mode
+
+Keep `USE_MINIFIED_ASSETS=false` for easier debugging with readable source files.
+
+## Future Optimizations
+
+### Potential Improvements
+
+1. **Critical CSS Extraction**: Extract above-the-fold CSS and inline it
+2. **Image Optimization**: Add WebP support, lazy loading, responsive images
+3. **HTTP/2 Server Push**: Push critical assets before they're requested
+4. **Service Worker**: Implement offline-first caching strategy
+5. **Brotli Compression**: Add Brotli for even better compression than GZip
+6. **CSS Purging**: Remove unused CSS rules in production
+7. **Code Splitting**: Split CSS/JS by route for smaller initial bundles
+8. **Preload Key Requests**: Preload critical API calls
+9. **Resource Prioritization**: Use `fetchpriority` for critical resources
+10. **CDN Integration**: Serve static assets from CDN
+
+### Monitoring
+
+Consider adding:
+- Web Vitals tracking (Core Web Vitals)
+- Real User Monitoring (RUM)
+- Lighthouse CI for automated performance testing
+- Bundle size tracking in CI/CD
+
+## Testing
+
+### Verify Optimizations
+
+1. **Check minified files exist**:
+ ```bash
+ ls -lh src/app/web/static/css/*.min.css
+ ls -lh src/app/web/static/js/*.min.js
+ ```
+
+2. **Test compression**:
+ ```bash
+ curl -H "Accept-Encoding: gzip" -I http://localhost:8000/static/css/base.min.css
+ # Should include: Content-Encoding: gzip
+ ```
+
+3. **Verify cache headers**:
+ ```bash
+ curl -I http://localhost:8000/static/css/base.min.css?v=2024051901
+ # Should include: Cache-Control: public, max-age=31536000, immutable
+ ```
+
+4. **Lighthouse audit**:
+ ```bash
+ lighthouse http://localhost:8000 --view
+ ```
+
+## Troubleshooting
+
+### Minification Issues
+
+If minified assets cause issues:
+1. Set `USE_MINIFIED_ASSETS=false`
+2. Check browser console for errors
+3. Verify minified files exist and are valid
+4. Re-run minification script
+
+### Cache Issues
+
+If changes aren't reflected:
+1. Update `STATIC_ASSET_VERSION` in config
+2. Clear browser cache
+3. Use incognito/private browsing
+4. Check Network tab for cache hits
+
+### Compression Issues
+
+If compression causes problems:
+1. Set `ENABLE_COMPRESSION=false`
+2. Check client Accept-Encoding headers
+3. Verify middleware order in application.py
+
+## Maintainers
+
+When modifying CSS or JavaScript:
+1. Edit source files (non-minified versions)
+2. Run minification script: `python3 scripts/minify_assets.py`
+3. Test both minified and non-minified versions
+4. Update `STATIC_ASSET_VERSION` if deploying
+
+## References
+
+- [Web.dev Performance Guide](https://web.dev/performance/)
+- [MDN Web Performance](https://developer.mozilla.org/en-US/docs/Web/Performance)
+- [HTMX Documentation](https://htmx.org/docs/)
+- [FastAPI Performance](https://fastapi.tiangolo.com/advanced/middleware/)
diff --git a/scripts/minify_assets.py b/scripts/minify_assets.py
new file mode 100755
index 0000000..92476ed
--- /dev/null
+++ b/scripts/minify_assets.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python3
+"""
+Minify CSS and JavaScript files for production.
+This script reduces file sizes by removing whitespace, comments, and optimizing code.
+"""
+import re
+from pathlib import Path
+
+
+def minify_css(content: str) -> str:
+ """Minify CSS by removing comments, whitespace, and optimizing."""
+ # Remove comments
+ content = re.sub(r'/\*.*?\*/', '', content, flags=re.DOTALL)
+ # Remove newlines and extra spaces
+ content = re.sub(r'\s+', ' ', content)
+ # Remove spaces around special characters
+ content = re.sub(r'\s*([{}:;,>+~])\s*', r'\1', content)
+ # Remove trailing semicolons
+ content = re.sub(r';}', '}', content)
+ return content.strip()
+
+
+def minify_js(content: str) -> str:
+ """Minify JavaScript by removing comments and unnecessary whitespace."""
+ # Remove single-line comments (but preserve URLs)
+ content = re.sub(r'(?:=+\-*/%!&|?])\s*', r'\1', content)
+ # Add back necessary spaces for keywords
+ content = re.sub(r'(\b(?:return|var|let|const|if|else|for|while|function|class)\b)', r' \1 ', content)
+ return content.strip()
+
+
+def process_files(source_dir: Path, output_dir: Path, extensions: dict):
+ """Process files with specified extensions using their minify functions."""
+ for ext, minify_func in extensions.items():
+ for file_path in source_dir.rglob(f'*.{ext}'):
+ # Skip already minified files
+ if '.min.' in file_path.name:
+ continue
+
+ content = file_path.read_text(encoding='utf-8')
+ minified = minify_func(content)
+
+ # Create output path
+ relative = file_path.relative_to(source_dir)
+ output_file = output_dir / relative.parent / f"{relative.stem}.min.{ext}"
+ output_file.parent.mkdir(parents=True, exist_ok=True)
+
+ # Write minified content
+ output_file.write_text(minified, encoding='utf-8')
+
+ # Calculate size reduction
+ original_size = len(content)
+ minified_size = len(minified)
+ reduction = ((original_size - minified_size) / original_size) * 100
+
+ print(f"✓ {relative}: {original_size:,} → {minified_size:,} bytes ({reduction:.1f}% reduction)")
+
+
+if __name__ == '__main__':
+ project_root = Path(__file__).parent.parent
+ static_dir = project_root / 'src' / 'app' / 'web' / 'static'
+
+ print("🚀 Minifying assets...")
+ print()
+
+ print("📦 CSS Files:")
+ css_dir = static_dir / 'css'
+ process_files(css_dir, css_dir, {'css': minify_css})
+
+ print()
+ print("📦 JavaScript Files:")
+ js_dir = static_dir / 'js'
+ process_files(js_dir, js_dir, {'js': minify_js})
+
+ print()
+ print("✨ Minification complete!")
diff --git a/src/app/core/application.py b/src/app/core/application.py
index 93a9b2c..6f953d5 100644
--- a/src/app/core/application.py
+++ b/src/app/core/application.py
@@ -4,10 +4,11 @@
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
-from starlette.staticfiles import StaticFiles
+from fastapi.middleware.gzip import GZipMiddleware
from app.core.config import get_settings
from app.core.session import InMemorySessionMiddleware
+from app.core.static_files import CachedStaticFiles
from app.web.templates import template_engine
from app.api.routes import onboarding as onboarding_routes
from app.api.routes import profile as profile_routes
@@ -27,6 +28,10 @@ def create_app() -> FastAPI:
app = FastAPI(title=settings.app_name)
+ # Add GZip compression for better performance
+ if settings.enable_compression:
+ app.add_middleware(GZipMiddleware, minimum_size=1000, compresslevel=6)
+
app.add_middleware(
InMemorySessionMiddleware,
max_age=60 * 60 * 24 * 30,
@@ -42,8 +47,8 @@ def create_app() -> FastAPI:
allow_headers=["*"],
)
- # Mount static assets (CSS, JS, images) served by the Jinja2 templates.
- app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
+ # Mount static assets (CSS, JS, images) with optimized caching.
+ app.mount("/static", CachedStaticFiles(directory=str(STATIC_DIR)), name="static")
# Register routers for server-rendered pages and API endpoints.
app.include_router(root_routes.router)
diff --git a/src/app/core/config.py b/src/app/core/config.py
index a91d1bf..4502b9d 100644
--- a/src/app/core/config.py
+++ b/src/app/core/config.py
@@ -28,6 +28,10 @@ class Settings(BaseSettings):
# Session management
session_secret: str = "development-session-secret-placeholder"
static_asset_version: str = "2024051901"
+
+ # Performance optimizations
+ use_minified_assets: bool = False
+ enable_compression: bool = True
@field_validator("session_secret")
@classmethod
diff --git a/src/app/core/static_files.py b/src/app/core/static_files.py
new file mode 100644
index 0000000..a669959
--- /dev/null
+++ b/src/app/core/static_files.py
@@ -0,0 +1,31 @@
+"""Optimized static file serving with caching headers."""
+
+from starlette.staticfiles import StaticFiles
+from starlette.responses import Response
+from starlette.types import Scope, Receive, Send
+
+
+class CachedStaticFiles(StaticFiles):
+ """Static files middleware with aggressive caching for immutable assets."""
+
+ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
+ """Add cache headers to static file responses."""
+
+ async def send_wrapper(message):
+ if message["type"] == "http.response.start":
+ headers = dict(message.get("headers", []))
+
+ # Add cache headers for static assets
+ # Assets with version query params are immutable
+ if b"Cache-Control" not in headers:
+ # Cache for 1 year for versioned assets
+ headers[b"Cache-Control"] = b"public, max-age=31536000, immutable"
+
+ # Add compression hint
+ headers[b"Vary"] = b"Accept-Encoding"
+
+ message["headers"] = list(headers.items())
+
+ await send(message)
+
+ await super().__call__(scope, receive, send_wrapper)
diff --git a/src/app/web/static/css/auth.min.css b/src/app/web/static/css/auth.min.css
new file mode 100644
index 0000000..1e4c97b
--- /dev/null
+++ b/src/app/web/static/css/auth.min.css
@@ -0,0 +1 @@
+.auth-page{min-height:calc(100vh - 6rem);display:flex;align-items:center;justify-content:center;padding:clamp(2rem,5vw,4rem);position:relative;overflow:hidden}.auth-page::before{content:"";position:absolute;inset:0;background:radial-gradient(circle at 10% 20%,rgba(59,130,246,0.14),transparent 55%),radial-gradient(circle at 85% 80%,rgba(16,185,129,0.15),transparent 60%),linear-gradient(135deg,rgba(15,23,42,0.6),rgba(30,64,175,0.4));opacity:0.75;pointer-events:none}.auth-login-section{position:relative;width:min(460px,100%);z-index:1}.auth-login-section::before{content:"";position:absolute;inset:-30px;border-radius:var(--radius-xl);background:linear-gradient(160deg,rgba(59,130,246,0.2),transparent 70%);filter:blur(45px);z-index:-1}.login-backdrop{position:relative;padding:clamp(2rem,4vw,2.75rem);border-radius:var(--radius-xl);border:1px solid rgba(148,163,184,0.25);backdrop-filter:blur(14px);background:rgba(15,23,42,0.55);box-shadow:0 18px 36px rgba(15,23,42,0.45)}.auth-feedback{border-radius:var(--radius-md);padding:1rem 1.2rem;margin-bottom:1.25rem;display:none;background:rgba(56,189,248,0.08);border:1px solid rgba(56,189,248,0.25);color:var(--text-primary)}.auth-feedback.visible{display:block}.auth-feedback[data-tone='success']{background:rgba(52,211,153,0.12);border-color:rgba(52,211,153,0.4)}.auth-feedback[data-tone='danger']{background:rgba(248,113,113,0.12);border-color:rgba(248,113,113,0.4);color:#fecaca}.auth-form{display:flex;flex-direction:column;gap:1.15rem}.auth-form label{display:flex;flex-direction:column;gap:0.45rem;font-weight:500;color:var(--text-primary)}.auth-form .input-hint{margin:0;font-size:0.85rem;font-weight:400;color:var(--text-secondary);line-height:1.4}.auth-form input{border-radius:var(--radius-sm);border:1px solid rgba(148,163,184,0.35);background:rgba(15,23,42,0.7);color:var(--text-primary);padding:0.85rem 1rem;font-size:0.95rem;transition:border-color var(--transition-base),box-shadow var(--transition-base),background var(--transition-base)}.auth-form input:focus{outline:none;border-color:rgba(56,189,248,0.85);box-shadow:0 0 0 3px rgba(56,189,248,0.22);background:rgba(15,23,42,0.85)}.login-header{display:flex;flex-direction:column;gap:0.4rem}.login-header h2{margin:0;font-size:clamp(1.8rem,3vw,2.2rem)}.login-header p{margin:0;color:var(--text-secondary)}.login-aux{display:flex;justify-content:flex-end}.forgot-link{font-size:0.85rem;color:rgba(191,219,254,0.9);text-decoration:none;border-bottom:1px solid transparent;transition:border-color var(--transition-base),color var(--transition-base)}.forgot-link:hover{color:rgba(224,242,254,1);border-color:rgba(191,219,254,0.5)}.login-form .btn{width:100%}.login-divider{text-transform:uppercase;letter-spacing:0.2em;font-size:0.75rem;text-align:center;color:rgba(148,163,184,0.75)}.register-button{text-align:center}.form-note{font-size:0.85rem;color:var(--muted);line-height:1.4;margin:0}@media (max-width:640px){.auth-page{padding:1.75rem 1.25rem 2.5rem}.login-backdrop{padding:1.75rem}}
\ No newline at end of file
diff --git a/src/app/web/static/css/base.min.css b/src/app/web/static/css/base.min.css
new file mode 100644
index 0000000..acc2131
--- /dev/null
+++ b/src/app/web/static/css/base.min.css
@@ -0,0 +1 @@
+:root{--gradient-background:radial-gradient(circle at 15% 20%,rgba(249,115,22,0.15),transparent 55%),radial-gradient(circle at 85% 15%,rgba(192,38,211,0.18),transparent 60%),linear-gradient(135deg,#0f172a,#1e293b 55%,#0b1120);--glass-surface:rgba(15,23,42,0.62);--glass-border:rgba(148,163,184,0.35);--glass-shadow:0 25px 45px rgba(15,23,42,0.45);--text-primary:#f8fafc;--text-secondary:#cbd5f5;--text-tertiary:rgba(203,213,225,0.78);--accent-primary:linear-gradient(135deg,#f97316,#c026d3);--accent-secondary:#38bdf8;--muted:#94a3b8;--success:#34d399;--danger:#f87171;--radius-lg:28px;--radius-md:20px;--radius-sm:14px;--radius-full:999px;--transition-base:180ms ease}body{min-height:100vh;margin:0;background:var(--gradient-background);color:var(--text-primary);font-family:"Inter",system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;line-height:1.6;position:relative}.background-aurora{position:fixed;inset:0;background:inherit;filter:blur(60px) saturate(140%);opacity:0.9;pointer-events:none;z-index:-2}body::before{content:"";position:fixed;inset:0;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160' viewBox='0 0 160 160'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='.06'%3E%3Cpath d='M80 0h1v160h-1zM0 80h160v1H0z'/%3E%3C/g%3E%3C/svg%3E");opacity:0.4;pointer-events:none;z-index:-1}.page-wrapper{width:min(1180px,100%);margin:0 auto;padding:2.5rem 1.5rem 4rem;display:flex;flex-direction:column;gap:2.75rem}.content{display:flex;flex-direction:column;gap:3rem}.glass-surface{backdrop-filter:blur(24px) saturate(140%);background:linear-gradient(145deg,rgba(15,23,42,0.65),rgba(15,23,42,0.4));border:1px solid var(--glass-border);border-radius:var(--radius-lg);box-shadow:var(--glass-shadow)}.glass-card{backdrop-filter:blur(22px) saturate(150%);background:rgba(15,23,42,0.68);border:1px solid rgba(148,163,184,0.25);border-radius:var(--radius-md);box-shadow:0 18px 40px rgba(8,15,29,0.35);transition:transform var(--transition-base),box-shadow var(--transition-base)}.glass-card:hover{transform:translateY(-6px);box-shadow:0 28px 60px rgba(8,15,29,0.45)}h1,h2,h3,h4{font-family:"Playfair Display","Times New Roman",serif;font-weight:600;line-height:1.25}p{color:var(--text-secondary)}.btn{display:inline-flex;align-items:center;justify-content:center;gap:0.5rem;border-radius:999px;padding:0.75rem 1.8rem;font-weight:600;text-decoration:none;cursor:pointer;border:none;transition:transform var(--transition-base),box-shadow var(--transition-base),background var(--transition-base)}.btn:hover{transform:translateY(-2px)}.gradient-button{background:var(--accent-primary);color:#0f172a;box-shadow:0 12px 30px rgba(249,115,22,0.3)}.gradient-button:hover{box-shadow:0 18px 40px rgba(192,38,211,0.25)}.btn-outline{background:transparent;border:1px solid rgba(56,189,248,0.35);color:var(--accent-secondary)}.btn-outline:hover{border-color:rgba(56,189,248,0.75);background:rgba(56,189,248,0.08)}.btn-ghost{background:transparent;color:var(--text-secondary);border:1px solid transparent}.btn-ghost:hover{color:var(--text-primary);border-color:rgba(148,163,184,0.3)}.button{display:inline-flex;align-items:center;justify-content:center;gap:0.5rem;border-radius:var(--radius-full);padding:0.75rem 1.9rem;font-weight:600;text-decoration:none;cursor:pointer;border:none;transition:transform var(--transition-base),box-shadow var(--transition-base),background var(--transition-base)}.button:focus-visible{outline:2px solid rgba(56,189,248,0.55);outline-offset:2px}.button:hover{transform:translateY(-2px)}.button-primary{background:var(--accent-primary);color:#0f172a;box-shadow:0 16px 32px rgba(249,115,22,0.24)}.button-primary:hover{box-shadow:0 22px 40px rgba(192,38,211,0.28)}.button-secondary{background:rgba(56,189,248,0.14);color:rgba(241,245,249,0.95);border:1px solid rgba(56,189,248,0.4)}.button-secondary:hover{background:rgba(56,189,248,0.2)}.button-ghost{background:transparent;color:rgba(226,232,240,0.95);border:1px solid rgba(148,163,184,0.25)}.button-ghost:hover{border-color:rgba(148,163,184,0.4);color:rgba(248,250,252,0.95)}.navbar{position:sticky;top:1.5rem;z-index:20;display:flex;align-items:center;justify-content:space-between;padding:1rem 1.5rem;gap:1rem}.navbar-collapsible{display:flex;align-items:center;gap:1.5rem;margin-left:auto}.navbar-brand .logo{font-family:"Playfair Display","Times New Roman",serif;font-size:1.4rem}.navbar-menu{list-style:none;display:flex;align-items:center;gap:1.5rem;padding:0;margin:0}.navbar-menu a{color:var(--text-secondary);text-decoration:none;font-weight:500;position:relative;padding:0.25rem 0}.navbar-menu a::after{content:"";position:absolute;left:0;bottom:-0.35rem;width:100%;height:2px;background:var(--accent-primary);transform:scaleX(0);transform-origin:left;transition:transform var(--transition-base)}.navbar-menu a:hover::after{transform:scaleX(1)}.navbar-menu a.active{color:var(--text-primary)}.navbar-menu a.active::after{transform:scaleX(1)}.navbar-actions{display:flex;align-items:center;gap:0.75rem}.navbar-dropdown{position:relative;display:inline-flex}.navbar-dropdown__toggle{display:inline-flex;align-items:center;gap:0.4rem;padding:0.4rem 0.75rem;border-radius:999px;cursor:pointer;color:var(--text-secondary);font-weight:600;text-decoration:none;user-select:none;margin:0}.navbar-dropdown__toggle:hover{color:var(--text-primary);background:rgba(255,255,255,0.06)}.navbar-dropdown__toggle::-webkit-details-marker{display:none}.navbar-dropdown__toggle:focus-visible{outline:2px solid var(--accent-secondary);outline-offset:3px}.navbar-dropdown[open] .navbar-dropdown__toggle{color:var(--text-primary);background:rgba(255,255,255,0.08)}.navbar-dropdown__icon{font-size:0.75rem;transition:transform var(--transition-fast)}.navbar-dropdown[open] .navbar-dropdown__icon{transform:rotate(180deg)}.navbar-dropdown__menu{position:absolute;top:calc(100%+0.75rem);right:0;min-width:200px;padding:0.75rem;border-radius:1rem;background:rgba(18,18,18,0.7);backdrop-filter:blur(16px);box-shadow:0 18px 40px rgba(15,23,42,0.35);list-style:none;display:grid;gap:0.35rem;z-index:25}.navbar-dropdown:not([open]) .navbar-dropdown__menu{display:none}.navbar-dropdown__menu a,.navbar-dropdown__menu button{display:flex;width:100%;align-items:center;gap:0.4rem;border:none;background:transparent;color:var(--text-secondary);font:inherit;padding:0.45rem 0.6rem;border-radius:0.65rem;cursor:pointer;text-align:left;text-decoration:none;transition:background var(--transition-fast),color var(--transition-fast)}.navbar-dropdown__menu a:hover,.navbar-dropdown__menu a:focus-visible,.navbar-dropdown__menu button:hover,.navbar-dropdown__menu button:focus-visible{color:var(--text-primary);background:rgba(255,255,255,0.08)}.navbar-actions .is-loading{opacity:0.6;pointer-events:none}.navbar-toggle{display:none;flex-direction:column;gap:0.3rem;background:none;border:none;cursor:pointer}.navbar-toggle span{width:20px;height:2px;background:var(--text-primary);border-radius:999px}.hero{padding:3rem 3.5rem;position:relative;overflow:hidden;display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:2.5rem}.hero::after{content:"";position:absolute;inset:0;background:linear-gradient(120deg,rgba(249,115,22,0.08),rgba(192,38,211,0.12));opacity:0.6;pointer-events:none}.hero>*{position:relative;z-index:1}.badge{display:inline-flex;align-items:center;gap:0.4rem;font-size:0.85rem;color:var(--accent-secondary);background:rgba(56,189,248,0.1);border:1px solid rgba(56,189,248,0.35);border-radius:999px;padding:0.35rem 0.85rem;letter-spacing:0.03em;text-transform:uppercase}.badge.brand{color:#f472b6;background:rgba(244,114,182,0.14);border-color:rgba(244,114,182,0.4)}.badge.creator{color:#facc15;background:rgba(250,204,21,0.16);border-color:rgba(250,204,21,0.45)}.badge.accent{color:#f97316;background:rgba(249,115,22,0.16);border-color:rgba(249,115,22,0.45)}.badge.subtle{color:var(--text-secondary);background:rgba(148,163,184,0.12);border-color:rgba(148,163,184,0.35)}.hero-copy h1{font-size:clamp(2.2rem,3vw,3.3rem);margin:1rem 0}.hero-copy p{max-width:540px}.filter-form{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:1rem;align-items:flex-end}.filter-form.single-field{grid-template-columns:1fr}.filter-hint{grid-column:1 / -1;font-size:0.85rem;color:var(--text-tertiary);margin:0}.catalog-controls{display:flex;flex-direction:column;gap:0.75rem}.catalog-tab-bar{display:grid;grid-template-columns:minmax(0,1fr) minmax(220px,320px);gap:0.9rem;align-items:center;background:rgba(15,23,42,0.45);border-radius:var(--radius-lg);padding:0.85rem 1rem;border:1px solid rgba(148,163,184,0.28);box-shadow:0 18px 38px rgba(8,15,29,0.28)}.catalog-search{justify-self:end;width:100%;max-width:360px;display:flex;flex-direction:column;gap:0.35rem}.catalog-search-input{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:0.5rem;background:linear-gradient(135deg,rgba(148,163,184,0.16),rgba(56,189,248,0.12));border:1px solid rgba(148,163,184,0.4);border-radius:var(--radius-full);padding:0.35rem 0.35rem 0.35rem 0.65rem;backdrop-filter:blur(16px) saturate(130%);box-shadow:inset 0 0 0 1px rgba(15,23,42,0.4);transition:border-color var(--transition-base),box-shadow var(--transition-base),background var(--transition-base)}.catalog-search-input:focus-within{border-color:rgba(56,189,248,0.65);box-shadow:0 12px 28px rgba(14,116,144,0.28);background:linear-gradient(135deg,rgba(148,163,184,0.18),rgba(56,189,248,0.18))}.catalog-search-icon{display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;color:rgba(148,163,184,0.85);pointer-events:none}.catalog-search-input svg{width:1.1rem;height:1.1rem}.catalog-search-input input{width:100%;background:transparent;border:none;color:var(--text-primary);font-size:0.95rem;padding:0.55rem 0.4rem}.catalog-search-input input::placeholder{color:rgba(226,232,240,0.62)}.catalog-search-input input:focus{outline:none}.catalog-search-button{display:inline-flex;align-items:center;justify-content:center;width:2.6rem;height:2.6rem;border-radius:var(--radius-full);border:none;background:linear-gradient(135deg,rgba(56,189,248,0.9),rgba(192,38,211,0.9));color:#0b1120;cursor:pointer;transition:transform var(--transition-base),box-shadow var(--transition-base),filter var(--transition-base);box-shadow:0 10px 28px rgba(56,189,248,0.32)}.catalog-search-button:hover,.catalog-search-button:focus{transform:translateY(-1px);box-shadow:0 14px 34px rgba(192,38,211,0.28);outline:none}.catalog-search-button svg{width:1.1rem;height:1.1rem}.catalog-search .filter-hint{margin:0;font-size:0.8rem;color:var(--text-tertiary)}.field{display:flex;flex-direction:column;gap:0.35rem;font-size:0.9rem;color:var(--text-secondary)}.field input,.field select{background:rgba(15,23,42,0.65);border:1px solid rgba(148,163,184,0.35);border-radius:var(--radius-md);padding:0.65rem 0.85rem;color:var(--text-primary);font-size:0.95rem;outline:none}.field select{cursor:pointer}.field.range .range-inputs{display:flex;align-items:center;gap:0.5rem}.field.range input[type="number"]{width:100%}.range-inputs .divider{color:var(--text-secondary)}.filter-form button{grid-column:1 / -1;justify-self:flex-start;margin-top:0.5rem}.hero-visual{position:relative;min-height:260px;display:flex;align-items:center;justify-content:center}.hero-aurora{position:absolute;width:320px;height:320px;border-radius:50%;background:radial-gradient(circle,rgba(249,115,22,0.45),rgba(192,38,211,0.1));filter:blur(30px);animation:pulse 6s ease-in-out infinite}.hero-bottle{position:relative;width:160px;display:flex;flex-direction:column;align-items:center;gap:0.4rem}.hero-bottle .cap{width:60px;height:24px;background:rgba(148,163,184,0.55);border-radius:12px}.hero-bottle .body{width:100%;height:180px;background:linear-gradient(145deg,rgba(56,189,248,0.4),rgba(192,38,211,0.4));border-radius:80px 80px 28px 28px;border:1px solid rgba(148,163,184,0.3);box-shadow:inset 0 12px 20px rgba(255,255,255,0.15)}.hero-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:1rem}.stat-card{padding:1.5rem;text-align:center}.stat-value{font-size:2rem;font-weight:700}.stat-label{color:var(--text-secondary);margin-top:0.4rem}.catalog{display:flex;flex-direction:column;gap:1.5rem}.catalog-header{display:flex;justify-content:space-between;gap:1.5rem;padding:2rem 2.5rem;align-items:center;flex-wrap:wrap}.catalog-header h2{margin-bottom:0.5rem}.tab-list{display:inline-flex;gap:0.75rem;background:rgba(148,163,184,0.1);padding:0.4rem;border-radius:999px}.tab{background:transparent;border:none;color:var(--text-secondary);padding:0.55rem 1.4rem;border-radius:999px;cursor:pointer;font-weight:500;transition:background var(--transition-base),color var(--transition-base)}.tab:hover,.tab:focus-visible{background:rgba(249,115,22,0.18);color:var(--text-primary)}.tab:focus-visible{outline:2px solid rgba(56,189,248,0.55);outline-offset:2px}.tab.is-active,.tab[aria-selected="true"]{background:rgba(249,115,22,0.24);color:var(--text-primary)}.tab-panel[hidden]{display:none}.filter-bar{padding:1.2rem 1.5rem;display:flex;justify-content:space-between;align-items:center;gap:1rem;flex-wrap:wrap;border-radius:var(--radius-md)}.filter-group{display:flex;gap:0.75rem;flex-wrap:wrap}.filter-chip{padding:0.45rem 1.1rem;background:rgba(15,23,42,0.6);border-radius:999px;border:1px solid rgba(148,163,184,0.3);color:var(--text-secondary);font-size:0.9rem}.search-box{display:inline-flex;align-items:center;gap:0.6rem;background:rgba(15,23,42,0.65);border-radius:999px;padding:0.45rem 1.1rem;border:1px solid rgba(148,163,184,0.3);width:min(320px,100%);color:var(--text-secondary)}.search-box input{flex:1;background:transparent;border:none;outline:none;color:var(--text-primary);font-size:0.95rem}.search-box .search-submit{display:inline-flex;align-items:center;justify-content:center;width:2.4rem;height:2.4rem;border-radius:var(--radius-full);border:none;background:linear-gradient(135deg,rgba(56,189,248,0.9),rgba(192,38,211,0.9));color:#0b1120;cursor:pointer;transition:transform var(--transition-base),box-shadow var(--transition-base);box-shadow:0 10px 24px rgba(56,189,248,0.28)}.search-box .search-submit:hover,.search-box .search-submit:focus-visible{transform:translateY(-1px);box-shadow:0 14px 32px rgba(192,38,211,0.24);outline:none}.search-box .search-submit svg{width:1.05rem;height:1.05rem}.product-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:1.5rem}.product-card{display:flex;flex-direction:column;overflow:hidden;position:relative}a.product-card{color:inherit;text-decoration:none}a.product-card:focus-visible{outline:2px solid rgba(56,189,248,0.55);outline-offset:3px}.product-badge{position:absolute;top:1rem;left:1rem;display:inline-flex;align-items:center;gap:0.35rem;padding:0.4rem 0.85rem;border-radius:999px;font-size:0.75rem;font-weight:600;letter-spacing:0.02em;text-transform:uppercase;background:rgba(15,23,42,0.75);border:1px solid rgba(148,163,184,0.35);box-shadow:0 10px 25px rgba(8,15,29,0.35)}.product-badge .badge-icon{font-size:0.95rem}.product-badge-sambatan{background:linear-gradient(135deg,rgba(249,115,22,0.8),rgba(192,38,211,0.8));color:#0f172a;border:1px solid rgba(248,250,252,0.6)}.product-media{height:180px;border-radius:var(--radius-md) var(--radius-md) 0 0;background:radial-gradient(circle at 30% 20%,rgba(249,115,22,0.4),transparent 60%),radial-gradient(circle at 70% 30%,rgba(56,189,248,0.35),transparent 65%),rgba(148,163,184,0.1)}.parfum-aurora{background:linear-gradient(135deg,rgba(249,115,22,0.45),rgba(56,189,248,0.3))}.parfum-tropis{background:linear-gradient(135deg,rgba(192,38,211,0.4),rgba(56,189,248,0.35))}.parfum-malam{background:linear-gradient(135deg,rgba(59,130,246,0.4),rgba(17,94,89,0.35))}.bahan-cendana{background:linear-gradient(135deg,rgba(180,83,9,0.38),rgba(249,115,22,0.24))}.bahan-jeruk{background:linear-gradient(135deg,rgba(251,191,36,0.34),rgba(234,179,8,0.26))}.alat-scale{background:linear-gradient(135deg,rgba(14,165,233,0.35),rgba(56,189,248,0.28))}.alat-strip{background:linear-gradient(135deg,rgba(147,197,253,0.32),rgba(126,34,206,0.24))}.community-lagoon{background:linear-gradient(135deg,rgba(56,189,248,0.38),rgba(16,185,129,0.32))}.community-solstice{background:linear-gradient(135deg,rgba(251,191,36,0.32),rgba(239,68,68,0.28))}.community-dawn{background:linear-gradient(135deg,rgba(110,231,183,0.32),rgba(96,165,250,0.35))}.material-citronella{background:linear-gradient(135deg,rgba(34,197,94,0.34),rgba(74,222,128,0.26))}.material-benzoin{background:linear-gradient(135deg,rgba(249,115,22,0.32),rgba(217,119,6,0.28))}.equipment-pipette{background:linear-gradient(135deg,rgba(59,130,246,0.3),rgba(125,211,252,0.28))}.equipment-scale{background:linear-gradient(135deg,rgba(30,64,175,0.32),rgba(129,140,248,0.28))}.misc-packaging{background:linear-gradient(135deg,rgba(244,114,182,0.32),rgba(236,72,153,0.24))}.misc-workshop{background:linear-gradient(135deg,rgba(99,102,241,0.3),rgba(168,85,247,0.26))}.product-content{display:flex;flex-direction:column;gap:0.75rem;padding:1.5rem}.marketplace-grid .product-content{padding:0;gap:0}.marketplace-grid .product-media{border-radius:0;width:100%;aspect-ratio:1 / 1}.marketplace-grid .product-info{display:flex;flex-direction:column;gap:0.4rem;padding:1.25rem 1.5rem 1.5rem}.marketplace-grid .product-name{font-size:1.1rem;font-weight:600}.marketplace-grid .product-brand{color:var(--text-secondary);text-transform:none;font-size:0.8rem;letter-spacing:0.02em;display:inline-flex;align-items:center;gap:0.35rem}.marketplace-grid .product-brand[role='link']{cursor:pointer;transition:color var(--transition-base)}.marketplace-grid .product-brand[role='link']:hover{color:var(--text-primary)}.marketplace-grid .product-brand[role='link']:focus-visible{outline:2px solid rgba(56,189,248,0.55);outline-offset:2px}.product-brand-label{display:inline-flex;align-items:center;gap:0.35rem}.brand-verified-badge{display:inline-flex;align-items:center;justify-content:center;width:1rem;height:1rem;border-radius:var(--radius-full);background:linear-gradient(135deg,rgba(56,189,248,0.85),rgba(192,38,211,0.85));color:#0f172a;box-shadow:0 6px 16px rgba(15,23,42,0.35)}.brand-verified-badge svg{width:0.6rem;height:0.6rem}.marketplace-grid .product-price{font-weight:600;font-size:1rem}.product-meta{display:flex;justify-content:space-between;align-items:center;gap:0.5rem;color:var(--text-secondary);font-size:0.85rem;text-transform:uppercase;letter-spacing:0.04em}.product-description{flex:1}.product-footer{display:flex;justify-content:space-between;align-items:flex-end;gap:1rem}.price{font-weight:700;font-size:1.1rem}.product-owner{font-size:0.85rem;color:var(--text-secondary)}.product-tags{display:flex;flex-wrap:wrap;gap:0.5rem;justify-content:flex-end}.product-tags .tag{font-size:0.75rem;padding:0.25rem 0.6rem;border-radius:999px;background:rgba(148,163,184,0.16);border:1px solid rgba(148,163,184,0.25);color:var(--text-secondary);letter-spacing:0.03em;text-transform:uppercase}.progress-indicator{display:flex;flex-direction:column;gap:0.4rem;min-width:160px;margin-top:0.75rem}.progress-label,.progress-deadline{font-size:0.85rem;color:var(--text-secondary)}.progress-track{position:relative;height:6px;background:rgba(148,163,184,0.25);border-radius:999px;overflow:hidden}.progress-fill{position:absolute;left:0;top:0;bottom:0;width:var(--progress);background:var(--accent-primary);border-radius:999px;transition:width 320ms ease}.section-header{display:flex;justify-content:space-between;align-items:flex-start;flex-wrap:wrap;gap:1.5rem}.section-header p{color:var(--text-secondary);margin-top:0.5rem;max-width:520px}.marketplace-grid{gap:1.75rem}.catalog-tabs{display:flex;gap:0.75rem;flex-wrap:wrap;flex:1 1 auto;overflow-x:auto;scrollbar-width:none}.catalog-tabs::-webkit-scrollbar{display:none}.catalog-tab{border:1px solid transparent;border-radius:var(--radius-full);padding:0.45rem 1.25rem;font-weight:500;font-size:0.95rem;background:transparent;color:var(--text-secondary);transition:all 180ms ease;cursor:pointer}.catalog-tab:hover,.catalog-tab:focus{color:var(--text-primary);border-color:rgba(148,163,184,0.35);outline:none}.catalog-tab.is-active{background:linear-gradient(135deg,rgba(56,189,248,0.28),rgba(147,197,253,0.24));color:var(--text-primary);border-color:rgba(148,163,184,0.4);box-shadow:0 16px 32px rgba(30,64,175,0.18)}@media (max-width:960px){.catalog-tab-bar{grid-template-columns:minmax(0,1fr);padding:0.85rem}.catalog-search{justify-self:stretch;max-width:none}.catalog-tabs{row-gap:0.6rem}}@media (max-width:640px){.catalog-tab-bar{gap:0.75rem}.catalog-search-input{grid-template-columns:auto 1fr auto;padding:0.3rem 0.3rem 0.3rem 0.55rem}.catalog-search-button{width:2.4rem;height:2.4rem}}.catalog-panel{display:flex;flex-direction:column;gap:1.4rem;margin-top:1rem}.catalog-panel.is-hidden{display:none}.panel-description{color:var(--text-secondary);max-width:640px}.empty-state{font-size:0.9rem;color:var(--text-tertiary);margin:0}.product-availability{margin-top:0.75rem;font-size:0.85rem;color:var(--text-secondary)}.product-perfumer{font-size:0.85rem;color:var(--accent-primary);margin:0.35rem 0 0}.product-card.is-filtered-out{display:none}.sambatan{color:#facc15;background:rgba(250,204,21,0.16);border:1px solid rgba(250,204,21,0.4)}.sambatan-highlight{display:flex;flex-direction:column;gap:1.25rem}.highlight-header{display:flex;justify-content:space-between;align-items:baseline;flex-wrap:wrap;gap:1rem}.highlight-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:1.5rem}.sambatan-card{padding:1.75rem;display:flex;flex-direction:column;gap:1rem}.card-header{display:flex;justify-content:space-between;align-items:center;font-size:0.85rem;color:var(--text-secondary)}.deadline{color:var(--accent-secondary)}.card-footer{margin-top:auto}.nusantarum{display:flex;flex-direction:column;gap:1.5rem}.nusantarum-header h2{margin-bottom:0.35rem}.story-carousel{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:1.5rem}.story-card{padding:1.6rem;display:flex;flex-direction:column;gap:0.75rem}.story-meta{display:flex;justify-content:space-between;align-items:center;color:var(--text-secondary);font-size:0.85rem}.story-link{color:var(--accent-secondary);text-decoration:none;font-weight:600}.story-link:hover{text-decoration:underline}.community-cta{padding:2.5rem 2.75rem;display:flex;justify-content:space-between;align-items:center;gap:2rem;flex-wrap:wrap}.community-cta p{max-width:460px}.newsletter-form{display:flex;gap:0.75rem;flex-wrap:wrap}.newsletter-form input{background:rgba(15,23,42,0.7);border:1px solid rgba(148,163,184,0.4);border-radius:999px;padding:0.75rem 1.4rem;min-width:240px;color:var(--text-primary)}.newsletter-form input::placeholder{color:var(--muted)}.footer{padding:1.8rem 2.2rem;display:flex;flex-direction:column;gap:1.5rem}.footer .logo{font-family:"Playfair Display","Times New Roman",serif;font-size:1.25rem}.footer-top{display:flex;gap:2.25rem;align-items:flex-start;justify-content:space-between;flex-wrap:wrap}.footer-brand{max-width:260px;display:flex;flex-direction:column;gap:0.45rem}.footer-brand p{margin:0;font-size:0.9rem;line-height:1.5}.footer-nav{display:grid;gap:1.25rem 2.5rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));flex:1 1 320px}.footer-group{display:flex;flex-direction:column;gap:0.6rem}.footer-group h4{font-size:0.95rem;margin:0}.footer-group ul{list-style:none;padding:0;margin:0;display:grid;gap:0.35rem}.footer-group a{color:var(--text-secondary);text-decoration:none}.footer-group a:hover{color:var(--accent-secondary)}.footer-bottom{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:0.75rem 1.5rem;padding-top:0.85rem;border-top:1px solid rgba(148,163,184,0.2)}.footer-social{list-style:none;padding:0;margin:0;display:flex;gap:1.1rem}.footer-social a{color:var(--text-secondary);text-decoration:none;font-size:0.9rem}.footer-social a:hover{color:var(--accent-secondary)}.footer-note{color:var(--muted);font-size:0.85rem}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}@keyframes pulse{0%,100%{transform:scale(1);opacity:0.9}50%{transform:scale(1.05);opacity:0.6}}@media (max-width:1024px){.navbar{flex-wrap:wrap;align-items:flex-start;gap:0.75rem}.navbar-toggle{display:flex;margin-left:auto}.navbar-collapsible{display:none;position:relative;width:100%;margin-left:0;padding:1.5rem 1.25rem;background:rgba(15,23,42,0.92);border:1px solid rgba(148,163,184,0.25);border-radius:var(--radius-md);box-shadow:0 18px 40px rgba(8,15,29,0.4);flex-direction:column;gap:1.5rem}.navbar[data-open="true"] .navbar-collapsible{display:flex}.navbar-menu{width:100%;flex-direction:column;align-items:flex-start;gap:1.1rem}.navbar-menu li{width:100%}.navbar-menu a{width:100%;display:block;padding:0.35rem 0}.navbar-actions{width:100%;flex-direction:column;align-items:stretch;gap:0.75rem}.navbar-actions .navbar-dropdown{width:100%}.hero{padding:2.5rem}.marketplace-hero{grid-template-columns:1fr;padding:2.25rem}.hero-filters{order:2}.filter-form{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}.section-header{align-items:stretch}.filter-bar{flex-direction:column;align-items:stretch}.product-footer{flex-direction:column;align-items:stretch}.progress-indicator{width:100%}.community-cta{padding:2rem}}@media (max-width:640px){.page-wrapper{padding:1.75rem 1rem 3rem}.hero{padding:2rem}.marketplace-hero{padding:1.75rem}.hero-filters{padding:1.5rem}.filter-form{grid-template-columns:1fr}.product-tags{justify-content:flex-start}.hero-stats{grid-template-columns:1fr}.catalog-header{padding:1.8rem}.tab-list{width:100%;justify-content:space-between}.search-box{width:100%}.newsletter-form{width:100%}.newsletter-form input,.newsletter-form .btn{width:100%}.footer{padding:1.6rem;gap:1.25rem}.footer-top{flex-direction:column;gap:1.5rem}.footer-bottom{flex-direction:column;align-items:flex-start;gap:0.65rem}.footer-social{gap:0.85rem}}.onboarding-hero{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:2rem;padding:2.5rem;align-items:center}.hero-progress{display:flex;flex-direction:column;gap:1.4rem}.progress-bar{width:100%;height:10px;background:rgba(148,163,184,0.22);border-radius:999px;overflow:hidden}.progress-fill{width:0%;height:100%;background:var(--accent-primary);transition:width var(--transition-base)}.progress-steps{list-style:none;margin:0;padding:0;display:grid;gap:1rem}.progress-step{display:grid;grid-template-columns:auto 1fr;gap:1rem;align-items:center;padding:0.75rem 1rem;border-radius:var(--radius-md);background:rgba(15,23,42,0.45);border:1px solid transparent}.progress-step .step-index{display:grid;place-items:center;width:32px;height:32px;border-radius:999px;border:2px solid rgba(148,163,184,0.45);font-weight:600}.progress-step.active{border-color:rgba(56,189,248,0.5);background:rgba(56,189,248,0.08)}.progress-step.active .step-index{border-color:var(--accent-secondary);color:var(--accent-secondary)}.progress-step.completed{border-color:rgba(52,211,153,0.4);background:rgba(16,185,129,0.12)}.progress-step.completed .step-index{border-color:var(--success);color:var(--success)}.onboarding-layout{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,1fr);gap:2.5rem}.onboarding-main{padding:2.25rem;display:flex;flex-direction:column;gap:1.75rem}.section-header{display:flex;align-items:center;justify-content:space-between;gap:1.5rem}.section-header h2{margin-bottom:0.35rem}.status-chip{display:inline-flex;align-items:center;padding:0.35rem 0.9rem;border-radius:999px;border:1px solid rgba(148,163,184,0.35);font-size:0.9rem;color:var(--text-secondary)}.feedback{min-height:1.75rem;border-radius:var(--radius-sm);padding:0.5rem 0.85rem;background:rgba(15,23,42,0.65);border:1px solid rgba(148,163,184,0.2);font-size:0.95rem;opacity:0;transition:opacity var(--transition-base)}.feedback.visible{opacity:1}.feedback[data-tone="success"]{border-color:rgba(52,211,153,0.45);color:var(--success)}.feedback[data-tone="danger"]{border-color:rgba(248,113,113,0.45);color:var(--danger)}.onboarding-forms{display:grid;gap:1.5rem}.onboarding-form{border:1px solid rgba(148,163,184,0.25);border-radius:var(--radius-md);padding:1.75rem;display:grid;gap:1.25rem;background:rgba(15,23,42,0.55)}.onboarding-form fieldset{border:none;padding:0;margin:0;display:grid;gap:1rem}.onboarding-form legend{font-weight:600;margin-bottom:0.5rem}.onboarding-form label{display:grid;gap:0.45rem;font-size:0.95rem}.onboarding-form input,.onboarding-form select{border-radius:var(--radius-sm);border:1px solid rgba(148,163,184,0.28);padding:0.65rem 0.85rem;background:rgba(15,23,42,0.75);color:var(--text-primary);font-size:1rem}.onboarding-form input:focus,.onboarding-form select:focus{outline:none;border-color:rgba(56,189,248,0.65);box-shadow:0 0 0 3px rgba(56,189,248,0.2)}.checkbox{display:flex !important;align-items:center;gap:0.6rem}.checkbox input[type="checkbox"]{width:18px;height:18px;accent-color:#f97316}.form-actions{display:flex;gap:0.75rem;flex-wrap:wrap}.form-help{font-size:0.9rem;color:rgba(203,213,225,0.8)}.debug-token{font-family:"Fira Code","Consolas",monospace;font-size:0.85rem;color:rgba(125,211,252,0.9)}.onboarding-sidebar{padding:2.25rem;display:grid;gap:1.5rem}.event-log{list-style:none;padding:0;margin:0;display:grid;gap:0.75rem}.event-log li{display:flex;align-items:center;justify-content:space-between;background:rgba(15,23,42,0.55);border-radius:var(--radius-sm);border:1px solid rgba(148,163,184,0.25);padding:0.6rem 0.9rem;font-size:0.9rem}.event-time{font-family:"Fira Code",monospace;color:rgba(148,163,184,0.85)}.event-name{font-weight:600;color:var(--text-primary)}.qa-notes{border-radius:var(--radius-md);border:1px dashed rgba(148,163,184,0.35);padding:1.25rem;background:rgba(15,23,42,0.45)}.qa-notes h3{margin-bottom:0.75rem}.qa-notes ul{margin:0;padding-left:1.1rem;color:rgba(203,213,225,0.85);display:grid;gap:0.35rem}@media (max-width:960px){.onboarding-layout{grid-template-columns:1fr}.section-header{flex-direction:column;align-items:flex-start}}@media (max-width:720px){.onboarding-hero{padding:2rem}.onboarding-form{padding:1.5rem}.sambatan-progress__meta{flex-direction:column;align-items:flex-start;gap:0.35rem}.slot-selector{grid-template-columns:repeat(3,minmax(2.4rem,auto))}}.marketplace-section{display:flex;flex-direction:column;gap:1.25rem;margin-top:1.75rem}.product-detail-page{padding:3rem 0 4rem;background:radial-gradient(circle at 10% 20%,rgba(56,189,248,0.18),transparent 55%),radial-gradient(circle at 80% 0%,rgba(99,102,241,0.28),transparent 52%),linear-gradient(180deg,rgba(15,23,42,0.95),rgba(15,23,42,0.9))}.product-detail-container{max-width:1100px;margin:0 auto;padding:0 1.5rem;display:flex;flex-direction:column;gap:2.5rem}.product-breadcrumb ol{list-style:none;display:flex;flex-wrap:wrap;gap:0.4rem;padding:0;margin:0;font-size:0.95rem;color:rgba(226,232,240,0.85)}.product-breadcrumb li{display:flex;align-items:center;gap:0.4rem}.product-breadcrumb li::after{content:"/";opacity:0.45}.product-breadcrumb li:last-child::after{content:none}.product-breadcrumb a{color:rgba(56,189,248,0.9);text-decoration:none}.product-breadcrumb a:hover{text-decoration:underline}.product-detail-hero{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,0.8fr);gap:2rem;padding:2.5rem;border-radius:var(--radius-xl,28px);background:rgba(15,23,42,0.55);backdrop-filter:blur(22px);border:1px solid rgba(148,163,184,0.25);position:relative}.product-hero-copy{display:grid;gap:1.1rem}.hero-kicker{display:inline-flex;align-self:flex-start;padding:0.35rem 0.85rem;border-radius:999px;background:rgba(56,189,248,0.12);border:1px solid rgba(56,189,248,0.35);font-size:0.9rem;letter-spacing:0.04em;text-transform:uppercase;color:rgba(125,211,252,0.95)}.product-detail-hero h1{margin:0;font-size:clamp(2.5rem,5vw,3.25rem);letter-spacing:-0.02em}.product-tagline{margin:0;font-size:1.05rem;color:rgba(203,213,225,0.8)}.product-summary{font-size:1.15rem;line-height:1.55;color:rgba(226,232,240,0.95)}.product-description{color:rgba(203,213,225,0.85);line-height:1.6}.product-pricing{display:flex;gap:0.85rem;align-items:baseline;font-weight:600}.product-pricing .price-primary{font-size:1.9rem;color:rgba(250,250,250,0.98)}.product-pricing .price-secondary{font-size:1rem;color:rgba(148,163,184,0.85)}.product-volume-options{display:flex;flex-wrap:wrap;gap:0.75rem}.volume-option{padding:0.75rem 1.1rem;border-radius:var(--radius-md);background:rgba(255,255,255,0.05);border:1px solid rgba(148,163,184,0.3);display:grid;gap:0.25rem}.volume-size{font-weight:600;color:rgba(248,250,252,0.95)}.volume-price{font-size:0.95rem;color:rgba(148,163,184,0.85)}.product-cta{width:fit-content;padding-inline:1.8rem;font-size:1rem}.origin-info{margin:0;font-size:0.95rem;color:rgba(148,163,184,0.85)}.product-hero-visual{position:relative;border-radius:var(--radius-lg);background:linear-gradient(160deg,rgba(56,189,248,0.35),rgba(99,102,241,0.35));border:1px solid rgba(148,163,184,0.2);overflow:hidden;display:grid;place-items:center}.product-visual-glow{width:240px;height:240px;border-radius:50%;background:radial-gradient(circle,rgba(191,219,254,0.65),rgba(59,130,246,0.15));filter:blur(0.5px)}.purchase-mode{display:grid;gap:1rem;padding:1.4rem 1.6rem;border-radius:var(--radius-md);border:1px solid rgba(148,163,184,0.25);background:rgba(15,23,42,0.5)}.purchase-mode--regular{background:linear-gradient(145deg,rgba(15,23,42,0.55),rgba(30,41,59,0.5))}.purchase-mode--sambatan{border-color:rgba(56,189,248,0.35);background:linear-gradient(150deg,rgba(30,64,175,0.55),rgba(56,189,248,0.3));box-shadow:0 18px 36px rgba(14,116,144,0.25)}.purchase-mode__header{display:grid;gap:0.6rem}.purchase-mode__header p{margin:0;color:rgba(226,232,240,0.9)}.purchase-mode__price{font-size:1.1rem;color:rgba(241,245,249,0.95)}.purchase-benefits{list-style:none;margin:0;padding:0;display:grid;gap:0.55rem;color:rgba(226,232,240,0.9)}.purchase-benefits li{display:flex;gap:0.55rem}.purchase-benefits li::before{content:"✶";color:rgba(56,189,248,0.8);margin-top:0.1rem}.purchase-footnote{margin:0;font-size:0.9rem;color:rgba(191,219,254,0.85)}.sambatan-progress{display:grid;gap:0.6rem}.sambatan-progress__bar{height:0.6rem;border-radius:var(--radius-full);background:rgba(15,23,42,0.6);border:1px solid rgba(148,163,184,0.25);overflow:hidden}.sambatan-progress__fill{display:block;height:100%;width:var(--progress,0%);border-radius:inherit;background:linear-gradient(90deg,rgba(56,189,248,0.9),rgba(129,140,248,0.9));transition:width 220ms ease}.sambatan-progress__meta{display:flex;justify-content:space-between;font-size:0.9rem;color:rgba(226,232,240,0.85)}.slot-selector{display:inline-grid;grid-template-columns:repeat(3,auto);gap:0.75rem;align-items:center}.slot-stepper{width:2.75rem;height:2.75rem;border-radius:var(--radius-full);border:1px solid rgba(148,163,184,0.35);background:rgba(15,23,42,0.6);color:rgba(241,245,249,0.9);font-size:1.4rem;line-height:1;display:grid;place-items:center;cursor:pointer;transition:transform var(--transition-base),border-color var(--transition-base)}.slot-stepper:hover,.slot-stepper:focus-visible{border-color:rgba(56,189,248,0.6);transform:translateY(-2px)}.slot-stepper:focus-visible{outline:2px solid rgba(56,189,248,0.45);outline-offset:2px}.slot-stepper:disabled{opacity:0.45;cursor:not-allowed;transform:none}.slot-input{width:4rem;text-align:center;padding:0.55rem 0.75rem;border-radius:var(--radius-sm);border:1px solid rgba(148,163,184,0.35);background:rgba(15,23,42,0.55);color:rgba(241,245,249,0.95);font-weight:600;font-size:1.05rem}.slot-input:focus{outline:none;border-color:rgba(56,189,248,0.65);box-shadow:0 0 0 2px rgba(56,189,248,0.2)}.slot-hint{margin:0;font-size:0.9rem;color:rgba(191,219,254,0.85)}.product-visual-rimba{background:linear-gradient(155deg,rgba(12,74,110,0.75),rgba(30,64,175,0.55))}.product-visual-sunset{background:linear-gradient(160deg,rgba(244,114,182,0.75),rgba(251,191,36,0.45))}.product-visual-lagoon{background:linear-gradient(160deg,rgba(56,189,248,0.75),rgba(14,116,144,0.55))}.product-visual-scale{background:linear-gradient(160deg,rgba(56,189,248,0.6),rgba(148,163,184,0.45))}.product-detail-grid{display:grid;grid-template-columns:minmax(0,1.2fr) minmax(0,1fr);gap:1.75rem}.scent-profile header h2,.experience-section header h2,.recommendations header h2,.featured-categories h2{margin-top:0;margin-bottom:0.75rem}.scent-columns{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:1.5rem}.scent-column h3{font-size:1.05rem;color:rgba(191,219,254,0.95)}.scent-column ul{list-style:none;margin:0;padding:0;display:grid;gap:0.35rem;color:rgba(226,232,240,0.85)}.experience-list{list-style:none;margin:0 0 1.5rem;padding:0;display:grid;gap:0.75rem;color:rgba(226,232,240,0.9)}.experience-list li{display:flex;gap:0.5rem;align-items:flex-start}.experience-list li::before{content:"✶";color:rgba(56,189,248,0.85);margin-top:0.1rem}.production-meta{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:1rem;padding-top:1rem;border-top:1px solid rgba(148,163,184,0.25)}.production-meta .meta-label{font-size:0.85rem;text-transform:uppercase;letter-spacing:0.08em;color:rgba(148,163,184,0.7)}.production-meta strong{font-size:1.1rem;color:rgba(250,250,250,0.95)}.featured-categories{display:grid;gap:1.2rem}ul.category-chips{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:0.6rem}.category-chip{padding:0.5rem 1rem;border-radius:999px;border:1px solid rgba(148,163,184,0.35);background:rgba(255,255,255,0.05);font-size:0.9rem;color:rgba(203,213,225,0.85)}.featured-summary p{margin:0;color:rgba(203,213,225,0.85);line-height:1.55}.recommendations{display:grid;gap:1.5rem}.recommendation-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:1.25rem}.recommendation-card{display:grid;gap:1rem;padding:1.25rem;border-radius:var(--radius-md);background:rgba(15,23,42,0.55);border:1px solid rgba(148,163,184,0.25)}.recommendation-visual{height:140px;border-radius:var(--radius-md);background:rgba(51,65,85,0.65);border:1px solid rgba(148,163,184,0.2)}.recommendation-body{display:grid;gap:0.45rem}.recommendation-body h3{margin:0}.recommendation-price{font-weight:600;color:rgba(248,250,252,0.95)}.product-detail-link{margin-left:auto}@media (max-width:1024px){.product-detail-hero{grid-template-columns:1fr}.product-detail-grid{grid-template-columns:1fr}}@media (max-width:720px){.product-detail-page{padding:2.5rem 0 3rem}.product-detail-hero{padding:2rem}.product-volume-options{flex-direction:column;align-items:stretch}.product-breadcrumb ol{font-size:0.85rem}}
\ No newline at end of file
diff --git a/src/app/web/static/css/brand.min.css b/src/app/web/static/css/brand.min.css
new file mode 100644
index 0000000..c8e8ca4
--- /dev/null
+++ b/src/app/web/static/css/brand.min.css
@@ -0,0 +1 @@
+.brand-page{display:grid;gap:3rem;padding-bottom:4rem}.button{display:inline-flex;align-items:center;justify-content:center;padding:0.75rem 1.5rem;border-radius:999px;border:1px solid rgba(255,255,255,0.35);background:rgba(255,255,255,0.12);color:inherit;font-weight:600;text-decoration:none;transition:background 0.2s ease,transform 0.2s ease}.button:hover{background:rgba(255,255,255,0.2);transform:translateY(-1px)}.button-secondary{background:linear-gradient(135deg,rgba(255,255,255,0.15),rgba(255,255,255,0.05))}.button-ghost{background:transparent;border-style:dashed}.button-small{padding:0.5rem 1rem;font-size:0.9rem}.brand-hero{display:grid;grid-template-columns:minmax(240px,1fr) 1.4fr;gap:2rem;padding:2.5rem;align-items:center}.brand-hero__branding{display:flex;align-items:center;gap:1.25rem;flex-wrap:wrap;margin-bottom:1.5rem}.brand-logo{width:104px;height:104px;border-radius:28px;object-fit:cover;background:rgba(15,23,42,0.6);border:1px solid rgba(255,255,255,0.2);box-shadow:0 20px 35px rgba(15,23,42,0.35)}.brand-logo--placeholder{display:inline-flex;align-items:center;justify-content:center;font-weight:700;font-size:2.1rem;letter-spacing:0.08em;width:104px;height:104px;border-radius:28px;background:linear-gradient(135deg,rgba(59,130,246,0.32),rgba(14,165,233,0.42));color:#e0f2fe;border:1px solid rgba(14,165,233,0.45);text-transform:uppercase}.brand-logo-upload{display:grid;gap:0.4rem}.brand-logo-upload__trigger{display:inline-flex;align-items:center;gap:0.5rem;padding:0.6rem 1.2rem;border-radius:999px;border:1px dashed rgba(148,163,184,0.55);background:rgba(15,23,42,0.45);font-weight:600;cursor:pointer}.brand-logo-upload__trigger:hover{background:rgba(30,41,59,0.7);border-color:rgba(148,163,184,0.8)}.brand-logo-upload__trigger input{display:none}.brand-logo-upload__hint{margin:0;font-size:0.75rem;color:rgba(226,232,240,0.75)}.brand-hero__media{width:100%;padding-top:75%;background-size:cover;background-position:center;border-radius:1.5rem;position:relative}.brand-hero__content h1{font-family:"Playfair Display",serif;font-size:clamp(2.4rem,3vw,3.6rem);margin:0}.brand-title-group{display:flex;align-items:center;flex-wrap:wrap;gap:0.75rem;margin-bottom:0.75rem}.brand-tagline{font-size:1.15rem;font-weight:500;margin-bottom:0.75rem}.brand-description{display:grid;gap:0.35rem;margin-bottom:1.5rem}.brand-description h2{font-size:0.75rem;text-transform:uppercase;letter-spacing:0.08em;color:rgba(255,255,255,0.65);margin:0}.brand-description p{margin:0;line-height:1.6}.brand-meta{display:grid;gap:0.5rem;margin:1.5rem 0}.brand-meta dt{font-size:0.75rem;text-transform:uppercase;letter-spacing:0.08em;color:rgba(255,255,255,0.65)}.brand-meta dd{margin:0.25rem 0 0;font-weight:500;display:flex;flex-wrap:wrap;gap:0.5rem}.badge.verified{color:#4ade80;background:rgba(74,222,128,0.18);border-color:rgba(34,197,94,0.45)}.chip{display:inline-flex;align-items:center;gap:0.35rem;padding:0.35rem 0.75rem;border-radius:999px;background:rgba(148,163,184,0.16);border:1px solid rgba(148,163,184,0.35);font-size:0.85rem;font-weight:500}.brand-form-page{padding:3rem 0 5rem;display:flex;justify-content:center}.brand-form-shell{width:min(1120px,100%);padding:2.5rem clamp(1.5rem,4vw,3rem);display:grid;gap:2.5rem}.brand-form-header{display:grid;gap:1rem}.brand-form-header__top{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:1rem}.brand-form-back{color:rgba(148,163,184,0.9);text-decoration:none;font-weight:500;transition:color 0.2s ease}.brand-form-back:hover{color:#f8fafc}.brand-form-chip{padding:0.25rem 0.75rem;border-radius:999px;border:1px solid rgba(148,163,184,0.4);background:rgba(148,163,184,0.12);font-size:0.75rem;letter-spacing:0.08em;text-transform:uppercase}.brand-form-header h1{margin:0;font-size:clamp(2rem,3vw,2.75rem)}.brand-form-header p{margin:0;color:rgba(226,232,240,0.82);line-height:1.7}.brand-form-progress{display:flex;gap:0.5rem;list-style:none;padding:0;margin:0;flex-wrap:wrap}.brand-form-progress__item{padding:0.35rem 0.75rem;border-radius:999px;border:1px dashed rgba(148,163,184,0.4);font-size:0.8rem;text-transform:uppercase;letter-spacing:0.08em;color:rgba(148,163,184,0.8)}.brand-form-progress__item--active{border-style:solid;background:rgba(59,130,246,0.18);border-color:rgba(59,130,246,0.45);color:#bfdbfe}.brand-form-errors{background:rgba(248,113,113,0.08);border:1px solid rgba(248,113,113,0.35);border-radius:1rem;padding:1.5rem;display:grid;gap:0.75rem}.brand-form-errors h2{margin:0;font-size:1.1rem;color:#fecaca}.brand-form-errors ul{margin:0;padding-left:1.25rem;color:#fecaca;display:grid;gap:0.35rem}.brand-form{display:grid;gap:2rem}.brand-form-layout{display:grid;grid-template-columns:minmax(0,2fr) minmax(260px,0.8fr);gap:clamp(2rem,4vw,3rem)}.brand-form-main{display:grid;gap:1.75rem}.brand-form-section{border:1px solid rgba(148,163,184,0.25);border-radius:1.5rem;padding:clamp(1.5rem,3vw,2rem);background:linear-gradient(135deg,rgba(15,23,42,0.65),rgba(15,23,42,0.5));display:grid;gap:1.5rem}.brand-form-section legend{font-size:1.2rem;font-weight:600;letter-spacing:-0.01em}.brand-form-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1.25rem 1.5rem}.brand-form-field{display:grid;gap:0.5rem}.brand-form-field span{font-weight:500}.brand-form-field input,.brand-form-field textarea,.brand-form-field select{width:100%;padding:0.75rem 1rem;border-radius:0.85rem;border:1px solid rgba(148,163,184,0.25);background:rgba(15,23,42,0.75);color:inherit;font:inherit;transition:border-color 0.2s ease,background 0.2s ease}.brand-form-field input:focus,.brand-form-field textarea:focus,.brand-form-field select:focus{outline:none;border-color:rgba(59,130,246,0.55);background:rgba(30,41,59,0.85)}.brand-form-full{grid-column:1 / -1}.brand-form-hint{margin:0;font-size:0.8rem;color:rgba(148,163,184,0.75)}.brand-form-checkbox{align-items:center;grid-template-columns:auto 1fr;gap:0.75rem}.brand-form-checkbox input{width:auto;transform:scale(1.1)}.brand-form-intro{margin:0;color:rgba(226,232,240,0.78)}.brand-member-list{display:grid;gap:1.25rem}.brand-member-card{position:relative;border:1px solid rgba(148,163,184,0.25);border-radius:1.25rem;padding:1.5rem;background:rgba(15,23,42,0.6);display:grid;gap:1rem}.brand-member-card legend{font-weight:600;font-size:1rem}.brand-member-remove{position:absolute;top:1rem;right:1rem;opacity:0.8}.brand-member-remove--hidden{visibility:hidden}.brand-member-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1rem 1.25rem}.brand-member-actions{display:flex;align-items:center;gap:1rem;flex-wrap:wrap}.brand-form-sidebar{display:grid;gap:1.5rem}.brand-form-card{border:1px solid rgba(148,163,184,0.2);border-radius:1.25rem;padding:clamp(1.25rem,3vw,1.75rem);background:rgba(15,23,42,0.55);display:grid;gap:0.75rem}.brand-form-card h3{margin:0;font-size:1.05rem}.brand-form-card p{margin:0;color:rgba(226,232,240,0.75)}.brand-form-card--tips ul{margin:0;padding-left:1.25rem;display:grid;gap:0.45rem;color:rgba(226,232,240,0.8)}.brand-form-sidebar-actions{display:grid;gap:0.5rem}.brand-form-actions{display:flex;justify-content:space-between;gap:1rem;flex-wrap:wrap}.brand-form-actions .button{min-width:180px}.input-error{border-color:rgba(248,113,113,0.8) !important;background:rgba(248,113,113,0.12) !important}@media (max-width:1024px){.brand-form-layout{grid-template-columns:1fr}.brand-form-sidebar{order:-1}}@media (max-width:720px){.brand-form-grid,.brand-member-grid{grid-template-columns:1fr}.brand-form-actions{flex-direction:column;align-items:stretch}.brand-form-actions .button{width:100%}}.chip-owner{background:rgba(59,130,246,0.14);border-color:rgba(59,130,246,0.45);color:#bfdbfe}.chip-muted{background:rgba(148,163,184,0.1);color:rgba(226,232,240,0.9)}.brand-cta{display:flex;gap:1rem;flex-wrap:wrap}.brand-section{display:grid;gap:1.5rem}.section-header h2{font-size:2rem;margin-bottom:0.5rem}.brand-story-list{display:grid;gap:1.5rem;grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.brand-story-item{position:relative;padding:1.75rem}.story-index{font-family:"Playfair Display",serif;font-size:1.5rem;color:rgba(255,255,255,0.4);position:absolute;top:1.25rem;right:1.5rem}.brand-product-grid{display:grid;gap:1.5rem;grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.brand-product-card{padding:1.75rem;display:grid;gap:0.75rem}.brand-product-card__header{display:flex;justify-content:space-between;align-items:baseline}.brand-product-card__note{color:rgba(255,255,255,0.8)}.brand-product-card__price{font-weight:600;font-size:1.1rem}.brand-product-card__availability{font-size:0.95rem;color:rgba(255,255,255,0.7)}.brand-product-card__actions{margin-top:0.5rem;display:flex}.brand-product-card__actions .button{flex:1}.brand-product-card__actions .button:focus-visible{outline:2px solid rgba(14,165,233,0.65);outline-offset:3px}.brand-collaboration .team-column{display:grid;gap:1rem}.brand-team-grid{display:grid;gap:2rem;grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.team-list{list-style:none;display:grid;gap:1rem;padding:0;margin:0}.team-card{display:grid;grid-template-columns:64px 1fr;gap:1rem;align-items:center;padding:1rem}.team-card img{width:64px;height:64px;object-fit:cover;border-radius:50%}.team-card--pending{border:1px dashed rgba(255,255,255,0.3)}.team-name{font-weight:600}.team-role{text-transform:capitalize;font-size:0.9rem;color:rgba(255,255,255,0.7)}.team-expertise{font-size:0.9rem;margin-top:0.25rem}.team-invited{font-size:0.8rem;color:rgba(255,255,255,0.6);margin-top:0.25rem}.team-actions{display:flex;gap:0.5rem;grid-column:1 / -1}.team-actions .button-small{font-size:0.85rem;padding:0.35rem 0.75rem}.invite-form{display:grid;gap:1rem;padding:1.5rem}.invite-form label{display:grid;gap:0.5rem;font-size:0.9rem}.invite-form input,.invite-form textarea{padding:0.75rem;border-radius:0.75rem;border:1px solid rgba(255,255,255,0.2);background:rgba(15,18,41,0.35);color:inherit}.brand-highlight-grid{display:grid;gap:1.5rem;grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.highlight-card{padding:1.75rem;display:grid;gap:0.75rem}.highlight-timestamp{font-size:0.85rem;text-transform:uppercase;letter-spacing:0.08em;color:rgba(255,255,255,0.6)}.brand-directory{display:grid;gap:2.5rem;padding-bottom:4rem}.brand-directory-grid{display:grid;gap:1.5rem;grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.brand-directory-card{padding:2rem;display:grid;gap:1rem}.brand-directory-card__header{display:flex;align-items:center;justify-content:flex-start}.brand-directory-logo{width:72px;height:72px;border-radius:1.25rem;object-fit:cover;background:rgba(15,23,42,0.55);border:1px solid rgba(255,255,255,0.15)}.brand-directory-logo--placeholder{display:inline-flex;align-items:center;justify-content:center;font-weight:700;font-size:1.5rem;width:72px;height:72px;border-radius:1.25rem;background:linear-gradient(135deg,rgba(59,130,246,0.32),rgba(14,165,233,0.42));color:#e0f2fe;text-transform:uppercase;letter-spacing:0.06em}.brand-directory-card__meta{display:flex;flex-direction:column;gap:0.5rem}.brand-directory-card__meta h2{font-family:"Playfair Display",serif;font-size:1.75rem;margin:0}.brand-directory-meta-extra{display:flex;flex-wrap:wrap;gap:0.75rem;font-size:0.95rem;color:rgba(226,232,240,0.85)}.brand-directory-meta-extra p{margin:0}.brand-directory-tagline{font-weight:500;margin-top:0.5rem}.brand-directory-card .badge.verified{align-self:flex-start}.brand-directory-location{font-size:0.9rem;color:rgba(255,255,255,0.6)}.brand-directory-summary{font-size:0.95rem;line-height:1.6}.brand-directory-focus{display:flex;gap:0.5rem;flex-wrap:wrap}@media (max-width:960px){.brand-hero{grid-template-columns:1fr}.brand-hero__media{padding-top:55%}}@media (max-width:640px){.brand-page{gap:2rem}.brand-hero{padding:1.75rem}.brand-product-grid,.brand-team-grid,.brand-highlight-grid,.brand-directory-grid{grid-template-columns:1fr}.team-card{grid-template-columns:48px 1fr}}
\ No newline at end of file
diff --git a/src/app/web/static/css/dashboard.min.css b/src/app/web/static/css/dashboard.min.css
new file mode 100644
index 0000000..0ff27cd
--- /dev/null
+++ b/src/app/web/static/css/dashboard.min.css
@@ -0,0 +1 @@
+.dashboard-hero{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:2.5rem;padding:2.75rem;align-items:center}.hero-badge{display:inline-flex;align-items:center;padding:0.35rem 0.9rem;border-radius:999px;background:rgba(148,163,184,0.18);border:1px solid rgba(148,163,184,0.45);font-size:0.85rem;letter-spacing:0.02em}.hero-main h1{font-size:clamp(2rem,4vw,2.75rem);margin:0.75rem 0 0.5rem}.hero-main p{font-size:1.05rem;max-width:36ch}.hero-meta{display:flex;flex-wrap:wrap;gap:0.75rem;margin:1.35rem 0;font-size:0.95rem;color:var(--text-secondary)}.hero-meta span{display:inline-flex;align-items:center;gap:0.4rem;padding:0.4rem 0.9rem;border-radius:999px;background:rgba(148,163,184,0.12);border:1px solid rgba(148,163,184,0.25)}.hero-actions{display:flex;flex-wrap:wrap;gap:0.85rem}.hero-kpis{align-self:stretch}.kpi-grid{list-style:none;display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:1.25rem;padding:0;margin:0}.kpi-card{padding:1.35rem 1.5rem}.kpi-label{font-size:0.95rem;color:var(--text-secondary);margin:0 0 0.5rem}.kpi-value{font-size:1.65rem;font-weight:600;margin:0 0 0.35rem}.kpi-delta{font-size:0.9rem;margin:0}.kpi-delta.positive{color:#4ade80}.kpi-delta.negative{color:#f97316}.dashboard-overview{padding:2.25rem;display:grid;gap:2rem}.section-heading{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:flex-start;gap:1.5rem}.section-heading h2{margin:0 0 0.35rem;font-size:1.8rem}.section-heading p{margin:0;max-width:48ch}.section-tools{display:flex;gap:0.75rem;flex-wrap:wrap}.overview-content{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,0.9fr);gap:2rem}.status-pills{display:flex;flex-wrap:wrap;gap:1rem}.status-pill{min-width:140px;padding:1rem 1.25rem;border-radius:var(--radius-md);border:1px solid rgba(148,163,184,0.25);background:rgba(15,23,42,0.6);display:grid;gap:0.25rem}.status-count{font-size:1.6rem;font-weight:600}.status-label{font-size:0.95rem;color:var(--text-secondary)}.status-pill.tone-info{border-color:rgba(56,189,248,0.45)}.status-pill.tone-primary{border-color:rgba(129,140,248,0.55)}.status-pill.tone-success{border-color:rgba(74,222,128,0.55)}.status-pill.tone-warning{border-color:rgba(250,204,21,0.55)}.notification-panel{display:grid;gap:1.2rem}.notification-panel h3{margin:0}.notification-list{list-style:none;display:grid;gap:1rem;margin:0;padding:0}.notification-item{padding:1.25rem 1.5rem;display:grid;gap:0.75rem}.notification-empty{font-size:0.9rem;color:var(--text-secondary);margin:0}.notification-header{display:flex;justify-content:space-between;font-size:0.9rem;color:var(--text-secondary)}.notification-item p{margin:0}.dashboard-management{display:grid;gap:2rem}.management-card{padding:2.25rem;display:grid;gap:1.5rem}.management-controls{display:flex;flex-wrap:wrap;gap:1.5rem;justify-content:space-between;align-items:center}.filter-chips{display:flex;flex-wrap:wrap;gap:0.65rem}.chip{display:inline-flex;align-items:center;justify-content:center;padding:0.4rem 0.95rem;border-radius:999px;border:1px solid rgba(148,163,184,0.35);background:rgba(148,163,184,0.12);color:var(--text-secondary);font-size:0.9rem;font-weight:500;cursor:pointer;transition:background var(--transition-base),color var(--transition-base),border-color var(--transition-base),transform var(--transition-base)}.chip:hover,.chip:focus-visible{border-color:rgba(96,165,250,0.7);color:var(--text-primary);transform:translateY(-1px)}.chip.is-active{background:var(--accent-primary);color:#0f172a;border-color:transparent;box-shadow:0 12px 24px rgba(192,38,211,0.25)}.search-field{display:grid;gap:0.35rem;font-size:0.9rem}.search-field input{background:rgba(15,23,42,0.7);border:1px solid rgba(148,163,184,0.35);border-radius:var(--radius-sm);padding:0.65rem 0.9rem;color:var(--text-primary)}.search-field input:focus{outline:2px solid rgba(96,165,250,0.6);outline-offset:2px}.table-wrapper{overflow-x:auto;border-radius:var(--radius-md)}.data-table{width:100%;border-collapse:collapse;min-width:680px}.data-table th,.data-table td{padding:0.9rem 1.1rem;text-align:left;border-bottom:1px solid rgba(148,163,184,0.2)}.data-table thead th{font-size:0.85rem;letter-spacing:0.02em;text-transform:uppercase;color:var(--text-secondary)}.data-table tbody tr:hover{background:rgba(15,23,42,0.55)}.table-primary{display:grid;gap:0.2rem}.primary-text{font-weight:600}.secondary-text{font-size:0.85rem;color:var(--text-secondary)}.status-badge{display:inline-flex;align-items:center;padding:0.35rem 0.75rem;border-radius:999px;font-size:0.8rem;border:1px solid rgba(148,163,184,0.3);background:rgba(148,163,184,0.12);text-transform:capitalize}.status-aktif{color:#4ade80;border-color:rgba(74,222,128,0.5)}.status-baru{color:#facc15;border-color:rgba(250,204,21,0.55)}.status-diproses{color:#38bdf8;border-color:rgba(56,189,248,0.55)}.status-dikirim{color:#a5b4fc;border-color:rgba(129,140,248,0.55)}.status-draft{color:#facc15;border-color:rgba(250,204,21,0.55)}.status-pending{color:#f97316;border-color:rgba(249,115,22,0.55)}.status-arsip{color:#a5b4fc;border-color:rgba(129,140,248,0.55)}.status-perlu-perhatian{color:#f97316;border-color:rgba(249,115,22,0.55)}.status-lengkap{color:#4ade80;border-color:rgba(74,222,128,0.55)}.status-perlu-revisi{color:#f97316;border-color:rgba(249,115,22,0.55)}.status-opsional{color:#a5b4fc;border-color:rgba(129,140,248,0.5)}.analytics-section{padding:2.5rem;display:grid;gap:1.75rem}.analytics-panel{display:grid;gap:1.5rem;padding:1.75rem;border-radius:var(--radius-lg);background:rgba(15,23,42,0.6);border:1px solid rgba(148,163,184,0.2)}.analytics-panel.is-hidden{display:none}.analytics-summary{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:1rem}.summary-label{font-size:0.85rem;color:var(--text-secondary)}.summary-value{font-size:1.4rem;font-weight:600}.analytics-chart{position:relative;height:220px;border-radius:var(--radius-md);overflow:hidden;background:linear-gradient(145deg,rgba(15,23,42,0.65),rgba(15,23,42,0.45));border:1px solid rgba(148,163,184,0.2)}.analytics-chart svg{width:100%;height:100%}.chart-area{stroke:none;opacity:0.55}.chart-line{fill:none;stroke:#38bdf8;stroke-width:2}.chart-label{position:absolute;bottom:6px;transform:translateX(-50%);font-size:0.7rem;color:var(--text-secondary);pointer-events:none}.analytics-details{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:1.5rem}.top-products ul,.customer-segments ul{list-style:none;margin:0;padding:0;display:grid;gap:0.75rem}.top-products li,.customer-segments li{display:flex;justify-content:space-between;font-size:0.95rem}.promotion-section{display:grid;gap:1.75rem;padding:2.25rem}.promotion-grid{display:grid;gap:1.5rem;grid-template-columns:repeat(auto-fit,minmax(240px,1fr))}.promotion-card{display:grid;gap:1rem;padding:1.5rem}.promotion-meta{display:flex;justify-content:space-between;font-size:0.85rem;color:var(--text-secondary)}.progress-track{position:relative;width:100%;height:10px;border-radius:999px;background:rgba(148,163,184,0.15);overflow:hidden}.progress-fill{position:absolute;inset:0;width:var(--progress);background:var(--accent-primary);border-radius:inherit}.promotion-actions{display:flex;gap:0.5rem;flex-wrap:wrap}.verification-section{display:grid;gap:2rem;grid-template-columns:minmax(0,1.15fr) minmax(0,0.85fr)}.verification-steps{padding:2.5rem;display:grid;gap:1.5rem}.step-list{list-style:none;display:grid;gap:1rem;margin:0;padding:0}.step-item{display:grid;grid-template-columns:auto 1fr;gap:1rem;align-items:start;padding:1.1rem 1.35rem;border-radius:var(--radius-md);border:1px solid rgba(148,163,184,0.2);background:rgba(15,23,42,0.55)}.step-icon{width:14px;height:14px;border-radius:50%;border:3px solid rgba(148,163,184,0.5);margin-top:0.4rem}.step-selesai .step-icon{border-color:#4ade80;background:rgba(74,222,128,0.35)}.step-revisi .step-icon{border-color:#f97316;background:rgba(249,115,22,0.3)}.step-menunggu .step-icon{border-color:rgba(148,163,184,0.4)}.verification-aside{padding:2rem;display:grid;gap:1.5rem}.document-list{list-style:none;margin:0;padding:0;display:grid;gap:1rem}.document-list li{display:flex;justify-content:space-between;align-items:flex-start;gap:1.25rem}.document-name{font-weight:600}.document-note{display:block;font-size:0.85rem;color:var(--text-secondary);margin-top:0.35rem}.timeline-heading{margin:0}.timeline{list-style:none;margin:0;padding:0;display:grid;gap:1.1rem}.timeline li{display:grid;grid-template-columns:auto 1fr;gap:1rem}.timeline-date{font-size:0.85rem;color:var(--text-secondary)}.timeline-actor{font-weight:600}.team-section{display:grid;gap:2rem;padding:2.5rem}.team-layout{display:grid;grid-template-columns:minmax(0,1.4fr) minmax(0,0.8fr);gap:2rem}.team-members table{min-width:720px}.permission-list{list-style:none;margin:0;padding:0;display:grid;gap:0.35rem}.team-sidebar{display:grid;gap:1.5rem}.invitation-card ul,.activity-card ul{list-style:none;margin:0;padding:0;display:grid;gap:1rem}.invitation-card li,.activity-card li{display:grid;gap:0.5rem;padding-bottom:0.75rem;border-bottom:1px solid rgba(148,163,184,0.15)}.invitation-meta{font-size:0.85rem;color:var(--text-secondary);display:flex;gap:0.75rem}.invitation-actions{display:flex;gap:0.5rem}.activity-time{font-size:0.85rem;color:var(--text-secondary)}.activity-actor{font-weight:600}@media (max-width:1024px){.dashboard-hero{grid-template-columns:1fr}.overview-content,.verification-section,.team-layout{grid-template-columns:1fr}.analytics-chart{height:200px}}@media (max-width:768px){.dashboard-hero,.dashboard-overview,.management-card,.analytics-section,.promotion-section,.team-section{padding:1.75rem}.status-pills{gap:0.75rem}.data-table{min-width:540px}.analytics-summary{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (max-width:600px){.section-heading{flex-direction:column;align-items:flex-start}.hero-actions{flex-direction:column;align-items:stretch}.chip{width:fit-content}}
\ No newline at end of file
diff --git a/src/app/web/static/css/moderation-dashboard.min.css b/src/app/web/static/css/moderation-dashboard.min.css
new file mode 100644
index 0000000..4c74d66
--- /dev/null
+++ b/src/app/web/static/css/moderation-dashboard.min.css
@@ -0,0 +1 @@
+.mod-hero{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:2.5rem;padding:2.75rem;align-items:start}.mod-hero__main h1{font-size:clamp(2rem,4vw,2.75rem);margin:0.5rem 0 0.75rem}.mod-hero__main .mission{font-size:1.05rem;margin:0 0 1rem;max-width:46ch}.role-badge{display:inline-flex;align-items:center;padding:0.4rem 1rem;border-radius:999px;background:rgba(148,163,184,0.2);border:1px solid rgba(148,163,184,0.4);font-size:0.85rem;letter-spacing:0.03em}.hero-meta{display:grid;gap:0.75rem;margin:1.5rem 0 1.25rem;grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}.hero-meta dt{font-size:0.8rem;text-transform:uppercase;letter-spacing:0.08em;color:rgba(203,213,225,0.8);margin-bottom:0.25rem}.hero-meta dd{margin:0;font-size:0.95rem}.hero-actions{display:flex;flex-wrap:wrap;gap:0.85rem}.acknowledgement{margin-top:1.25rem;font-size:0.95rem;color:var(--text-secondary)}.mod-section-tabs{margin:2.5rem 0 1.5rem;padding:1.25rem 2.5rem 1rem;display:block}.mod-section-tabs .tab-bar{display:flex;align-items:center;gap:1.25rem}.mod-section-tabs .tab-scroller{position:relative;flex:1 1 auto;overflow-x:auto;padding-bottom:0.35rem;scroll-snap-type:x proximity;-webkit-overflow-scrolling:touch;mask-image:linear-gradient(90deg,rgba(0,0,0,0) 0%,#000 6%,#000 94%,rgba(0,0,0,0) 100%)}.mod-section-tabs .tab-scroller::-webkit-scrollbar{display:none}.mod-section-tabs .tab-scroller{-ms-overflow-style:none;scrollbar-width:none}.mod-section-tabs .tab-list{list-style:none;margin:0;padding:0;display:flex;gap:0.65rem;min-width:max-content}.mod-section-tabs .tab-list__item{flex:0 0 auto}.mod-section-tabs .tab-link{display:grid;gap:0.15rem;padding:0.7rem 1.3rem;border-radius:var(--radius-md);border:1px solid transparent;background:rgba(15,23,42,0.25);color:var(--text-secondary);cursor:pointer;text-align:left;min-width:130px;transition:background 0.2s ease,color 0.2s ease,border-color 0.2s ease,box-shadow 0.2s ease;scroll-snap-align:center;text-decoration:none}.mod-section-tabs .tab-link .tab-label{font-size:0.95rem;font-weight:600;color:inherit}.mod-section-tabs .tab-link .tab-subtitle{font-size:0.7rem;text-transform:uppercase;letter-spacing:0.12em;color:rgba(148,163,184,0.85)}.mod-section-tabs .tab-link:is(:hover,:focus-visible){background:rgba(59,130,246,0.18);color:var(--text-primary);border-color:rgba(59,130,246,0.25);box-shadow:0 1px 0 rgba(148,163,184,0.2)}.mod-section-tabs .tab-link.is-active{color:var(--text-primary);background:rgba(59,130,246,0.22);border-color:rgba(59,130,246,0.35);box-shadow:0 10px 30px rgba(59,130,246,0.2)}.mod-section-tabs .tab-link.is-active .tab-subtitle{color:rgba(226,232,240,0.9)}.mod-section-tabs .tab-indicator{position:absolute;left:0;bottom:0;height:3px;width:0;border-radius:999px;background:linear-gradient(90deg,rgba(191,219,254,0.65) 0%,rgba(59,130,246,0.95) 100%);opacity:0;transition:transform 0.28s ease,width 0.28s ease,opacity 0.18s ease}.mod-section-tabs .tab-indicator.is-visible{opacity:1}.mod-section-tabs .tab-actions{flex:0 0 auto}.mod-section-tabs .tab-actions .btn{white-space:nowrap}.mod-hero__kpis{align-self:stretch}.kpi-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:1.25rem;list-style:none;padding:0;margin:0}.kpi-card{padding:1.4rem 1.5rem}.kpi-card .kpi-label{margin:0;color:var(--text-secondary);font-size:0.95rem}.kpi-card .kpi-value{margin:0.5rem 0 0.35rem;font-size:1.65rem;font-weight:600}.kpi-card .kpi-delta{margin:0;font-size:0.9rem}.kpi-card.tone-success{border-left:3px solid rgba(52,211,153,0.8)}.kpi-card.tone-warning{border-left:3px solid rgba(250,204,21,0.75)}.kpi-card.tone-info{border-left:3px solid rgba(56,189,248,0.75)}.kpi-card.tone-positive{border-left:3px solid rgba(129,140,248,0.75)}.mod-overview{padding:2.5rem;display:grid;gap:2.25rem}.overview-grid{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,0.95fr);gap:2.25rem}.summary-pills{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}.summary-pill{padding:1.1rem 1.35rem;border-radius:var(--radius-md);border:1px solid rgba(148,163,184,0.25);background:rgba(15,23,42,0.6);display:grid;gap:0.2rem}.summary-pill .summary-value{font-size:1.45rem;font-weight:600}.summary-pill .summary-label{font-size:0.9rem;color:var(--text-secondary)}.summary-pill.tone-danger{border-color:rgba(248,113,113,0.5)}.summary-pill.tone-warning{border-color:rgba(250,204,21,0.5)}.summary-pill.tone-primary{border-color:rgba(129,140,248,0.5)}.summary-pill.tone-info{border-color:rgba(56,189,248,0.5)}.alert-stream{display:grid;gap:1.2rem}.alert-list{list-style:none;margin:0;padding:0;display:grid;gap:1.1rem}.alert-item{padding:1.35rem 1.5rem;display:grid;gap:0.75rem}.alert-header{display:flex;justify-content:space-between;align-items:center;font-size:0.85rem;text-transform:uppercase;letter-spacing:0.05em}.alert-severity{color:var(--text-secondary)}.alert-item.severity-kritis{border-left:3px solid rgba(248,113,113,0.8)}.alert-item.severity-penting{border-left:3px solid rgba(129,140,248,0.75)}.alert-item.severity-pengingat{border-left:3px solid rgba(56,189,248,0.75)}.alert-actions{display:flex;gap:0.75rem;flex-wrap:wrap}.mod-team{display:grid}.team-roster{padding:2.5rem;display:grid;gap:2rem}.team-layout{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,0.8fr);gap:2.25rem}.team-table{display:grid;gap:0.75rem}.team-header,.team-row{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:1rem;padding:0.9rem 1.1rem;border-radius:var(--radius-md);background:rgba(15,23,42,0.55);border:1px solid rgba(148,163,184,0.18)}.team-header{font-size:0.85rem;text-transform:uppercase;letter-spacing:0.05em;background:rgba(15,23,42,0.7)}.team-sidepanel{display:grid;gap:1.75rem}.invite-panel ul,.audit-trail ol{margin:0;padding:0;list-style:none;display:grid;gap:1rem}.invite-panel li,.audit-trail li{background:rgba(15,23,42,0.55);border:1px solid rgba(148,163,184,0.18);border-radius:var(--radius-md);padding:1rem 1.2rem;display:grid;gap:0.5rem}.panel-actions{display:flex;gap:0.75rem;flex-wrap:wrap}.audit-time{font-size:0.8rem;color:var(--text-secondary);text-transform:uppercase;letter-spacing:0.05em}.mod-queues{padding:2.5rem;display:grid;gap:2.25rem}.queue-grid{display:grid;grid-template-columns:minmax(0,0.55fr) minmax(0,1.45fr);gap:2rem}.queue-sidebar ul{list-style:none;margin:0 0 1.5rem;padding:0;display:grid;gap:0.75rem}.queue-sidebar li{display:flex;align-items:center;gap:0.8rem;font-size:0.95rem}.queue-sidebar .indicator{width:12px;height:12px;border-radius:999px;display:inline-block}.indicator.tone-danger{background:rgba(248,113,113,0.85)}.indicator.tone-warning{background:rgba(250,204,21,0.85)}.indicator.tone-primary{background:rgba(129,140,248,0.85)}.indicator.tone-info{background:rgba(56,189,248,0.85)}.queue-note{font-size:0.9rem;color:var(--text-secondary)}.queue-table{width:100%;border-collapse:collapse;background:rgba(15,23,42,0.55);border:1px solid rgba(148,163,184,0.18);border-radius:var(--radius-md);overflow:hidden}.queue-table th,.queue-table td{padding:0.85rem 1rem;text-align:left;border-bottom:1px solid rgba(148,163,184,0.12)}.queue-table thead{background:rgba(15,23,42,0.7);font-size:0.85rem;text-transform:uppercase;letter-spacing:0.05em}.queue-table tbody tr:last-child td{border-bottom:none}.priority-badge{display:inline-flex;align-items:center;padding:0.3rem 0.75rem;border-radius:999px;font-size:0.85rem;border:1px solid transparent}.priority-merah{background:rgba(248,113,113,0.18);border-color:rgba(248,113,113,0.45)}.priority-kuning{background:rgba(250,204,21,0.18);border-color:rgba(250,204,21,0.45)}.priority-hijau{background:rgba(52,211,153,0.18);border-color:rgba(52,211,153,0.45)}.mod-curation{padding:2.5rem;display:grid;gap:2.25rem}.curation-grid{display:grid;grid-template-columns:minmax(0,0.6fr) minmax(0,1.4fr);gap:2rem}.summary-list{list-style:none;margin:0 0 1.5rem;padding:0;display:grid;gap:0.85rem}.summary-list li{display:grid;gap:0.2rem}.summary-list .summary-value{font-size:1.35rem;font-weight:600}.summary-list .summary-label{font-size:0.95rem;color:var(--text-secondary)}.summary-list .tone-success{color:#34d399}.summary-list .tone-danger{color:#f87171}.summary-list .tone-warning{color:#fbbf24}.summary-list .tone-primary{color:#818cf8}.checklist{list-style:none;margin:0;padding:0;display:grid;gap:0.6rem;font-size:0.95rem}.curation-table,.team-performance{width:100%;border-collapse:collapse;background:rgba(15,23,42,0.55);border:1px solid rgba(148,163,184,0.18);border-radius:var(--radius-md);overflow:hidden}.curation-table th,.curation-table td,.team-performance th,.team-performance td{padding:0.85rem 1rem;text-align:left;border-bottom:1px solid rgba(148,163,184,0.12)}.curation-table thead,.team-performance thead{background:rgba(15,23,42,0.7);font-size:0.85rem;text-transform:uppercase;letter-spacing:0.05em}.mod-analytics{padding:2.5rem;display:grid;gap:2.25rem}.analytics-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.1fr);gap:2rem}.insight-cards{display:grid;gap:1.25rem}.insight-card{padding:1.4rem 1.6rem;display:grid;gap:0.6rem}.insight-card h3{margin:0}.insight-card .insight-value{font-size:1.8rem;font-weight:600;margin:0}.insight-card.tone-warning{border-left:3px solid rgba(250,204,21,0.75)}.insight-card.tone-info{border-left:3px solid rgba(56,189,248,0.75)}.insight-card.tone-success{border-left:3px solid rgba(52,211,153,0.75)}.analytics-details{display:grid;gap:1.75rem}.heatmap{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:1rem}.heatmap-slot{border:1px solid rgba(148,163,184,0.18);border-radius:var(--radius-md);padding:1rem 1.2rem;background:rgba(15,23,42,0.55);display:grid;gap:0.35rem}.heatmap-slot.state-kritikal{border-color:rgba(248,113,113,0.5)}.heatmap-slot.state-padat{border-color:rgba(250,204,21,0.45)}.heatmap-slot.state-stabil{border-color:rgba(56,189,248,0.45)}.heatmap-slot.state-rendah{border-color:rgba(129,140,248,0.35)}.violation-list{margin:0;padding:0 0 0 1.25rem;display:grid;gap:0.6rem}.mod-policies{padding:2.5rem;display:grid;gap:2.25rem}.policy-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:2rem}.policy-list{list-style:none;margin:0;padding:0;display:grid;gap:1rem}.policy-list li{padding:1.3rem 1.5rem;display:grid;gap:0.6rem}.policy-tags{display:flex;flex-wrap:wrap;gap:0.5rem}.policy-tags span{padding:0.35rem 0.8rem;border-radius:999px;background:rgba(148,163,184,0.15);border:1px solid rgba(148,163,184,0.25);font-size:0.85rem}.template-list,.automation-list{list-style:none;margin:0 0 1.25rem;padding:0;display:grid;gap:0.8rem}.automation-list li{padding-left:1.25rem;position:relative}.automation-list li::before{content:"•";position:absolute;left:0;color:rgba(56,189,248,0.75)}.mod-help{padding:2.5rem;display:grid;gap:2.25rem}.help-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:2rem}.resource-list,.contact-list{list-style:none;margin:0;padding:0;display:grid;gap:1rem}.resource-list li{padding:1.2rem 1.4rem;display:grid;gap:0.5rem}.contact-list li{background:rgba(15,23,42,0.55);border:1px solid rgba(148,163,184,0.18);border-radius:var(--radius-md);padding:1rem 1.2rem}.feedback-box{margin-top:1.5rem;padding:1.4rem 1.6rem;display:grid;gap:0.75rem}@media (max-width:1024px){.mod-hero,.overview-grid,.team-layout,.queue-grid,.curation-grid,.analytics-grid,.policy-grid,.help-grid{grid-template-columns:1fr}.mod-hero{padding:2.25rem}}@media (max-width:768px){.team-header,.team-row{grid-template-columns:repeat(2,minmax(0,1fr))}.queue-table,.curation-table,.team-performance{display:block;overflow-x:auto;white-space:nowrap}}
\ No newline at end of file
diff --git a/src/app/web/static/css/nusantarum.min.css b/src/app/web/static/css/nusantarum.min.css
new file mode 100644
index 0000000..b4e3eef
--- /dev/null
+++ b/src/app/web/static/css/nusantarum.min.css
@@ -0,0 +1 @@
+.nusantarum-page{display:grid;gap:2.5rem;padding-block:2rem 4rem;color:var(--text-primary)}.nusantarum-hero{display:grid;gap:2rem;padding:clamp(2rem,5vw,3rem);border-radius:28px;background:linear-gradient(135deg,rgba(15,23,42,0.9),rgba(30,41,59,0.65));border:1px solid rgba(255,255,255,0.18);backdrop-filter:blur(18px);box-shadow:0 32px 80px rgba(15,23,42,0.45)}.nusantarum-hero__copy{display:grid;gap:1rem}.nusantarum-hero__eyebrow{font-size:0.85rem;letter-spacing:0.28em;text-transform:uppercase;color:rgba(255,255,255,0.65)}.nusantarum-hero h1{font-family:'Playfair Display',serif;font-size:clamp(2.5rem,4vw,3.5rem);font-weight:700;letter-spacing:-0.02em}.nusantarum-hero p{max-width:60ch;font-size:1rem;line-height:1.7;color:rgba(255,255,255,0.85)}.nusantarum-hero__stats{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}.nusantarum-hero__stats div{padding:1.2rem 1.4rem;border-radius:18px;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.15)}.nusantarum-hero__stats dt{font-size:0.85rem;text-transform:uppercase;letter-spacing:0.14em;color:rgba(255,255,255,0.65);margin-bottom:0.35rem}.nusantarum-hero__stats dd{font-size:clamp(1.8rem,2vw+1rem,2.4rem);font-weight:600;margin:0}.nusantarum-tabs{display:flex;flex-wrap:wrap;gap:0.75rem}.nusantarum-tab{display:inline-flex;align-items:center;gap:0.65rem;padding:0.6rem 1.3rem;border-radius:999px;border:1px solid transparent;background:rgba(255,255,255,0.15);color:inherit;cursor:pointer;transition:transform 0.2s ease,box-shadow 0.2s ease,border 0.2s ease}.nusantarum-tab[aria-selected='true']{background:linear-gradient(135deg,rgba(251,191,36,0.9),rgba(236,72,153,0.85));border-color:rgba(255,255,255,0.45);color:#0f172a;box-shadow:0 12px 32px rgba(236,72,153,0.35)}.nusantarum-tab:hover,.nusantarum-tab:focus-visible{border-color:rgba(255,255,255,0.5);transform:translateY(-2px)}.nusantarum-tab__count{display:inline-flex;align-items:center;justify-content:center;min-width:2rem;padding:0.15rem 0.5rem;border-radius:999px;background:rgba(15,23,42,0.4);color:inherit;font-size:0.85rem;font-weight:600}.nusantarum-controls{display:grid;gap:1rem}.nusantarum-search{display:flex;flex-wrap:wrap;gap:1rem;align-items:center}.nusantarum-search input[type='search']{flex:1;min-width:min(360px,100%);padding:0.85rem 1.2rem;border-radius:18px;border:1px solid rgba(255,255,255,0.25);background:rgba(15,23,42,0.55);color:inherit;font-size:1rem;transition:border 0.2s ease,box-shadow 0.2s ease}.nusantarum-search input[type='search']:focus{outline:none;border-color:rgba(251,191,36,0.7);box-shadow:0 0 0 2px rgba(251,191,36,0.35)}.nusantarum-search input[type='search']::placeholder{color:rgba(255,255,255,0.6)}.nusantarum-search-results{display:grid;gap:1.2rem;padding:1.3rem;border-radius:20px;background:rgba(15,23,42,0.65);border:1px solid rgba(255,255,255,0.18);box-shadow:inset 0 1px 0 rgba(255,255,255,0.08)}.nusantarum-search-results__group{display:grid;gap:0.6rem}.nusantarum-search-results__group h3{font-size:0.9rem;text-transform:uppercase;letter-spacing:0.18em;color:rgba(255,255,255,0.6)}.nusantarum-search-results ul{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:0.5rem}.nusantarum-search-results__pill{display:inline-flex;align-items:center;gap:0.4rem;padding:0.35rem 0.8rem;border-radius:999px;background:rgba(255,255,255,0.14);font-size:0.85rem}.nusantarum-search-results__message{font-size:0.9rem;color:rgba(255,255,255,0.7)}.nusantarum-search-results__placeholder{display:grid;gap:0.75rem}.nusantarum-body{display:grid;gap:1.5rem}.nusantarum-content{display:grid;gap:1.5rem}@media (min-width:1024px){.nusantarum-hero{grid-template-columns:minmax(0,1fr) 320px;align-items:center}.nusantarum-body{grid-template-columns:minmax(0,320px) minmax(0,1fr);align-items:start}}.nusantarum-sidebar{position:relative}.nusantarum-filter-panel{position:sticky;top:1.5rem;display:grid;gap:1.25rem;padding:1.75rem;border-radius:24px;background:rgba(15,23,42,0.72);border:1px solid rgba(255,255,255,0.16)}.nusantarum-filter-panel h2{font-size:1.15rem;font-weight:600;margin:0}.nusantarum-filter-panel h3{font-size:0.95rem;text-transform:uppercase;letter-spacing:0.16em;color:rgba(255,255,255,0.6);margin-bottom:0.5rem}.filter-actions{display:flex;justify-content:flex-end;margin-top:0.5rem}.filter-submit{display:inline-flex;align-items:center;gap:0.5rem;padding:0.7rem 1.35rem;border-radius:999px;border:1px solid rgba(255,255,255,0.28);background:linear-gradient(135deg,rgba(251,191,36,0.88),rgba(236,72,153,0.82));color:#0f172a;font-weight:600;letter-spacing:0.02em;box-shadow:0 12px 32px rgba(236,72,153,0.25);cursor:pointer;transition:transform 0.2s ease,box-shadow 0.2s ease,opacity 0.2s ease}.filter-submit:hover,.filter-submit:focus-visible{transform:translateY(-1px);box-shadow:0 18px 40px rgba(236,72,153,0.35);outline:none}.filter-submit:active{transform:translateY(0);box-shadow:0 8px 22px rgba(236,72,153,0.28)}.text-muted{color:rgba(255,255,255,0.7);font-size:0.95rem;line-height:1.6}.filter-chip-group{display:flex;flex-wrap:wrap;gap:0.5rem}.filter-chip{position:relative;display:inline-flex;align-items:center;justify-content:center;padding:0.45rem 0.9rem;border-radius:999px;border:1px solid rgba(255,255,255,0.25);background:transparent;color:inherit;cursor:pointer;overflow:hidden}.filter-chip input[type='checkbox']{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer}.filter-chip span{pointer-events:none;transition:transform 0.2s ease}.filter-chip input[type='checkbox']:checked+span{transform:translateY(-1px);font-weight:600}.toggle{display:inline-flex;gap:0.75rem;align-items:center;font-size:0.95rem}.toggle input[type='checkbox']{width:1.15rem;height:1.15rem;accent-color:#fbbf24}.nusantarum-card-grid{display:grid;gap:1.25rem;grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.nusantarum-card{display:grid;gap:1.2rem;padding:1.6rem;border-radius:22px;background:rgba(15,23,42,0.68);border:1px solid rgba(255,255,255,0.16);transition:transform 0.2s ease,box-shadow 0.2s ease}.nusantarum-card:hover,.nusantarum-card:focus-within{transform:translateY(-4px);box-shadow:0 18px 50px rgba(15,23,42,0.5)}.nusantarum-card__header{display:flex;gap:1rem;align-items:center}.nusantarum-card__avatar{width:3rem;height:3rem;border-radius:50%;background:linear-gradient(135deg,rgba(251,191,36,0.9),rgba(236,72,153,0.9));display:inline-flex;align-items:center;justify-content:center;font-weight:600;color:#0f172a}.nusantarum-card__title{display:flex;flex-wrap:wrap;gap:0.5rem;font-size:1.2rem;font-weight:600}.nusantarum-card__badge{display:inline-flex;align-items:center;gap:0.3rem;padding:0.25rem 0.6rem;border-radius:999px;background:rgba(34,197,94,0.16);color:rgba(134,239,172,1);font-size:0.75rem;text-transform:uppercase;letter-spacing:0.12em}.nusantarum-card__meta{margin:0;font-size:0.9rem;color:rgba(255,255,255,0.7)}.nusantarum-card__description{margin:0;font-size:0.95rem;color:rgba(255,255,255,0.78)}.nusantarum-card__stats{display:flex;flex-wrap:wrap;gap:0.5rem;align-items:center}.nusantarum-stat-pill{display:inline-flex;align-items:center;gap:0.3rem;padding:0.35rem 0.8rem;border-radius:999px;background:rgba(255,255,255,0.12);font-size:0.85rem;color:rgba(255,255,255,0.85)}.nusantarum-card__footer{display:flex;justify-content:space-between;align-items:center;gap:1rem;flex-wrap:wrap}.nusantarum-link{color:#fbbf24;text-decoration:none;font-weight:600;transition:color 0.2s ease}.nusantarum-link:hover,.nusantarum-link:focus{color:#f59e0b;text-decoration:underline}.nusantarum-table-wrapper{overflow-x:auto;border-radius:20px;border:1px solid rgba(255,255,255,0.16);background:rgba(15,23,42,0.72)}.nusantarum-table{width:100%;border-collapse:collapse;min-width:640px}.nusantarum-table th,.nusantarum-table td{padding:1rem 1.25rem;border-bottom:1px solid rgba(255,255,255,0.08);text-align:left;vertical-align:top}.nusantarum-table thead th{font-size:0.85rem;text-transform:uppercase;letter-spacing:0.18em;color:rgba(255,255,255,0.65)}.nusantarum-table__sort{display:inline-flex;align-items:center;gap:0.35rem;padding:0;border:none;background:none;color:inherit;font:inherit;text-transform:inherit;letter-spacing:inherit;cursor:pointer}.nusantarum-table__sort:hover,.nusantarum-table__sort:focus-visible{color:rgba(255,255,255,0.9);outline:none}.nusantarum-table__sort-indicator{font-size:0.85rem;opacity:0.75}.nusantarum-table tbody tr:last-child th,.nusantarum-table tbody tr:last-child td{border-bottom:none}.nusantarum-table__description{margin:0.45rem 0 0;font-size:0.9rem;color:rgba(255,255,255,0.7)}.nusantarum-table__meta{font-size:0.85rem;color:rgba(255,255,255,0.6);margin:0.25rem 0 0}.nusantarum-aroma-group{display:flex;flex-wrap:wrap;gap:0.4rem}.nusantarum-badge{display:inline-flex;align-items:center;padding:0.3rem 0.7rem;border-radius:999px;background:rgba(251,191,36,0.18);color:rgba(255,255,255,0.85);font-size:0.8rem;letter-spacing:0.03em}.nusantarum-empty{padding:2.2rem;border-radius:20px;background:rgba(15,23,42,0.68);border:1px solid rgba(255,255,255,0.16);display:grid;gap:0.75rem;justify-items:center;text-align:center}.nusantarum-empty h3{font-size:1.3rem;margin:0}.nusantarum-empty__suggestions{list-style:disc;text-align:left;padding-left:1.25rem;display:grid;gap:0.35rem;font-size:0.95rem;color:rgba(255,255,255,0.75)}.nusantarum-pagination{display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap}.nusantarum-pagination__button{padding:0.6rem 1.3rem;border-radius:999px;border:1px solid rgba(255,255,255,0.25);background:rgba(15,23,42,0.65);color:inherit;cursor:pointer;transition:transform 0.2s ease,box-shadow 0.2s ease,border 0.2s ease}.nusantarum-pagination__button:hover,.nusantarum-pagination__button:focus-visible{border-color:rgba(251,191,36,0.7);transform:translateY(-2px);box-shadow:0 12px 24px rgba(251,191,36,0.25)}.nusantarum-pagination__button[disabled]{opacity:0.5;cursor:not-allowed;transform:none;box-shadow:none}.nusantarum-pagination__status{font-size:0.9rem;color:rgba(255,255,255,0.7)}.sync-status-list{display:grid;gap:0.5rem}.sync-status-item{display:flex;justify-content:space-between;gap:0.5rem;font-size:0.85rem;color:rgba(255,255,255,0.7)}@media (max-width:768px){.nusantarum-table{min-width:100%}.nusantarum-table th,.nusantarum-table td{padding-inline:1rem}.nusantarum-tabs{gap:0.5rem}.nusantarum-tab{width:100%;justify-content:center}}
\ No newline at end of file
diff --git a/src/app/web/static/css/profile.min.css b/src/app/web/static/css/profile.min.css
new file mode 100644
index 0000000..113ec8c
--- /dev/null
+++ b/src/app/web/static/css/profile.min.css
@@ -0,0 +1 @@
+.profile-page{display:flex;flex-direction:column;gap:2.5rem}.glass-panel{backdrop-filter:blur(24px) saturate(160%);background:linear-gradient(145deg,rgba(15,23,42,0.75),rgba(30,41,59,0.55));border:1px solid rgba(148,163,184,0.25);border-radius:var(--radius-lg);box-shadow:0 25px 45px rgba(8,15,29,0.45)}.profile-hero{display:grid;grid-template-columns:160px 1fr;gap:2rem;padding:2.5rem;align-items:center}.profile-hero__avatar{width:160px;height:160px;border-radius:50%;overflow:hidden;border:3px solid rgba(148,163,184,0.35);box-shadow:0 14px 28px rgba(8,15,29,0.4)}.profile-hero__avatar img{width:100%;height:100%;object-fit:cover}.profile-hero__content{display:flex;flex-direction:column;gap:1rem}.profile-hero__headline{display:flex;justify-content:space-between;gap:1rem;align-items:start}.profile-hero__headline h1{margin:0;font-size:clamp(2.1rem,2vw+1.2rem,2.6rem)}.profile-hero__username{margin:0.25rem 0 0;color:var(--muted);font-weight:500}.profile-hero__bio{margin:0;font-size:1.05rem;color:var(--text-secondary)}.profile-hero__meta{list-style:none;display:flex;flex-wrap:wrap;gap:0.75rem 1.5rem;padding:0;margin:0;color:var(--muted)}.profile-badges{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:0.75rem}.profile-badge{display:inline-flex;align-items:center;gap:0.65rem;padding:0.45rem 1rem;border-radius:999px;background:rgba(148,163,184,0.18);border:1px solid rgba(148,163,184,0.25)}.profile-badge__label{font-weight:600;letter-spacing:0.02em}.profile-badge__meta{font-size:0.9rem;color:var(--accent-secondary)}.profile-badge--perfumer{background:linear-gradient(135deg,rgba(192,38,211,0.25),rgba(14,116,144,0.15));border-color:rgba(192,38,211,0.35)}.profile-badge--brand-owner{background:linear-gradient(135deg,rgba(249,115,22,0.25),rgba(244,114,182,0.18));border-color:rgba(249,115,22,0.35)}.profile-follow{display:flex;align-items:center;gap:0.75rem}.profile-follow__button,.profile-follow__edit{display:inline-flex;align-items:center;justify-content:center;border-radius:999px;padding:0.65rem 1.8rem;font-weight:600;background:var(--accent-primary);color:#0f172a;border:none;cursor:pointer;text-decoration:none;transition:transform var(--transition-base),box-shadow var(--transition-base);box-shadow:0 16px 30px rgba(192,38,211,0.35)}.profile-follow__button:hover,.profile-follow__edit:hover{transform:translateY(-2px)}.profile-follow__button--muted{background:rgba(148,163,184,0.2);color:var(--text-primary);box-shadow:none;border:1px solid rgba(148,163,184,0.35)}.profile-follow__button--ghost{background:transparent;border:1px solid rgba(148,163,184,0.35);color:var(--text-secondary);box-shadow:none}.profile-follow__button--ghost:hover{color:var(--text-primary)}.profile-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:1rem;padding:1.5rem 2rem}.profile-stat{display:flex;flex-direction:column;gap:0.35rem;text-align:center}.profile-stat__label{color:var(--muted);font-size:0.95rem}.profile-stat__value{font-size:1.6rem;font-weight:600;color:var(--text-primary);background:none;border:none;cursor:pointer;padding:0.25rem;transition:color var(--transition-base),transform var(--transition-base)}.profile-stat__value:hover{color:var(--accent-secondary);transform:translateY(-2px)}.profile-tabs{padding:2rem;display:flex;flex-direction:column;gap:1.5rem}.profile-edit-page{display:flex;justify-content:center;padding:2rem 0 4rem}.profile-edit-page__shell{display:flex;flex-direction:column;gap:1.5rem;width:min(720px,100%)}.profile-edit-page__back{color:var(--accent-secondary);text-decoration:none;font-weight:600;display:inline-flex;align-items:center;gap:0.35rem}.profile-edit-page__back:focus,.profile-edit-page__back:hover{text-decoration:underline}.profile-edit{padding:2.25rem;display:flex;flex-direction:column;gap:1.75rem}.profile-edit__header{display:flex;gap:1.25rem;align-items:center}.profile-edit__avatar{width:80px;height:80px;border-radius:50%;overflow:hidden;border:2px solid rgba(148,163,184,0.35);flex-shrink:0}.profile-edit__avatar img{width:100%;height:100%;object-fit:cover}.profile-edit__intro h1{margin:0;font-size:1.6rem}.profile-edit__intro p{margin:0.35rem 0 0;color:var(--muted)}.profile-edit__feedback{padding:0.75rem 1rem;border-radius:var(--radius-md);font-weight:500}.profile-edit__feedback--success{background:rgba(34,197,94,0.12);color:rgb(134,239,172);border:1px solid rgba(34,197,94,0.35)}.profile-edit__feedback--info{background:rgba(148,163,184,0.12);color:rgba(226,232,240,0.9);border:1px solid rgba(148,163,184,0.3)}.profile-edit__form{display:flex;flex-direction:column;gap:1.25rem}.profile-edit__field{display:flex;flex-direction:column;gap:0.5rem}.profile-edit__field label{font-weight:600}.profile-edit__field input,.profile-edit__field textarea{background:rgba(15,23,42,0.35);border:1px solid rgba(148,163,184,0.25);border-radius:var(--radius-md);padding:0.75rem 1rem;color:var(--text-primary);font:inherit;transition:border-color var(--transition-base),box-shadow var(--transition-base)}.profile-edit__field input:focus,.profile-edit__field textarea:focus{border-color:var(--accent-secondary);box-shadow:0 0 0 3px rgba(192,38,211,0.25);outline:none}.profile-edit__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:1rem}.profile-edit__counter{color:var(--muted);display:block}.profile-edit__actions{display:flex;flex-wrap:wrap;gap:1rem;align-items:center}.profile-edit__submit{background:var(--accent-primary);color:#0f172a;border:none;border-radius:999px;padding:0.75rem 1.75rem;font-weight:600;cursor:pointer;transition:transform var(--transition-base),box-shadow var(--transition-base);box-shadow:0 16px 30px rgba(192,38,211,0.35)}.profile-edit__submit:hover{transform:translateY(-1px)}.profile-edit__submit:focus-visible{outline:3px solid rgba(192,38,211,0.6);outline-offset:2px}.profile-edit__cancel{color:var(--muted);text-decoration:none;font-weight:500}.profile-edit__cancel:focus,.profile-edit__cancel:hover{text-decoration:underline}@media (max-width:640px){.profile-edit{padding:1.75rem}.profile-edit__header{flex-direction:column;align-items:flex-start}.profile-edit__avatar{width:96px;height:96px}.profile-edit__actions{flex-direction:column;align-items:stretch}.profile-edit__cancel{text-align:center}}.profile-tabs__nav{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:0.75rem}.profile-tabs__button{padding:0.75rem 1rem;border-radius:var(--radius-sm);background:rgba(148,163,184,0.14);border:1px solid transparent;color:var(--text-secondary);font-weight:600;cursor:pointer;transition:background var(--transition-base),border var(--transition-base)}.profile-tabs__button--active,.profile-tabs__button:hover{background:rgba(56,189,248,0.18);border-color:rgba(56,189,248,0.35);color:var(--text-primary)}.profile-tabs__content{display:flex;flex-direction:column;gap:1.25rem}.profile-timeline{list-style:none;display:flex;flex-direction:column;gap:1rem;padding:0;margin:0}.profile-timeline__item{padding:1.5rem;border-radius:var(--radius-md);border:1px solid rgba(148,163,184,0.25)}.profile-timeline__title{margin:0;font-size:1.2rem}.profile-timeline__time{color:var(--muted);font-size:0.95rem}.profile-list{list-style:none;padding:1.25rem 1.5rem;margin:0;border-radius:var(--radius-md);border:1px solid rgba(148,163,184,0.25);display:flex;flex-direction:column;gap:0.85rem}.profile-list__item{color:var(--text-secondary)}.profile-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:1.25rem}.profile-card{padding:1.5rem;border-radius:var(--radius-md);border:1px solid rgba(148,163,184,0.25);display:flex;flex-direction:column;gap:0.75rem;transition:transform var(--transition-base),box-shadow var(--transition-base)}.profile-card:hover{transform:translateY(-4px);box-shadow:0 20px 40px rgba(8,15,29,0.45)}.profile-card__header{display:flex;justify-content:space-between;align-items:center;gap:0.75rem}.profile-card__title{margin:0}.profile-card__brand{color:var(--muted);font-weight:500}.profile-card__notes{margin:0;color:var(--text-secondary);font-weight:500}.profile-card__highlight{margin:0;color:var(--muted);font-size:0.95rem}.profile-card__cta{align-self:flex-start;padding:0.55rem 1.2rem;border-radius:999px;border:1px solid rgba(56,189,248,0.45);color:var(--accent-secondary);text-decoration:none;font-weight:600;transition:background var(--transition-base),color var(--transition-base)}.profile-card__cta:hover{background:rgba(56,189,248,0.15);color:var(--text-primary)}.profile-card__badge{padding:0.3rem 0.8rem;border-radius:999px;font-size:0.85rem;background:rgba(148,163,184,0.18);border:1px solid rgba(148,163,184,0.25);text-transform:capitalize}.profile-card__badge--active{background:rgba(56,189,248,0.2);border-color:rgba(56,189,248,0.45)}.profile-empty{padding:2rem;text-align:center;border-radius:var(--radius-md);border:1px dashed rgba(148,163,184,0.35);color:var(--text-secondary)}.profile-empty--subtle{padding:1rem 1.25rem;border-style:solid}.profile-modal{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;pointer-events:none}.profile-modal__overlay{position:fixed;inset:0;backdrop-filter:blur(6px);background:rgba(8,15,29,0.45);display:flex;align-items:center;justify-content:center;pointer-events:auto;padding:2rem}.profile-modal__content{width:min(420px,100%);padding:1.5rem;border-radius:var(--radius-md);display:flex;flex-direction:column;gap:1rem}.profile-modal__header{display:flex;justify-content:space-between;align-items:center}.profile-modal__header h2{margin:0}.profile-modal__close{background:transparent;border:none;color:var(--text-secondary);font-size:1.25rem;cursor:pointer}.profile-modal__list{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:0.85rem}.profile-modal__item{display:flex;align-items:center;gap:0.85rem}.profile-modal__avatar{width:40px;height:40px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;background:rgba(148,163,184,0.2);font-weight:600}.profile-modal__name{font-weight:600}.profile-modal__username{color:var(--muted);font-size:0.9rem}.profile-modal__empty{color:var(--text-secondary);text-align:center}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media (max-width:768px){.profile-hero{grid-template-columns:1fr;text-align:center}.profile-hero__headline{flex-direction:column;align-items:center}.profile-follow{justify-content:center}.profile-stats{grid-template-columns:repeat(2,minmax(120px,1fr));padding:1.25rem}.profile-tabs{padding:1.5rem}}
\ No newline at end of file
diff --git a/src/app/web/static/css/purchase-workflow.min.css b/src/app/web/static/css/purchase-workflow.min.css
new file mode 100644
index 0000000..b63118c
--- /dev/null
+++ b/src/app/web/static/css/purchase-workflow.min.css
@@ -0,0 +1 @@
+.purchase-hero{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,320px);gap:2rem;padding:2.5rem;align-items:start}.purchase-hero .hero-copy h1{font-size:clamp(2.2rem,3vw,2.8rem);margin-bottom:1rem}.purchase-hero .hero-copy p{margin:0}.purchase-hero .badge{display:inline-flex;align-items:center;gap:0.5rem;padding:0.35rem 1rem;border-radius:999px;background:rgba(56,189,248,0.12);color:var(--accent-secondary);font-weight:600;letter-spacing:0.02em;margin-bottom:1.5rem}.status-legend h2{margin-top:0;margin-bottom:1rem;font-size:1.35rem}.status-legend ul{list-style:none;padding:0;margin:0;display:grid;gap:1rem}.status-legend li{display:grid;grid-template-columns:auto 1fr;gap:0.75rem;align-items:start}.status-icon{display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;border-radius:999px;background:rgba(148,163,184,0.15);font-size:1.25rem}.status-label{margin:0;color:var(--text-primary);font-weight:600}.status-description{margin:0.35rem 0 0;font-size:0.95rem}.flow-nav{padding:1.75rem;display:grid;gap:1rem}.flow-nav h2{margin:0;font-size:1.4rem}.flow-nav ol{list-style:none;padding:0;margin:0;display:flex;gap:1rem;flex-wrap:wrap}.flow-nav a{color:var(--text-primary);text-decoration:none;font-weight:600;padding:0.5rem 1.25rem;border-radius:999px;border:1px solid rgba(148,163,184,0.35);background:rgba(15,23,42,0.45);transition:transform var(--transition-base),border-color var(--transition-base)}.flow-nav a:hover{transform:translateY(-2px);border-color:rgba(56,189,248,0.6)}.flow-section{padding:2.25rem;display:grid;gap:2rem}.flow-header{display:grid;grid-template-columns:minmax(0,1.2fr) minmax(0,0.8fr);gap:2.5rem;align-items:start}.flow-summary{color:var(--text-secondary);margin-bottom:0.75rem}.flow-persona{margin:0;color:var(--text-secondary)}.flow-meta{display:grid;gap:1.5rem;justify-items:start}.status-chip{display:inline-flex;align-items:center;gap:0.5rem;padding:0.5rem 1.2rem;border-radius:999px;font-weight:600;border:1px solid rgba(148,163,184,0.4);background:rgba(15,23,42,0.5)}.metric-list{background:rgba(15,23,42,0.45);border:1px solid rgba(148,163,184,0.25);border-radius:var(--radius-md);padding:1.25rem 1.5rem;box-shadow:inset 0 0 0 1px rgba(56,189,248,0.08)}.metric-list h3{margin-top:0;margin-bottom:0.75rem;font-size:1.1rem}.metric-list ul{margin:0;padding-left:1.1rem;display:grid;gap:0.5rem}.flow-steps{list-style:none;margin:0;padding:0;display:grid;gap:1.5rem}.flow-step{background:rgba(15,23,42,0.55);border-radius:var(--radius-md);border:1px solid rgba(148,163,184,0.25);padding:1.75rem;box-shadow:0 16px 45px rgba(8,15,29,0.35);backdrop-filter:blur(18px);transition:transform var(--transition-base),box-shadow var(--transition-base)}.flow-step:hover{transform:translateY(-4px);box-shadow:0 24px 55px rgba(8,15,29,0.45)}.step-header{display:grid;grid-template-columns:auto 1fr auto;gap:1.25rem;align-items:center;margin-bottom:1.25rem}.step-index{width:2.75rem;height:2.75rem;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;background:var(--accent-primary);color:#0f172a;font-weight:700;font-size:1.2rem;box-shadow:0 12px 30px rgba(249,115,22,0.25)}.step-stage{margin:0;text-transform:uppercase;letter-spacing:0.08em;font-size:0.85rem;color:var(--accent-secondary)}.step-header h3{margin:0.25rem 0 0;font-size:1.35rem}.step-status{display:inline-flex;align-items:center;gap:0.5rem;padding:0.35rem 0.9rem;border-radius:999px;font-weight:600;border:1px solid rgba(148,163,184,0.35);background:rgba(148,163,184,0.12)}.step-body{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1.5rem}.step-body h4{margin-top:0;font-size:1.05rem}.step-body ul{margin:0;padding-left:1.1rem;display:grid;gap:0.6rem}.foundation-notes{padding:2rem 2.25rem;display:grid;gap:1rem}.foundation-notes ul{margin:0;padding-left:1.2rem;display:grid;gap:0.5rem}.step-status.status-live,.status-chip.status-live,.status-icon.status-live{border-color:rgba(52,211,153,0.4);background:rgba(52,211,153,0.18)}.step-status.status-ready,.status-chip.status-ready,.status-icon.status-ready{border-color:rgba(56,189,248,0.45);background:rgba(56,189,248,0.16)}.step-status.status-in-design,.status-chip.status-in-design,.status-icon.status-in-design{border-color:rgba(192,132,252,0.4);background:rgba(192,132,252,0.16)}.step-status.status-in-discovery,.status-chip.status-in-discovery,.status-icon.status-in-discovery{border-color:rgba(248,180,0,0.4);background:rgba(248,180,0,0.2)}@media (max-width:1024px){.purchase-hero{grid-template-columns:minmax(0,1fr)}.status-legend{order:2}.flow-header{grid-template-columns:1fr}.flow-meta{justify-items:stretch}.step-body{grid-template-columns:1fr}}@media (max-width:640px){.purchase-hero,.flow-section,.foundation-notes{padding:1.75rem}.flow-nav ol{flex-direction:column}.step-header{grid-template-columns:1fr;justify-items:start}.step-status{margin-top:0.75rem}}
\ No newline at end of file
diff --git a/src/app/web/static/css/ui-ux-tracker.min.css b/src/app/web/static/css/ui-ux-tracker.min.css
new file mode 100644
index 0000000..a550ef0
--- /dev/null
+++ b/src/app/web/static/css/ui-ux-tracker.min.css
@@ -0,0 +1 @@
+.top-anchor{position:relative;top:-120px}.tracker-hero{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:2rem;padding:2.5rem;align-items:start}.tracker-hero .badge{display:inline-flex;align-items:center;gap:0.5rem;padding:0.35rem 1rem;border-radius:999px;background:rgba(148,163,184,0.18);color:var(--text-secondary);font-size:0.9rem;letter-spacing:0.02em;text-transform:uppercase}.tracker-hero h1{margin-top:1.2rem;margin-bottom:1rem;font-size:clamp(1.8rem,4vw,2.6rem)}.tracker-hero p{margin:0.75rem 0;max-width:36ch}.tracker-hero .hero-subcopy{color:var(--text-primary);font-weight:500}.status-legend{padding:1.8rem;display:flex;flex-direction:column;gap:1rem}.status-legend h2{margin:0;font-size:1.15rem}.status-legend ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:0.75rem}.status-legend li{display:flex;align-items:center;gap:0.65rem;font-weight:500}.status-icon{display:inline-flex;align-items:center;justify-content:center;width:1.8rem;height:1.8rem;border-radius:0.75rem;background:rgba(148,163,184,0.12);font-size:1rem}.status-todo{color:var(--muted)}.status-progress{color:var(--accent-secondary)}.status-done{color:var(--success)}.section-nav{display:grid;gap:1rem;padding:1.8rem 2rem}.section-nav h2{margin:0;font-size:1.25rem}.section-nav ol{margin:0;padding-left:1.2rem;display:grid;gap:0.6rem}.section-nav a{color:var(--text-secondary);text-decoration:none;position:relative}.section-nav a::after{content:"";position:absolute;left:0;bottom:-0.2rem;width:100%;height:2px;background:var(--accent-primary);transform:scaleX(0);transform-origin:left;transition:transform var(--transition-base)}.section-nav a:hover::after,.section-nav a:focus-visible::after{transform:scaleX(1)}.tracker-section{padding:2.25rem 2.4rem;display:flex;flex-direction:column;gap:1.75rem}.section-header{display:flex;align-items:start;justify-content:space-between;gap:1.5rem}.section-eyebrow{text-transform:uppercase;letter-spacing:0.12em;font-size:0.8rem;color:var(--muted);margin:0}.section-header h2{margin:0.25rem 0 0;font-size:clamp(1.5rem,3vw,2.1rem)}.section-top-link{text-decoration:none;color:var(--text-secondary);font-size:1.4rem;transition:color var(--transition-base),transform var(--transition-base)}.section-top-link:hover,.section-top-link:focus-visible{color:var(--accent-secondary);transform:translateY(-2px)}.task-grid{display:grid;gap:1.4rem;grid-template-columns:repeat(auto-fit,minmax(240px,1fr))}.task-card{display:flex;flex-direction:column;gap:1rem;padding:1.6rem;border-radius:var(--radius-md);background:rgba(15,23,42,0.72);border:1px solid rgba(148,163,184,0.25);box-shadow:0 20px 45px rgba(8,15,29,0.35);transition:transform var(--transition-base),box-shadow var(--transition-base)}.task-card:hover{transform:translateY(-4px);box-shadow:0 28px 60px rgba(8,15,29,0.4)}.task-card header{display:flex;align-items:center;gap:0.9rem}.task-card h3,.task-card h4{margin:0;font-size:1.2rem}.task-card p{margin:0;color:var(--text-secondary)}.task-card footer{display:flex;flex-direction:column;gap:0.3rem;margin-top:auto;font-size:0.9rem}.task-card .label{text-transform:uppercase;letter-spacing:0.08em;color:var(--muted);font-weight:600}.task-card .deliverable{word-break:break-word;color:var(--text-primary)}.task-group{display:flex;flex-direction:column;gap:1.25rem;padding:1.6rem 1.8rem;border-radius:var(--radius-md);background:rgba(15,23,42,0.55);border:1px solid rgba(148,163,184,0.2)}.task-group h3{margin:0;font-size:1.3rem}.grouped-section{display:grid;gap:1.6rem}.tracker-note{padding:2rem 2.3rem;display:grid;gap:0.75rem}.tracker-note h2{margin:0}@media (max-width:720px){.tracker-hero{padding:2rem}.section-header{flex-direction:column;align-items:flex-start}.section-top-link{align-self:flex-end}.task-group{padding:1.4rem}}
\ No newline at end of file
diff --git a/src/app/web/static/js/dashboard-brand-owner.min.js b/src/app/web/static/js/dashboard-brand-owner.min.js
new file mode 100644
index 0000000..c047b1c
--- /dev/null
+++ b/src/app/web/static/js/dashboard-brand-owner.min.js
@@ -0,0 +1 @@
+( function (){ function normalise(value){ return (value||"").toString().toLowerCase().normalize("NFD").replace(/\p{Diacritic}/gu,"");} function activateTabGroup(buttons,targetKey,{buttonDatasetKey,panels,panelDatasetKey,shouldFocus=true}={}){ let activeButton=null;buttons.forEach((button)=>{ const key=buttonDatasetKey?button.dataset[buttonDatasetKey]:undefined; const isActive=key===targetKey;button.classList.toggle("is-active",isActive);button.setAttribute("aria-selected",String(isActive));button.setAttribute("tabindex",isActive?"0":"-1"); if (isActive){activeButton=button;}}); if (panels&&panelDatasetKey){panels.forEach((panel)=>{ const panelKey=panel.dataset[panelDatasetKey]; const isMatch=panelKey===targetKey;panel.classList.toggle("is-hidden",!isMatch); if (isMatch){panel.removeAttribute("hidden");panel.setAttribute("aria-hidden","false");} else {panel.setAttribute("hidden","hidden");panel.setAttribute("aria-hidden","true");}});} if (activeButton&&shouldFocus){activeButton.focus();} return activeButton;} function bindProductFilters(){ const buttons=Array.from(document.querySelectorAll("[data-product-filter]")); const rows=document.querySelectorAll("[data-product-row]"); const searchInput=document.querySelector("[data-product-search]"); if (!buttons.length) return ; let activeFilter=buttons.find((button)=>button.classList.contains("is-active"))?.dataset.productFilter||"semua";activateTabGroup(buttons,activeFilter,{buttonDatasetKey:"productFilter",shouldFocus:false,}); function apply(){ const query=normalise(searchInput?searchInput.value.trim():"");rows.forEach((row)=>{ const status=row.dataset.status||""; const name=normalise(row.dataset.name||""); const sku=normalise(row.dataset.sku||""); const matchesFilter=activeFilter==="semua"||status===activeFilter; const matchesQuery=!query||name.includes(query)||sku.includes(query); const shouldShow=matchesFilter&&matchesQuery;row.hidden=!shouldShow;});}buttons.forEach((button,index)=>{button.addEventListener("click",()=>{ const target=button.dataset.productFilter; if (!target) return ;activeFilter=target;activateTabGroup(buttons,target,{buttonDatasetKey:"productFilter"});apply();});button.addEventListener("keydown",(event)=>{ const {key}=event; const isNext=key==="ArrowRight"||key==="ArrowDown"; const isPrev=key==="ArrowLeft"||key==="ArrowUp"; if (!isNext&&!isPrev) return ;event.preventDefault(); const offset=isNext?1:-1; const nextIndex=(index+offset+buttons.length)%buttons.length; const nextButton=buttons[nextIndex]; const target=nextButton?.dataset.productFilter; if (!target) return ;activeFilter=target;activateTabGroup(buttons,target,{buttonDatasetKey:"productFilter"});apply();});}); if (searchInput){["input","change"].forEach((eventName)=>{searchInput.addEventListener(eventName,apply);});}} function bindOrderFilters(){ const buttons=Array.from(document.querySelectorAll("[data-order-filter]")); const rows=document.querySelectorAll("[data-order-row]"); const searchInput=document.querySelector("[data-order-search]"); if (!buttons.length) return ; let activeFilter=buttons.find((button)=>button.classList.contains("is-active"))?.dataset.orderFilter||"semua";activateTabGroup(buttons,activeFilter,{buttonDatasetKey:"orderFilter",shouldFocus:false,}); function apply(){ const query=normalise(searchInput?searchInput.value.trim():"");rows.forEach((row)=>{ const status=normalise(row.dataset.status||""); const invoice=normalise(row.dataset.invoice||""); const customer=normalise(row.dataset.customer||""); const matchesFilter=activeFilter==="semua"||status===normalise(activeFilter); const matchesQuery=!query||invoice.includes(query)||customer.includes(query); const shouldShow=matchesFilter&&matchesQuery;row.hidden=!shouldShow;});}buttons.forEach((button,index)=>{button.addEventListener("click",()=>{ const target=button.dataset.orderFilter; if (!target) return ;activeFilter=target;activateTabGroup(buttons,target,{buttonDatasetKey:"orderFilter"});apply();});button.addEventListener("keydown",(event)=>{ const {key}=event; const isNext=key==="ArrowRight"||key==="ArrowDown"; const isPrev=key==="ArrowLeft"||key==="ArrowUp"; if (!isNext&&!isPrev) return ;event.preventDefault(); const offset=isNext?1:-1; const nextIndex=(index+offset+buttons.length)%buttons.length; const nextButton=buttons[nextIndex]; const target=nextButton?.dataset.orderFilter; if (!target) return ;activeFilter=target;activateTabGroup(buttons,target,{buttonDatasetKey:"orderFilter"});apply();});}); if (searchInput){["input","change"].forEach((eventName)=>{searchInput.addEventListener(eventName,apply);});}} function renderChart(chartEl){ const pointsAttr=chartEl.dataset.chartPoints; if (!pointsAttr) return ; const points=pointsAttr .split(",").map((value)=>Number.parseFloat(value.trim())).filter((value)=>Number.isFinite(value)); if (points.length<2) return ; const labelsAttr=chartEl.dataset.chartLabels||""; const labels=labelsAttr.split(",").map((label)=>label.trim()); const maxValue=Math.max(...points); const minValue=Math.min(...points); const range=maxValue-minValue||1; const svgWidth=100; const svgHeight=40; const verticalPadding=6; const usableHeight=svgHeight-verticalPadding*2; const stepX=svgWidth/(points.length-1); const line=chartEl.querySelector("[data-chart-line]"); const area=chartEl.querySelector("[data-chart-area]"); if (!line||!area) return ; const coordinates=points.map((value,index)=>{ const normalised=(value-minValue)/range; const y=svgHeight-verticalPadding-normalised*usableHeight; const x=index*stepX; return [x,y];}); const polylinePoints=coordinates.map(([x,y])=>`${x},${y}`).join(" ");line.setAttribute("points",polylinePoints); const areaPath=[`M0 ${svgHeight}`,`L${coordinates[0][0]}${coordinates[0][1]}`,...coordinates.slice(1).map(([x,y])=>`L${x}${y}`),`L${coordinates[coordinates.length-1][0]}${svgHeight}`,"Z",].join(" ");area.setAttribute("d",areaPath); if (labels.length===points.length){ const existingLabels=chartEl.querySelectorAll(".chart-label");existingLabels.forEach((label)=>label.remove());labels.forEach((label,index)=>{ const marker=document.createElement("span");marker.className="chart-label";marker.textContent=label;marker.style.left=`${(index/(labels.length-1||1))*100}%`;chartEl.appendChild(marker);});}} function initialiseAnalytics(){ const buttons=Array.from(document.querySelectorAll("[data-analytics-range]")); const panels=Array.from(document.querySelectorAll("[data-analytics-panel]")); if (!buttons.length) return ; let activeRange=buttons.find((button)=>button.classList.contains("is-active"))?.dataset.analyticsRange||buttons[0]?.dataset.analyticsRange;activateTabGroup(buttons,activeRange,{buttonDatasetKey:"analyticsRange",panels,panelDatasetKey:"analyticsPanel",shouldFocus:false,});buttons.forEach((button,index)=>{button.addEventListener("click",()=>{ const target=button.dataset.analyticsRange; if (!target) return ;activeRange=target;activateTabGroup(buttons,target,{buttonDatasetKey:"analyticsRange",panels,panelDatasetKey:"analyticsPanel",});});button.addEventListener("keydown",(event)=>{ const {key}=event; const isNext=key==="ArrowRight"||key==="ArrowDown"; const isPrev=key==="ArrowLeft"||key==="ArrowUp"; if (!isNext&&!isPrev) return ;event.preventDefault(); const offset=isNext?1:-1; const nextIndex=(index+offset+buttons.length)%buttons.length; const nextButton=buttons[nextIndex]; const target=nextButton?.dataset.analyticsRange; if (!target) return ;activeRange=target;activateTabGroup(buttons,target,{buttonDatasetKey:"analyticsRange",panels,panelDatasetKey:"analyticsPanel",});});});document.querySelectorAll("[data-chart]").forEach((chartEl)=>{renderChart(chartEl);});} function bindNotificationActions(){ const list=document.querySelector("[data-notification-list]"); if (!list) return ; const emptyState=document.querySelector("[data-notification-empty]");list.addEventListener("click",(event)=>{ const target=event.target; if (!(target instanceof HTMLElement)) return ; if (!target.matches("[data-dismiss-notification]")) return ; const item=target.closest(".notification-item"); if (!item) return ;item.remove(); if (!list.children.length&&emptyState){emptyState.hidden=false;}});}document.addEventListener("DOMContentLoaded",()=>{bindProductFilters();bindOrderFilters();initialiseAnalytics();bindNotificationActions();});})();
\ No newline at end of file
diff --git a/src/app/web/static/js/home-tabs.min.js b/src/app/web/static/js/home-tabs.min.js
new file mode 100644
index 0000000..a11e063
--- /dev/null
+++ b/src/app/web/static/js/home-tabs.min.js
@@ -0,0 +1 @@
+( function (){ const tabLists=document.querySelectorAll('[role="tablist"]'); if (!tabLists.length){ return ;} const activateTab=(tabs,panels,tab,{focus=true}={})=>{ const panelId=tab.getAttribute('aria-controls'); const nextPanel=panelId?document.getElementById(panelId):null;tabs.forEach((candidate)=>{ const isSelected=candidate===tab;candidate.setAttribute('aria-selected',String(isSelected));candidate.tabIndex=isSelected?0:-1;candidate.classList.toggle('is-active',isSelected);});panels.forEach((panel)=>{ if (!panel){ return ;} const shouldShow=panel===nextPanel; if (shouldShow){panel.removeAttribute('hidden');} else {panel.setAttribute('hidden','');}}); if (focus){tab.focus();}};tabLists.forEach((tabList)=>{ const tabs=Array.from(tabList.querySelectorAll('[role="tab"]')); const panels=tabs.map((tab)=>{ const panelId=tab.getAttribute('aria-controls'); return panelId?document.getElementById(panelId):null;}); if (!tabs.length){ return ;} const initiallySelected=tabs.find((tab)=>tab.getAttribute('aria-selected')==='true')||tabs[0];activateTab(tabs,panels,initiallySelected,{focus:false});tabList.addEventListener('click',(event)=>{ const target=event.target.closest('[role="tab"]'); if (!target||!tabList.contains(target)){ return ;}event.preventDefault();activateTab(tabs,panels,target);});tabList.addEventListener('keydown',(event)=>{ const {key}=event; const currentIndex=tabs.indexOf(document.activeElement); let nextIndex=null; if (key==='ArrowRight'||key==='ArrowDown'){nextIndex=(currentIndex+1)%tabs.length;} else if (key==='ArrowLeft'||key==='ArrowUp'){nextIndex=(currentIndex-1+tabs.length)%tabs.length;} else if (key==='Home'){nextIndex=0;} else if (key==='End'){nextIndex=tabs.length-1;} if (nextIndex===null){ return ;}event.preventDefault(); const nextTab=tabs[nextIndex];activateTab(tabs,panels,nextTab);});});})();
\ No newline at end of file
diff --git a/src/app/web/static/js/moderation-dashboard.min.js b/src/app/web/static/js/moderation-dashboard.min.js
new file mode 100644
index 0000000..74c1a0f
--- /dev/null
+++ b/src/app/web/static/js/moderation-dashboard.min.js
@@ -0,0 +1 @@
+( function (){ function copyToClipboard(text){ if (!text) return Promise.resolve(false); if (navigator.clipboard&&typeof navigator.clipboard.writeText===" function "){ return navigator.clipboard .writeText(text).then( function (){ return true;}, function (){ return legacyCopy(text);});} return Promise.resolve(legacyCopy(text));} function legacyCopy(text){ var textarea=document.createElement("textarea");textarea.value=text;textarea.setAttribute("readonly","readonly");textarea.style.position="fixed";textarea.style.top="-1000px";document.body.appendChild(textarea);textarea.select(); var succeeded=false;try{succeeded=document.execCommand("copy");}catch(err){succeeded=false;}document.body.removeChild(textarea); return succeeded;} function toggleState(element,attribute,state){ if (!element) return ;element.setAttribute(attribute,String(Boolean(state))); if (state){element.classList.add("is-active");} else {element.classList.remove("is-active");}} function activateTab(trigger,options){ if (!trigger) return ; var opts=options||{}; var container=trigger.closest("[data-tab-group]"); if (!container) return ; var tabs=container.querySelectorAll('[data-action="jump-section"]');Array.prototype.forEach.call(tabs, function (tab){tab.classList.remove("is-active");});trigger.classList.add("is-active"); if (!opts.silent){ensureTabVisible(container,trigger);}requestFrame( function (){updateTabIndicator(container,trigger);});} function scrollToTarget(targetSelector){ if (!targetSelector) return false; var target=document.querySelector(targetSelector); if (!target) return false; if (typeof target.scrollIntoView===" function "){target.scrollIntoView({behavior:"smooth",block:"start"}); return true;} return false;} function handleAction(trigger,action,event){switch(action){case "share-report":{ var shareUrl=trigger.dataset.shareUrl||window.location.href;copyToClipboard(shareUrl).then( function (success){ var message=success?trigger.dataset.feedbackSuccess||"Tautan laporan disalin":trigger.dataset.feedbackError||"Tidak dapat menyalin tautan";trigger.setAttribute("data-feedback",message);trigger.classList.add("has-feedback");window.setTimeout( function (){trigger.classList.remove("has-feedback");trigger.removeAttribute("data-feedback");},2000);});break;}case "refresh-snapshot":{window.location.reload();break;}case "focus-mode":{ var focusTarget=trigger.dataset.focusTarget; if (focusTarget){window.location.href=focusTarget; return ;}document.body.classList.toggle("is-focus-mode");toggleState(trigger,"aria-pressed",document.body.classList.contains("is-focus-mode"));break;}case "bulk-action":{ var targetSelector=trigger.dataset.bulkTarget; var bulkContainer=targetSelector?document.querySelector(targetSelector):null; var isActive=trigger.getAttribute("aria-pressed")==="true";isActive=!isActive;toggleState(trigger,"aria-pressed",isActive); if (bulkContainer){bulkContainer.classList.toggle("is-bulk-select",isActive);}break;}case "invite-resend":{ var email=trigger.dataset.inviteEmail||"pengguna";dispatchToast("Undangan dikirim ulang ke "+email+".");break;}case "invite-cancel":{ var cancelEmail=trigger.dataset.inviteEmail||"pengguna";dispatchToast("Undangan untuk "+cancelEmail+" dibatalkan.");break;}case "invite-open":{dispatchToast("Panel undangan dibuka.");break;}case "jump-section":{ var targetSelector=trigger.dataset.target||trigger.getAttribute("href"); var scrolled=scrollToTarget(targetSelector);activateTab(trigger); if (scrolled&&event&&typeof event.preventDefault===" function "){event.preventDefault();} return scrolled;}case "scroll-top":{ if (event&&typeof event.preventDefault===" function "){event.preventDefault();} if (typeof window.scrollTo===" function "){window.scrollTo({top:0,behavior:"smooth"});} else {window.scrollTo(0,0);} return true;}case "view-sop":case "add-moderator":default:{break;}}} function dispatchToast(message){ if (!message) return ; var event;try{event=new CustomEvent("mod:toast",{detail:{message:message}});}catch(error){event=document.createEvent("CustomEvent");event.initCustomEvent("mod:toast",false,false,{message:message});}document.dispatchEvent(event);} function bindActions(){document.addEventListener("click", function (event){ var target=event.target; if (!(target instanceof Element)){ return ;} var trigger=target.closest("[data-action]"); if (!trigger){ return ;} var action=trigger.dataset.action; if (!action){ return ;} var handled=handleAction(trigger,action,event); if (handled===true&&typeof event.preventDefault===" function "){event.preventDefault();}});}document.addEventListener("DOMContentLoaded", function (){bindActions();setupTabGroups();updateAllTabIndicators();}); if (typeof window!=="undefined"){window.addEventListener("resize", function (){updateAllTabIndicators();});window.addEventListener("orientationchange", function (){updateAllTabIndicators();});} function ensureTabVisible(container,tab){ if (!container||!tab) return ; var scroller=container.querySelector(".tab-scroller"); if (!scroller){ return ;} var left=tab.offsetLeft; var right=left+tab.offsetWidth; var viewStart=scroller.scrollLeft; var viewEnd=viewStart+scroller.clientWidth; var targetLeft=null; if (leftviewEnd){targetLeft=right-scroller.clientWidth;} if (targetLeft===null){ return ;} if (typeof scroller.scrollTo===" function "){scroller.scrollTo({left:targetLeft,behavior:"smooth"});} else {scroller.scrollLeft=targetLeft;}} function requestFrame(callback){ if (typeof window!=="undefined"&&typeof window.requestAnimationFrame===" function "){window.requestAnimationFrame(callback); return ;}callback();} function updateTabIndicator(container,activeTab){ if (!container||!activeTab) return ; var indicator=container.querySelector(".tab-indicator"); if (!indicator) return ; var scroller=container.querySelector(".tab-scroller")||container; var activeRect=activeTab.getBoundingClientRect(); var scrollerRect=scroller.getBoundingClientRect(); var scrollLeft=typeof scroller.scrollLeft==="number"?scroller.scrollLeft:0; var offset=activeRect.left-scrollerRect.left+scrollLeft;indicator.style.transform="translateX("+offset+"px)";indicator.style.width=activeRect.width+"px";indicator.classList.add("is-visible");} function updateAllTabIndicators(){ var groups=document.querySelectorAll("[data-tab-group]"); if (!groups.length){ return ;}requestFrame( function (){Array.prototype.forEach.call(groups, function (group){ var active=group.querySelector(".tab-link.is-active"); if (active){updateTabIndicator(group,active);}});});} function setupTabGroups(){ var groups=document.querySelectorAll("[data-tab-group]"); if (!groups.length){ return ;}Array.prototype.forEach.call(groups, function (group){ var tabs=group.querySelectorAll('[data-action="jump-section"]'); if (!tabs.length){ return ;} var initialActive=group.querySelector(".tab-link.is-active")||tabs[0]; if (initialActive){activateTab(initialActive,{silent:true});} if (typeof IntersectionObserver!==" function "){ return ;} var tabSections=[];Array.prototype.forEach.call(tabs, function (tab){ var targetSelector=tab.dataset.target||tab.getAttribute("href"); if (!targetSelector){ return ;} var section=document.querySelector(targetSelector); if (!section){ return ;}tabSections.push({tab:tab,section:section});}); if (!tabSections.length){ return ;} var observer=new IntersectionObserver( function (entries){ var candidate=null; for ( var i=0;i{ const navbars=Array.from(document.querySelectorAll(".navbar")); const configs=[]; const mobileQuery=window.matchMedia("(max-width:1024px)");navbars.forEach((nav)=>{ const toggle=nav.querySelector(".navbar-toggle"); const collapsible=nav.querySelector(".navbar-collapsible"); if (!toggle||!collapsible){ return ;} const setOpenState=(isOpen)=>{nav.dataset.open=isOpen?"true":"false";toggle.setAttribute("aria-expanded",isOpen?"true":"false");toggle.setAttribute("aria-label",isOpen?"Tutup navigasi":"Buka navigasi"); if (mobileQuery.matches){collapsible.setAttribute("aria-hidden",isOpen?"false":"true");} else {collapsible.setAttribute("aria-hidden","false");} if (isOpen){nav.classList.add("navbar--open");} else {nav.classList.remove("navbar--open");}};setOpenState(false); const handleBreakpointChange=()=>{ const isOpen=nav.dataset.open==="true";setOpenState(isOpen);}; if (typeof mobileQuery.addEventListener===" function "){mobileQuery.addEventListener("change",handleBreakpointChange);} else if (typeof mobileQuery.addListener===" function "){mobileQuery.addListener(handleBreakpointChange);} const toggleOpen=()=>{ const isOpen=nav.dataset.open==="true";setOpenState(!isOpen);}; const close=()=>setOpenState(false);toggle.addEventListener("click",(event)=>{event.preventDefault();toggleOpen();});collapsible.addEventListener("click",(event)=>{ const interactive=event.target.closest("a,button"); if (!interactive||interactive===toggle){ return ;}close();});configs.push({toggle,close,nav});}); if (configs.length===0){ return ;}document.addEventListener("keydown",(event)=>{ if (event.key!=="Escape"){ return ;}configs.forEach(({nav,toggle,close})=>{ if (nav.dataset.open==="true"){close();toggle.focus();}});});});
\ No newline at end of file
diff --git a/src/app/web/static/js/newsletter.js b/src/app/web/static/js/newsletter.js
new file mode 100644
index 0000000..3a0e594
--- /dev/null
+++ b/src/app/web/static/js/newsletter.js
@@ -0,0 +1,57 @@
+(function () {
+ document.addEventListener("DOMContentLoaded", () => {
+ const form = document.querySelector(".newsletter-form");
+ if (!form) {
+ return;
+ }
+
+ const statusRegion = form.querySelector("#newsletter-status");
+ const submitButton = form.querySelector("button[type='submit']");
+
+ const setStatus = (message, tone) => {
+ if (!statusRegion) {
+ return;
+ }
+ statusRegion.textContent = message;
+ statusRegion.dataset.tone = tone;
+ };
+
+ form.addEventListener("submit", async (event) => {
+ event.preventDefault();
+ event.stopPropagation();
+
+ if (!submitButton) {
+ return;
+ }
+
+ const formData = new FormData(form);
+ submitButton.disabled = true;
+ setStatus("Mengirim...", "pending");
+
+ try {
+ const response = await fetch(form.action, {
+ method: "POST",
+ headers: {
+ Accept: "application/json",
+ },
+ body: formData,
+ });
+
+ const payload = await response.json().catch(() => null);
+
+ if (response.ok) {
+ const successMessage = payload?.message ?? "Terima kasih! Email kamu sudah terdaftar.";
+ setStatus(successMessage, "success");
+ form.reset();
+ } else {
+ const errorMessage = payload?.message ?? "Alamat email tidak valid. Coba lagi.";
+ setStatus(errorMessage, "error");
+ }
+ } catch (error) {
+ setStatus("Terjadi kendala jaringan. Silakan coba lagi.", "error");
+ } finally {
+ submitButton.disabled = false;
+ }
+ });
+ });
+})();
diff --git a/src/app/web/static/js/newsletter.min.js b/src/app/web/static/js/newsletter.min.js
new file mode 100644
index 0000000..3e9d1db
--- /dev/null
+++ b/src/app/web/static/js/newsletter.min.js
@@ -0,0 +1 @@
+( function (){document.addEventListener("DOMContentLoaded",()=>{ const form=document.querySelector(".newsletter-form"); if (!form){ return ;} const statusRegion=form.querySelector("#newsletter-status"); const submitButton=form.querySelector("button[type='submit']"); const setStatus=(message,tone)=>{ if (!statusRegion){ return ;}statusRegion.textContent=message;statusRegion.dataset.tone=tone;};form.addEventListener("submit",async(event)=>{event.preventDefault();event.stopPropagation(); if (!submitButton){ return ;} const formData=new FormData(form);submitButton.disabled=true;setStatus("Mengirim...","pending");try{ const response=await fetch(form.action,{method:"POST",headers:{Accept:"application/json",},body:formData,}); const payload=await response.json().catch(()=>null); if (response.ok){ const successMessage=payload?.message??"Terima kasih!Email kamu sudah terdaftar.";setStatus(successMessage,"success");form.reset();} else { const errorMessage=payload?.message??"Alamat email tidak valid. Coba lagi.";setStatus(errorMessage,"error");}}catch(error){setStatus("Terjadi kendala jaringan. Silakan coba lagi.","error");}finally{submitButton.disabled=false;}});});})();
\ No newline at end of file
diff --git a/src/app/web/static/js/nusantarum-tabs.min.js b/src/app/web/static/js/nusantarum-tabs.min.js
new file mode 100644
index 0000000..5e9b362
--- /dev/null
+++ b/src/app/web/static/js/nusantarum-tabs.min.js
@@ -0,0 +1 @@
+( function (){ function setupTabs(){ const tablist=document.querySelector('.nusantarum-tabs'); const tabPanel=document.getElementById('nusantarum-tab-content'); if (!tablist){ return ;} const tabs=Array.from(tablist.querySelectorAll('[role="tab"]')); if (!tabs.length){ return ;} function updateTabState(selectedTab,{shouldFocus=true}={}){ if (!selectedTab){ return ;}tabs.forEach((tab)=>{ const isActive=tab===selectedTab;tab.setAttribute('aria-selected',isActive?'true':'false');tab.setAttribute('tabindex',isActive?'0':'-1');tab.classList.toggle('is-active',isActive); if (isActive&&shouldFocus){tab.focus();}}); if (tabPanel){tabPanel.setAttribute('aria-busy','true');}}tabs.forEach((tab)=>{ const isActive=tab.getAttribute('aria-selected')==='true';tab.setAttribute('tabindex',isActive?'0':'-1');tab.classList.toggle('is-active',isActive); if (tab.dataset.nusantarumTabsBound==='true'){ return ;}tab.dataset.nusantarumTabsBound='true';tab.addEventListener('click',(event)=>{updateTabState(event.currentTarget);});tab.addEventListener('keydown',(event)=>{ const currentIndex=tabs.indexOf(event.currentTarget); if (currentIndex<0){ return ;} let nextTab=null;switch(event.key){case 'ArrowRight':case 'ArrowDown':nextTab=tabs[(currentIndex+1)%tabs.length];break;case 'ArrowLeft':case 'ArrowUp':nextTab=tabs[(currentIndex-1+tabs.length)%tabs.length];break;case 'Home':nextTab=tabs[0];break;case 'End':nextTab=tabs[tabs.length-1];break;default: return ;} if (nextTab){event.preventDefault();nextTab.focus();nextTab.click();}});});} function handleBeforeRequest(event){ const tabPanel=document.getElementById('nusantarum-tab-content'); if (!tabPanel){ return ;} const requestElement=event.detail?event.detail.elt:event.target; if (!requestElement){ return ;} const hxTarget=requestElement.getAttribute('hx-target'); if (hxTarget==='#nusantarum-tab-content'){tabPanel.setAttribute('aria-busy','true');}} function handleAfterSwap(event){ const tabPanel=document.getElementById('nusantarum-tab-content'); if (!tabPanel){ return ;} const swapTarget=event.detail?event.detail.target:null; if (event.target===tabPanel||swapTarget===tabPanel){tabPanel.setAttribute('aria-busy','false');setupTabs();}}document.addEventListener('htmx:beforeRequest',handleBeforeRequest);document.addEventListener('htmx:afterSwap',handleAfterSwap); if (document.readyState==='loading'){document.addEventListener('DOMContentLoaded',setupTabs);} else {setupTabs();}})();
\ No newline at end of file
diff --git a/src/app/web/static/js/session.min.js b/src/app/web/static/js/session.min.js
new file mode 100644
index 0000000..01a8f8d
--- /dev/null
+++ b/src/app/web/static/js/session.min.js
@@ -0,0 +1 @@
+( function (){ function handleLogout(event){ const trigger=event.target.closest('[data-action="logout"]'); if (!trigger){ return ;}event.preventDefault(); if (trigger.dataset.loading==='true'){ return ;}trigger.dataset.loading='true';trigger.classList.add('is-loading');fetch('/api/auth/logout',{method:'POST'}).catch(()=>{}).finally(()=>{ const redirect=trigger.dataset.redirect; if (redirect){window.location.href=redirect;} else {window.location.reload();}});}document.addEventListener('click',handleLogout);})();
\ No newline at end of file
diff --git a/src/app/web/templates/__init__.py b/src/app/web/templates/__init__.py
index 1700ef3..b8df4ce 100644
--- a/src/app/web/templates/__init__.py
+++ b/src/app/web/templates/__init__.py
@@ -15,5 +15,6 @@
template_engine.env.globals.update(
app_name=settings.app_name,
static_asset_version=settings.static_asset_version,
- static_asset_query=f"v={settings.static_asset_version}",
+ static_asset_query=settings.static_asset_version,
+ use_minified=getattr(settings, 'use_minified_assets', False),
)
diff --git a/src/app/web/templates/auth.html b/src/app/web/templates/auth.html
index e67fcad..68aa58b 100644
--- a/src/app/web/templates/auth.html
+++ b/src/app/web/templates/auth.html
@@ -1,7 +1,7 @@
{% extends 'base.html' %}
{% block head_extra %}
-
+
{% endblock %}
{% block content %}
diff --git a/src/app/web/templates/base.html b/src/app/web/templates/base.html
index 01baee4..8bb496a 100644
--- a/src/app/web/templates/base.html
+++ b/src/app/web/templates/base.html
@@ -4,16 +4,36 @@
{{ title or app_name }} – Sensasiwangi.id
+
+
+
+
+
+
+
-
-
- {% block head_extra %}{% endblock %}
-
+
+
+
+
+
+ {% block head_extra %}{% endblock %}
+
+
+
+
@@ -25,8 +45,8 @@
{% include 'partials/footer.html' %}
{% block body_scripts %}
-
-
+
+
{% endblock %}