PLW PiecesFoundation 05
Palette
Type
Shape
Accent

Piece · composed section

Hero, editorial

The flagship opener: an asymmetric, type-forward layout with a rule-led kicker, an oversized display headline, and a stat aside. Built from cluster + buttons + tokens, so it re-skins from courthouse to brutalist with no markup change.

AEditorial variant
Whitman & Associates · Est. 1994

Representation that reads the room.

A mid-market firm for clients who expect the website to carry the same authority as the practice.

See our results
30 yrs
Continuous practice across three states
$240M
Recovered for clients since 2010

Semantics & a11y

  • Headline is the section's <h1>/<h2>; the kicker is a paragraph, not a heading.
  • Stats are real text, not images, so they are read in order and scale with type.
  • Single primary action plus a quiet secondary link keeps the focus order clean.

Composed from

ContainerHeading clusterEyebrowButtonLink--font-display--text-7xl--color-accent--border-heavy
// HeroEditorial.tsx — composed from Container, Cluster, Button.
export function HeroEditorial({ kicker, title, lede, primary, stats }: HeroProps) {
  return (
    <Container><div className="py-[var(--space-12)] grid gap-[var(--space-12)] items-end md:grid-cols-[1.35fr_1fr]">
      <div>
        <p className="flex items-center gap-[var(--space-3)] mb-[var(--space-6)] font-[var(--font-mono)] text-[var(--text-xs)] uppercase tracking-[.16em] text-[var(--color-muted)] before:w-[var(--space-12)] before:h-[var(--border-default)] before:bg-[var(--color-accent)]">{kicker}</p>
        <h1 className="font-[var(--font-display)] text-[clamp(var(--text-5xl),7vw,var(--text-7xl))] leading-[0.98] tracking-[-0.02em] text-[var(--color-fg)] mb-[var(--space-6)]">{title}</h1>
        <p className="text-[var(--text-xl)] text-[var(--color-muted)] max-w-[42ch] mb-[var(--space-8)]">{lede}</p>
        <Button size="lg">{primary}</Button>
      </div>
      <dl className="border-t-[length:var(--border-heavy)] border-[var(--color-fg)] pt-[var(--space-5)]">
        {stats.map(s => (
          <div key={s.label}><dd className="font-[var(--font-display)] text-[var(--text-4xl)] text-[var(--color-fg)]">{s.value}</dd>
          <dt className="text-[var(--text-sm)] text-[var(--color-muted)]">{s.label}</dt></div>
        ))}
      </dl>
    </div></Container>
  );
}

Piece · card

Feature card

Icon, title, and a short body, for a three-up grid of capabilities. Optional hover lift (a translate on most shapes, a hard nudge on brutalist).

AThree-up

Litigation

Trial-ready from day one, with the preparation to settle on your terms.

Corporate

From formation to exit, the steady hand on every transaction.

Real estate

Closings, disputes, and development, handled end to end.

Semantics & a11y

  • Each card is an <article> with a real heading; the icon is decorative (aria-hidden).
  • Hover lift is presentational; keyboard users reach any inner link normally.
  • Icon tile contrast comes from a color-mix tint, legible on every palette.

Composed from

Card baseIcon wrapperHeading--color-surface--color-accent--radius-lg--shadow-lg
// FeatureCard.tsx
export const FeatureCard = ({ icon, title, children }: FeatureProps) =>
  <article className="flex flex-col gap-[var(--space-3)] p-[var(--space-6)] rounded-[var(--radius-lg)]
    bg-[var(--color-surface)] border-[length:var(--border-thin)] border-[color:var(--color-border)]
    transition hover:-translate-y-[3px] hover:shadow-[var(--shadow-lg)]">
    <span aria-hidden className="grid place-items-center w-11 h-11 rounded-[var(--radius-md)]
      bg-[color-mix(in_srgb,var(--color-accent)_16%,var(--color-bg))] text-[var(--color-accent)]">{icon}</span>
    <h3 className="font-[var(--font-display)] text-[var(--text-xl)] text-[var(--color-fg)]">{title}</h3>
    <p className="text-[var(--text-sm)] text-[var(--color-muted)] leading-[var(--leading-normal)]">{children}</p>
  </article>;

