# Timebank.cc Style Guide

This document outlines the styling conventions and theme system for the Timebank.cc application. It serves as the authoritative reference for all UI styling patterns used throughout the application.

**Reference Implementation:** `resources/views/mailings/manage.blade.php` and `resources/views/livewire/mailings/manage.blade.php` demonstrate all core UI patterns and should be consulted when building new views.

## Theme System Overview

The application uses a sophisticated configuration-based multi-theme system that allows different installations to have unique visual identities. The system is built on four core components:

### Core Architecture

1. **Theme Configuration**: `config/themes.php` - Centralized theme definitions with colors, typography, and metadata
2. **Theme Helpers**: `app/Helpers/ThemeHelper.php` - PHP functions for accessing theme data throughout the application  
3. **CSS Custom Properties**: `resources/css/app.css` - Automatically generated theme-aware CSS variables
4. **Tailwind Integration**: `tailwind.config.js` - Theme-aware utility classes using CSS custom properties

### Available Themes

1. **timebank_cc** (default) - Gray, black and white professional theme
2. **uuro** - Black, white and cyan theme with vibrant accents (inspired by buuro.net)
3. **vegetable** - Green, natural theme with earth tones (inspired by lekkernassuh.org)  
4. **yellow** - High-contrast yellow and black theme (inspired by yellowbrick.nl)

Themes are activated via the `TIMEBANK_THEME` environment variable and can be switched per installation without code changes.

## Theme Configuration Structure

Each theme in `config/themes.php` follows this standardized structure:

```php
'theme_name' => [
    'name' => 'Display Name',
    'description' => 'Theme description',
    'colors' => [
        // Primary color scale (required)
        'primary' => [
            50 => '#F6F8F9',    // Lightest
            100 => '#EBEDEE', 
            200 => '#DCDEDF',
            300 => '#CDCFD0',   // Border colors
            400 => '#B8BABB',   // Muted elements
            500 => '#999B9C',   // Main brand color
            600 => '#6E6F70',
            700 => '#434343',
            800 => '#242424',
            900 => '#1A1A1A',   // Darkest, headers
        ],
        
        // Semantic colors (required)
        'secondary' => '#6B7280',   // Secondary brand color
        'accent' => '#434343',      // Accent color for highlights
        'brand' => '#000000',       // Brand/header backgrounds
        'logo' => '#000000',        // Logo and icon colors
        'background' => '#FFFFFF',  // Page background
        'surface' => '#F9FAFB',     // Card/surface backgrounds
        
        // Text colors (required)
        'text' => [
            'primary' => '#111827',   // Main text
            'secondary' => '#6B7280', // Secondary text, subtitles
            'light' => '#9CA3AF',     // Muted text, placeholders
        ],
        
        // Theme-specific colors (optional)
        'success' => '#00D084',        // Uuro: success states
        'danger' => '#CF2E2E',         // Uuro: error states
        'warning' => '#FF6900',        // Uuro: warning states  
        'info' => '#0693E3',           // Uuro: info states
        'surface_alt' => '#E2E2C7',    // Vegetable: alternative surface
        'neutral' => [                 // Yellow: neutral color scale
            'dark' => '#2F2E2E',
            'medium' => '#5D5B5B',
            'light' => '#EFEFEF',
        ],
        'surface_dark' => '#000000',   // Yellow: dark surface
        'accent_dark' => '#001B2F',    // Yellow: dark accent
    ],
    'typography' => [
        // Base typography (required)
        'font_family_body' => 'Roboto, sans-serif',
        'font_family_heading' => 'Oswald, sans-serif',
        'font_size_base' => '16px',
        'line_height_base' => '1.5',
        'heading_transform' => 'uppercase', // or 'none'
        
        // Theme-specific typography (optional)
        'font_family_quote' => 'Georgia, serif',     // Yellow theme
        'line_height_heading' => '1.4',              // Vegetable theme
        'font_sizes' => [                            // Uuro theme
            'small' => '13px',
            'medium' => '20px', 
            'large' => '36px',
            'x-large' => '42px',
        ],
        'heading_sizes' => [                         // Vegetable theme
            'h1' => '23px',
            'h2' => '36px',
            'h3' => '18px', 
            'h4' => '17px',
        ],
        'font_weights' => [                          // Yellow theme
            'regular' => '400',
            'medium' => '500',
            'semibold' => '600',
            'bold' => '700',
            'extrabold' => '800',
        ],
    ],
]
```

## PHP Theme Helper Functions

The `app/Helpers/ThemeHelper.php` file provides convenient functions for accessing theme data throughout the application:

### Core Functions

```php
// Get current theme data
$theme = theme();           // Returns full theme array with 'id' key added
$themeName = theme_name();  // Returns theme display name (e.g., "Uuro")  
$themeId = theme_id();      // Returns theme identifier (e.g., "uuro")

// Get specific theme values
$color = theme_color('primary.500');           // Returns '#64748B' (hex value)
$logoColor = theme_color('logo');              // Returns logo color
$bodyFont = theme_font('font_family_body');    // Returns typography setting

// Get theme values with defaults
$customColor = theme_color('custom.color', '#000000');  // Returns default if not found
$customFont = theme_font('custom_font', 'Arial');       // Returns default if not found

// Theme checking
if (is_theme('vegetable')) {
    // Vegetable theme specific logic
}

// Access nested values
$textColor = theme('colors.text.primary');     // Direct config access
$fontWeight = theme('typography.font_weights.bold'); // Access nested arrays
```

### Dynamic CSS Variable Generation

