IGrow Group of Companies

IGrow Design System — Responsive Guidelines

← Design System

Design System Index | Component Reference | Token Reference


IGrow Design System — Responsive Guidelines

This document defines how to build responsively for IGrow digital surfaces. All rules apply across HTML/CSS, Tailwind, React, and WordPress unless a stack-specific note says otherwise.

Traffic context. 80% of IGrow traffic is on Android devices. The two dominant screen sizes are 384 × 832 px (Android mobile, portrait) and 1920 × 1080 px (desktop). Every layout decision should be validated at these two anchors first, then at the breakpoint boundaries in between.


1. Mobile-first principle

Write base styles that work at 384px — no media query required. Then layer overrides upward using min-width breakpoints. Never write max-width media queries in product UI; they fight the cascade and produce fragile code.

System chrome exception. The design system's own documentation site and preview pages use max-width queries internally for their navigation drawers and layout switches. This is a pragmatic exception for tooling — it does not apply to product UI built with this system.

/* ✅ Mobile-first */
.ig-listing-grid { grid-template-columns: 1fr; }

@media (min-width: 768px) { .ig-listing-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .ig-listing-grid { grid-template-columns: repeat(3, 1fr); } }

/* ❌ Max-width — avoid */
@media (max-width: 767px) { .ig-listing-grid { grid-template-columns: 1fr; } }

2. Breakpoint reference

