Design System

The complete component gallery for the Preston Trail Ward website. Every button, banner, card, hero, list, and badge on the site, each shown at desktop and mobile sizes. Components here reuse the exact same classes as the live pages, so this page can never drift from the site.

How to use

Every configurable component can be dropped into a markdown page as a {{name key="value"}} directive. build.py expands it into the canonical markup. Buttons use the "Label|/url" spec; tertiary links use "Label|/url; Label|/url". The dark flag can be bare ({{contact-card ... dark}}) or dark="true". Omit a parameter to take its default. Unknown directive names pass through untouched.

{{card title="Sample card title" body="Sample body text."
       image="/assets/img/dallas-temple.jpg"
       primary="Primary action|/visit-us"
       secondary="Secondary action|/events"}}

Design tokens

The single source of truth. Every component below is built from these variables, so a palette or spacing change lands everywhere at once.

Palette

Midnight--midnightDark surfaces, brand
Midnight deep--midnight-deepFooter
Sky--skyPrimary actions
Sky deep--sky-deepLinks, hover
Sky bright--sky-brightText on dark
Sky soft--sky-softTint surfaces
Paper--paperPage background
Card--cardCard surfaces
Ink--inkBody text
Ink soft--ink-softSecondary text
Muted--mutedMuted labels
Line--lineHairline borders

Type scale

Display heading

Fraunces 600, clamp(2.6rem, 9vw, 4.6rem). Hero and page titles.

Section heading

Fraunces 600, clamp(1.7rem, 4vw, 2.4rem).

Card heading

Fraunces 600, 1.3rem.

Body copy reads like this. Warm and natural, never flowery.

System stack, 1rem, line-height 1.65, ink.

Lede paragraph on a dark hero.

1.1rem, softened white, max 46rem. For dark heroes only.

Kicker label

0.72rem, 700, uppercase, 0.12em tracking, sky-deep.

Spacing, radius, shadow, layout

TokenValueUse
--space-xs0.5remTight gaps
--space-sm0.75remCard gaps
--space-md1remDefault gap
--space-lg1.5remSection gaps
--space-xl2.5remLarge gaps
--space-2xl3.5remSection padding
--radius-sm10pxSmall controls
--radius14pxCards, panels
--radius-pill999pxButtons, badges
--shadowlayered softCards, panels
--maxw1120pxPage container
--maxw-prose46remReading column

Buttons

Three-tier hierarchy. .btn-primary (solid sky) is the single most important action per card or section. The ghost button has two canonical forms: .btn-ghost for dark backgrounds and .btn-on-light for light ones. Buttons can carry an inline SVG icon with .btn-icon (1.15em, aligned to the label), as on scheduling buttons. Two equal CTAs split 50/50 with .duo-btns and are never stacked. A lone card CTA goes full-width on mobile. Tertiary actions are quiet text links (.card-links), never buttons. Components emit buttons through their parameters; authors never hand-write button markup.

Buttons on dark

The same buttons on midnight. .btn-outline-light is the compact outline for dark bands.

Card: text only, one button

The simplest card. The lone CTA goes full-width on mobile.

Parameters

ParameterTypeDefaultDescription
kickerstring""Small uppercase label above the title.
titlestring""Card heading.
bodystring""Body copy.
imageURL""Optional 16:9 header image.
image_altstringtitleImage alt text. Defaults to the title.
primary"Label|URL"noneMain button (solid sky).
secondary"Label|URL"noneSupporting button (outline). Two buttons split 50/50.
links"Label|URL; ..."noneTertiary quiet links below the buttons.
card_urlURL""Whole-card tap target (uses the primary button destination).
variant""/"horizontal"""Horizontal layout: image left, content right on desktop.

Directive

{{card kicker="Sample label" title="Sample card title"
       body="Sample body text shows how the component looks."
       image="/assets/img/dallas-temple.jpg"
       primary="Primary action|#"
       secondary="Secondary action|#"
       links="Quiet link one|#; Quiet link two|#"
       variant="horizontal"}}

Desktop

Sample card title

Sample body text shows how the component looks with a typical amount of copy.

Mobile

Sample card title

Sample body text shows how the component looks with a typical amount of copy.

Card: image top, kicker, tertiary links

Image header with a kicker label, one primary button, and quiet tertiary links below it.

Desktop

Mobile

Card: horizontal, two buttons

variant="horizontal": image left, content right on desktop; stacks like a normal card on mobile. Two equal CTAs split 50/50.

Desktop