```php
// Generate CSS custom properties for current theme
$cssVars = theme_css_vars(); 
// Returns: "--color-primary-500: 100 116 139; --color-brand: 25 2 54; --font-family-body: system-ui, -apple-system, sans-serif; ..."

// Helper function for color conversion
$rgbValue = hexToRgb('#64748B');  // Returns "100 116 139" (space-separated RGB)
```

## CSS Architecture

### Automatic CSS Custom Property Generation

Colors from `config/themes.php` are automatically converted to CSS custom properties in RGB format (enabling alpha transparency):

```css
/* Generated automatically via theme_css_vars() function */
[data-theme="uuro"] {
  --color-primary-50: 248 250 252;      /* From #F8FAFC */
  --color-primary-500: 100 116 139;     /* From #64748B */
  --color-primary-900: 15 23 42;        /* From #0F172A */
  --color-brand: 25 2 54;               /* From #190236 */
  --color-logo: 25 2 54;                /* From #190236 */
  --color-background: 255 255 255;      /* From #FFFFFF */
  --color-text-primary: 0 0 0;          /* From #000000 */
  
  /* Typography variables */
  --font-family-body: system-ui, -apple-system, sans-serif;
  --font-family-heading: system-ui, -apple-system, sans-serif;
  --line-height-base: 1.6;
  --heading-transform: none;
}
```

### Tailwind CSS Integration

Theme colors integrate with Tailwind using RGB format with alpha value support:

```javascript
// tailwind.config.js
colors: {
  // Primary color scale
  primary: {
    50: 'rgb(var(--color-primary-50) / <alpha-value>)',
    500: 'rgb(var(--color-primary-500) / <alpha-value>)',
    900: 'rgb(var(--color-primary-900) / <alpha-value>)',
  },
  
  // Semantic theme colors
  'theme-secondary': 'rgb(var(--color-secondary) / <alpha-value>)',
  'theme-accent': 'rgb(var(--color-accent) / <alpha-value>)',
  'theme-brand': 'rgb(var(--color-brand) / <alpha-value>)',
  'theme-logo': 'rgb(var(--color-logo) / <alpha-value>)',
  'theme-background': 'rgb(var(--color-background) / <alpha-value>)',
  'theme-surface': 'rgb(var(--color-surface) / <alpha-value>)',
  
  'theme-text': {
    primary: 'rgb(var(--color-text-primary) / <alpha-value>)',
    secondary: 'rgb(var(--color-text-secondary) / <alpha-value>)',
    light: 'rgb(var(--color-text-light) / <alpha-value>)',
  },
}
```

### CSS Utility Classes

Additional utility classes are defined in `resources/css/app.css`:

```css
.bg-theme-brand {
  background-color: rgb(var(--color-brand));
}

.fill-theme-logo {
  fill: rgb(var(--color-logo));
}

.text-theme-logo {
  color: rgb(var(--color-logo));
}

.border-theme-border {
  border-color: rgb(var(--color-primary-300));
}
```

## Color Usage Guidelines

### Primary Color Scale Usage
- **50-200**: Light backgrounds, subtle accents, hover states
- **300-400**: Borders, muted elements, disabled states
- **500**: Main brand color, primary buttons, links
- **600-900**: Text colors, dark backgrounds, headers

### Semantic Color Guidelines

#### Background Colors
- `theme-background`: Main page background (typically white)
- `theme-surface`: Card backgrounds, modal backgrounds, raised surfaces  
- `theme-brand`: Strong brand elements, page headers, primary buttons

#### Text Colors  
- `theme-text-primary`: Main body text, headings
- `theme-text-secondary`: Secondary text, captions, metadata
- `theme-text-light`: Muted text, placeholders, disabled text

#### Accent Colors
- `theme-secondary`: Secondary brand elements, alternative buttons
- `theme-accent`: Highlights, badges, accent elements
- `theme-logo`: Logos, icons, brand symbols

### Theme-Specific Color Usage

#### Uuro Theme Status Colors
```php
// Available via theme_color() function
$success = theme_color('success');  // '#00D084' - vivid green cyan
$danger = theme_color('danger');    // '#CF2E2E' - vivid red  
$warning = theme_color('warning');  // '#FF6900' - luminous orange
$info = theme_color('info');        // '#0693E3' - vivid cyan blue
```

#### Vegetable Theme Natural Colors
```php
$surfaceAlt = theme_color('surface_alt');  // '#E2E2C7' - light beige alternative
```

#### Yellow Theme Neutral System
```php
$darkNeutral = theme_color('neutral.dark');     // '#2F2E2E'
$mediumNeutral = theme_color('neutral.medium'); // '#5D5B5B' 
$lightNeutral = theme_color('neutral.light');   // '#EFEFEF'
$surfaceDark = theme_color('surface_dark');     // '#000000'
$accentDark = theme_color('accent_dark');       // '#001B2F'
```

## UI Component Patterns

This section documents the standard UI patterns used throughout the application, based on the reference implementation in `resources/views/livewire/mailings/manage.blade.php`.

### Page Layout Structure

#### Standard Management Page Layout
```html
<x-app-layout>
    <x-slot name="header">
            {{ __('Page Title') }}
    </x-slot>

    <div class="py-6">
        <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
            <div class="bg-theme-background overflow-hidden shadow-xl sm:rounded-lg">
                <div class="p-12 px-6 sm:px-20 bg-theme-background">

                    <!-- Page title and description -->
                    <div class="mt-4 text-2xl">
                        {{ __('Page Heading') }}
                    </div>

                    <div class="mt-6 text-theme-secondary">
                        {{ __('Page description text...') }}
                    </div>

                    <!-- Main content (Livewire component) -->
                    @livewire('component.name')

                </div>
            </div>
        </div>

        <!-- Optional: Scroll-to-top script -->
        @push('scripts')
        <script>
        document.addEventListener('scroll-to-top', event => {
            window.scrollTo({ top: 0, behavior: 'smooth' });
        });
        </script>
        @endpush
    </div>
</x-app-layout>
```