Five named tiers, Tailwind-aligned. The CSS custom properties below are for reference — they cannot be used inside @media queries (CSS custom properties don't interpolate there). Use the raw pixel values in CSS or the sm: / md: / lg: / xl: / 2xl: prefixes in Tailwind.

Tier Token min-width Typical context
base 0 px Android mobile, portrait — your primary target
sm --bp-sm 640 px Large phone landscape, small tablet
md --bp-md 768 px Tablet portrait
lg --bp-lg 1024 px Tablet landscape, small laptop
xl --bp-xl 1280 px Standard desktop
2xl --bp-2xl 1536 px Wide desktop — covers your 1920 px majority

Key rule: If a behaviour should apply to the 384 px majority, it belongs in base styles — no media query. If a behaviour should apply to the 1920 px majority, it belongs at 2xl — and it should look intentional, not just "wider".


3. Gutters

Gutters are the horizontal padding applied to page-level containers. Use the canonical tokens — do not pick ad-hoc --space-* values for container edges.

Token Value Apply at
--gutter-mobile 16 px base (384 px)
--gutter-tablet 24 px md (768 px+)
--gutter-desktop 32 px lg (1024 px+)

HTML / CSS

.ig-container {
  width: 100%;
  padding-inline: var(--gutter-mobile);
}

@media (min-width: 768px)  { .ig-container { padding-inline: var(--gutter-tablet); } }
@media (min-width: 1024px) { .ig-container { padding-inline: var(--gutter-desktop); } }

Tailwind

<div class="px-gutter-mobile md:px-gutter-tablet lg:px-gutter-desktop max-w-igrow-lg mx-auto">
  …
</div>

React

<div style={{
  paddingInline: 'var(--gutter-mobile)',
  maxWidth: 'var(--container-lg)',
  margin: '0 auto',
}}>
  {/* or use a <Container> wrapper component */}
</div>

WordPress (theme.json)

The repo's system/wordpress/theme.json registers spacing via spacingSizes. Add the gutter sizes to that array so the block editor exposes them as presets:

{
  "settings": {
    "spacing": {
      "spacingSizes": [
        { "slug": "gutter-mobile",  "name": "Gutter Mobile",  "size": "16px" },
        { "slug": "gutter-tablet",  "name": "Gutter Tablet",  "size": "24px" },
        { "slug": "gutter-desktop", "name": "Gutter Desktop", "size": "32px" }
      ]
    }
  }
}

In PHP templates, reference the CSS custom property that theme.json generates:

<div style="padding-inline: var(--wp--preset--spacing--gutter-mobile);">

4. Spacing scale per breakpoint

The design system uses a 4 px base scale (--space-1 through --space-10). When adapting spacing across breakpoints, never jump more than 2 steps between tiers.

Context base (384 px) md (768 px) 2xl (1536 px)
Section vertical padding --space-7 (48 px) --space-8 (64 px) --space-10 (128 px)
Card internal padding --space-4 (16 px) --space-5 (24 px) --space-5 (24 px)
Stack / list gap --space-3 (12 px) --space-4 (16 px) --space-5 (24 px)
Inline element gap --space-2 (8 px) --space-2 (8 px) --space-3 (12 px)

Why the 2xl step up matters. On a 1920 px screen, inheriting 48 px section padding from mobile makes the layout feel cramped and unintentional. Stepping up to 128 px creates the premium, spacious feel the brand calls for — it also signals to the user that whitespace is deliberate, not accidental.


5. Fluid typography

For headings and display copy, prefer the clamp()-based fluid tokens over static values. These scale continuously with the viewport — no media-query breakpoints needed.

Token Range Use for
--fs-fluid-display 40 → 72 px Hero display headlines
--fs-fluid-hero 32 → 56 px Hero titles
--fs-fluid-h1 28 → 40 px Page <h1>
--fs-fluid-h2 24 → 32 px Section headings
--fs-fluid-h3 20 → 28 px Card / sub-section headings
--fs-fluid-lead 17 → 20 px Lead paragraphs below a hero

Static tokens for body and UI. Body copy (--fs-16), captions (--fs-12), labels (--fs-14), and button text should use fixed sizes. Scaling body text with the viewport degrades readability.

The ceilings are intentional. The fluid tokens cap at defined maxima — display stops at 72 px, h1 stops at 40 px, lead stops at 20 px. These are correct for 1920 px screens. Do not override them upward.

HTML / CSS

h1 { font-size: var(--fs-fluid-h1); line-height: var(--lh-heading); }
.hero__title { font-size: var(--fs-fluid-hero); line-height: var(--lh-tight); }

Tailwind

<h1 class="text-fluid-h1 leading-heading">…</h1>
<p class="text-fluid-lead leading-body">…</p>

React

<h1 style={{ fontSize: 'var(--fs-fluid-h1)', lineHeight: 'var(--lh-heading)' }}>…</h1>

WordPress (theme.json)

{
  "styles": {
    "elements": {
      "h1": { "typography": { "fontSize": "clamp(1.75rem, 1rem + 2.5vw, 2.5rem)" } },
      "h2": { "typography": { "fontSize": "clamp(1.5rem, 1rem + 1.8vw, 2rem)" } }
    }
  }
}

6. Layout

Band + container pattern

Every page section uses a full-bleed band with a constrained inner container. The band takes colour, imagery, or gradient to the screen edge. The container limits content width. This applies at all widths — it is especially important at 1920 px where unconstrained content looks adrift.

<!-- Full-bleed band, constrained content -->
<section class="ig-hero-section" style="background-image: url(…)">
  <div class="ig-container">          <!-- constrained wrapper -->
    <h1 class="ig-hero-section__title">…</h1>
    <p class="ig-hero-section__body">…</p>
  </div>
</section>

This applies to the nav, hero, every section band, and the footer. The nav bar always spans the full viewport width. Only the nav's inner content (logo + links) is constrained.

Container sizes

Token Value When to use
--container-sm 760 px Focused content: forms, blog posts, CTA bands
--container-md 1200 px Standard pages
--container-lg 1400 px Wide pages: property listings, dashboards

At 1920 px, max content width is --container-lg. The space outside it is intentional whitespace or band colour — never an empty void to apologise for.

Prose max-width

Body copy, lead paragraphs, and form fields should be capped at approximately 70ch (~680 px) regardless of container width. This is a readability rule — long line lengths slow reading comprehension.

.article-body { max-width: 70ch; }

Column grid

Breakpoint Columns
base 4
md 8
lg+ 12

Property card grid

The property card grid uses a specific column progression:

Breakpoint Columns
base 1
md 2
lg 3
xl+ 4
<!-- HTML / CSS -->
<div class="ig-grid ig-grid--cards">…</div>

<!-- Tailwind -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-igrow-4">…</div>

Imagery aspect ratios at 2xl

Hero and banner images need explicit aspect ratios at wide viewports to prevent awkward stretching.

Context Aspect ratio Token
Hero / full-bleed banner 21 / 9 --aspect-banner
Property card thumbnail 3 / 2 --aspect-card
Standard hero 16 / 9 --aspect-hero

At 2xl, apply aspect-ratio: var(--aspect-banner) to hero sections so they fill the canvas proportionally rather than growing arbitrarily tall.

Deliberate whitespace at 2xl

Large screens should feel spacious and premium — not sparse. Step up section padding intentionally at 2xl:

.ig-section { padding-block: var(--space-7); }                      /* 48px — mobile */
@media (min-width: 768px)  { .ig-section { padding-block: var(--space-8); } }  /* 64px  */
@media (min-width: 1536px) { .ig-section { padding-block: var(--space-10); } } /* 128px — 2xl */

7. Component responsive behaviour

For component-specific markup and variants, see the Component Reference. This section covers responsive behaviour only.

Breakpoint Behaviour
base → md Hamburger toggle visible; nav links hidden; drawer opens as <dialog>
lg+ Full nav links visible; hamburger hidden
  • Mobile nav height: 56 px (--nav-height-mobile)
  • Desktop nav height: 72 px (--nav-height-desktop)
  • The nav bar is always full-bleed. The inner content is constrained to --container-lg.
  • Account for nav height when positioning sticky or full-screen elements: top: var(--nav-height-mobile) / top: var(--nav-height-desktop).

Hero

Breakpoint Behaviour
base Single column; title and body stacked; aspect-ratio: 16/9 minimum
md+ Full-bleed photo hero with overlay; title large-left / body beneath
2xl aspect-ratio: var(--aspect-banner) (21/9)

Use --fs-fluid-hero for the title — it handles the 384 px → 1920 px range without breakpoint overrides.

Property card grid

See the column progression in Layout → Property card grid.

Cards inside the grid lock their thumbnail to aspect-ratio: var(--aspect-card) (3/2) at all sizes. Do not allow card thumbnails to resize proportionally with text — the image height should be stable.

Buttons

Breakpoint Behaviour
base Full-width (ig-btn--block) for primary CTAs in forms and hero sections
sm+ Auto-width (inline); right-size for the context
lg+ Use ig-btn--lg for primary hero CTAs

Buttons inside a card footer or listing bar are never full-width — only standalone hero/form CTAs go full-width at mobile.

<!-- Full-width on mobile only -->
<a class="ig-btn ig-btn--primary ig-btn--block sm:w-auto">Request a viewing</a>

Forms

Breakpoint Behaviour
base Single column; all fields full-width
md+ Two-column grid for multi-field forms (name + surname, city + province)

Form containers should use max-width: var(--container-sm) (760 px) — forms should never stretch to --container-lg. Apply inputmode and autocomplete attributes on every field: they directly improve the 384 px Android experience by triggering the correct keyboard and autofilling common values.

<form style="max-width: var(--container-sm)">
  <div class="ig-field-group ig-field-group--2col">
    <div class="ig-field">…</div>
    <div class="ig-field">…</div>
  </div>
</form>

Tables

Breakpoint Behaviour
base → md .ig-table-wrap enables horizontal scroll; table renders at natural width
md+ Table fits the container; no horizontal scroll needed

Always wrap .ig-table in .ig-table-wrap. Never hide table columns on mobile — horizontal scroll is preferable to missing data. If a table has more than 6 columns, consider a card-based alternative for mobile.

Typography headings

Always use fluid tokens for h1–display-level headings. Use static tokens for body, labels, captions, and UI text.

Element Token
Display / hero --fs-fluid-display, --fs-fluid-hero
<h1> --fs-fluid-h1
<h2> --fs-fluid-h2
<h3> --fs-fluid-h3
Lead paragraph --fs-fluid-lead
Body copy --fs-16 (static)
Labels / captions --fs-14 / --fs-12 (static)

8. Testing checklist

Test in this order — the two majority sizes first, then the boundaries.

  • 384 px — no horizontal scroll; all content accessible; primary CTA full-width; body copy legible
  • 1920 px — content constrained by container-lg; whitespace feels intentional; no text larger than fluid ceilings; hero aspect ratio correct
  • 640 px (sm boundary) — inline buttons switch from full-width to auto
  • 768 px (md boundary) — nav links appear; gutter increases; form goes 2-col
  • 1024 px (lg boundary) — full desktop nav; gutter at desktop size
  • 1280 px (xl boundary) — 4-column card grid kicks in
  • Rotate 384 px device to landscape (667 px wide) — layout should not break
  • Verify prefers-reduced-motion — all transitions should collapse to near-zero