Piece · card

Service card

A numbered, horizontal card for an indexed list of services, heavier than a feature card, with a forward link. Reads like a table of contents for the practice.

AIndexed list
01

Commercial litigation

Disputes between businesses, from contract breaches to partnership dissolutions.

Learn more
02

Corporate counsel

Ongoing advisory for growing companies, billed on a predictable retainer.

Learn more

Semantics & a11y

  • Number is decorative; the title heading carries the meaning.
  • Forward link uses the standalone Link primitive for a consistent affordance.
  • Two-column grid collapses to one on mobile.

Composed from

Card baseHeadingLink--font-mono--color-accent--space-5
// ServiceCard.tsx
export const ServiceCard = ({ index, title, children, href }: ServiceProps) =>
  <article className="grid grid-cols-[auto_1fr] gap-[var(--space-5)] p-[var(--space-6)] rounded-[var(--radius-lg)]
    bg-[var(--color-surface)] border-[length:var(--border-thin)] border-[color:var(--color-border)]">
    <span aria-hidden className="font-[var(--font-mono)] text-[var(--color-accent)] font-semibold">{index}</span>
    <div>
      <h3 className="font-[var(--font-display)] text-[var(--text-2xl)] text-[var(--color-fg)] mb-[var(--space-2)]">{title}</h3>
      <p className="text-[var(--text-sm)] text-[var(--color-muted)] mb-[var(--space-4)]">{children}</p>
      <Link tone="standalone" href={href}>Learn more</Link>
    </div>
  </article>;

Piece · card

Pricing card

Plan, price, feature list, and CTA. The featured plan inverts to the foreground color (tokens remapped locally) so it stands out on any palette without a hardcoded dark.

AThree tiers

Consult

$0intro call

A 30-minute assessment of your matter.

  • Case review
  • Written summary

Matter

Customper case

Fixed or contingency fee for a single matter.

  • Scoped engagement
  • Flexible fee structure

Semantics & a11y

  • Featured plan remaps --color-surface/muted/border locally so its check marks and text stay legible on the dark ground.
  • Each plan is an <article>; the price is real text for screen readers and zoom.
  • One CTA per card; the featured CTA is the only primary on the row.

Composed from

Card baseBadgeButton--color-fg--color-accent--text-5xl--space-5
// PricingCard.tsx — featured inverts via local token remap, no hardcoded dark.
export function PricingCard({ plan, price, per, features, cta, featured }: PricingProps) {
  return (
    <article className={`flex flex-col gap-[var(--space-5)] p-[var(--space-8)] rounded-[var(--radius-lg)] border h-full
      ${featured
        ? "bg-[var(--color-fg)] text-white border-[var(--color-fg)] [--color-muted:color-mix(in_srgb,#fff_64%,transparent)]"
        : "bg-[var(--color-surface)] border-[var(--color-border)]"}`}>
      <p className="font-[var(--font-mono)] text-[var(--text-xs)] uppercase tracking-wide text-[var(--color-muted)]">{plan}</p>
      <div className="font-[var(--font-display)] text-[var(--text-5xl)]">{price}<span className="text-[var(--text-sm)] text-[var(--color-muted)]">{per}</span></div>
      <ul className="flex flex-col gap-[var(--space-3)]">{features.map(f => <li key={f}>✓ {f}</li>)}</ul>
      <Button className="mt-auto w-full" variant={featured ? "primary" : "secondary"}>{cta}</Button>
    </article>
  );
}

Piece · card

Stat card

A single big number with a label, for a credential bar. The number is display-font; an accent fragment can highlight part of the figure.

ACredential bar
30+
Years in practice
$240M
Recovered for clients
98%
Matters settled favorably
3
States licensed

Semantics & a11y

  • Figures are real text; the accent fragment is an <em> styled, not color-only meaning.
  • Four-up bar collapses responsively; each cell keeps equal height.

Composed from