**Key Patterns:**
- Header slot: `text-xl text-theme-light leading-tight`
- Container: `max-w-7xl mx-auto sm:px-6 lg:px-8`
- Card wrapper: `bg-theme-background overflow-hidden shadow-xl sm:rounded-lg`
- Inner padding: `p-12 px-6 sm:px-20 bg-theme-background`
- Page title: `mt-4 text-2xl`
- Description: `mt-6 text-theme-secondary`

### Action Buttons Section

#### Top Action Bar with Primary and Danger Actions
```html
<div class="mb-6 flex items-center justify-between">
    <!-- Primary Action (left side) -->
    <x-jetstream.button wire:click="openCreateModal" class="bg-theme-brand hover:bg-opacity-80">
        {{ __('Create Item') }}
    </x-jetstream.button>

    <!-- Destructive Action (right side) -->
    <x-jetstream.danger-button
        :disabled="$bulkDisabled"
        title="{{ __('Delete selection') }}"
        wire:click.prevent="openBulkDeleteModal">
        <x-icon class="mr-3 h-5 w-5" name="trash" />
        {{ __('Delete') }} {{ __('selection') }}
    </x-jetstream.danger-button>
</div>
```

**Key Patterns:**
- Container: `mb-6 flex items-center justify-between`
- Primary button: `bg-theme-brand hover:bg-opacity-80`
- Icon spacing: `mr-3 h-5 w-5`
- Use `wire:click` for Livewire actions
- Use `:disabled` for reactive disabling

### Search and Filters

#### Search Input with Clear Button
```html
<div class="mb-6">
    <div class="mb-4 flex items-center">
        <div class="relative w-1/3">
            <input
                class="w-full rounded-md border border-theme-primary px-3 py-1 pr-10 text-theme-primary shadow-sm focus:border-theme-primary focus:outline-none focus:ring focus:ring-theme-primary sm:text-sm"
                placeholder="{{ __('Search items') . '...' }}"
                type="text"
                wire:model.live="search">

            @if ($search)
                <button
                    class="absolute inset-y-0 right-0 flex items-center pr-3 text-theme-secondary hover:text-theme-primary focus:outline-none"
                    wire:click.prevent="$set('search', '')">
                    <x-icon mini name="backspace" solid />
                </button>
            @endif
        </div>
    </div>
</div>
```

**Key Patterns:**
- Search container: `relative w-1/3`
- Input classes: `w-full rounded-md border border-theme-primary px-3 py-1 pr-10 text-theme-primary shadow-sm focus:border-theme-primary focus:outline-none focus:ring focus:ring-theme-primary sm:text-sm`
- Clear button: positioned absolutely, `inset-y-0 right-0`, with `text-theme-secondary hover:text-theme-primary`
- Use `wire:model.live` for real-time search

#### Filter Dropdowns Row
```html
<div class="mb-4 flex items-center space-x-3">
    <div>
        <x-select
            :clearable="true"
            class="!w-60"
            placeholder="{{ __('Filter by category') }}"
            wire:model.live="categoryFilter">
            <x-select.option label="{{ __('Option 1') }}" value="option1" />
            <x-select.option label="{{ __('Option 2') }}" value="option2" />
        </x-select>
    </div>

    <div>
        <x-select
            :clearable="true"
            class="!w-60"
            placeholder="{{ __('Filter by status') }}"
            wire:model.live="statusFilter">
            <x-select.option label="{{ __('Active') }}" value="active" />
            <x-select.option label="{{ __('Inactive') }}" value="inactive" />
        </x-select>
    </div>
</div>
```

**Key Patterns:**
- Container: `mb-4 flex items-center space-x-3`
- Select width: `!w-60` (use `!` to override default)
- Always use `:clearable="true"` for filters
- Use `wire:model.live` for immediate filtering

### Data Tables