Mobile

Banner: light

dark="false" renders the white-card variant for light pages.

Desktop

Sample banner title Sample banner copy with one bold lead-in.

Mobile

Sample banner title Sample banner copy with one bold lead-in.

Band: dark

Midnight band. Dark bands break up the page rhythm; never put two light alt sections back to back.

Parameters

ParameterTypeDefaultDescription
kickerstring""Pill label above the title.
titlestring""Band heading.
bodystring""Band copy.
primary"Label|URL"noneThe band's single button.
dark"true"/"false""true"Midnight band or light band.

Directive

{{band kicker="Sample kicker" title="Sample band title"
       body="Sample band copy."
       primary="Primary action|#"
       dark="true"}}

Desktop

Sample kicker

Sample band title

Sample band copy.

Primary action

Mobile

Sample kicker

Sample band title

Sample band copy.

Primary action

Band: light

dark="false" renders the light variant with hairline rules top and bottom.

Desktop

Sample kicker

Sample band title

Sample band copy.

Primary action

Mobile

Sample kicker

Sample band title

Sample band copy.

Primary action

Contact card: grid layout

The default layout="grid": channel columns on desktop, stacked on mobile. Phone numbers display formatted, e.g. (555) 123-4567.

Parameters

ParameterTypeDefaultDescription
namestringrequiredPerson or group name. Never bolded.
telphonenoneRenders Call (tel:) and Text (sms:) channels. Shown formatted, e.g. (972) 322-5863.
emailaddressnoneRenders the Email (mailto:) channel.
schedule"Label|URL; ..." noneRenders Schedule channels with calendar icons, one per entry. Label shows as the channel value, e.g. a person's name; the link opens the scheduling page.
layout"grid"/"list"/"inline""grid"Grid: channel columns on desktop, stacked on mobile. List: compact rows with chevrons. Inline: concise name plus action pills in one row, no values.
darkflaglightDark variant for dark backgrounds.

Directive

{{contact-card name="Sample Name"
               tel="+15551234567"
               email="[email protected]"
               layout="grid" dark}}

Contact card: grid on dark

.contact-card--dark for dark banners, bands, and panels. Sky-bright icons and dividers on midnight.

Contact card: grid dynamic states

Phone present but no email renders Call and Text only. Email only renders the Email channel alone. The component adapts; authors never hand-build the row.

Contact card: list layout

layout="list": compact rows with chevrons. On mobile the value wraps under the label.

Contact card: list on dark

The list layout on dark surfaces.

Contact card: inline layout

layout="inline": the concise card. Name plus action pills in one row, no values shown. For tight spots like banners where the full card would take too much vertical space.

Desktop

Sample Name

Mobile

Sample Name

Contact card: inline on dark

The inline layout on dark surfaces.

Desktop

Sample Name

Mobile

Sample Name

Contact card: schedule channels

The schedule parameter renders Schedule channels with calendar icons instead of Call/Text/Email, one per "Label|URL" entry. Same card, same layouts; the link opens the scheduling page.

Image hero

Full-bleed hero. Images are official Church artwork or landmark photos, never photos of strangers. Demo height is capped; the live hero is 78vh.

Parameters

ParameterTypeDefaultDescription
kickerstring""Small uppercase label above the title.
titlestring""Display title.
subtitlestring""Supporting copy.
imageURL""Full-bleed background image. Solid midnight without one.
image_altstringtitleImage alt text.
primary"Label|URL"noneMain call to action.
secondary"Label|URL"noneGhost call to action.

Directive

{{hero kicker="Sample kicker" title="Sample hero title"
       subtitle="Sample supporting copy."
       image="/assets/img/hero-chapel.jpg"
       primary="Primary action|#"
       secondary="Secondary action|#"}}

Desktop

Sample image

Sample kicker

Sample hero title

Sample supporting copy.

Mobile

Sample image

Sample kicker

Sample hero title

Sample supporting copy.

Page hero

Solid midnight hero with a lede line.

Parameters

ParameterTypeDefaultDescription
titlestring""Page title.
ledestring""Supporting line under the title.
imageURL""Optional image under the overlay.
image_altstringtitleImage alt text.

Directive

{{page-hero title="Sample page title"
            lede="Sample supporting line."
            image="/assets/img/dallas-temple.jpg"}}

Desktop

Sample page title

Sample supporting line.

Mobile

Sample page title

Sample supporting line.

Page hero with image

The lede is optional; an image can sit under the overlay.

Desktop

