Application standards

The website.

Use this chapter when you are building an Alix web page. It defines the layouts, spacing and responsive behaviour implemented by the components. Start with the 50% centre line, choose a section layout, then apply the page gutter and section spacing shown here. Thin gold lines mark the measurements drawn over each specimen.

Centre line
50% · aligned to the X
Breakpoints
md 768 · lg 1024
Page gutter
24 · 40 · 64
Section rhythm
80 · 112
W1

Centre the composition

The 50% line is the website's main alignment. In the hero, the X in the wordmark lands on that line and the two media panels meet there. Reuse the same split in the sections below so text, media and colour fields share one vertical edge. Use an off-centre division only for the two-thirds layout or the fixed title rail.

Where the data meets the shop floor.

Teams test the forecast against what is happening on site, assign an owner and track the change each week.

Measurements are shown from the md breakpoint (768px). At phone width the grid has not split yet, so there is nothing to measure.

HomepageHeader calculates the wordmark width so the X lands at 50% (left + width × 0.8417 = 50%). The two media panels and the block below meet on the same line.
W2

Set the page width

The page has one width constraint: --page-max-width at 1728px. Below it, the page follows the viewport. Above it, the whole page centres with equal margins. Apply the cap once, at the page root; never apply it to individual sections.

Viewport below 1728px

The canvas follows the viewport width.

= viewport

Viewport at 1728px

The canvas reaches its cap.

1728px

Viewport above 1728px

The canvas holds 1728px and centres. The outer margins grow evenly.

1728px
The cap is --page-max-width (1728px), set once on the page root. Individual sections never carry it, and full-bleed sections still reach the canvas edges.
W3

Choose a section type

Every section uses one of two outer-spacing modes. An editorial section uses SiteContainer for the page gutter and adds its own vertical padding. A full-bleed section spans the canvas and adds no outer spacing. The component then owns its internal space: Surface-based blocks use p-10, PostRowBlock uses py-10, and Hero media fills its grid tracks.

page · vertical stack of sections
editorial section · gutter + section padding
full-bleed CMS block · no outer spacing
Surface tile · p-10 internal paddingcontent · elements & patterns
The diagram shows both modes. An editorial section contains SiteContainer and its content. A full-bleed, Surface-based CMS block contains Grid, Surface and content. Not every section needs Grid or Surface.
Which wrapper owns each space
SiteContainerResponsive page padding: px-6 md:px-10 lg:px-16.Use on editorial content. It does not set the 1728px page cap.site shell · not in the registry, copy the classes
SectionWrapperSection semantics and an anchor target. No spacing.Leave it unpadded so full-bleed blocks can meet edge to edge.@alix/sectionWrapper
SurfaceInternal tile padding (p-10 · 40px) and surface colours.Adds no margin or outer padding.@alix/surface
W4

Choose a column layout

Use one of the six layouts shown below. Halves suit text with media; quarters suit card rows; thirds suit three equal cards; the 25/25/50 split adds two supporting tiles; two-thirds creates a main and an aside; the rail keeps a fixed title or filter column beside fluid content. Each row names the implementation and its breakpoint behaviour.

Halves

Text beside media, or two equal text tiles (Layout=50/50).

TextAndMedia · TextAndText

1 col → md 2

1⁄2
1⁄2

Quarters

Card rows and post feeds.

PostRowBlock columns={4}

1 col → md 2 → lg 4

1⁄4
1⁄4
1⁄4
1⁄4

Thirds

Three-card rows when the content suits three equal items.

PostRowBlock columns={3}

1 col → md 2 → lg 3

1⁄3
1⁄3
1⁄3

The split

Two supporting tiles beside a half-width media tile (Layout=25/25/50).

TextAndMedia textTileVariant="split"

1 col → md the full split

1⁄4
1⁄4
1⁄2

The two-thirds

A primary content area beside a narrower aside.

no block · raw Grid + col-span (W8)

1 col → md 2 equal → lg 2:1 (the asymmetry appears at lg)

2⁄3
1⁄3

The rail

A 256px title or filter rail beside fluid content.

PeopleGrid