#### Complete Table Structure
```html
<div class="bg-white shadow-sm rounded-lg overflow-hidden">
    <table class="min-w-full divide-y divide-gray-200">
        <thead class="bg-gray-50">
            <tr>
                <!-- Checkbox column -->
                <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                    <!-- Optional: Select all checkbox -->
                </th>

                <!-- Sortable column -->
                <th class="px-3 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer align-middle"
                    wire:click="sortBy('title')">
                    <div class="flex items-center space-x-1">
                        <span>{{ __('Title') }}</span>
                        @if($sortField === 'title')
                            <span class="text-gray-400">
                                @if($sortDirection === 'asc') ↑ @else ↓ @endif
                            </span>
                        @endif
                    </div>
                </th>

                <!-- Non-sortable column -->
                <th class="px-3 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider align-middle">
                    {{ __('Column Name') }}
                </th>

                <!-- Actions column (right-aligned) -->
                <th class="px-3 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider align-middle w-32">
                    {{ __('Actions') }}
                </th>
            </tr>
        </thead>
        <tbody class="bg-white divide-y divide-gray-200">
            @forelse($items as $item)
                <tr>
                    <!-- Checkbox cell -->
                    <td class="px-3 py-4 whitespace-nowrap">
                        <input
                            type="checkbox"
                            value="{{ $item->id }}"
                            wire:model.live="bulkSelected"
                            class="rounded border-gray-300 text-theme-brand focus:ring-theme-brand">
                    </td>

                    <!-- Title cell with subtitle -->
                    <td class="px-3 py-4 whitespace-nowrap">
                        <div>
                            <div class="text-sm font-medium text-gray-900">{{ $item->title }}</div>
                            <div class="text-sm text-gray-500">{{ $item->subtitle }}</div>
                        </div>
                    </td>

                    <!-- Standard text cell -->
                    <td class="px-3 py-4 whitespace-nowrap text-sm text-gray-500">
                        {{ $item->description }}
                    </td>

                    <!-- Status badge cell -->
                    <td class="px-3 py-4 whitespace-nowrap">
                        <span class="inline-flex px-2 py-1 text-xs font-medium rounded-full
                            @if($item->status === 'active') bg-green-100 text-green-800
                            @elseif($item->status === 'pending') bg-yellow-100 text-yellow-800
                            @elseif($item->status === 'inactive') bg-gray-100 text-gray-800
                            @else bg-theme-danger-light text-theme-danger-dark @endif">
                            {{ ucfirst($item->status) }}
                        </span>
                    </td>

                    <!-- Date cell (multi-line format) -->
                    <td class="px-3 py-4 text-sm text-gray-500">
                        @if($item->date)
                            <div class="leading-tight">
                                <div>{{ $item->date->format('M j') }}</div>
                                <div>{{ $item->date->format('Y') }}</div>
                                <div class="text-xs">{{ $item->date->format('H:i') }}</div>
                            </div>
                        @else
                            -
                        @endif
                    </td>

                    <!-- Avatar cell -->
                    <td class="px-3 py-4">
                        @if($item->user)
                            <div class="relative block cursor-pointer"
                                onclick="window.location='{{ url('user/' . $item->user->id) }}'"
                                title="{{ $item->user->name }}">
                                <img class="mx-auto h-6 w-6 rounded-full object-cover outline outline-1 outline-offset-0 outline-gray-600"
                                     src="{{ $item->user->avatar_url }}"
                                     alt="profile">
                            </div>
                        @else
                            <span class="text-sm text-gray-400">-</span>
                        @endif
                    </td>

                    <!-- Actions cell -->
                    <td class="px-3 py-4 whitespace-nowrap text-center text-sm font-medium">
                        <div class="flex items-center justify-center space-x-1">
                            <!-- Edit button -->
                            <x-jetstream.secondary-button
                                title="{{ __('Edit') }}"
                                wire:click="openEditModal({{ $item->id }})">
                                <span wire:loading.remove wire:target="openEditModal">
                                    <x-icon class="h-5 w-5" name="pencil-square" />
                                </span>
                                <span wire:loading wire:target="openEditModal">
                                    <svg class="animate-spin h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
                                        <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
                                        <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
                                    </svg>
                                </span>
                            </x-jetstream.secondary-button>

                            <!-- Delete button -->
                            <x-jetstream.danger-button
                                wire:click="delete({{ $item->id }})"
                                title="{{ __('Delete') }}">
                                <span wire:loading.remove wire:target="delete">
                                    <x-icon class="h-5 w-5" name="trash" solid />
                                </span>
                            </x-jetstream.danger-button>
                        </div>
                    </td>
                </tr>
            @empty
                <tr>
                    <td colspan="8" class="px-6 py-12 text-center text-gray-500">
                        {{ __('No items found.') }}
                    </td>
                </tr>
            @endforelse
        </tbody>
    </table>

    <!-- Pagination -->
    @if($items->hasPages())
        <div class="px-6 py-3 border-t border-gray-200">
            {{ $items->links('livewire.long-paginator') }}
        </div>
    @endif
</div>
```

**Key Patterns:**
- Table wrapper: `bg-white shadow-sm rounded-lg overflow-hidden`
- Table: `min-w-full divide-y divide-gray-200`
- Header: `bg-gray-50`, headers use `px-3 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider align-middle`
- Sortable headers: add `cursor-pointer` and `wire:click="sortBy('field')"`
- Sort indicators: `text-gray-400` with ↑/↓ characters
- Body: `bg-white divide-y divide-gray-200`
- Cells: `px-3 py-4` (standard), `px-6 py-3` (checkbox column)
- Action buttons: `space-x-1` between buttons
- Empty state: full colspan, `px-6 py-12 text-center text-gray-500`
- Pagination wrapper: `px-6 py-3 border-t border-gray-200`

#### Status Badge Patterns
```html
<!-- Success/Active status -->
<span class="inline-flex px-2 py-1 text-xs font-medium rounded-full bg-green-100 text-green-800">
    {{ __('Active') }}
</span>

<!-- Warning/Pending status -->
<span class="inline-flex px-2 py-1 text-xs font-medium rounded-full bg-yellow-100 text-yellow-800">
    {{ __('Pending') }}
</span>

<!-- Neutral/Draft status -->
<span class="inline-flex px-2 py-1 text-xs font-medium rounded-full bg-gray-100 text-gray-800">
    {{ __('Draft') }}
</span>

<!-- Theme-aware status -->
<span class="inline-flex px-2 py-1 text-xs font-medium rounded-full bg-theme-surface text-theme-primary">
    {{ __('Processing') }}
</span>

<!-- Danger/Error status -->
<span class="inline-flex px-2 py-1 text-xs font-medium rounded-full bg-theme-danger-light text-theme-danger-dark">
    {{ __('Failed') }}
</span>
```

**Key Patterns:**
- Base classes: `inline-flex px-2 py-1 text-xs font-medium rounded-full`
- Use semantic colors: green (success), yellow (warning), gray (neutral), theme-danger (error)

### Modals

