recipe-manager/public/index.html

1225 lines
67 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ForkFolio – Curated Recipe Manager</title>
<!-- Google Fonts Outfit & Inter -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=Outfit:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<!-- Lucide Icons -->
<script src="https://unpkg.com/lucide@latest"></script>
<!-- Custom Styling -->
<link rel="stylesheet" href="style.css">
</head>
<body class="dark-theme">
<!-- Top Navigation -->
<header class="app-header">
<div class="header-logo" style="cursor: pointer;" id="header-logo">
<div class="logo-icon"><i data-lucide="cooking-pot"></i></div>
<span class="logo-text">Fork<span>Folio</span></span>
</div>
<div class="header-actions">
<!-- Desktop Actions -->
<div class="user-badge-container" id="user-badge-container" style="display: none;">
<span class="user-display"><i data-lucide="user"></i> <span id="user-display-name">@chef</span></span>
<button class="btn btn-icon-round" id="btn-settings" title="Application Settings"><i data-lucide="settings"></i></button>
<button class="btn btn-icon-round" id="btn-logout" title="Log Out"><i data-lucide="log-out"></i></button>
</div>
<button class="btn btn-outline" id="tab-user-admin" style="display: none;" title="User Admin Management Console">
<i data-lucide="shield"></i> <span>User Admin</span>
</button>
<button class="btn btn-outline" id="btn-manual-add" title="Create Recipe Manually">
<i data-lucide="plus"></i> <span>Manual Recipe</span>
</button>
<button class="theme-toggle" id="theme-toggle" title="Toggle Theme">
<i data-lucide="sun" class="sun-icon"></i>
<i data-lucide="moon" class="moon-icon"></i>
</button>
<!-- Mobile Consolidated Header Group -->
<div class="mobile-header-group" id="mobile-header-group" style="display: none;">
<button class="mobile-header-tab active" id="mobile-header-tab-cookbook" title="My Cookbook">
<i data-lucide="book-open"></i>
</button>
<button class="mobile-header-tab" id="mobile-header-tab-community" title="Shared Cookbook">
<i data-lucide="globe"></i>
</button>
<button class="mobile-header-tab" id="mobile-header-tab-shopping" title="Shopping Lists" style="position: relative;">
<i data-lucide="shopping-cart"></i>
<span class="shopping-badge-mobile" id="mobile-shopping-tab-badge" style="display: none;">0</span>
</button>
<button class="mobile-header-btn-add" id="mobile-header-btn-add" title="Add Recipe">
<i data-lucide="plus"></i>
</button>
<button class="mobile-header-tab" id="mobile-header-btn-profile" title="Chef Profile">
<i data-lucide="user"></i>
</button>
</div>
</div>
</header>
<!-- Main Workspace -->
<main class="app-container">
<!-- Hero / URL Input Bar -->
<section class="scraping-hero">
<div class="hero-content">
<h1>Save Recipes from Anywhere Instantly</h1>
<p>Paste any cooking link below. Our engine will extract ingredients, directions, times, and images directly into your personal digital cookbook.</p>
</div>
<form class="url-input-form" id="url-scrape-form">
<div class="input-wrapper">
<i data-lucide="link" class="input-icon"></i>
<input type="url" id="scrape-url-input" placeholder="Paste recipe link, Instagram, Facebook Reel, or TikTok here..." autocomplete="off">
</div>
<div class="hero-buttons-group">
<button type="submit" class="btn btn-primary" id="btn-scrape-submit">
<i data-lucide="wand-2"></i> <span>Extract Recipe</span>
</button>
<button type="button" class="btn btn-outline" id="btn-social-import" title="Import from Instagram, Facebook, TikTok, or Social Caption">
<i data-lucide="instagram"></i> <span>Social Import</span>
</button>
<input type="file" id="scan-image-input" accept="image/*" style="display: none;">
<button type="button" class="btn btn-accent" id="btn-scan-image" title="Scan Recipe from Photo">
<i data-lucide="camera"></i> <span>Scan Photo</span>
</button>
</div>
</form>
</section>
<!-- Recipe Library Dashboard -->
<section class="library-section">
<div class="library-header">
<div class="dashboard-tabs">
<button class="dashboard-tab-btn active" id="tab-my-cookbook">
<i data-lucide="book-open"></i> <span>My Cookbook</span>
</button>
<button class="dashboard-tab-btn" id="tab-community-vault">
<i data-lucide="globe"></i> <span>Shared Cookbook</span>
</button>
<button class="dashboard-tab-btn" id="tab-shopping-lists">
<i data-lucide="shopping-cart"></i> <span>Shopping Lists</span>
<span class="shopping-badge" id="shopping-tab-badge" style="display: none;">0</span>
</button>
</div>
<!-- Search and Filters -->
<div class="filter-controls">
<div class="search-wrapper">
<i data-lucide="search" class="search-icon"></i>
<input type="text" id="library-search" placeholder="Search recipes...">
</div>
</div>
</div>
<!-- Dynamic Mobile Section Title -->
<h2 class="library-view-title" id="library-view-title" style="display: none;">My Cookbook</h2>
<!-- Recipes Grid -->
<div class="recipes-grid" id="recipes-grid">
<!-- Recipe cards will be loaded here dynamically -->
</div>
<!-- Empty State -->
<div class="empty-state" id="empty-state">
<div class="empty-icon"><i data-lucide="folder-open"></i></div>
<h3>Your cookbook is empty</h3>
<p>Insert a cooking web link above or create one manually to build your digital recipe collections.</p>
</div>
<!-- Shopping Lists Workspace Panel -->
<div id="shopping-lists-panel" style="display: none;" class="shopping-panel-container">
<!-- Top Selector & List Management Bar -->
<div class="shopping-header-bar">
<div class="shopping-list-selector-group">
<label for="shopping-list-select" class="shopping-select-label">
<i data-lucide="clipboard-list"></i> <span>Active List:</span>
</label>
<select id="shopping-list-select" class="shopping-select"></select>
<button type="button" class="btn btn-outline btn-sm" id="btn-shopping-new-list" title="Create New List">
<i data-lucide="plus"></i> <span>New List</span>
</button>
<button type="button" class="btn btn-outline btn-sm" id="btn-shopping-rename-list" title="Rename Active List">
<i data-lucide="edit-2"></i> <span>Rename</span>
</button>
<button type="button" class="btn btn-outline btn-sm btn-danger-text" id="btn-shopping-delete-list" title="Delete Active List">
<i data-lucide="trash-2"></i>
</button>
</div>
<div class="shopping-share-group">
<span id="shopping-share-stats-badge" class="shopping-stats-pill" style="display: none;">
<i data-lucide="eye"></i> <span class="val">0 Visitors</span>
</span>
<button type="button" class="btn btn-outline btn-sm" id="btn-shopping-share" title="Share Shopping List Link">
<i data-lucide="share-2"></i> <span>Share Link</span>
</button>
<button type="button" class="btn btn-outline btn-sm btn-danger-text" id="btn-shopping-revoke-share" style="display: none;" title="Disable Public Share Link">
<i data-lucide="link-2-off"></i> <span>Revoke Link</span>
</button>
<button type="button" class="btn btn-outline btn-sm" id="btn-shopping-copy-text" title="Copy Formatted List to Clipboard">
<i data-lucide="copy"></i> <span>Copy Text</span>
</button>
</div>
</div>
<!-- Quick-Add Manual Item & View Controls -->
<div class="shopping-controls-row">
<form id="shopping-add-item-form" class="shopping-add-form">
<div class="input-wrapper">
<i data-lucide="plus-circle" class="input-icon"></i>
<input type="text" id="shopping-add-item-input" placeholder="Add an item (e.g., 2 lbs ground beef, Whole milk, Paper towels)..." autocomplete="off">
</div>
<button type="submit" class="btn btn-primary">
<i data-lucide="plus"></i> <span>Add Item</span>
</button>
</form>
<div class="shopping-view-toggles">
<label class="shopping-consolidate-toggle" title="Combine duplicate ingredients and sum compatible quantities across recipes">
<input type="checkbox" id="toggle-consolidate-items" checked>
<span class="toggle-track"><span class="toggle-thumb"></span></span>
<span class="toggle-label">Consolidate Ingredients</span>
</label>
<select id="shopping-group-by" class="shopping-select shopping-select-sm" title="Group Items By">
<option value="aisle">Group by Aisle</option>
<option value="recipe">Group by Recipe</option>
</select>
<button type="button" class="btn btn-outline btn-sm" id="btn-shopping-clear-checked" title="Remove Checked Items">
<i data-lucide="check-check"></i> <span>Clear Checked</span>
</button>
<button type="button" class="btn btn-outline btn-sm btn-danger-text" id="btn-shopping-clear-all" title="Clear Entire List">
<i data-lucide="eraser"></i> <span>Clear All</span>
</button>
</div>
</div>
<!-- Grouped Checklist Cards -->
<div id="shopping-lists-content" class="shopping-aisles-grid"></div>
<!-- Empty State for Shopping List -->
<div class="empty-state" id="shopping-empty-state" style="display: none;">
<div class="empty-icon"><i data-lucide="shopping-basket"></i></div>
<h3>This shopping list is empty</h3>
<p>Type an item above or click "Add to Shopping List" inside any recipe to populate your groceries.</p>
</div>
</div>
<!-- User Admin Management Console -->
<div id="user-admin-panel" style="display: none;" class="admin-panel-container">
<!-- Admin Console Sub-Tabs -->
<div class="admin-tabs" style="display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 24px; border-bottom: 1px solid var(--border-color); padding-bottom: 12px;">
<button class="btn btn-primary" id="btn-admin-tab-users" style="padding: 8px 16px; border-radius: 6px; font-size: 0.9rem; display: flex; align-items: center; gap: 6px;">
<i data-lucide="users" style="width: 16px; height: 16px;"></i> <span>Chef Accounts</span>
</button>
<button class="btn btn-outline" id="btn-admin-tab-shares" style="padding: 8px 16px; border-radius: 6px; font-size: 0.9rem; display: flex; align-items: center; gap: 6px;">
<i data-lucide="globe" style="width: 16px; height: 16px;"></i> <span>Public Shared Links</span>
</button>
<button class="btn btn-outline" id="btn-admin-tab-backups" style="padding: 8px 16px; border-radius: 6px; font-size: 0.9rem; display: flex; align-items: center; gap: 6px;">
<i data-lucide="hard-drive" style="width: 16px; height: 16px;"></i> <span>Database Backups</span>
</button>
</div>
<!-- Section 1: Chef Accounts Management -->
<div id="admin-users-section">
<div class="admin-panel-header" style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px;">
<div>
<h3 style="font-size: 1.4rem; color: var(--text-main); margin-bottom: 4px;">Chef Profiles Management</h3>
<p style="font-size: 0.85rem; color: var(--text-muted);">Create new user profiles and delete accounts with custom recipe preservation options.</p>
</div>
<button class="btn btn-primary" id="btn-admin-add-user">
<i data-lucide="user-plus"></i> <span>Create Chef Account</span>
</button>
</div>
<div class="table-responsive">
<table class="admin-users-table">
<thead>
<tr>
<th>Username</th>
<th>Account Type</th>
<th>Created Date</th>
<th style="text-align: right;">Actions</th>
</tr>
</thead>
<tbody id="admin-users-list">
<!-- Dynamic list loaded via JS -->
</tbody>
</table>
</div>
</div>
<!-- Section 2: Shared Recipes & Visitor Statistics -->
<div id="admin-shares-section" style="display: none;">
<div class="admin-panel-header" style="margin-bottom: 24px;">
<h3 style="font-size: 1.4rem; color: var(--text-main); margin-bottom: 4px;">Public Shared Links</h3>
<p style="font-size: 0.85rem; color: var(--text-muted);">Monitor publicly active recipe shares, track dynamic visitor analytics, and manage access overrides.</p>
</div>
<div class="table-responsive">
<table class="admin-users-table">
<thead>
<tr>
<th>Recipe Title</th>
<th>Shared By</th>
<th>Shared Date</th>
<th>Unique Visitors</th>
<th style="text-align: right;">Actions</th>
</tr>
</thead>
<tbody id="admin-shares-list">
<!-- Dynamic list loaded via JS -->
</tbody>
</table>
</div>
</div>
<!-- Section 3: Cloud & Manual Database Backups -->
<div id="admin-backups-section" style="display: none;">
<div class="admin-panel-header backup-top-header">
<div>
<h3 style="font-size: 1.4rem; color: var(--text-main); margin-bottom: 4px;">Database Backup & Recovery Console</h3>
<p style="font-size: 0.85rem; color: var(--text-muted);">
Back up users, recipes, embedded dish photos, and shopping lists to Wasabi S3, Google Drive, or directly to your local computer. No backup files are retained on the server disk.
</p>
</div>
<div class="backup-quick-actions">
<button type="button" class="btn btn-primary" id="btn-backup-run-cloud" title="Run immediate cloud backup to enabled providers">
<i data-lucide="cloud-upload"></i> <span>Backup to Cloud Now</span>
</button>
<button type="button" class="btn btn-outline" id="btn-backup-restore-cloud-modal" style="border-color: rgba(16, 185, 129, 0.45); color: #10b981;" title="Browse and restore backups directly from Google Drive or Wasabi S3">
<i data-lucide="cloud-download"></i> <span>Restore from Cloud</span>
</button>
<button type="button" class="btn btn-outline" id="btn-backup-download-db" title="Download SQLite .db snapshot to your computer">
<i data-lucide="download"></i> <span>Download .DB</span>
</button>
<button type="button" class="btn btn-outline" id="btn-backup-download-json" title="Download full JSON archive with embedded images to your computer">
<i data-lucide="file-json"></i> <span>Download .JSON</span>
</button>
<input type="file" id="backup-restore-file-input" accept=".db,.sqlite,.json" style="display: none;">
<button type="button" class="btn btn-outline" id="btn-backup-restore-local" title="Restore database from a .db or .json file on your computer">
<i data-lucide="upload"></i> <span>Restore from File</span>
</button>
</div>
</div>
<div id="backup-status-banner" class="backup-status-alert" style="display: none;"></div>
<form id="admin-backup-config-form" class="backup-config-grid">
<!-- Card 1: Automated Schedule & Archive Options -->
<div class="backup-config-card">
<div class="backup-card-header">
<div class="backup-card-title">
<i data-lucide="calendar-clock"></i>
<h4>Automated Schedule & Format</h4>
</div>
<span id="backup-last-run-badge" class="shopping-stats-pill" style="display: none;">Never run</span>
</div>
<div class="form-group">
<label for="backup-schedule-frequency">Cloud Backup Schedule</label>
<select id="backup-schedule-frequency" class="shopping-select" style="width: 100%;">
<option value="off">Manual Backups Only (Schedule Off)</option>
<option value="6h">Every 6 Hours</option>
<option value="12h">Every 12 Hours</option>
<option value="daily">Daily</option>
<option value="weekly">Weekly</option>
</select>
</div>
<div class="form-grid-2" id="backup-time-row">
<div class="form-group">
<label for="backup-schedule-time">Time of Day (24h)</label>
<input type="time" id="backup-schedule-time" value="02:00" class="shopping-select" style="width: 100%;">
</div>
<div class="form-group" id="backup-day-group">
<label for="backup-schedule-day">Day of Week (Weekly)</label>
<select id="backup-schedule-day" class="shopping-select" style="width: 100%;">
<option value="0">Sunday</option>
<option value="1">Monday</option>
<option value="2">Tuesday</option>
<option value="3">Wednesday</option>
<option value="4">Thursday</option>
<option value="5">Friday</option>
<option value="6">Saturday</option>
</select>
</div>
</div>
<div class="form-grid-2">
<div class="form-group">
<label for="backup-retention-count">Cloud Retention (Keep Last N)</label>
<select id="backup-retention-count" class="shopping-select" style="width: 100%;">
<option value="7">Keep Last 7 Backups</option>
<option value="14" selected>Keep Last 14 Backups</option>
<option value="30">Keep Last 30 Backups</option>
<option value="60">Keep Last 60 Backups</option>
<option value="0">Unlimited</option>
</select>
</div>
<div class="form-group">
<label for="backup-format">Cloud Backup Format</label>
<select id="backup-format" class="shopping-select" style="width: 100%;">
<option value="both">Both (.DB Snapshot + .JSON Archive)</option>
<option value="db">SQLite .DB Snapshot Only</option>
<option value="json">JSON Archive Only</option>
</select>
</div>
</div>
<div class="form-group" style="margin-top: 8px;">
<label class="checkbox-container" style="display: flex; align-items: center; gap: 8px; cursor: pointer;">
<input type="checkbox" id="backup-embed-images" checked style="cursor: pointer;">
<span class="checkbox-label" style="font-size: 0.88rem; color: var(--text-main);">
Fetch & embed external recipe images into JSON backup archives
</span>
</label>
</div>
</div>
<!-- Card 2: Wasabi / S3 Connection -->
<div class="backup-config-card">
<div class="backup-card-header">
<div class="backup-card-title">
<i data-lucide="database"></i>
<h4>Wasabi / S3 Connection</h4>
</div>
<label class="shopping-consolidate-toggle">
<input type="checkbox" id="backup-s3-enabled">
<span class="toggle-track"><span class="toggle-thumb"></span></span>
<span class="toggle-label">Enable S3</span>
</label>
</div>
<div class="form-grid-2">
<div class="form-group">
<label for="backup-s3-endpoint">S3 Endpoint URL</label>
<input type="text" id="backup-s3-endpoint" placeholder="https://s3.us-east-1.wasabisys.com">
</div>
<div class="form-group">
<label for="backup-s3-region">Region</label>
<input type="text" id="backup-s3-region" placeholder="us-east-1">
</div>
</div>
<div class="form-grid-2">
<div class="form-group">
<label for="backup-s3-bucket">Bucket Name</label>
<input type="text" id="backup-s3-bucket" placeholder="my-forkfolio-backups">
</div>
<div class="form-group">
<label for="backup-s3-prefix">Folder Prefix</label>
<input type="text" id="backup-s3-prefix" placeholder="forkfolio-backups/">
</div>
</div>
<div class="form-grid-2">
<div class="form-group">
<label for="backup-s3-access-key">Access Key ID</label>
<input type="text" id="backup-s3-access-key" placeholder="Wasabi Access Key" autocomplete="off">
</div>
<div class="form-group">
<label for="backup-s3-secret-key">Secret Access Key</label>
<input type="password" id="backup-s3-secret-key" placeholder="Wasabi Secret Key" autocomplete="off">
</div>
</div>
<div style="display: flex; justify-content: flex-end; margin-top: 6px;">
<button type="button" class="btn btn-outline btn-sm" id="btn-backup-test-s3">
<i data-lucide="plug-zap"></i> <span>Test S3 Connection</span>
</button>
</div>
</div>
<!-- Card 3: Google Drive Connection -->
<div class="backup-config-card">
<div class="backup-card-header">
<div class="backup-card-title">
<i data-lucide="cloud"></i>
<h4>Google Drive Connection</h4>
</div>
<label class="shopping-consolidate-toggle">
<input type="checkbox" id="backup-gdrive-enabled">
<span class="toggle-track"><span class="toggle-thumb"></span></span>
<span class="toggle-label">Enable Drive</span>
</label>
</div>
<!-- Step 1: One-Click Google Account Connection -->
<div id="gdrive-connection-box" style="background: var(--bg-main); border: 1px solid var(--border); border-radius: 10px; padding: 14px 16px; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 12px;">
<div style="display: flex; align-items: center; gap: 10px;">
<div id="gdrive-status-dot" style="width: 10px; height: 10px; border-radius: 50%; background: var(--text-muted); flex-shrink: 0;"></div>
<div>
<div id="gdrive-status-title" style="font-weight: 600; font-size: 0.92rem; color: var(--text-main);">Not Connected to Google Drive</div>
<div id="gdrive-status-subtitle" style="font-size: 0.8rem; color: var(--text-muted);">Click Authorize with Google to link your account in one click.</div>
</div>
</div>
<div style="display: flex; align-items: center; gap: 8px;">
<button type="button" class="btn btn-primary btn-sm" id="btn-backup-authorize-gdrive">
<i data-lucide="log-in"></i> <span id="btn-authorize-gdrive-label">Authorize with Google</span>
</button>
<button type="button" class="btn btn-outline btn-sm hidden" id="btn-backup-disconnect-gdrive" title="Disconnect Google Drive Account">
<i data-lucide="unlink"></i> <span>Disconnect</span>
</button>
</div>
</div>
<!-- Step 2: Select Where Backups Should Go -->
<div id="gdrive-folder-picker-section" style="margin-top: 6px;">
<div class="form-group" style="margin-bottom: 8px;">
<label for="backup-gdrive-folder-select">Select Backup Destination Folder in Google Drive</label>
<div style="display: flex; gap: 8px; align-items: center; flex-wrap: wrap;">
<select id="backup-gdrive-folder-select" style="flex: 1; min-width: 200px;" disabled>
<option value="">Authorize with Google first to select a folder...</option>
</select>
<button type="button" class="btn btn-outline btn-sm" id="btn-gdrive-new-folder" disabled title="Create a new folder in Google Drive">
<i data-lucide="folder-plus"></i> <span>New Folder</span>
</button>
<button type="button" class="btn btn-outline btn-sm" id="btn-gdrive-refresh-folders" disabled title="Refresh folder list from Google Drive">
<i data-lucide="refresh-cw"></i>
</button>
</div>
<small class="form-hint" id="gdrive-folder-hint">Once connected, choose any folder in your Google Drive and it saves automatically.</small>
</div>
</div>
<div id="gdrive-inline-status" class="hidden" style="font-size: 0.84rem; padding: 8px 12px; border-radius: 8px; margin-top: 4px;"></div>
<div style="display: flex; justify-content: flex-end; align-items: center; gap: 8px; margin-top: 6px;">
<button type="button" class="btn btn-outline btn-sm" id="btn-backup-test-gdrive">
<i data-lucide="plug-zap"></i> <span>Test Drive Connection</span>
</button>
</div>
</div>
<div class="backup-save-bar">
<button type="submit" class="btn btn-primary" id="btn-backup-save-config">
<i data-lucide="save"></i> <span>Save Backup Configuration & Schedule</span>
</button>
</div>
</form>
<!-- Cloud Backup History Table -->
<div style="margin-top: 32px;">
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 12px; margin-bottom: 12px;">
<div>
<h4 style="font-size: 1.15rem; color: var(--text-main); margin-bottom: 2px;">Cloud Backup History & Recovery</h4>
<p style="font-size: 0.8rem; color: var(--text-muted); margin: 0;">Restore your database directly from any Google Drive or Wasabi S3 backup below, or stream a copy to your computer.</p>
</div>
<button type="button" class="btn btn-outline btn-sm" id="btn-sync-cloud-backups" title="Scan Google Drive and Wasabi S3 for existing backup files">
<i data-lucide="refresh-cw"></i> <span>Sync from Cloud</span>
</button>
</div>
<div class="table-responsive">
<table class="admin-users-table">
<thead>
<tr>
<th>Backup Date</th>
<th>Trigger</th>
<th>Contents</th>
<th>Size</th>
<th>Cloud Destinations</th>
<th>Status</th>
<th style="text-align: right;">Actions</th>
</tr>
</thead>
<tbody id="admin-backups-history-list">
<!-- Populated via JS -->
</tbody>
</table>
</div>
</div>
</div>
</div>
</section>
</main>
<!-- RESTORE FROM CLOUD MODAL -->
<div class="modal-overlay" id="restore-cloud-modal">
<div class="modal-box max-width-lg">
<div class="modal-header">
<h3 style="display: flex; align-items: center; gap: 8px;">
<i data-lucide="cloud-download" style="color: #10b981;"></i>
<span>Restore Database from Cloud Storage</span>
</h3>
<button class="close-btn" onclick="closeModal('restore-cloud-modal')"><i data-lucide="x"></i></button>
</div>
<div class="modal-body">
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 12px; margin-bottom: 16px;">
<div style="display: flex; gap: 8px; align-items: center; flex-wrap: wrap;">
<label for="cloud-restore-provider-filter" style="font-size: 0.85rem; color: var(--text-muted); font-weight: 600;">Cloud Source:</label>
<select id="cloud-restore-provider-filter" class="shopping-select" style="min-width: 190px;">
<option value="all">All Connected Clouds (Drive & S3)</option>
<option value="gdrive">Google Drive Only</option>
<option value="s3">Wasabi S3 Only</option>
</select>
</div>
<button type="button" class="btn btn-outline btn-sm" id="btn-refresh-cloud-modal">
<i data-lucide="refresh-cw"></i> <span>Scan Cloud Now</span>
</button>
</div>
<div id="cloud-restore-modal-status" class="hidden" style="font-size: 0.85rem; padding: 10px 14px; border-radius: 8px; margin-bottom: 14px;"></div>
<div id="cloud-restore-files-container" style="max-height: 420px; overflow-y: auto; display: flex; flex-direction: column; gap: 10px;">
<!-- Populated dynamically with discovered Google Drive / Wasabi S3 backups -->
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline" onclick="closeModal('restore-cloud-modal')">Close</button>
</div>
</div>
</div>
<!-- RESTORE SCOPE MODAL (ALL USERS VS SINGLE USER) -->
<div class="modal-overlay" id="restore-scope-modal">
<div class="modal-box" style="max-width: 540px;">
<div class="modal-header">
<h3 style="display: flex; align-items: center; gap: 8px;">
<i data-lucide="rotate-ccw" style="color: var(--accent);"></i>
<span>Choose What to Restore</span>
</h3>
<button class="close-btn" onclick="closeModal('restore-scope-modal')"><i data-lucide="x"></i></button>
</div>
<div class="modal-body" style="display: flex; flex-direction: column; gap: 14px;">
<div id="restore-scope-backup-summary" style="background: var(--bg-main); border: 1px solid var(--border); border-radius: 10px; padding: 12px 14px; font-size: 0.88rem; color: var(--text-muted);">
Inspecting backup contents...
</div>
<div style="display: flex; flex-direction: column; gap: 10px;">
<label id="restore-scope-card-all" style="display: flex; align-items: flex-start; gap: 12px; background: var(--bg-main); border: 1px solid var(--accent); border-radius: 10px; padding: 14px; cursor: pointer;">
<input type="radio" name="restore-scope-mode" id="restore-scope-all" value="all" checked style="margin-top: 4px; cursor: pointer;">
<div>
<div style="font-weight: 600; color: var(--text-main); font-size: 0.95rem;">Restore Entire Database (All Users)</div>
<div id="restore-scope-all-desc" style="font-size: 0.82rem; color: var(--text-muted); margin-top: 2px;">
Replaces all users, recipes, images, and shopping lists with this backup.
</div>
</div>
</label>
<label id="restore-scope-card-single" style="display: flex; align-items: flex-start; gap: 12px; background: var(--bg-main); border: 1px solid var(--border); border-radius: 10px; padding: 14px; cursor: pointer;">
<input type="radio" name="restore-scope-mode" id="restore-scope-single" value="single" style="margin-top: 4px; cursor: pointer;">
<div style="flex: 1;">
<div style="font-weight: 600; color: var(--text-main); font-size: 0.95rem;">Restore a Single User's Data Only</div>
<div style="font-size: 0.82rem; color: var(--text-muted); margin-top: 2px; margin-bottom: 10px;">
Restores only the selected user's account, recipes, images, and shopping lists. All other users remain untouched.
</div>
<select id="restore-target-user-select" class="shopping-select" style="width: 100%;" disabled>
<option value="">Loading users from backup...</option>
</select>
</div>
</label>
</div>
<div id="restore-scope-status" class="hidden" style="font-size: 0.85rem; padding: 10px 12px; border-radius: 8px;"></div>
</div>
<div class="modal-footer" style="display: flex; justify-content: flex-end; gap: 10px;">
<button type="button" class="btn btn-outline" onclick="closeModal('restore-scope-modal')">Cancel</button>
<button type="button" class="btn btn-primary" id="btn-confirm-scoped-restore">
<i data-lucide="rotate-ccw"></i> <span>Restore Selected Data</span>
</button>
</div>
</div>
</div>
<!-- SOCIAL POST CAPTION EXTRACTOR MODAL (INSTAGRAM, FACEBOOK & TIKTOK) -->
<div class="modal-overlay" id="social-caption-modal">
<div class="modal-box max-width-md">
<div class="modal-header">
<h3 style="display: flex; align-items: center; gap: 8px;">
<i data-lucide="instagram" id="social-modal-icon" style="color: #e1306c;"></i>
<span id="social-modal-title">Instagram Recipe Import</span>
</h3>
<button class="close-btn" onclick="closeModal('social-caption-modal')"><i data-lucide="x"></i></button>
</div>
<div class="modal-body">
<p class="form-help" id="social-modal-hint" style="margin-bottom: 14px; font-size: 0.9rem; line-height: 1.4;">
Instagram restricts automated scraping of post captions. Simply copy the caption text from the Reel or post and paste it below—ForkFolio will parse the recipe and format the ingredients automatically!
</p>
<div id="social-post-preview" style="display: none; align-items: center; gap: 12px; margin-bottom: 14px; padding: 10px; background: rgba(0,0,0,0.04); border-radius: 8px; border: 1px solid var(--border-color, rgba(255,255,255,0.1));">
<img id="social-post-cover" src="" alt="Post cover" style="width: 54px; height: 54px; object-fit: cover; border-radius: 6px; display: none;">
<div style="overflow: hidden;">
<div id="social-post-author" style="font-weight: 600; font-size: 0.95rem;"></div>
<div id="social-post-url-display" style="font-size: 0.8rem; color: var(--text-muted); word-break: break-all;"></div>
</div>
</div>
<form id="social-caption-form">
<input type="hidden" id="social-input-url">
<input type="hidden" id="social-input-author">
<input type="hidden" id="social-input-cover">
<div class="form-group" style="margin-bottom: 14px;">
<label for="social-caption-text" style="display: flex; justify-content: space-between; font-weight: 600;">
<span>Post Caption / Recipe Text *</span>
</label>
<textarea id="social-caption-text" rows="8" placeholder="Paste the post caption here...&#10;&#10;e.g.&#10;Creamy Garlic Tuscan Chicken&#10;Ingredients:&#10;2 chicken breasts&#10;1 cup heavy cream&#10;1 cup spinach&#10;Directions: 1. Heat pan..." required style="width: 100%; font-family: inherit; font-size: 0.9rem;"></textarea>
</div>
</form>
</div>
<div class="modal-footer" style="display: flex; justify-content: flex-end; gap: 10px;">
<button type="button" class="btn btn-outline" onclick="closeModal('social-caption-modal')">Cancel</button>
<button type="submit" form="social-caption-form" class="btn btn-primary" id="btn-social-extract">
<i data-lucide="wand-2"></i> <span>Extract Recipe</span>
</button>
</div>
</div>
</div>
<!-- SCRAPE PREVIEW & EDIT DIALOG -->
<div class="modal-overlay" id="save-modal">
<div class="modal-box max-width-lg">
<div class="modal-header">
<h3 id="modal-action-title">Scraped Recipe Draft</h3>
<button class="close-btn" onclick="closeModal('save-modal')"><i data-lucide="x"></i></button>
</div>
<div class="modal-body">
<form id="recipe-edit-form">
<input type="hidden" id="edit-recipe-id">
<div class="form-grid-2">
<div class="form-group">
<label for="edit-title">Recipe Title *</label>
<input type="text" id="edit-title" required placeholder="e.g. Garlic Butter Roast Salmon">
</div>
<div class="form-group">
<label for="edit-source">Source URL</label>
<input type="url" id="edit-source" placeholder="Origin link">
</div>
</div>
<div class="form-group">
<label for="edit-description">Description / Short Review</label>
<textarea id="edit-description" rows="2" placeholder="Brief note about the dish..."></textarea>
</div>
<div class="form-grid-3">
<div class="form-group">
<label for="edit-servings">Servings</label>
<input type="text" id="edit-servings" placeholder="e.g., 4">
</div>
<div class="form-group">
<label for="edit-prep-time">Prep Time</label>
<input type="text" id="edit-prep-time" placeholder="e.g., 15 mins">
</div>
<div class="form-group">
<label for="edit-cook-time">Cook Time</label>
<input type="text" id="edit-cook-time" placeholder="e.g., 30 mins">
</div>
</div>
<!-- Image Chooser -->
<div class="form-group">
<label>Cover Image</label>
<p class="form-help">Select one of the images extracted from the site, or paste a custom URL below.</p>
<div class="image-gallery-selector" id="image-selection-grid">
<!-- Dynamically loaded thumbnail options -->
</div>
<div class="input-wrapper custom-img-url-wrapper">
<input type="url" id="edit-image-url" placeholder="Or enter a direct custom image URL...">
</div>
</div>
<!-- Share Option -->
<div class="form-group share-toggle-group">
<label class="checkbox-container">
<input type="checkbox" id="edit-is-public" checked>
<span class="checkbox-label"><i data-lucide="globe" style="width: 14px; height: 14px; display: inline-block; vertical-align: middle; margin-right: 4px;"></i> Share with ForkFolio Community (Public)</span>
</label>
<p class="form-help text-sm opacity-80" style="margin-top: 4px; font-size: 0.8rem; color: var(--text-muted);">If enabled, this recipe will be shared to the global Shared Cookbook feed for everyone to view and clone.</p>
</div>
<!-- AI Polish Suggestion Banner -->
<div class="ai-polish-banner" id="ai-polish-banner" style="display: none;">
<div class="ai-polish-info">
<div class="ai-polish-icon"><i data-lucide="sparkles"></i></div>
<div class="ai-polish-text">
<span class="ai-polish-title" id="ai-polish-title">Extracted with local engine</span>
<span class="ai-polish-subtitle" id="ai-polish-subtitle">Want AI to polish measurements, separate run-on steps, and format times?</span>
</div>
</div>
<button type="button" class="btn btn-outline btn-sm" id="btn-ai-polish">
<i data-lucide="wand-2"></i> <span>Polish with AI</span>
</button>
</div>
<div class="form-grid-2">
<!-- Ingredients Editing -->
<div class="form-group">
<label>Ingredients (one per line)</label>
<textarea id="edit-ingredients" rows="8" placeholder="1 lb Pasta&#10;2 tbsp Olive oil&#10;4 cloves Garlic..." required></textarea>
</div>
<!-- Instructions Editing -->
<div class="form-group">
<label>Instructions (one step per line)</label>
<textarea id="edit-instructions" rows="8" placeholder="Boil water and cook pasta.&#10;Sauté garlic in olive oil.&#10;Combine pasta and sauce..." required></textarea>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline" onclick="closeModal('save-modal')">Discard</button>
<button type="submit" form="recipe-edit-form" class="btn btn-primary" id="btn-save-confirm">
<i data-lucide="save"></i> <span>Save to Vault</span>
</button>
</div>
</div>
</div>
<!-- INTERACTIVE RECIPE DETAIL VIEWER -->
<div class="modal-overlay" id="detail-modal">
<div class="modal-box max-width-xl no-padding">
<div class="detail-hero-banner" id="recipe-detail-banner">
<button class="detail-back-btn" onclick="closeModal('detail-modal')"><i data-lucide="arrow-left"></i> <span>Back</span></button>
<div class="detail-actions">
<button class="btn btn-accent" id="btn-detail-clone" style="display: none;" title="Clone to My Cookbook">
<i data-lucide="copy"></i> <span>Clone to My Cookbook</span>
</button>
<button class="btn btn-icon-round" id="btn-detail-share" title="Generate Public Share Link"><i data-lucide="share-2"></i></button>
<button class="btn btn-icon-round btn-danger-hover" id="btn-detail-revoke-share" style="display: none;" title="Disable Public Share Link"><i data-lucide="link-2-off" style="color: var(--danger);"></i></button>
<button class="btn btn-icon-round" id="btn-detail-edit" title="Edit Recipe"><i data-lucide="edit"></i></button>
<button class="btn btn-icon-round btn-danger-hover" id="btn-detail-delete" title="Delete Recipe"><i data-lucide="trash-2"></i></button>
</div>
</div>
<div class="detail-main-content">
<div class="detail-header-info">
<h2 id="recipe-detail-title">Garlic Butter Salmon</h2>
<div class="recipe-creator-credit" id="recipe-detail-creator" style="display: none; margin-bottom: 12px;">
<span class="creator-badge" style="font-size: 0.85rem; padding: 4px 8px; background: rgba(245, 158, 11, 0.15); border: 1px dashed rgba(245, 158, 11, 0.3); border-radius: 6px; color: #f59e0b; display: inline-flex; align-items: center; gap: 4px;"><i data-lucide="user" style="width: 12px; height: 12px;"></i> Shared by <span id="recipe-detail-creator-name">@chef</span></span>
</div>
<div class="recipe-meta-tags">
<span id="tag-servings"><i data-lucide="users"></i> <span class="val">4 servings</span></span>
<span id="tag-prep"><i data-lucide="clock"></i> Prep: <span class="val">15 mins</span></span>
<span id="tag-cook"><i data-lucide="flame"></i> Cook: <span class="val">25 mins</span></span>
<span id="tag-total"><i data-lucide="timer"></i> Total: <span class="val">40 mins</span></span>
<a id="tag-source" href="#" target="_blank" rel="noopener noreferrer" style="display: none;">
<i data-lucide="external-link"></i> <span class="val">Original Source</span>
</a>
<span id="tag-share-stats" style="display: none; background: rgba(99, 102, 241, 0.12); border: 1px dashed rgba(99, 102, 241, 0.3); color: #6366f1;">
<i data-lucide="eye" style="color: #6366f1;"></i> <span class="val">0 Visitors</span>
</span>
</div>
<p class="recipe-detail-desc" id="recipe-detail-description">A quick and delicious salmon dinner.</p>
</div>
<div class="detail-tabs-container">
<!-- Serving Adjuster -->
<div class="servings-scaler-panel">
<span class="scale-label">Scale Ingredients:</span>
<div class="scaler-controls">
<button class="scaler-btn" id="scaler-minus"><i data-lucide="minus"></i></button>
<span class="scaler-val" id="current-servings-val">1x</span>
<button class="scaler-btn" id="scaler-plus"><i data-lucide="plus"></i></button>
</div>
<button class="btn btn-accent cooking-mode-trigger" id="btn-trigger-cookmode">
<i data-lucide="chef-hat"></i> <span>Start Cooking Mode</span>
</button>
</div>
<div class="detail-split-layout">
<!-- Left: Ingredients Checklist -->
<div class="detail-ingredients-column">
<div class="detail-ingredients-header">
<div>
<h3>Ingredients</h3>
<p class="section-subtext">Check off items you already have at home</p>
</div>
<div class="detail-add-to-list-bar">
<select id="detail-shopping-list-select" class="shopping-select shopping-select-sm" title="Select Shopping List"></select>
<button type="button" class="btn btn-primary btn-sm" id="btn-add-recipe-to-list" title="Add unchecked ingredients to selected shopping list">
<i data-lucide="shopping-cart"></i> <span>Add to List</span>
</button>
</div>
</div>
<ul class="ingredients-check-list" id="recipe-detail-ingredients">
<!-- Checkbox elements populated via JS -->
</ul>
</div>
<!-- Right: Instructions Checklist -->
<div class="detail-instructions-column">
<h3>Cooking Directions</h3>
<p class="section-subtext">Track your progress step-by-step</p>
<ol class="instructions-progress-list" id="recipe-detail-instructions">
<!-- Steps populated via JS -->
</ol>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- FULLSCREEN INTERACTIVE COOKING MODE -->
<div class="modal-overlay cooking-mode-overlay" id="cooking-mode-modal">
<div class="cooking-container">
<div class="cooking-header">
<div class="cooking-brand">
<i data-lucide="chef-hat"></i> <span>Cooking Assistant</span>
</div>
<div class="cooking-title-indicator" id="cook-recipe-title">Garlic Salmon</div>
<!-- Live Stopwatch / Timer -->
<div class="cook-timer-panel">
<div class="timer-display" id="cook-timer-val">00:00</div>
<button class="timer-btn" id="cook-timer-play" title="Play/Pause stopwatch"><i data-lucide="play"></i></button>
<button class="timer-btn btn-outline" id="cook-timer-reset" title="Reset stopwatch"><i data-lucide="rotate-ccw"></i></button>
</div>
<button class="close-btn color-white" onclick="exitCookingMode()"><i data-lucide="x"></i></button>
</div>
<div class="cooking-stepper-box">
<div class="step-progress-track">
<div class="step-progress-bar" id="cook-progress-bar"></div>
</div>
<div class="cooking-slide">
<span class="cooking-step-badge" id="cook-step-index">STEP 1 of 5</span>
<div class="cooking-step-text" id="cook-step-instruction">Boil water and cook pasta.</div>
</div>
</div>
<div class="cooking-controls">
<button class="btn btn-outline btn-lg color-white" id="cook-btn-prev">
<i data-lucide="chevron-left"></i> <span>Prev Step</span>
</button>
<div class="step-dots" id="cook-step-dots">
<!-- Step indicator bullet points -->
</div>
<button class="btn btn-accent btn-lg" id="cook-btn-next">
<span>Next Step</span> <span class="btn-icon-wrapper"><i data-lucide="chevron-right"></i></span>
</button>
</div>
</div>
</div>
<!-- LOADING / SCRAPING STATUS SCREEN -->
<div class="modal-overlay loading-overlay" id="loading-overlay">
<div class="loader-card">
<div class="spinner-outer">
<div class="spinner-inner"></div>
<i data-lucide="cooking-pot" class="spinner-logo"></i>
</div>
<h3>Extracting Recipe Data</h3>
<p class="loader-subtitle">Retrieving site contents and parsing culinary structures...</p>
<ul class="loader-steps">
<li class="loader-step active" id="loader-step-fetch">
<span class="step-icon-wrapper"><i data-lucide="check-circle-2"></i></span> <span>Connecting to source URL...</span>
</li>
<li class="loader-step" id="loader-step-parse">
<span class="step-icon-wrapper"><i data-lucide="circle-dashed" class="spinning-icon"></i></span> <span>Parsing schema structures...</span>
</li>
<li class="loader-step" id="loader-step-images">
<span class="step-icon-wrapper"><i data-lucide="circle" class="dot-icon"></i></span> <span>Extracting high-res dish photos...</span>
</li>
</ul>
</div>
</div>
<!-- AUTHENTICATION DIALOG (LOG IN ONLY) -->
<div class="modal-overlay" id="auth-modal" style="display: flex;">
<div class="modal-box max-width-xs auth-modal-box">
<div class="modal-header justify-center border-none pb-0">
<div class="auth-logo">
<div class="logo-icon"><i data-lucide="cooking-pot"></i></div>
<h2>Fork<span>Folio</span></h2>
</div>
</div>
<div class="modal-body auth-modal-body">
<div id="auth-error-msg" class="auth-error-alert" style="display: none;">
<i data-lucide="alert-circle" class="error-alert-icon"></i>
<span id="auth-error-text">Error message here</span>
</div>
<!-- Log In Form -->
<form id="login-form">
<div class="form-group mb-4">
<label for="login-username">Username</label>
<div class="input-wrapper">
<input type="text" id="login-username" required placeholder="Enter username" autocomplete="username">
</div>
</div>
<div class="form-group mb-6">
<label for="login-password">Password</label>
<div class="input-wrapper">
<input type="password" id="login-password" required placeholder="Enter password" autocomplete="current-password">
</div>
</div>
<button type="submit" class="btn btn-primary btn-full-width">
<i data-lucide="log-in"></i> <span>Log In</span>
</button>
</form>
</div>
</div>
</div>
<!-- ADMIN: CREATE USER MODAL -->
<div class="modal-overlay" id="admin-create-user-modal">
<div class="modal-box max-width-xs">
<div class="modal-header">
<h3>Create New Chef Account</h3>
<button class="close-btn" onclick="closeModal('admin-create-user-modal')"><i data-lucide="x"></i></button>
</div>
<div class="modal-body">
<div id="admin-create-error" class="auth-error-alert" style="display: none;">
<i data-lucide="alert-circle" class="error-alert-icon"></i>
<span id="admin-create-error-text"></span>
</div>
<form id="admin-create-user-form">
<div class="form-group mb-3">
<label for="admin-new-username">Username *</label>
<div class="input-wrapper">
<input type="text" id="admin-new-username" required placeholder="e.g. chef_julie" autocomplete="off">
</div>
<p class="form-help text-sm opacity-80" style="margin-top: 4px; font-size: 0.8rem; color: var(--text-muted);">Lowercase letters, numbers, underscores (3-20 characters).</p>
</div>
<div class="form-group mb-6">
<label for="admin-new-password">Temporary Password *</label>
<div class="input-wrapper">
<input type="password" id="admin-new-password" required placeholder="Minimum 6 characters" autocomplete="off">
</div>
</div>
<button type="submit" class="btn btn-primary btn-full-width">
<i data-lucide="user-plus"></i> <span>Create Account</span>
</button>
</form>
</div>
</div>
</div>
<!-- ADMIN: DELETE USER CONFIRMATION MODAL -->
<div class="modal-overlay" id="admin-delete-user-modal">
<div class="modal-box max-width-xs">
<div class="modal-header border-none pb-0">
<h3 style="color: var(--danger); display: flex; align-items: center; gap: 8px;">
<i data-lucide="trash-2"></i> Delete Chef Account
</h3>
<button class="close-btn" onclick="closeModal('admin-delete-user-modal')"><i data-lucide="x"></i></button>
</div>
<div class="modal-body" style="padding-top: 12px;">
<input type="hidden" id="delete-user-target-id">
<p style="font-size: 0.95rem; line-height: 1.5; color: var(--text-main); margin-bottom: 20px;">
Are you sure you want to delete account <strong id="delete-user-target-name">@username</strong>? This action cannot be undone.
</p>
<div class="form-group" style="background: rgba(245, 158, 11, 0.08); border: 1px dashed rgba(245, 158, 11, 0.25); border-radius: 8px; padding: 12px; margin-bottom: 24px;">
<label class="checkbox-container" style="align-items: flex-start;">
<input type="checkbox" id="delete-user-preserve-recipes" checked>
<span class="checkbox-label" style="font-size: 0.9rem; line-height: 1.4; color: var(--text-main); font-weight: 500;">
<i data-lucide="globe" style="width: 14px; height: 14px; display: inline-block; vertical-align: middle; margin-right: 4px;"></i> Keep recipes in Shared Cookbook?
</span>
</label>
<p style="font-size: 0.75rem; color: var(--text-muted); margin-top: 6px; padding-left: 30px; margin-bottom: 0;">
If enabled, this chef's private recipes will be transferred to a public archive in the Shared Cookbook. If disabled, all recipes owned by this chef will be purged.
</p>
</div>
<div style="display: flex; gap: 12px; justify-content: flex-end;">
<button class="btn btn-outline" onclick="closeModal('admin-delete-user-modal')">Cancel</button>
<button class="btn btn-danger" id="btn-admin-confirm-delete" style="background-color: var(--danger); color: white;">
<span>Delete Account</span>
</button>
</div>
</div>
</div>
</div>
<!-- SETTINGS MODAL -->
<div class="modal-overlay" id="settings-modal">
<div class="modal-box max-width-xs">
<div class="modal-header">
<h3 style="display: flex; align-items: center; gap: 8px;">
<i data-lucide="settings"></i> Application Settings
</h3>
<button class="close-btn" onclick="closeModal('settings-modal')"><i data-lucide="x"></i></button>
</div>
<div class="modal-body" style="padding-top: 12px;">
<div id="settings-status-msg" class="auth-error-alert" style="display: none; background: rgba(16, 185, 129, 0.1); border-color: rgba(16, 185, 129, 0.3); color: #10b981; margin-bottom: 16px; padding: 10px; border-radius: 8px; font-size: 0.85rem; align-items: center; gap: 8px;">
<i data-lucide="check-circle" style="color: #10b981; width: 16px; height: 16px; flex-shrink: 0;"></i>
<span id="settings-status-text">Credentials saved successfully.</span>
</div>
<!-- SECTION 1: AI API CREDENTIALS -->
<div class="settings-section" style="margin-bottom: 24px;">
<div class="settings-section-title" style="display: flex; align-items: center; gap: 8px; font-weight: 600; font-size: 1.05rem; border-bottom: 1px solid var(--border-color); padding-bottom: 8px; margin-bottom: 12px; color: var(--text-main);">
<i data-lucide="brain-circuit" style="color: var(--primary); width: 18px; height: 18px;"></i>
<span>AI API Credentials</span>
</div>
<p style="font-size: 0.85rem; line-height: 1.4; color: var(--text-muted); margin-bottom: 16px;">
Configure your system-wide Google Gemini credentials and model to enable recipe photo scanning and AI text polishing.
</p>
<form id="settings-api-form" style="margin-bottom: 8px;">
<div class="form-group mb-3">
<label for="settings-gemini-key" style="font-size: 0.85rem; margin-bottom: 6px; display: block; font-weight: 500;">Google Gemini API Key</label>
<div class="input-wrapper" style="position: relative; display: flex; align-items: center;">
<input type="password" id="settings-gemini-key" placeholder="Enter your Gemini API key..." autocomplete="off" style="width: 100%; padding-right: 40px; height: 40px; border-radius: var(--border-radius-md); border: 1px solid var(--border-color); background: rgba(0,0,0,0.2); color: var(--text-main); padding-left: 12px;">
<button type="button" id="btn-toggle-gemini-key" style="position: absolute; right: 10px; background: none; border: none; color: var(--text-muted); cursor: pointer;" title="Toggle Visibility">
<i data-lucide="eye" style="width: 16px; height: 16px;"></i>
</button>
</div>
</div>
<div class="form-group mb-4">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px;">
<label for="settings-gemini-model" style="font-size: 0.85rem; display: block; font-weight: 500;">AI Model</label>
<button type="button" id="btn-discover-models" class="btn btn-secondary btn-sm" style="font-size: 0.75rem; padding: 2px 10px; height: 28px; display: inline-flex; align-items: center; gap: 5px; cursor: pointer;" title="Query Google API for available models on your key">
<i data-lucide="refresh-cw" style="width: 13px; height: 13px;"></i>
<span>Discover Models</span>
</button>
</div>
<select id="settings-gemini-model" style="width: 100%; height: 40px; border-radius: var(--border-radius-md); border: 1px solid var(--border-color); background: var(--bg-card, #1e2430); color: var(--text-main); padding-left: 12px; padding-right: 12px; font-size: 0.85rem; cursor: pointer;">
<option value="gemini-2.5-flash">Gemini 2.5 Flash (Stable Recommended)</option>
<option value="gemini-3.8-flash">Gemini 3.8 Flash (Newest Flash)</option>
<option value="gemini-flash-latest">Gemini Flash Latest</option>
<option value="gemini-2.5-pro">Gemini 2.5 Pro</option>
<option value="gemini-4-argon">Gemini 4 Argon</option>
</select>
<span id="models-status-hint" style="font-size: 0.75rem; color: var(--text-muted); margin-top: 4px; display: block;">Powers both recipe photo scanning and AI text polishing.</span>
</div>
<button type="submit" class="btn btn-primary" style="width: 100%; height: 40px;">
<i data-lucide="save"></i> <span>Save Settings</span>
</button>
</form>
</div>
<!-- SECTION 2: SHOPPING LIST PREFERENCES -->
<div class="settings-section" style="margin-bottom: 24px;">
<div class="settings-section-title" style="display: flex; align-items: center; gap: 8px; font-weight: 600; font-size: 1.05rem; border-bottom: 1px solid var(--border-color); padding-bottom: 8px; margin-bottom: 12px; color: var(--text-main);">
<i data-lucide="shopping-cart" style="color: var(--primary); width: 18px; height: 18px;"></i>
<span>Shopping List Preferences</span>
</div>
<p style="font-size: 0.85rem; line-height: 1.4; color: var(--text-muted); margin-bottom: 12px;">
Choose the default behavior for the ingredient consolidation toggle when opening your shopping lists.
</p>
<div style="display: flex; flex-direction: column; gap: 8px;">
<label class="checkbox-container" style="display: flex; align-items: center; gap: 8px; cursor: pointer;">
<input type="checkbox" id="settings-default-consolidate" checked style="cursor: pointer;">
<span class="checkbox-label" style="font-size: 0.85rem; color: var(--text-main);">Consolidate duplicate ingredients by default</span>
</label>
</div>
</div>
<!-- SECTION 3: LINKED MOBILE DEVICES -->
<div class="settings-section" style="margin-bottom: 24px;">
<div class="settings-section-title" style="display: flex; align-items: center; justify-content: space-between; font-weight: 600; font-size: 1.05rem; border-bottom: 1px solid var(--border-color); padding-bottom: 8px; margin-bottom: 12px; color: var(--text-main);">
<div style="display: flex; align-items: center; gap: 8px;">
<i data-lucide="smartphone" style="color: var(--primary); width: 18px; height: 18px;"></i>
<span>Linked Mobile Devices</span>
</div>
<button type="button" id="btn-refresh-devices" class="btn btn-secondary btn-sm" style="font-size: 0.75rem; padding: 2px 10px; height: 28px; display: inline-flex; align-items: center; gap: 5px; cursor: pointer;" title="Refresh list of linked devices">
<i data-lucide="refresh-cw" style="width: 13px; height: 13px;"></i>
</button>
</div>
<p style="font-size: 0.85rem; line-height: 1.4; color: var(--text-muted); margin-bottom: 12px;">
Mobile apps authorized with persistent tokens. Devices inactive for 90 days expire automatically.
</p>
<div id="linked-devices-list" style="display: flex; flex-direction: column; gap: 8px;">
<div style="font-size: 0.85rem; color: var(--text-muted); font-style: italic; padding: 8px 0;">Loading linked devices...</div>
</div>
</div>
<!-- SECTION 4: CULINARY OPTIONS (COMING SOON) -->
<div class="settings-section" style="opacity: 0.55; margin-bottom: 24px;">
<div class="settings-section-title" style="display: flex; align-items: center; justify-content: space-between; font-weight: 600; font-size: 1.05rem; border-bottom: 1px solid var(--border-color); padding-bottom: 8px; margin-bottom: 12px; color: var(--text-main);">
<div style="display: flex; align-items: center; gap: 8px;">
<i data-lucide="cooking-pot" style="color: var(--text-muted); width: 18px; height: 18px;"></i>
<span>Cookbook Options</span>
</div>
<span style="font-size: 0.65rem; background: var(--border-color); padding: 2px 6px; border-radius: 4px; color: var(--text-muted); text-transform: uppercase; font-weight: 700; font-family: var(--font-heading);">Coming Soon</span>
</div>
<p style="font-size: 0.85rem; line-height: 1.4; color: var(--text-muted); margin-bottom: 12px;">
Set default preferences for unit systems, portions, and timer configurations.
</p>
<div style="display: flex; flex-direction: column; gap: 8px;">
<label class="checkbox-container" style="cursor: not-allowed; display: flex; align-items: center; gap: 6px;">
<input type="checkbox" disabled style="cursor: not-allowed;">
<span class="checkbox-label" style="font-size: 0.85rem; color: var(--text-muted);">Default to Metric Units (grams, milliliters)</span>
</label>
<label class="checkbox-container" style="cursor: not-allowed; display: flex; align-items: center; gap: 6px;">
<input type="checkbox" disabled style="cursor: not-allowed;">
<span class="checkbox-label" style="font-size: 0.85rem; color: var(--text-muted);">Sound notifications on timer completion</span>
</label>
</div>
</div>
<div style="display: flex; justify-content: flex-end;">
<button class="btn btn-outline" onclick="closeModal('settings-modal')" style="width: 100%;">
<span>Close Settings</span>
</button>
</div>
</div>
</div>
</div>
<!-- MOBILE SYSTEM COMPONENTS -->
<!-- Mobile Profile Drawer Sheet -->
<div class="modal-overlay" id="mobile-profile-modal">
<div class="modal-box max-width-xs mobile-profile-sheet">
<div class="bottom-sheet-handle"></div>
<div class="modal-header">
<h3>Chef Profile</h3>
<button class="close-btn" onclick="closeModal('mobile-profile-modal')"><i data-lucide="x"></i></button>
</div>
<div class="modal-body text-center" style="display: flex; flex-direction: column; align-items: center; gap: 16px;">
<div class="profile-avatar-large">
<i data-lucide="user"></i>
</div>
<div>
<h2 class="profile-username" id="mobile-profile-username" style="font-size: 1.6rem; color: var(--text-main); margin-bottom: 4px;">@chef</h2>
<span class="admin-role-badge chef" id="mobile-profile-role" style="font-size: 0.8rem; padding: 4px 10px; border-radius: var(--border-radius-full);">Chef Account</span>
</div>
<div class="mobile-profile-actions" style="width: 100%; display: flex; flex-direction: column; gap: 12px; margin-top: 8px;">
<button class="btn btn-outline btn-full-width" id="mobile-btn-theme-toggle" style="justify-content: flex-start; padding-left: 20px;">
<i data-lucide="sun" class="sun-icon"></i>
<i data-lucide="moon" class="moon-icon" style="display: none;"></i>
<span style="margin-left: 8px;">Toggle Theme</span>
</button>
<button class="btn btn-outline btn-full-width" id="mobile-btn-settings" style="justify-content: flex-start; padding-left: 20px;">
<i data-lucide="settings"></i>
<span style="margin-left: 8px;">Application Settings</span>
</button>
<button class="btn btn-outline btn-full-width" id="mobile-btn-admin" style="display: none; justify-content: flex-start; padding-left: 20px; border-color: var(--primary); color: var(--primary);">
<i data-lucide="shield"></i>
<span style="margin-left: 8px;">User Admin Panel</span>
</button>
<button class="btn btn-danger btn-full-width" id="mobile-btn-logout" style="justify-content: flex-start; padding-left: 20px; background-color: rgba(239, 68, 68, 0.1); border: 1px solid rgba(239, 68, 68, 0.2); color: var(--danger);">
<i data-lucide="log-out"></i>
<span style="margin-left: 8px;">Log Out</span>
</button>
</div>
</div>
</div>
</div>
<script>
// Initialize Lucide Icons initially
window.addEventListener('DOMContentLoaded', () => {
lucide.createIcons();
});
</script>
<!-- Frontend Javascript -->
<script src="app.js"></script>
</body>
</html>