stacked below lg → rail w-64 · 256px from lg

Fixed · w-64 · 256px
Fluid
The proportional layouts resolve on twelve columns: 6+6, 4+4+4, 3+3+3+3, 3+3+6 and 8+4. The rail is different: it stays 256px wide from lg while the content beside it remains fluid.

Turnaround, led from the front.

Senior operators work with your team, find the cash and track delivery against the plan each week.

Measurements are shown from the md breakpoint (768px). At phone width the grid has not split yet, so there is nothing to measure.

the call site, exactly what renders above
<TextAndMedia
  textTileVariant="titleAndText"
  textTile={{
    bgColor: "default",
    sectionTitle: {
      title: "Turnaround, led from the front.",
      description: "Senior operators work with your team, find the cash…",
      align: "start",
    },
    buttonGroup: {},
  }}
  media={{ type: "image", src: cms.image, alt: "" }}
  ratio="16/9"
/>
TextAndMedia implements halves with <Grid columns={2} gap="none">. The tiles meet on the centre line; Surface provides the p-10 internal padding.

Measurements are shown from the md breakpoint (768px). At phone width the grid has not split yet, so there is nothing to measure.

the call site, card data straight off a query
<PostRowBlock
  columns={4}
  contentCards={posts.map((p) => ({
    variant: "news",
    alignment: "vertical",
    media: { type: "image", src: p.cover, alt: "" },
    tagline: p.category,
    title: p.title,
    excerpt: p.summary,
    href: p.href,
  }))}
/>
PostRowBlock implements a quartered card row using gap="none" and hairline dividers between cards. It renders two columns from md and four from lg.

The plan becomes weekly actions.

Senior teams assign an owner to each action and report progress every week.
Every action has an owner.

Measurements are shown from the md breakpoint (768px). At phone width the grid has not split yet, so there is nothing to measure.

the call site
<TextAndText
  contentLeft={{
    bgColor: "primary",
    sectionTitle: {
      title: "The plan becomes weekly actions.",
      description: "Senior teams assign an owner to each action…",
      align: "start",
    },
    buttonGroup: {},
  }}
  contentRight={{
    bgColor: "greyGradient",
    sectionTitle: {
      variant: "largeText",
      description: "Every action has an owner.",
      align: "start",
    },
    buttonGroup: {},
  }}
/>
TextAndText uses the same 50/50 grid. Each Surface keeps its own padding, so the two colour fields need no gap between them.
W5

Add responsive behaviour

Write the phone layout first. At md (768px), most sections move from one column to two and the page gutter increases. At lg (1024px), card rows reach three or four columns and the gutter increases again. Grid accepts one to four equal columns and applies those changes for you.

--breakpoint-smsm:
40rem · 640px

Use only for small-control adjustments. Page layout starts changing at md.

--breakpoint-mdmd:
48rem · 768px

Primary page breakpoint. Grids move to two columns; display type, page gutter and section padding step up.

--breakpoint-lglg:
64rem · 1024px

Secondary page breakpoint. Card rows reach their full column count and the page gutter reaches 64px.

--breakpoint-xlxl:
80rem · 1280px

Available from Tailwind. Used only by a small number of components.

--breakpoint-2xl2xl:
96rem · 1536px

Available from Tailwind. No current page layout depends on it.

Grid adds columns at md and lg
base 0 – 767px · 1 col
md 768px · 2 col
lg 1024px · 4 col
Grid columns={4} renders one column by default, two from md, and four from lg. Start with the base layout, then add complexity at wider breakpoints with md:grid-cols-2 and lg:grid-cols-4. Do not write a desktop layout and override it for smaller screens.
W6

Apply the page gutter

SiteContainer provides the horizontal page gutter: 24px at base, 40px at md and 64px at lg. Use it around editorial content. Do not wrap full-bleed sections in it. Apply the 1728px maximum width to the whole page, not to individual sections.

Latest thinking