#### Standard Dialog Modal Structure
```html
<x-jetstream.dialog-modal wire:model.live="showModal" wire:key="showModal" maxWidth="2xl">
    <x-slot name="title">
        {{ __('Modal Title') }}
    </x-slot>

    <x-slot name="content">
        <!-- Modal content here -->
        <div class="space-y-6">
            <!-- Form fields, text, etc. -->
        </div>
    </x-slot>

    <x-slot name="footer">
        <x-jetstream.secondary-button wire:click="closeModal">
            {{ __('Cancel') }}
        </x-jetstream.secondary-button>

        <x-jetstream.button wire:click="save" class="ml-3 bg-theme-brand">
            {{ __('Save') }}
        </x-jetstream.button>
    </x-slot>
</x-jetstream.dialog-modal>
```

**Key Patterns:**
- Use `wire:model.live` for modal visibility
- Add `wire:key` to prevent state issues
- Standard sizes: `sm`, `md`, `lg`, `xl`, `2xl`
- Footer buttons: Cancel (secondary) on left, Primary action on right with `ml-3`
- Primary actions use `bg-theme-brand`

#### Confirmation Modal Pattern
```html
<x-jetstream.dialog-modal wire:model.live="showConfirmModal" wire:key="showConfirmModal">
    <x-slot name="title">
        {{ __('Confirm Action') }}
    </x-slot>

    <x-slot name="content">
        {{ __('Are you sure you want to perform this action?') }}<br>
        {{ __('This action cannot be undone.') }}
        <br><br>
        <strong>{{ __('Details') }}: {{ $itemName }}</strong>
    </x-slot>

    <x-slot name="footer">
        <x-jetstream.secondary-button wire:click="$set('showConfirmModal', false)">
            {{ __('Cancel') }}
        </x-jetstream.secondary-button>

        <x-jetstream.danger-button wire:click="confirmAction" class="ml-3">
            {{ __('Confirm') }}
        </x-jetstream.danger-button>
    </x-slot>
</x-jetstream.dialog-modal>
```

**Key Patterns:**
- Destructive actions use `danger-button`
- Include warning text and action details
- Use `$set('property', value)` for simple state changes

#### Preview Modal with Iframe
```html
<x-jetstream.dialog-modal wire:model.live="showPreviewModal" wire:key="showPreviewModal" maxWidth="2xl">
    <x-slot name="title">
        {{ __('Preview') }}
    </x-slot>

    <x-slot name="content">
        <div class="space-y-6">
            <!-- Mobile-sized preview frame -->
            <div class="flex justify-center">
                <div class="border border-gray-300 rounded-3xl overflow-hidden bg-white shadow-inner shadow-2xl" style="width: 322px; height: 570px;">
                    <iframe
                        srcdoc="{!! e($previewHtml) !!}"
                        style="width:100%;height:100%;border:0;background:#f4f4f4;"
                    ></iframe>
                </div>
            </div>

            <!-- Additional content below preview -->
            <div class="border-t border-gray-200 pt-6">
                <h3 class="text-sm font-medium text-gray-700 mb-3">{{ __('Additional Options') }}</h3>
                <!-- More content here -->
            </div>
        </div>
    </x-slot>

    <x-slot name="footer">
        <x-jetstream.secondary-button wire:click="closePreview">
            {{ __('Close') }}
        </x-jetstream.secondary-button>
    </x-slot>
</x-jetstream.dialog-modal>
```

**Key Patterns:**
- Mobile preview: `width: 322px; height: 570px` in `rounded-3xl` container
- Sections separated by: `border-t border-gray-200 pt-6`
- Section headers: `text-sm font-medium text-gray-700 mb-3`

### Form Elements

#### Standard Input with Label
```html
<div>
    <label class="block text-sm text-gray-700 mb-2">
        {{ __('Field Label') }}
    </label>
    <x-input
        wire:model="fieldName"
        type="text"
        placeholder="{{ __('Enter value') }}"
        class="w-full"
    />
    @error('fieldName')
        <p class="mt-1 text-sm text-red-600">{{ $message }}</p>
    @enderror
</div>
```

**Key Patterns:**
- Label: `block text-sm text-gray-700 mb-2`
- Error message: `mt-1 text-sm text-red-600`
- Always include `@error` directives below inputs

#### Checkbox with Label
```html
<label class="flex items-center space-x-3">
    <input
        type="checkbox"
        wire:model="fieldName"
        class="rounded border-gray-300 text-theme-brand shadow-sm focus:border-theme-brand focus:ring focus:ring-theme-brand focus:ring-opacity-50"
    >
    <span class="text-sm text-gray-700">
        {{ __('Option label') }}
    </span>
</label>
```

**Key Patterns:**
- Container: `flex items-center space-x-3`
- Checkbox classes: `rounded border-gray-300 text-theme-brand shadow-sm focus:border-theme-brand focus:ring focus:ring-theme-brand focus:ring-opacity-50`
- Label text: `text-sm text-gray-700`

#### Info Box Pattern
```html
<div class="mt-4 p-3 bg-theme-surface rounded-md border border-theme-border">
    <p class="text-sm text-theme-primary">
        <strong>{{ __('Label:') }}</strong> {{ $value }}
    </p>
    <p class="text-sm text-theme-secondary mt-1">
        {{ __('Additional information text.') }}
    </p>
</div>
```

**Key Patterns:**
- Container: `p-3 bg-theme-surface rounded-md border border-theme-border`
- Primary text: `text-sm text-theme-primary`
- Secondary text: `text-sm text-theme-secondary mt-1`

### Notification Banners and Alerts