Sample image

Sample page title

Mobile

Sample image

Sample page title

Centered hero

Gradient band, centered: kicker, title, supporting line.

Desktop

Sample kicker

Sample page title

Sunday, January 4, 2026

Mobile

Sample kicker

Sample page title

Sunday, January 4, 2026

Event card: vertical

The canonical event tile: image top with the category pill overlaid, title, description, date/time/location rows with icons, and a quiet Learn More link.

Parameters

ParameterTypeDefaultDescription
layout"vertical"/"horizontal"/"compact""vertical"Vertical: image top. Horizontal: image left. Compact: date block left, no image.
pillstring""Category pill text (overlaid on the image when there is one).
pill_color"sky"/"sky-deep"/"midnight"/"soft""sky"Pill color, palette only.
titlestring""Event title.
bodystring""Short description.
monstring""Date block month, e.g. MAY.
daystring""Date block day, e.g. 16.
dowstring""Date block weekday, e.g. FRI.
date_labelstring""Full date line with icon, e.g. Friday, May 16, 2025.
time_labelstring""Time line with icon, e.g. 7:00 PM - 9:00 PM.
locationstring""Location line with pin icon.
imageURL""Optional header image (not on compact).
image_altstringtitleImage alt text.
urlURL""Quiet Learn More link destination.
link_labelstring"Learn More"Quiet link label.

Directive

{{event-card layout="vertical" pill="Sample category"
  title="Sample Event" body="Sample body text."
  date_label="Friday, May 16, 2025"
  time_label="7:00 PM - 9:00 PM" location="Sample location"
  image="/assets/img/dallas-temple.jpg" url="/events/sample"}}

Desktop

Sample EventSample category

Sample Event

Sample body text shows how the component looks with a typical amount of copy.

  • Friday, May 16, 2025
  • 7:00 PM - 9:00 PM
  • Sample location

Learn More

Mobile

Sample EventSample category

Sample Event

Sample body text shows how the component looks with a typical amount of copy.

  • Friday, May 16, 2025
  • 7:00 PM - 9:00 PM
  • Sample location

Learn More

Event card: horizontal

Image left, content right on desktop; stacks on mobile. For hero banners and sidebar placements.

Desktop

Sample EventSample category

Sample Event

Sample body text shows how the component looks with a typical amount of copy.

  • Saturday, May 31, 2025
  • 10:00 AM - 12:00 PM
  • Sample location

Learn More

Mobile

Sample EventSample category

Sample Event

Sample body text shows how the component looks with a typical amount of copy.

  • Saturday, May 31, 2025
  • 10:00 AM - 12:00 PM
  • Sample location

Learn More

Event card: compact

Date block left, pill, title, time and location, quiet link. For 3-column grids and dense upcoming lists. No image.

Desktop

Sample category

Sample Event

1:00 PM - 4:00 PM · Sample location

Learn More

Mobile

Sample category

Sample Event

1:00 PM - 4:00 PM · Sample location

Learn More

Upcoming card: horizontal

Timely and upcoming events lead with a prominent date block: title, time and location line, short description, and a calendar link. The homepage timely banner uses this pattern with a Today/Tomorrow label.

Parameters

ParameterTypeDefaultDescription
layout"horizontal"/"image"/"tile""horizontal"Horizontal: date block and calendar link. Image: dark card with photo. Tile: compact date block.
monstring""Date block month, e.g. MAY.
daystring""Date block day, e.g. 16.
dowstring""Date block weekday, e.g. FRI.
pillstring""Category pill text.
pill_color"sky"/"sky-deep"/"midnight"/"soft""sky"Pill color, palette only.
titlestring""Event title.
metastring""Time and location line, e.g. 7:00 PM - 9:00 PM - Room 201.
bodystring""Short description.
urlURL""Event details destination.
imageURL""Photo for the image layout.
image_altstringtitleImage alt text.
when_labelstring""Urgency label, e.g. Today or Tomorrow.

Directive

{{upcoming layout="horizontal" mon="MAY" day="16" dow="FRI"
  when_label="This Friday" title="Sample Upcoming Event"
  meta="7:00 PM - 9:00 PM - Sample location"
  body="Sample body text." url="/events/sample"}}

Desktop

This Friday

Sample Upcoming Event

7:00 PM - 9:00 PM - Sample location

Sample body text shows how the component looks with a typical amount of copy.

Mobile

This Friday

Sample Upcoming Event

7:00 PM - 9:00 PM - Sample location