Analysis from senior operators on cash, capability and delivery.
The shaded bands show the actual SiteContainer padding: px-6 md:px-10 lg:px-16 (24 → 40 → 64). Full-bleed sections skip this wrapper. Each block then applies its own internal spacing.
Responsive layout values in code
Page gutterpx-6 md:px-10 lg:px-1624 · 40 · 64pxHorizontal padding supplied by SiteContainer. Apply it to editorial content, not full-bleed sections.
Section rhythmpy-20 md:py-2880 · 112pxVertical padding set on each editorial section.
Tile insetp-1040pxInternal padding supplied by Surface-based tiles. Other blocks own their internal spacing.
Canvas max-widthmx-auto w-full max-w-page1728pxApply once to the page root. The page fills the viewport up to 1728px, then centres.
Figma reference values
container-padding-xNot shipped CSS
Figma stores a single 24px gutter. Code uses responsive px-6 md:px-10 lg:px-16 through SiteContainer.24px
section-padding-yNot shipped CSS
Figma stores 96px. Code uses py-20 md:py-28 for editorial sections; full-bleed blocks own their internal spacing.96px
section-title-gap-smNot shipped CSS
SectionTitle uses gap-2 at base and gap-3 from lg for size sm.16px
section-title-gap-mdNot shipped CSS
SectionTitle uses gap-3 at base and gap-4 from lg for size md.20px
section-title-gap-lgNot shipped CSS
SectionTitle uses gap-4 at base and gap-5 from lg for size lg.20px
section-title-gap-xlNot shipped CSS
SectionTitle uses gap-5 at base and gap-6 from lg for size xl.24px
W7

Space the sections

Editorial sections and CMS blocks use different spacing rules. Give an editorial section py-20 md:py-28 and, when it follows another editorial section, a border-t. Render CMS blocks next to one another with no added outer gap or padding. Each block owns its internal spacing: Surface-based blocks use p-10 and PostRowBlock uses py-10. SectionTitle controls the gap between its own title and content.

Editorial sectionWrap the content in SiteContainer. Add py-20 md:py-28 to the section and border-t when it follows another editorial section.
CMS block runRender blocks next to one another. Add no gap, padding or spacing wrapper.

Our services

Six practices covering performance improvement, turnaround and restructuring.

Latest thinking

Practical analysis on working capital, delivery and team capability.

Cash tracked every week.

The team reports each working-capital action against the agreed baseline.
Variance reported against the plan.

Delivery tracked against the plan.

Each week, the team reports the result, owner and next action.
Editorial sections use 80px vertical padding at base and 112px from md (py-20 md:py-28). CMS blocks meet with no added gap. Surface-based blocks use p-10; PostRowBlock owns py-10.
Don't add a gap between CMS blocks. Their surfaces are designed to meet edge to edge.
Don't invent a new editorial section gap. Use py-20 md:py-28.
W8

Implement the grid

Use Grid for equal columns and gaps from the spacing scale. Use Container to limit the line length of prose inside a section. Use raw Tailwind utilities only for layouts Grid does not support, such as two-thirds. Apply max-w-page once, at the page root.

Use Grid for equal columns

columns sets the final equal-column count. gap selects a value from the spacing scale. Two columns suit split sections; four suit card rows. The component supports up to four columns.

grid.tsx
import { Grid } from "@/components/ui/grid";

// columns step up by breakpoint; gap defaults to "xl" (40px)
//   columns={2} → 1 → md:2          (split sections)
//   columns={4} → 1 → md:2 → lg:4   (card rows)
//   columns={3} → 1 → md:2 → lg:3   (three-card rows)
<Grid columns={4} gap="lg">
  <Card /> <Card /> <Card /> <Card />
</Grid>
gap tokenpxclass
gap="none"0gap-0
gap="xxs"4gap-1
gap="xs"8gap-2
gap="sm"12gap-3
gap="md"16gap-4
gap="lg"24gap-6
gap="xl"40gap-10

Limit prose width

Container limits the width of its children for readable prose. It does not change the width of the surrounding section. Choose a width from the --container-* scale.

container.tsx
import { Container } from "@/components/ui/container";

<Container width="lg">
  <article>Long-form copy, capped for readability.</article>
</Container>

container-sm 384 · container-md 448 · container-lg 512 · container-xl 576 · container-2xl 672 (px)