#### Informational Banner (Grayscale)
```html
<div class="mb-6 rounded-md bg-gray-50 border border-gray-300 p-4">
    <div class="flex">
        <div class="flex-shrink-0">
            <svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
                <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z" clip-rule="evenodd" />
            </svg>
        </div>
        <div class="ml-3">
            <h3 class="text-sm font-medium text-gray-800">
                {{ __('Banner Heading') }}
            </h3>
            <div class="mt-2 text-sm text-gray-600">
                <p>
                    {{ __('Informational message content goes here. This is a neutral notification.') }}
                </p>
            </div>
        </div>
    </div>
</div>
```

**Key Patterns:**
- Background: `bg-gray-50` (professional, non-alarming)
- Border: `border border-gray-300` (subtle, matches table styling)
- Icon: `h-5 w-5 text-gray-400` (muted)
- Heading: `text-sm font-medium text-gray-800`
- Body text: `text-sm text-gray-600`
- Use for: maintenance notices, informational messages, neutral alerts

#### Warning Banner (Grayscale with Warning Icon)
```html
<div class="mb-6 rounded-md bg-gray-50 border border-gray-300 p-4">
    <div class="flex">
        <div class="flex-shrink-0">
            <svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
                <path fill-rule="evenodd" d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd" />
            </svg>
        </div>
        <div class="ml-3">
            <h3 class="text-sm font-medium text-gray-800">
                {{ __('Site Under Maintenance') }}
            </h3>
            <div class="mt-2 text-sm text-gray-600">
                <p>
                    {{ __('The site is currently undergoing maintenance. Only users with administrator access can log in at this time.') }}
                </p>
            </div>
        </div>
    </div>
</div>
```

**Key Patterns:**
- Same styling as informational banner
- Use warning triangle icon for cautionary messages
- Keep grayscale to avoid alarm
- Use for: system notices, maintenance messages, non-critical warnings

#### Error Message (Red)
```html
<div class="mb-4 rounded-md bg-red-50 border border-red-200 p-4">
    <div class="flex">
        <div class="flex-shrink-0">
            <svg class="h-5 w-5 text-red-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
                <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z" clip-rule="evenodd" />
            </svg>
        </div>
        <div class="ml-3">
            <div class="text-sm text-red-800">
                <p>{{ __('Login is currently disabled due to site maintenance.') }}</p>
            </div>
        </div>
    </div>
</div>
```

**Key Patterns:**
- Background: `bg-red-50`
- Border: `border border-red-200`
- Icon: `h-5 w-5 text-red-400` (X circle for errors)
- Text: `text-sm text-red-800`
- Use for: actual errors, failed actions, critical issues

#### Success Message (Green)
```html
<div class="mb-4 rounded-md bg-green-50 border border-green-200 p-4">
    <div class="flex">
        <div class="flex-shrink-0">
            <svg class="h-5 w-5 text-green-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
                <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" />
            </svg>
        </div>
        <div class="ml-3">
            <div class="text-sm text-green-800">
                <p>{{ __('Your changes have been saved successfully.') }}</p>
            </div>
        </div>
    </div>
</div>
```

**Key Patterns:**
- Background: `bg-green-50`
- Border: `border border-green-200`
- Icon: `h-5 w-5 text-green-400` (checkmark circle)
- Text: `text-sm text-green-800`
- Use for: successful operations, confirmations

**Banner/Alert Usage Guidelines:**
- **Grayscale**: Default for informational, maintenance, or neutral system messages
- **Red**: Only for actual errors or failed actions
- **Green**: Only for successful completions
- **Yellow**: Avoid; use grayscale for warnings instead (more professional)
- Icon size: Always `h-5 w-5`
- Icon position: Always in flex-shrink-0 container with `ml-3` for text
- Common SVG icons: info circle, warning triangle, X circle, checkmark circle

### Buttons and Actions

#### Button Component Usage
```html
<!-- Primary action button -->
<x-jetstream.button wire:click="action" class="bg-theme-brand hover:bg-opacity-80">
    {{ __('Primary Action') }}
</x-jetstream.button>

<!-- Secondary action button -->
<x-jetstream.secondary-button wire:click="action" title="{{ __('Tooltip') }}">
    <x-icon class="h-5 w-5" name="icon-name" />
</x-jetstream.secondary-button>

<!-- Danger/destructive button -->
<x-jetstream.danger-button wire:click="delete" :disabled="$isDisabled">
    <x-icon class="mr-3 h-5 w-5" name="trash" />
    {{ __('Delete') }}
</x-jetstream.danger-button>

<!-- Light button (for pagination, filters) -->
<x-jetstream.light-button wire:click="action">
    {{ __('Light Action') }}
</x-jetstream.light-button>
```

**Key Patterns:**
- Primary buttons: `bg-theme-brand hover:bg-opacity-80`
- Icon-only buttons: use `title` attribute for accessibility
- Icons with text: `mr-3` for spacing
- Icon size: `h-5 w-5` (standard), `h-6 w-6` (large)
- Use `:disabled` for reactive disable state

#### Loading State Pattern
```html
<x-jetstream.button
    wire:click="action"
    wire:loading.attr="disabled"
    wire:target="action"
    class="bg-theme-brand">
    <span wire:loading.remove wire:target="action">
        {{ __('Submit') }}
    </span>
    <span wire:loading wire:target="action">
        {{ __('Processing...') }}
    </span>
</x-jetstream.button>
```

OR with spinner:

```html
<x-jetstream.secondary-button wire:click="action">
    <span wire:loading.remove wire:target="action">
        <x-icon class="h-5 w-5" name="icon-name" />
    </span>
    <span wire:loading wire:target="action">
        <svg class="animate-spin h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
            <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
            <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
        </svg>
    </span>
</x-jetstream.secondary-button>
```

