# CSS Organization Guide for Modyo

> **Critical Guide**: Understanding when to use CSS templates vs snippets is essential for proper CSS organization in Modyo. This guide addresses the most common architecture mistake.

---

## Table of Contents

1. [The Problem: CSS Templates vs Snippets](#the-problem-css-templates-vs-snippets)
2. [When to Use CSS Templates](#when-to-use-css-templates)
3. [When to Use CSS Snippets](#when-to-use-css-snippets)
4. [Recommended Architecture](#recommended-architecture)
5. [Component Naming Conventions](#component-naming-conventions)
6. [Implementation Examples](#implementation-examples)
7. [Common Mistakes](#common-mistakes)

---

## The Problem: CSS Templates vs Snippets

### ⚠️ Critical Issue Discovered (Iteration 11)

**CSS templates CANNOT include Liquid snippet references** because:
- CSS/JS templates are served from CDN
- Liquid preprocessing happens before CDN caching
- `{% snippet 'name' %}` tags are **stripped out** during CDN processing
- Result: Empty CSS file, no styles applied

### ❌ WRONG Pattern

```liquid
<!-- globals.css (CSS template) -->
{% snippet 'footer_css' %}  <!-- THIS GETS STRIPPED OUT -->
{% snippet 'header_css' %}  <!-- THIS GETS STRIPPED OUT -->

/* Actual CSS */
body { margin: 0; }
```

**Result**: The snippet includes are removed, only `body { margin: 0; }` remains.

### ✅ CORRECT Pattern

```liquid
<!-- In head snippet or layout -->
{{ 'globals' | asset_url: 'css' | stylesheet_tag: media: 'screen', nonce: csp_nonce }}
{% snippet 'footer_css' %}
{% snippet 'header_css' %}
{{ 'base' | asset_url: 'css' | stylesheet_tag: media: 'screen', nonce: csp_nonce }}
```

---

## When to Use CSS Templates

### Use CSS Templates For:

✅ **Global stylesheets** that need CDN caching:
- `root.css` - CSS variables and design tokens
- `base.css` - Base styles (typography, resets, utilities)
- `theme.css` - Theme-specific styles
- `layout.css` - Grid systems and layout utilities

✅ **Pure CSS without Liquid logic**:
- No variables, no conditionals, no loops
- Static styles that don't change per request

✅ **Styles that benefit from CDN edge caching**:
- Large CSS files (Bootstrap, vendor libraries)
- Rarely-changing styles

### How to Reference CSS Templates

```liquid
<!-- In head snippet -->
{{ 'root' | asset_url: 'css' | stylesheet_tag: media: 'screen', nonce: csp_nonce }}
{{ 'base' | asset_url: 'css' | stylesheet_tag: media: 'screen', nonce: csp_nonce }}
```

### Creating CSS Templates

```typescript
// Using MCP tools
mcp__modyo-mcp__template-create({
  platformSlug: "fed-team",
  siteId: 4612,
  name: "globals",
  type: "css",
  body: "/* Global styles */\nbody { margin: 0; }"
})
```

---

## When to Use CSS Snippets

### Use CSS Snippets For:

✅ **Component-specific styles**:
- Footer styles (`footer_css`)
- Header styles (`header_css`)
- Navigation styles (`navigation_css`)
- Widget-specific styles

✅ **Styles that need CSP nonce**:
- All inline `<style>` tags must include nonce
- CSS snippets can use `{{csp_nonce}}` template variable
- CSS templates cannot (CDN-served, no dynamic content)

✅ **Styles with Liquid logic**:
- Conditional styles based on site settings
- Dynamic values from content
- User-specific styling

✅ **Server-rendered component styles**:
- Styles for header, footer, widgets that render on server
- Styles that need access to Liquid drops (user, session, content)

### How to Create CSS Snippets

```typescript
// Using MCP tools
mcp__modyo-mcp__template-create({
  platformSlug: "fed-team",
  siteId: 4612,
  name: "footer_css",
  type: "snippet",
  body: `<style nonce="{{csp_nonce}}">
/* Footer-specific styles */
.footer-accordion .accordion-button {
  background: linear-gradient(135deg, #002a8d 0%, #004bb5 100%);
  color: white;
}
</style>`
})
```

### How to Reference CSS Snippets

```liquid
<!-- In head snippet -->
{% snippet 'footer_css' %}
{% snippet 'header_css' %}
{% snippet 'navigation_css' %}
```

---

## Recommended Architecture

### Complete CSS Loading Order

```liquid
<!-- In head snippet (_head.html.liquid) -->

<!-- 1. Root CSS Variables (CSS template) -->
{{ 'root' | asset_url: 'css' | stylesheet_tag: media: 'screen', nonce: csp_nonce }}

<!-- 2. Global Utility CSS (CSS template, optional) -->
{{ 'globals' | asset_url: 'css' | stylesheet_tag: media: 'screen', nonce: csp_nonce }}

<!-- 3. Component-Specific CSS (Snippets) -->
{% snippet 'header_css' %}
{% snippet 'navigation_css' %}
{% snippet 'footer_css' %}
<!-- Add more component snippets as needed -->

<!-- 4. Base Styles (CSS template) -->
{{ 'base' | asset_url: 'css' | stylesheet_tag: media: 'screen', nonce: csp_nonce }}

<!-- 5. Page-specific CSS (if needed) -->
{% if template == 'home' %}
  {% snippet 'home_css' %}
{% endif %}
```

### Why This Order?

1. **Root first**: CSS variables must be defined before use
2. **Globals**: General utilities and resets
3. **Components**: Specific component styles (can use root variables)
4. **Base**: Core typography and element styles
5. **Page-specific**: Override or extend for specific pages

---

## Component Naming Conventions

### CSS Snippet Naming Pattern

Use `{{component_name}}_css` format:

```
✅ footer_css
✅ header_css
✅ navigation_css
✅ hero_banner_css
✅ product_card_css
✅ sidebar_css
```

### Why This Pattern?

- **Consistent**: Easy to find and maintain
- **Descriptive**: Name indicates purpose
- **Organized**: Groups by component
- **Searchable**: Quick to locate in template list

### CSS Template Naming Pattern

Use descriptive, generic names:

```
✅ root.css
✅ base.css
✅ theme.css
✅ layout.css
✅ utilities.css
```

---

## Implementation Examples

### Example 1: Footer Component CSS

**Step 1: Check if snippet exists**
```typescript
// List snippets to avoid duplicates
mcp__modyo-mcp__template-list({
  platformSlug: "fed-team",
  siteId: 4612,
  type: "snippet"
})
```

**Step 2: Create footer_css snippet**
```typescript
mcp__modyo-mcp__template-create({
  platformSlug: "fed-team",
  siteId: 4612,
  name: "footer_css",
  type: "snippet"
})
```

**Step 3: Add CSS content**
```typescript
mcp__modyo-mcp__template-save({
  platformSlug: "fed-team",
  siteId: 4612,
  templateId: 561234,  // From create response
  body: `<style nonce="{{csp_nonce}}">
/* Footer Styles */
.site-footer {
  background: var(--color-primary);
  color: white;
  padding: 3rem 0;
}

.footer-accordion .accordion-button {
  background: linear-gradient(135deg, #002a8d 0%, #004bb5 100%);
  color: white;
  border: none;
}

.footer-accordion .accordion-button:not(.collapsed) {
  background: linear-gradient(135deg, #001f6d 0%, #003a95 100%);
}

@media (max-width: 767px) {
  .site-footer {
    padding: 2rem 0;
  }
}
</style>`
})
```

**Step 4: Reference in head template**
```liquid
<!-- In _head.html.liquid snippet -->
{% snippet 'footer_css' %}
```

**Step 5: Publish both snippets**
```typescript
mcp__modyo-mcp__release-create({
  platformSlug: "fed-team",
  siteId: 4612,
  data: {
    template: [
      { id: 561234, selected: true },  // footer_css
      { id: 560123, selected: true }   // _head
    ]
  }
})
```

### Example 2: Global CSS Variables (CSS Template)

**Step 1: Create root.css template**
```typescript
mcp__modyo-mcp__template-create({
  platformSlug: "fed-team",
  siteId: 4612,
  name: "root",
  type: "css"
})
```

**Step 2: Add CSS variables**
```css
:root {
  /* Colors - Mibanco Style */
  --color-primary: #005596;
  --color-secondary: #0066cc;
  --color-accent: #00a8e8;

  /* Typography */
  --font-family-base: 'Montserrat', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-size-base: 1rem;
  --line-height-base: 1.7;

  /* Spacing */
  --spacing-unit: 0.5rem;
  --spacing-xs: calc(var(--spacing-unit) * 1);
  --spacing-sm: calc(var(--spacing-unit) * 2);
  --spacing-md: calc(var(--spacing-unit) * 3);
  --spacing-lg: calc(var(--spacing-unit) * 4);
  --spacing-xl: calc(var(--spacing-unit) * 6);

  /* Border Radius */
  --radius-sm: 0.25rem;
  --radius-md: 0.5rem;
  --radius-lg: 1rem;
  --radius-full: 9999px;

  /* Shadows */
  --shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.1);
  --shadow-md: 0 4px 8px rgba(0, 0, 0, 0.12);
  --shadow-lg: 0 8px 16px rgba(0, 0, 0, 0.15);
}
```

**Step 3: Reference in head**
```liquid
{{ 'root' | asset_url: 'css' | stylesheet_tag: media: 'screen', nonce: csp_nonce }}
```

### Example 3: Widget-Specific CSS

For widgets, you have two options:

**Option A: Include CSS in widget definition** (best for widget-specific styles)
```typescript
mcp__modyo-mcp__widget-definition-update({
  platformSlug: "fed-team",
  siteId: 4612,
  widgetId: 86891,
  html: "<!-- Widget HTML -->",
  css: `
/* Hero Banner Widget Styles */
.hero-banner {
  min-height: 500px;
  position: relative;
}
`,
  js: ""
})
```

**Option B: Create snippet for shared widget styles**
```liquid
<!-- For styles shared across multiple widgets -->
{% snippet 'widget_common_css' %}
```

---

## Common Mistakes

### ❌ Mistake 1: Trying to Include Snippets in CSS Templates

```liquid
<!-- globals.css (CSS template) -->
{% snippet 'footer_css' %}  <!-- STRIPPED OUT, WON'T WORK -->
```

**Fix**: Reference snippets in HTML head, not in CSS templates.

### ❌ Mistake 2: Missing CSP Nonce in Snippets

```liquid
<!-- footer_css snippet -->
<style>  <!-- WRONG: No nonce, will be blocked by CSP -->
.footer { background: blue; }
</style>
```

**Fix**: Always include nonce:
```liquid
<style nonce="{{csp_nonce}}">
.footer { background: blue; }
</style>
```

### ❌ Mistake 3: Using Snippets for Large Static CSS

```liquid
<!-- base_css snippet with 5000 lines of CSS -->
<style nonce="{{csp_nonce}}">
/* 5000 lines of static CSS... */
</style>
```

**Fix**: Use CSS template for large static files (better CDN caching):
```typescript
// Create as CSS template instead
mcp__modyo-mcp__template-create({
  name: "base",
  type: "css",  // Not snippet
  body: "/* 5000 lines of CSS */"
})
```

### ❌ Mistake 4: Creating Duplicate Snippets

```typescript
// Creating footer_css twice
mcp__modyo-mcp__template-create({ name: "footer_css", type: "snippet" })
mcp__modyo-mcp__template-create({ name: "footer_css", type: "snippet" })  // ERROR or duplicate
```

**Fix**: Always check existence first:
```typescript
// 1. List to check if exists
const templates = await mcp__modyo-mcp__template-list({
  platformSlug: "fed-team",
  siteId: 4612,
  type: "snippet"
})

// 2. Check if footer_css already exists
const exists = templates.some(t => t.name === "footer_css")

// 3. Only create if doesn't exist
if (!exists) {
  await mcp__modyo-mcp__template-create({ name: "footer_css", type: "snippet" })
}
```

### ❌ Mistake 5: Forgetting to Publish Snippets

```typescript
// Created/updated snippet but didn't publish
mcp__modyo-mcp__template-save({ templateId: 123, body: "..." })
// FORGOT TO PUBLISH - changes not visible on site
```

**Fix**: Always publish after changes:
```typescript
// Get publishable elements
const elements = await mcp__modyo-mcp__release-get-elements-to-publish({
  platformSlug: "fed-team",
  siteId: 4612
})

// Publish template(s)
await mcp__modyo-mcp__release-create({
  platformSlug: "fed-team",
  siteId: 4612,
  data: {
    template: elements.templates.filter(t => t.id === 123).map(t => ({ id: t.id, selected: true }))
  }
})
```

---

## Workflow Checklist

When organizing component CSS:

- [ ] ✅ Determine if CSS is component-specific or global
- [ ] ✅ Choose CSS template (global, static) or snippet (component, dynamic)
- [ ] ✅ Check if snippet/template already exists (`template-list`)
- [ ] ✅ Use correct naming convention (`footer_css`, `root.css`)
- [ ] ✅ Include CSP nonce in snippets: `<style nonce="{{csp_nonce}}">`
- [ ] ✅ Reference CSS templates via `asset_url | stylesheet_tag`
- [ ] ✅ Reference snippets via `{% snippet 'name' %}`
- [ ] ✅ Add to head in correct order (root → components → base)
- [ ] ✅ Publish all related templates together
- [ ] ✅ Test on live site to verify styles applied

---

## Quick Reference Table

| Use Case | Solution | Example | CSP Nonce | CDN Cached |
|----------|----------|---------|-----------|------------|
| Global CSS variables | CSS Template | `root.css` | ❌ No | ✅ Yes |
| Base typography | CSS Template | `base.css` | ❌ No | ✅ Yes |
| Footer component | CSS Snippet | `footer_css` | ✅ Yes | ❌ No |
| Header component | CSS Snippet | `header_css` | ✅ Yes | ❌ No |
| Widget styles | Widget CSS Property | In widget definition | N/A | ✅ Yes |
| Conditional styles | CSS Snippet | With Liquid logic | ✅ Yes | ❌ No |

---

## Related Documentation

- [Liquid Best Practices](./LIQUID_BEST_PRACTICES.md) - Liquid syntax and patterns
- [Template Workflows Guide](./TEMPLATE_WORKFLOWS.md) - Safe template editing
- [Widget Workflows Guide](./WIDGET_WORKFLOWS.md) - Widget development patterns
- [Modyo Snippets Architecture](./MODYO_SNIPPETS_ARCHITECTURE.md) - Deep dive into snippet system

---

## Further Reading

- [Modyo Documentation: Templates](https://docs.modyo.com/en/platform/channels/templates.html)
- [CSP Guide](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)
- [CSS Architecture Patterns](https://web.dev/css-architecture/)

---

**Last Updated**: October 23, 2025
**Source**: Iteration 11 findings from mcp-improvements.md