Build unequal columns

If a layout needs unequal tracks, use raw Tailwind utilities. Keep the same mobile-first rule: one column at base, then md: and lg:. Use column spans for a wider main and narrower aside.

layout.tsx
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
  <div className="lg:col-span-2">Main, two of three columns</div>
  <div>Aside, the remaining column</div>
</div>
CMS blocks such as TextAndMedia and TextAndText already use <Grid columns={2} gap="none"> internally. Do not add another layout wrapper around them.

Build the title rail

Use a flex layout for the fixed title rail. Below lg, stack the rail above the content. From lg, set the rail to w-64 (256px) and let the content take the remaining width.

peopleGrid.tsx
<div className="flex flex-col gap-8 lg:flex-row lg:items-start">
  <Stack gap="lg" className="lg:w-64 lg:shrink-0">rail</Stack>
  <div className="flex-1">content</div>
</div>
W9

Assemble a page

Apply the page cap at the root. Add the slot-based Hero, then editorial sections with their own gutter and vertical padding. Render CMS blocks separately with no added outer spacing. The navbar and footer exist in Figma but do not yet ship in the registry. SiteContainer is also pending, so use its gutter classes directly.

page.tsx
import { HomepageHeader, HomepageHeaderSlide } from "@/components/homeHeader";
import { SectionTitle } from "@/components/sectionTitle";
import { TextAndMedia } from "@/components/textAndMediaBlock";
import { TextAndText } from "@/components/textAndText";
import PostRowBlock from "@/components/postRowBlock";

export default function Page() {
  return (
    // canvas: full-bleed to --page-max-width, then centres
    <main className="mx-auto w-full max-w-page">
      {/* 0 · Navbar: designed, not yet in the registry (roadmap) */}

      {/* 1 · Hero: slot-based section, media is yours (next/image, video) */}
      <HomepageHeader>
        <HomepageHeaderSlide
          left={<img src={cms.hero.left} alt="" className="size-full object-cover" />}
          right={<video src={cms.hero.loop} autoPlay muted loop playsInline
                   className="size-full object-cover" />}
        />
      </HomepageHeader>

      {/* 2 · Editorial section: vertical padding + page gutter */}
      <section className="border-t border-border py-20 md:py-28">
        <div className="px-6 md:px-10 lg:px-16">
          <SectionTitle headingSize="lg" headingTag="h2" align="start" title="Latest thinking" />
        </div>
      </section>

      {/* 3 · Full-bleed CMS blocks: adjacent, with no added outer spacing */}
      <PostRowBlock columns={4} contentCards={cms.posts} />
      <TextAndMedia {...cms.textAndMedia} />
      <TextAndText {...cms.textAndText} />

      {/* 4 · Footer: designed, not yet in the registry (roadmap) */}
    </main>
  );
}
The example applies each spacing rule once: page max-width at the root, vertical padding on the editorial section, the page gutter on its inner div, and no added outer spacing around the CMS blocks.
W10

Compare page layouts

These studies show how the approved divisions can combine across a page. Use them to check the balance and sequence of a composition, not as fixed page templates. Every study uses only the layouts from W4.

Home hero · flush halves + image band
Title rail + posts
Gapped quarters over flush halves
Navy band over quarters
Halves, alternating sides
The two-thirds
Gallery quarters + caption
Image band over flush halves
W11

Find the right component

Choose by contract, not folder alone. Components, elements and slot-based patterns use ReactNode slots when engineers need composition. CMS-shaped patterns and most sections take serialisable data for direct CMS mapping. Hero is the deliberate exception: it is a section by scale but uses media slots. The component directory documents the contract for each item.

W12

Avoid common mistakes

Most page errors come from applying a valid rule at the wrong layer. Keep 50/50 layouts centred, use SiteContainer only for editorial content, apply the 1728px cap only to the page, and build from the phone layout up.

Keep 50/50 layouts on the centre line. Do not use 48/52.
Keep SiteContainer's page gutter on editorial content.
Apply the 1728px cap to the page root, not to one section.
Build up from the phone layout. Do not squeeze a desktop grid onto a phone.