Sample body text shows how the component looks with a typical amount of copy.

Upcoming card: image

Dark card for visual impact: photo left with the date block overlaid, title, meta, description, quiet link.

Desktop

Sample Upcoming Event

Sample Upcoming Event

10:00 AM - 12:00 PM - Room 201

Sample body text shows how the component looks with a typical amount of copy.

Learn More

Mobile

Sample Upcoming Event

Sample Upcoming Event

10:00 AM - 12:00 PM - Room 201

Sample body text shows how the component looks with a typical amount of copy.

Learn More

Upcoming card: tile

Compact tile for upcoming grids and sidebars: date block, category pill, title, meta, quiet link.

Desktop

Sample category

Sample Event

1:00 PM - 4:00 PM - Sample location

Learn More

Mobile

Sample category

Sample Event

1:00 PM - 4:00 PM - Sample location

Learn More

Event schedule

The canonical event listing on every page: month dividers, prominent date blocks (month, day, weekday pill), category pills, weekday line, linked titles, time and location meta with icons, quiet links. Past events auto-hide client-side the day after they pass. Built in Python, not through a directive. The app.js hooks (.ym-event[data-date], .ym-mon, .ym-day, .ym-weekday) must never be renamed.

Desktop

October 2027
November 2027

Mobile

October 2027
November 2027

Badges

.ym-badge (This week) is injected by app.js from the visitor's Sunday-to-Saturday calendar week. .tag-badge pills label event audiences. .event-badge marks detail-page status, and .upcoming-label flags upcoming items.

Desktop

Upcoming Event Upcoming This week Sample tag

Mobile

Upcoming Event Upcoming This week Sample tag

Event flyer card

Image-led card for image-forward event layouts.

Event detail rows

The labeled-row pattern (.detail-list) shared by event pages: bold label left, unbolded value right.

Desktop

DateSaturday, January 9, 2027
Time7:00 PM
LocationSample location

Mobile

DateSaturday, January 9, 2027
Time7:00 PM
LocationSample location

Missionary cards

Tappable roster cards. Serving cards open the mission spotlight and fly the map; returned cards with a researched mission location open their exact mission. Names are never bolded. Tapping a card never follows the email link (clicks on links are ignored by the card handler).

Desktop

Sample Name
Sample Mission
[email protected]
Sample Name
Sample Mission
Sample language

Showing 2 currently serving

Mobile

Sample Name
Sample Mission
[email protected]
Sample Name
Sample Mission
Sample language

Showing 2 currently serving

Roster search, expander, regions

Live search filters cards by name or mission; the expander reveals returned missionaries grouped under region headings. Shown here inert.

Desktop

Sample Region 12

Mobile

Sample Region 12

Spotlight card

One serving missionary: photo, mission, place and landmark, one fact, photo credit, ONE primary write-them button, then tertiary links.

Desktop

Sample image

Sample Name

Sample Mission

Sample place · Sample landmark

One researched fact about the mission area.

Photo: Author / Wikimedia Commons (CC BY-SA 4.0)

Mobile

Sample image

Sample Name

Sample Mission

Sample place · Sample landmark

One researched fact about the mission area.

Photo: Author / Wikimedia Commons (CC BY-SA 4.0)

Labeled rows

The labeled-row pattern: bold uppercase label left, unbolded value right. Used for program metadata and event detail rows. Member names are never bold.

Desktop

Sample labelSample value
Sample labelSample value
Sample kindSample detail
Sample kindSample detail

Mobile

Sample labelSample value
Sample labelSample value
Sample kindSample detail
Sample kindSample detail

Section title, look-ahead, search, quick link

Centered section titles with a sky rule; one-line look-ahead rows; the events search field with its result count; quick-link tiles.

Desktop

Sample Section Title

Sunday, January 4 Sample look-ahead blurb

3 events found

Sample Link Up next: Sample Event (Jan 9, 2027)

Mobile

Sample Section Title

Sunday, January 4 Sample look-ahead blurb

3 events found

Sample Link Up next: Sample Event (Jan 9, 2027)

Groups dropdown

Desktop: a positioned menu on hover or focus. Mobile: an accordion section inside the drawer.

Desktop and mobile

Mobile drawer and toggle

The hamburger animates to a close icon; the drawer slides in from the right as a full-screen fixed panel with the Groups accordion expanded. Focus is trapped inside while open. The frosted-glass blur lives on .site-header::before, never on the header itself, so iOS Safari keeps the drawer anchored to the viewport.