## Layouts: The Page Wrapper System

**Layouts** are special templates that wrap all page HTML. They are similar to snippets but serve as the complete HTML document structure.

### Layout vs Snippet

| Feature | Layout | Snippet |
|---------|--------|---------|
| **Purpose** | Complete HTML document wrapper | Reusable component |
| **Structure** | Full `<html>`, `<head>`, `<body>` | Partial HTML fragment |
| **Special Drops** | `{{ html5 }}`, `{{ content_for_layout }}` | Standard Liquid drops |
| **Page Relationship** | One layout per page | Many snippets per page |
| **Grid Invocation** | Via `content_for_layout` | Via `{% snippet %}` tag |

### Special Layout Drops

#### 1. `{{ html5 }}` - HTML5 Document Tags

Modyo provides the `html5` drop to generate proper HTML5 opening and closing tags:

```liquid
{{ html5.open_tag }}
<!-- Renders: <!DOCTYPE html><html> -->

{{ html5.close_tag }}
<!-- Renders: </html> -->
```

**Why use this?** Modyo can inject metadata, language attributes, and other required HTML attributes automatically.

#### 2. `{{ content_for_layout }}` - Page Content Placeholder

This is the **critical drop** that renders page-specific content within the layout:

```liquid
<body>
  {% snippet 'header' %}

  <main>
    {{ content_for_layout }}  <!-- Page content renders here -->
  </main>

  {% snippet 'footer' %}
</body>
```

**What `content_for_layout` does**:
1. Determines the page's `grid_type` (e.g., "full_grid", "full_three_cols_grid")
2. Invokes the corresponding grid snippet (e.g., `{% snippet 'full_grid' %}`)
3. Grid snippet receives `page_grid` object with widgets organized by column
4. Grid snippet loops through columns and renders widgets

### Complete Layout Structure

Here's a typical Modyo layout with all components:

```liquid
{{ html5.open_tag }}
<head>
  {% snippet 'head' %}
  {% snippet 'head_tag_manager' %}
  {% snippet 'seo' %}

  <!-- Custom head content -->
  <link rel="stylesheet" href="{{ site.url }}/assets/styles.css">
</head>

<body>
  {% snippet 'body_tag_manager' %}
  {% snippet 'header' %}

  <main class="main-content">
    {{ content_for_layout }}  <!-- Grid snippet renders here -->
  </main>

  {% snippet 'footer' %}
  {% snippet 'notifications_html' %}

  <!-- Custom scripts -->
  <script src="{{ site.url }}/assets/main.js"></script>
</body>
{{ html5.close_tag }}
```

### The `content_for_layout` Rendering Process

Understanding this process is **essential** for understanding Modyo's rendering engine:

```
┌─────────────────────────────────────────────────────────────┐
│ 1. Layout renders with {{ content_for_layout }}             │
└─────────────────────┬───────────────────────────────────────┘
                      │
                      ▼
┌─────────────────────────────────────────────────────────────┐
│ 2. Modyo checks page.grid_type (e.g., "full_three_cols_grid")│
└─────────────────────┬───────────────────────────────────────┘
                      │
                      ▼
┌─────────────────────────────────────────────────────────────┐
│ 3. Modyo invokes matching grid snippet:                     │
│    {% snippet 'full_three_cols_grid' %}                     │
└─────────────────────┬───────────────────────────────────────┘
                      │
                      ▼
┌─────────────────────────────────────────────────────────────┐
│ 4. Grid snippet receives page_grid object:                  │
│    - page_grid.column_0 = [widget1, widget2]               │
│    - page_grid.column_1 = [widget3]                        │
│    - page_grid.column_2 = [widget4, widget5]               │
└─────────────────────┬───────────────────────────────────────┘
                      │
                      ▼
┌─────────────────────────────────────────────────────────────┐
│ 5. Grid snippet loops through columns:                      │
│    {% for widget in page_grid.column_0 %}                  │
│      {% snippet widget %}                                   │
│    {% endfor %}                                             │
└─────────────────────┬───────────────────────────────────────┘
                      │
                      ▼
┌─────────────────────────────────────────────────────────────┐
│ 6. Widget snippet determines type and renders:              │
│    - custom_widget → checks widget.sync                    │
│    - rich_text_widget → renders HTML                       │
│    - text_widget → renders text                            │
└─────────────────────────────────────────────────────────────┘
```

### Layout + Page + Grid Integration

**Example**: Page with `grid_type: "full_three_cols_grid"`