Card base--font-display--text-5xl--color-accent--color-muted
// StatCard.tsx
export const StatCard = ({ value, accent, label }: StatProps) =>
  <div className="p-[var(--space-6)] rounded-[var(--radius-lg)] bg-[var(--color-surface)] border border-[var(--color-border)]">
    <div className="font-[var(--font-display)] text-[var(--text-5xl)] text-[var(--color-fg)] leading-none">
      {value}{accent && <em className="not-italic text-[var(--color-accent)]">{accent}</em>}
    </div>
    <div className="text-[var(--text-sm)] text-[var(--color-muted)] mt-[var(--space-2)]">{label}</div>
  </div>;

Piece · card

Testimonial card

A quote, a star rating, and an attribution with an initial avatar. The avatar squares off on brutalist shapes; stars use the accent.

ATwo-up

They treated a stressful year like it was routine. That calm was worth more than any billboard promise.

D
Dana R.Manufacturing client

The only firm that returned every call the same day, and explained things in plain language.

M
Marcus L.Real estate developer

Semantics & a11y

  • Real <blockquote>/quote text; stars are decorative, pair with a text rating for AT if used as data.
  • Avatar initial is a fallback when there is no photo; add alt when a photo is used.

Composed from

Card baseBlockquote--color-accent--radius-pill--font-display
// TestimonialCard.tsx
export const TestimonialCard = ({ quote, name, role, initial }: TestiProps) =>
  <article className="flex flex-col gap-[var(--space-5)] p-[var(--space-8)] h-full rounded-[var(--radius-lg)] bg-[var(--color-surface)] border border-[var(--color-border)]">
    <Stars className="text-[var(--color-accent)]" />
    <p className="font-[var(--font-display)] text-[var(--text-xl)] text-[var(--color-fg)] leading-[var(--leading-snug)]">{quote}</p>
    <footer className="flex items-center gap-[var(--space-3)] mt-auto">
      <span className="grid place-items-center w-[42px] h-[42px] rounded-[var(--radius-pill)] bg-[color-mix(in_srgb,var(--color-accent)_22%,var(--color-bg))] text-[var(--color-accent)] font-[var(--font-display)]">{initial}</span>
      <div className="text-[var(--text-sm)]"><b className="block text-[var(--color-fg)]">{name}</b><span className="text-[var(--color-muted)]">{role}</span></div>
    </footer>
  </article>;

Piece · interactive

FAQ item

An accordion row: a question button and a collapsing answer. Single-open per group, full keyboard support, and a plus/minus icon drawn from the accent. Click a question to toggle.

AAccordion group
Yes. Every engagement starts with a 30-minute call to assess your matter and outline the road ahead, at no charge and with no obligation.
We use fixed fees, monthly retainers, or contingency depending on the matter, agreed in writing before any work begins. No surprise invoices.
Yes. You get a named lead attorney as your single point of contact, not a rotating cast of associates you have never met.

Semantics & a11y

  • Question is a real <button> with aria-expanded reflecting state; Enter/Space toggle it.
  • Answer height animates via max-height; content stays in the DOM and readable order.
  • Single-open per [data-faq-group]; the icon is decorative and mirrors state visually.

Composed from

--font-display--color-fg--color-accent--color-border--color-muted--color-ring--space-5
// FaqItem.tsx — controlled, single-open handled by the parent group.
export function FaqItem({ q, a, open, onToggle }: FaqProps) {
  return (
    <div className="border-t border-[var(--color-border)]">
      <button type="button" aria-expanded={open} onClick={onToggle}
        className="w-full flex items-center justify-between gap-[var(--space-4)] py-[var(--space-5)]
          text-left font-[var(--font-display)] text-[var(--text-lg)] text-[var(--color-fg)]
          focus-visible:outline focus-visible:outline-[color:var(--color-ring)]">
        <span>{q}</span><PlusMinus open={open} />
      </button>
      <div className={`overflow-hidden transition-[max-height] duration-200 ${open ? "max-h-80" : "max-h-0"}`}>
        <p className="pb-[var(--space-5)] text-[var(--color-muted)] leading-[var(--leading-relaxed)] max-w-[64ch]">{a}</p>
      </div>
    </div>
  );
}