Layout

Stable

The structural layer between tokens and components. Controls how sections, containers, grids, and stacks arrange content on the page.


The Four-Layer Mental Model

Every page section nests these four layers in order. Each layer has one job and should never do another layer's job.

Pattern — always nest in this order
<section class="vi-section vi-section--subtle">       ← bg color + vertical padding
  <div class="vi-container">                          ← max-width + horizontal gutters
    <div class="vi-grid vi-grid--3">                  ← column structure
      <article class="vi-card vi-card--raised">       ← component
        ...
      </article>
    </div>
  </div>
</section>
The rule

Never put layout responsibilities (margin, padding, width, grid) on a component class. Never put component styles on a layout class. If you're adding margin-top to a vi-card, stop — a layout class should handle that.

vi-section

Full-width horizontal bands. Controls vertical padding and background color. Use <section>, <header>, or <footer> — not <div> when the semantic element applies.

Background variants

vi-section--white
vi-section--subtle
vi-section--dark
vi-section--brand
HTML
<section class="vi-section vi-section--white">...</section>
<section class="vi-section vi-section--subtle">...</section>
<section class="vi-section vi-section--dark">...</section>
<section class="vi-section vi-section--brand">...</section>

Size variants (vertical padding)

vi-section--sm  |  48px top + bottom
vi-section (default)  |  64px top + bottom
vi-section--lg  |  96px top + bottom
HTML
<section class="vi-section vi-section--sm">...</section>
<section class="vi-section">...</section>
<section class="vi-section vi-section--lg">...</section>

vi-container

Centers content and constrains max-width. Always lives inside a vi-section. Never use a container without a section wrapper.

vi-section (full width)
vi-container (max-width, centered)
HTML
<!-- Default: 1200px max-width -->
<div class="vi-container">...</div>

<!-- Narrow: 800px — for blog posts, article text -->
<div class="vi-container vi-container--narrow">...</div>

<!-- Wide: 1440px — for large image layouts -->
<div class="vi-container vi-container--wide">...</div>

vi-section-header

Centered intro block for section headings. Optional — not every section needs one. Place it directly inside vi-container, before the grid.

What We Do

Our Services

We help brands communicate clearly and consistently across every touchpoint, from strategy through execution.

vi-card
vi-card
vi-card
HTML
<section class="vi-section vi-section--subtle">
  <div class="vi-container">

    <div class="vi-section-header">
      <span class="vi-badge vi-badge--brand">What We Do</span>
      <h2 class="vi-section-header__title">Our Services</h2>
      <p class="vi-section-header__text">Supporting copy here.</p>
    </div>

    <div class="vi-grid vi-grid--3">
      <!-- cards go here -->
    </div>

  </div>
</section>

vi-grid

CSS Grid column layouts. Collapses to a single column on mobile. Always lives inside vi-container.

Equal columns

1
2
1
2
3
1
2
3
4
HTML
<div class="vi-grid vi-grid--2">...</div>
<div class="vi-grid vi-grid--3">...</div>
<div class="vi-grid vi-grid--4">...</div>

Asymmetric splits

For hero sections with image + text, or content + sidebar layouts.

Content (2fr)
Sidebar (1fr)
Sidebar (1fr)
Content (2fr)
Content (3fr / 60%)
Image (2fr / 40%)
HTML
<!-- 66% content + 33% sidebar -->
<div class="vi-grid vi-grid--2-1">
  <div>Main content</div>
  <aside>Sidebar</aside>
</div>

<!-- 60% text + 40% image -->
<div class="vi-grid vi-grid--3-2">
  <div class="vi-stack">
    <h2>Heading</h2>
    <p>Copy...</p>
    <a class="vi-btn vi-btn--primary">CTA</a>
  </div>
  <div class="vi-ratio vi-ratio--4-3">
    <img src="..." alt="...">
  </div>
</div>

Auto-fill grid

The browser fills as many columns as fit at a minimum of 280px. Best for card grids where you don't want to worry about breakpoints.

card
card
card
card
card
HTML — auto-fill, no breakpoints needed
<div class="vi-grid vi-grid--auto">
  <!-- fills columns at min 280px — responsive automatically -->
  <article class="vi-card vi-card--raised">...</article>
  <article class="vi-card vi-card--raised">...</article>
  <article class="vi-card vi-card--raised">...</article>
</div>

vi-stack

Adds consistent vertical spacing between sibling elements. Use inside a grid column to space headings, paragraphs, and buttons — no manual margins needed.

Element 1
Element 2
Element 3
vi-stack--sm (16px gap)
Element 1
Element 2
Element 3
vi-stack (24px gap)
Element 1
Element 2
Element 3
vi-stack--lg (32px gap)
HTML — hero column with stack
<div class="vi-grid vi-grid--3-2">

  <!-- Left column: stacked text + CTA -->
  <div class="vi-stack">
    <span class="vi-badge vi-badge--brand">New</span>
    <h1>Page Heading</h1>
    <p>Supporting subtext that describes the value proposition.</p>
    <div class="vi-row">
      <a class="vi-btn vi-btn--primary vi-btn--lg">Get Started</a>
      <a class="vi-btn vi-btn--ghost vi-btn--lg">Learn More</a>
    </div>
  </div>

  <!-- Right column: image -->
  <div class="vi-ratio vi-ratio--4-3">
    <img src="hero.jpg" alt="...">
  </div>