**Layout** (`layouts/default.liquid`):
```liquid
{{ html5.open_tag }}
<head>
  {% snippet 'head' %}
</head>
<body>
  {% snippet 'header' %}
  <main>
    {{ content_for_layout }}  <!-- Triggers grid rendering -->
  </main>
  {% snippet 'footer' %}
</body>
{{ html5.close_tag }}
```

**Page Configuration**:
```typescript
{
  name: "Homepage",
  path: "/",
  grid_type: "full_three_cols_grid",  // Determines which grid snippet
  layout: "default",                   // Uses layouts/default.liquid
  widgets: [
    { column: 0, position: 0, type: "custom_widget" },
    { column: 1, position: 0, type: "custom_widget" },
    { column: 2, position: 0, type: "rich_text" }
  ]
}
```

**Grid Snippet** (`snippets/grids/full_three_cols_grid.liquid`):
```liquid
<div class="row">
  <div class="col-md-4">
    {% for widget in page_grid.column_0 %}
      {% snippet widget %}
    {% endfor %}
  </div>
  <div class="col-md-4">
    {% for widget in page_grid.column_1 %}
      {% snippet widget %}
    {% endfor %}
  </div>
  <div class="col-md-4">
    {% for widget in page_grid.column_2 %}
      {% snippet widget %}
    {% endfor %}
  </div>
</div>
```

**Final HTML Output**:
```html
<!DOCTYPE html>
<html>
<head>
  <!-- head snippet content -->
</head>
<body>
  <!-- header snippet content -->
  <main>
    <div class="row">
      <div class="col-md-4">
        <!-- widget in column 0 -->
      </div>
      <div class="col-md-4">
        <!-- widget in column 1 -->
      </div>
      <div class="col-md-4">
        <!-- widget in column 2 -->
      </div>
    </div>
  </main>
  <!-- footer snippet content -->
</body>
</html>
```

### The `page_grid` Object

When `content_for_layout` invokes a grid snippet, Modyo constructs the `page_grid` object by organizing widgets:

```typescript
// Modyo internally builds page_grid from page.widgets
page_grid = {
  id: 12345,
  cache_key: "grid_12345_v2",

  // Single column grids
  main_widgets: [widget1, widget2, widget3],  // All widgets

  // Multi-column grids
  column_0: [widget1, widget4],  // Widgets where column === 0
  column_1: [widget2, widget5],  // Widgets where column === 1
  column_2: [widget3, widget6],  // Widgets where column === 2

  // Sidebar grids
  sidebar: [widget7, widget8]    // Sidebar widgets
}
```

**Widget positioning rules**:
- Widgets sorted by `position` within each column
- `column` value must match grid type's available columns
- Example: `full_grid` only allows `column: 0`, `full_three_cols_grid` allows `column: 0, 1, 2`

### Base Snippets in Layouts

Layouts typically include **base shared snippets** that are used across all pages:

#### `shared/general/head` Snippet
```liquid
<!-- snippets/shared/general/head.liquid -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ page.title }} - {{ site.name }}</title>
<meta name="description" content="{{ page.description }}">

<!-- Favicon -->
<link rel="icon" href="{{ site.favicon }}">

<!-- Site CSS -->
<link rel="stylesheet" href="{{ site.url }}/assets/main.css">
```

**Usage in layout**:
```liquid
<head>
  {% snippet 'head' %}  <!-- Includes base meta tags -->
  <!-- Additional custom head content -->
</head>
```

### Layout Management via Tools

Layouts are managed like other templates:

```typescript
// List layouts
template-list-layouts({ platformSlug, siteId })

// Get layout
template-get({ platformSlug, siteId, templateId })

// Create layout
template-create({
  platformSlug,
  siteId,
  name: "custom_layout",
  type: "layout",
  body: "{{ html5.open_tag }}..."
})

// Update layout
template-update({ platformSlug, siteId, templateId, template: { body } })
```

### Layout Types

Modyo supports multiple layout types for different page purposes:

| Layout Type | Purpose | Example Use Case |
|------------|---------|------------------|
| `default` | Standard pages | Homepage, about, contact |
| `content` | Content pages | Blog posts, articles |
| `error` | Error pages | 404, 500 errors |
| `custom` | Custom layouts | Landing pages, campaigns |

**Assigning layout to page**:
```typescript
page-create({
  name: "Homepage",
  path: "/",
  layout: "default",  // Uses layouts/default.liquid
  grid_type: "full_grid"
})
```

### Error Layouts and Templates

**Error Layout** (`layouts/site/error.html.liquid`)