**Key Patterns:**
- Use `wire:loading.attr="disabled"` to prevent double-clicks
- Use `wire:target` to scope loading state to specific action
- Provide text feedback OR spinner during loading
- Spinner classes: `animate-spin h-5 w-5 text-white`

### Spacing and Layout

#### Standard Spacing Scale
- **Section spacing:** `mt-12` (top margin for major sections)
- **Element spacing:** `mb-6` (bottom margin for groups), `mb-4` (between related items)
- **Inline spacing:** `space-x-1` (tight), `space-x-3` (standard), `mr-3` (icon before text)
- **Content spacing:** `space-y-6` (form sections), `space-y-3` (form fields)
- **Padding:** `p-3` (small boxes), `p-6` (standard), `p-12` (page content)

## Styling Best Practices

### 1. Use Theme-Aware Classes

✅ **Recommended:**
```html
<div class="bg-theme-brand text-theme-text-primary">
<button class="border-primary-300 bg-theme-surface hover:bg-primary-50">
<header class="bg-primary-900 text-white">
```

❌ **Avoid:**
```html
<div class="bg-black text-gray-900">
<button class="border-gray-300 bg-white hover:bg-gray-50">  
<header class="bg-gray-900 text-white">
```

### 2. Consistent Component Styling

#### Form Components
```html
<input class="border border-primary-300 bg-theme-background rounded-md shadow-sm focus:border-primary-500">
<select class="border border-primary-300 bg-theme-background rounded-md">
```

#### Cards and Surfaces  
```html
<div class="bg-theme-surface rounded-lg shadow border border-primary-200">
<div class="bg-theme-background p-6 rounded-md">
```

#### Headers and Navigation
```html
<header class="bg-theme-brand text-white">
<nav class="bg-primary-900 text-theme-text-primary">
```

### 3. Semi-Transparent Overlays

Use modern Tailwind opacity syntax for better performance:

```html
<!-- Recommended -->
<div class="bg-theme-brand/60">        <!-- 60% opacity -->
<div class="bg-primary-500/25">        <!-- 25% opacity -->

<!-- Avoid -->
<div class="bg-theme-brand bg-opacity-60">
<div class="bg-primary-500 bg-opacity-25">
```

### 4. Logo and Icon Theming

SVG elements should use theme-aware classes:

```html
<svg class="fill-theme-logo w-8 h-8">
  <!-- SVG paths automatically use theme logo color -->
</svg>

<i class="text-theme-logo text-xl"></i>  <!-- Icon fonts -->
```

## Component-Specific Guidelines

### Amount Input Component
Unified wrapper approach for multi-part inputs:
```html
<div class="amount-wrapper flex items-center rounded-md border border-primary-300 bg-theme-background shadow-sm overflow-hidden {{ $maxLengthHoursInput > 4 ? 'w-full' : 'w-40' }}">
  <span class="text-theme-text-secondary">€</span>
  <input class="border-0 focus:ring-0">
</div>
```

### Event Cards  
Full-height cards with image backgrounds:
```html
<div class="relative flex h-[430px] flex-col justify-end bg-theme-background">
  <!-- Image background -->
  <div class="absolute inset-0 z-0 h-full w-full">
    <img class="absolute inset-0 z-0 h-full w-full object-cover">
  </div>
  
  <!-- Semi-transparent overlay -->
  <div class="absolute inset-0 z-10 bg-black/50"></div>
  
  <!-- Fallback gradient -->
  <div class="absolute inset-0 z-0 bg-gradient-to-br from-theme-secondary to-theme-brand"></div>
  
  <!-- Content -->
  <div class="relative z-20 p-14 text-white">
    <h2 class="text-4xl font-semibold">Event Title</h2>
  </div>
</div>
```

## Typography System

### Font Family Configuration
Access theme fonts using helper functions:

```php
// In PHP/Livewire components
$bodyFont = theme_font('font_family_body');     // 'Roboto, sans-serif'
$headingFont = theme_font('font_family_heading'); // 'Oswald, sans-serif'  
$quoteFont = theme_font('font_family_quote');   // 'Georgia, serif' (Yellow theme)
```

### Text Transform Rules
- **Timebank_cc**: Uppercase headings (`heading_transform: 'uppercase'`)
- **Other themes**: Normal case headings (`heading_transform: 'none'`)

```php
// Conditional styling based on theme
if (is_theme('timebank_cc')) {
    $headingClass = 'uppercase';
} else {
    $headingClass = 'normal-case';
}
```

## Development Workflow

### Adding New Theme Colors

1. **Add color to theme configuration** in `config/themes.php`:
```php
'themes' => [
    'theme_name' => [
        'colors' => [
            'new-color' => '#FF0000',           // Single color
            'new-scale' => [                   // Color scale  
                50 => '#FFF5F5',
                500 => '#FF0000',
                900 => '#7F1D1D',
            ],
        ],
    ],
]
```

2. **CSS custom properties are automatically generated** via `theme_css_vars()` function (no manual CSS needed)

3. **Add Tailwind utility classes** in `tailwind.config.js`:
```javascript
colors: {
  'theme-new-color': 'rgb(var(--color-new-color) / <alpha-value>)',
  'new-scale': {
    50: 'rgb(var(--color-new-scale-50) / <alpha-value>)',
    500: 'rgb(var(--color-new-scale-500) / <alpha-value>)',
    900: 'rgb(var(--color-new-scale-900) / <alpha-value>)',
  },
}
```

4. **Create additional CSS utility classes** if needed in `resources/css/app.css`:
```css
.bg-theme-new-color {
  background-color: rgb(var(--color-new-color));
}

.border-new-color-500 {
  border-color: rgb(var(--color-new-scale-500));
}
```