</div>

Full page example

A complete page using every layout layer together. This is the pattern for a typical marketing page or WordPress template.

HTML — full page structure
<!-- HERO -->
<section class="vi-section vi-section--lg vi-section--dark">
  <div class="vi-container">
    <div class="vi-grid vi-grid--3-2">
      <div class="vi-stack">
        <span class="vi-badge vi-badge--info">Now Available</span>
        <h1>We Build Brands That Last</h1>
        <p>Strategy, design, and execution for growing companies.</p>
        <div class="vi-row">
          <a href="/contact" class="vi-btn vi-btn--primary vi-btn--lg">Start a Project</a>
          <a href="/work"    class="vi-btn vi-btn--ghost vi-btn--lg">See Our Work</a>
        </div>
      </div>
      <div class="vi-ratio vi-ratio--4-3">
        <img src="hero.jpg" alt="VI team at work">
      </div>
    </div>
  </div>
</section>

<!-- SERVICES -->
<section class="vi-section vi-section--subtle">
  <div class="vi-container">
    <div class="vi-section-header">
      <span class="vi-badge vi-badge--brand">What We Do</span>
      <h2 class="vi-section-header__title">Our Services</h2>
      <p class="vi-section-header__text">Full-service brand and digital.</p>
    </div>
    <div class="vi-grid vi-grid--3">
      <article class="vi-card vi-card--raised">...</article>
      <article class="vi-card vi-card--raised">...</article>
      <article class="vi-card vi-card--raised">...</article>
    </div>
  </div>
</section>

<!-- RECENT WORK -->
<section class="vi-section vi-section--white">
  <div class="vi-container">
    <div class="vi-section-header vi-section-header--left">
      <h2 class="vi-section-header__title">Recent Work</h2>
      <p class="vi-section-header__text">Selected projects.</p>
    </div>
    <div class="vi-grid vi-grid--auto">
      <article class="vi-card vi-card--raised vi-card--interactive">...</article>
      <article class="vi-card vi-card--raised vi-card--interactive">...</article>
      <article class="vi-card vi-card--raised vi-card--interactive">...</article>
      <article class="vi-card vi-card--raised vi-card--interactive">...</article>
    </div>
  </div>
</section>

<!-- CTA BAND -->
<section class="vi-section vi-section--brand">
  <div class="vi-container vi-container--narrow">
    <div class="vi-section-header">
      <h2 class="vi-section-header__title">Ready to get started?</h2>
      <p class="vi-section-header__text">Let's build something great together.</p>
      <div class="vi-row">
        <a href="/contact" class="vi-btn vi-btn--primary"
           style="background:white; color:var(--color-interactive-default);">
          Contact Us
        </a>
      </div>
    </div>
  </div>
</section>

Class reference

Section

ClassDescription
vi-sectionBase. Full-width band, standard vertical padding (64px).
vi-section--smCompact padding (48px). Tight sections, footer areas.
vi-section--lgLarge padding (96px). Hero sections, feature highlights.
vi-section--flushNo padding. For full-bleed image sections.
vi-section--whiteWhite background.
vi-section--subtleLight grey background. Alternates visual weight.
vi-section--darkDark background, light text.
vi-section--brandBrand color background, white text.

Container

ClassDescription
vi-container1200px max-width, centered, responsive gutters.
vi-container--narrow800px max-width. Blog posts, article body.
vi-container--wide1440px max-width. Large image layouts.
vi-container--fullNo max-width constraint.

Section Header

ClassDescription
vi-section-headerCentered intro block. Flex column with gap.
vi-section-header--leftLeft-aligned variant.
vi-section-header__titleSection heading (use h2).
vi-section-header__textSupporting subtext below heading.

Grid

ClassColumnsResponsive
vi-grid--22 equal→ 1 col at 768px
vi-grid--33 equal→ 2 col at 1024px → 1 col at 768px
vi-grid--44 equal→ 2 col at 1024px → 1 col at 768px
vi-grid--2-166% / 33%→ 1 col at 768px
vi-grid--1-233% / 66%→ 1 col at 768px
vi-grid--3-260% / 40%→ 1 col at 768px
vi-grid--2-340% / 60%→ 1 col at 768px
vi-grid--autoAuto-fill at 280px minAutomatic
vi-grid--gap-sm16px gap (modifier, combine with any grid)
vi-grid--gap-lg32px gap (modifier, combine with any grid)

Stack

ClassDescription
vi-stack24px top margin between siblings. Default.
vi-stack--sm16px gap. Tight stacks, caption text.
vi-stack--lg32px gap. Loose stacks, major content sections.

Row & Utilities

ClassDescription
vi-rowFlex row, centered vertically, 16px gap.
vi-row--wrapAllows items to wrap to next line.
vi-row--centerJustify center.
vi-row--betweenSpace between.
vi-row--endJustify end.
vi-ratio--16-916:9 aspect ratio box.
vi-ratio--4-34:3 aspect ratio box.
vi-ratio--1-1Square aspect ratio box.
vi-dividerHorizontal rule using border token.