The error layout is a special layout that renders error templates through `{{ content_for_layout }}`. Unlike standard layouts that render pages, error layouts render error templates.

**Structure**:
```liquid
{% html5 %}
<head>
  {% snippet 'shared/general/head' %}
</head>

{% body %}
<div id="modyo-site-alert-wrapper"></div>

{{ content_for_layout }}  <!-- Renders error templates here -->

{% endbody %}

{% endhtml5 %}
```

**Key Principle**: Error layouts should stay simple and minimal - all error-specific styling should be in the error templates themselves.

**Error Templates**

Error templates are rendered BY the error layout when specific error conditions occur. They contain the actual error content and styling.

| Template | Path | When Displayed | Template ID (Example) |
|----------|------|----------------|----------------------|
| **Disabled** | `site/errors/disabled.html.liquid` | Site administratively disabled | 560803 |
| **404 Not Found** | `site/custom/404.html.liquid` | Page not found | - |
| **Template Error** | `site/errors/template.html.liquid` | Liquid rendering error | - |

#### Disabled Error Template Design

The disabled error template uses a highly disruptive emergency alert aesthetic to clearly communicate that the site is inaccessible.

**Design Principles**:
- **High Contrast**: Dark red/black backgrounds with bright danger colors
- **Multiple Animations**: 8 simultaneous animations create urgency
- **Clear Messaging**: Unambiguous "SITE DISABLED" communication
- **Emergency Theme**: Warning stripes, pulsing borders, shaking icons
- **Professional**: Despite disruption, maintains modern aesthetic

**Visual Components**:
```
error-disabled-page (main container)
├── warning-stripes (animated background hazard pattern)
├── disabled-container (main content box)
│   ├── warning-icon (animated SVG exclamation)
│   ├── disabled-title ("SITE DISABLED")
│   ├── disabled-subtitle ("Access Temporarily Suspended")
│   ├── disabled-message (explanation text)
│   ├── status-bars (3 animated loading bars)
│   └── contact-info (admin contact message)
```

**Color Palette**:
- Background gradient: `#1a0000 → #330000` (dark red)
- Danger red: `#ff0000` (title, borders, glows)
- Warning yellow: `#ffc800` (icon, subtitle)
- Container: `rgba(0, 0, 0, 0.8)` (pure black)
- Body text: `rgba(255, 255, 255, 0.9)` (white)

**Animation System** (8 animations):
1. **danger-pulse** (3s): Pulsing radial gradients on background
2. **stripes-move** (20s): Diagonal hazard stripes slide continuously
3. **container-flash** (2s): Border color and glow intensity pulse
4. **icon-shake** (0.5s): Warning icon rotates ±5 degrees
5. **circle-pulse** (1.5s): SVG stroke width pulses 4px → 6px
6. **text-blink** (1s): Exclamation mark flashes on/off
7. **title-glitch** (3s): Random position shifts with cyan/magenta aberration
8. **subtitle-fade** (2s): Opacity fades 100% → 50%

**Typography**:
```css
/* Title */
font-size: clamp(2.5rem, 8vw, 5rem);
font-weight: 900;
color: #ff0000;
letter-spacing: 0.5rem;
text-shadow: 0 0 20px rgba(255, 0, 0, 0.8),
             0 0 40px rgba(255, 0, 0, 0.5),
             0 0 60px rgba(255, 0, 0, 0.3);

/* Subtitle */
font-size: clamp(1.25rem, 3vw, 2rem);
font-weight: 700;
color: #ffc800;
letter-spacing: 0.3rem;
```

**Responsive Design**:
- Breakpoint: 768px
- Desktop: 150px icon, 4rem padding, full letter spacing
- Mobile: 100px icon, 3rem padding, reduced letter spacing

**Accessibility**:
```css
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
```

**CSP Compliance**:
```html
<style nonce="{{csp_nonce}}">
  /* All inline styles use nonce attribute */
</style>
```

**Technical Features**:
- Inline SVG for performance (no external requests)
- GPU-accelerated animations (transform/opacity)
- No JavaScript dependency
- Zero external dependencies
- ~7KB file size including all styles

**Testing Disabled State**:
1. Navigate to Site Settings → General
2. Toggle "Site Enabled" to OFF
3. Visit site URL
4. Disabled template displays

**Related Documentation**:
- Full implementation: [DISABLED_ERROR_TEMPLATE.md](DISABLED_ERROR_TEMPLATE.md)
- Template management: [src/tools/channels/templates/CLAUDE.md](../src/tools/channels/templates/CLAUDE.md)

---