5. **Use in PHP/Livewire components**:
```php
$newColor = theme_color('new-color');        // Returns '#FF0000'
$lightShade = theme_color('new-scale.50');   // Returns '#FFF5F5'
$darkShade = theme_color('new-scale.900');   // Returns '#7F1D1D'
```

### Testing Themes

Test theme functionality using helper functions:

```bash
# Test individual theme colors
TIMEBANK_THEME=timebank_cc php artisan tinker --execute="echo 'Timebank_cc primary: ' . theme_color('primary.500');"
TIMEBANK_THEME=uuro php artisan tinker --execute="echo 'Uuro primary: ' . theme_color('primary.500');"
TIMEBANK_THEME=vegetable php artisan tinker --execute="echo 'Vegetable primary: ' . theme_color('primary.500');"
TIMEBANK_THEME=yellow php artisan tinker --execute="echo 'Yellow primary: ' . theme_color('primary.500');"

# Test theme metadata
php artisan tinker --execute="echo 'Current theme: ' . theme_name() . ' (' . theme_id() . ')';"

# Test theme-specific colors
TIMEBANK_THEME=uuro php artisan tinker --execute="echo 'Uuro success: ' . theme_color('success');"
TIMEBANK_THEME=vegetable php artisan tinker --execute="echo 'Vegetable surface_alt: ' . theme_color('surface_alt');"

# Test typography
php artisan tinker --execute="echo 'Body font: ' . theme_font('font_family_body');"

# Required after config changes
php artisan config:clear
```

### Environment Setup  

```bash
# Set theme in .env file
TIMEBANK_THEME=uuro

# Clear Laravel config cache (required after .env changes)
php artisan config:clear

# Rebuild frontend assets with theme
npm run build
```

### Theme Switching Workflow

```bash
# Switch to different theme
echo "TIMEBANK_THEME=vegetable" >> .env

# Clear caches
php artisan config:clear
php artisan view:clear

# Rebuild assets
npm run build

# Test theme colors
php artisan tinker --execute="echo theme_name() . ': ' . theme_color('primary.500');"
```

## File Structure

```
config/
  themes.php                           # Main theme configuration file
  
app/  
  Helpers/
    ThemeHelper.php                    # Theme helper functions and utilities
    
resources/
  css/
    app.css                           # CSS custom properties and utility classes
  views/
    layouts/
      app.blade.php                   # Theme data-attribute integration
    components/
      jetstream/
        application-logo.blade.php    # Theme-aware main logo
        authentication-card-logo.blade.php  # Theme-aware auth logo
        
tailwind.config.js                   # Tailwind theme color integration
references/
  THEME_IMPLEMENTATION.md            # Detailed implementation documentation
```

## Migration from Hard-coded Styles

### 1. Identify Hard-coded Colors

**Class Name Conversions:**
- `bg-black` → `bg-theme-brand`
- `text-gray-900` → `text-theme-text-primary`
- `border-gray-300` → `border-primary-300`  
- `bg-white` → `bg-theme-background`
- `bg-gray-50` → `bg-theme-surface`

### 2. Use Theme Helper Functions in PHP

Replace hard-coded values with theme helpers:

```php
// Before: Hard-coded values
$primaryColor = '#999B9C';
$backgroundColor = '#FFFFFF';
$textColor = '#111827';

// After: Theme helpers
$primaryColor = theme_color('primary.500');
$backgroundColor = theme_color('background');  
$textColor = theme_color('text.primary');
```

### 3. Conditional Theme Logic

Handle theme-specific differences:

```php
// Theme-specific behavior
if (is_theme('vegetable')) {
    $surfaceColor = theme_color('surface_alt');  // Light beige
    $lineHeight = theme_font('line_height_base'); // 1.8 for readability
} else {
    $surfaceColor = theme_color('surface');      // Standard surface
    $lineHeight = theme_font('line_height_base'); // Theme default
}

// Theme-specific status colors
if (is_theme('uuro')) {
    $successColor = theme_color('success');      // Vivid green cyan
    $dangerColor = theme_color('danger');        // Vivid red
} else {
    $successColor = '#22c55e';                   // Fallback green
    $dangerColor = '#ef4444';                    // Fallback red
}
```

### 4. Component Migration Process

1. **Audit component** for hard-coded colors and styles
2. **Replace classes** with theme-aware equivalents
3. **Add PHP logic** for theme-specific behavior using helper functions
4. **Test across all themes** using environment variable switching
5. **Verify accessibility** and contrast ratios

## Accessibility Guidelines

### Color Contrast Requirements
- Maintain WCAG AA contrast ratios (4.5:1) across all themes
- Test text readability on all background combinations
- Verify logo visibility on different header backgrounds

### Theme Testing Checklist
- [ ] Form elements clearly distinguishable in all themes
- [ ] Focus states visible with theme colors
- [ ] Error states readable with theme danger colors  
- [ ] Interactive elements have sufficient contrast
- [ ] Logo/icons visible on theme backgrounds

## Performance Considerations

### CSS Custom Properties Benefits
- Efficient theme switching without rebuilding CSS
- Single CSS bundle supports all themes  
- Runtime theme changes possible (if needed)
- Excellent browser support and performance

### Optimization Guidelines
- Use shared utility classes when possible
- Minimize theme-specific CSS overrides
- Leverage Tailwind's purging for unused theme classes
- Keep theme configurations lean and focused

### Build Performance
- Themes are compiled at build time for optimal performance
- CSS custom properties enable single bundle for all themes
- No runtime theme computation overhead