Layout
Medice’s page rhythm comes from two classes and one layout component. Once you know them, every band on the site is predictable.
The container and the band
.site-container { @apply mx-auto w-full max-w-6xl px-6 lg:px-8; }
.section { @apply py-14 md:py-22; }
Every band in the design is py-[88px], which .section expresses as py-22 at md and up, relaxing to py-14 on small screens. The container owns the horizontal gutter; the section owns the vertical rhythm. Nothing else should set page-level padding.
A typical section is therefore:
<section class="section">
<div class="site-container">
<!-- content -->
</div>
</section>
Alternating bands set bg-background-alt on the outer <section>, which is why the container is a separate inner element — the tint runs full-bleed while the content stays in the measure.
Breakpoints
The design’s breakpoint/* values are Tailwind’s defaults, with one addition:
| Name | Width |
|---|---|
xs |
400px |
sm |
640px |
md |
768px |
lg |
1024px |
xl |
1280px |
2xl |
1536px |
xs exists for the narrowest phones, where a two-column card grid still fits but a three-column one does not. It is used sparingly; most responsive work happens at md and lg.
The two layouts
src/layouts/BaseLayout.astro is the whole shell: <!doctype html>, <html lang> from siteSettings, the <head> delegated to BaseHead, and a <body> with a single <slot />. It is the only place global.css is imported.
src/layouts/BaseHead.astro owns everything in <head> — meta, OG, JSON-LD, favicons, the font preload and the sitemap link. See SEO.
Both are intentionally chrome-free. Neither renders a header or a footer; those are Sections/Global/Header.astro and Sections/Global/Footer.astro, composed per page. That means a page can legitimately omit them — the dev-only UI catalog does — without a special layout variant.
BaseLayout’s props are title, description, optional image and noindex, and the SEO pass-throughs schema and article.
Composing a page
---
import BaseLayout from "@layouts/BaseLayout.astro";
import Header from "@components/Sections/Global/Header.astro";
import Footer from "@components/Sections/Global/Footer.astro";
import Hero from "@components/Sections/Home/Hero.astro";
---
<BaseLayout title="…" description="…">
<Header />
<main>
<Hero />
<!-- more sections -->
</main>
<Footer />
</BaseLayout>
Every route file in the theme is this shape. The route owns the URL, the SEO props and the section order; the sections own the markup.
The sticky header
The header is sticky at 114px, and two things in the codebase depend on that number.
.article-prose headings carry scroll-mt-32 so an anchor jump from the “On this page” panel does not land the heading underneath the header. Any other in-page anchor target needs the same treatment.
If you change the header’s height, scroll-mt-32 is what to change with it.
The Global sections
src/components/Sections/Global/ holds the blocks two or more page groups draw. It is worth knowing what is there before building something that already exists:
Header and PrimaryNav · Footer · Wordmark · PageHero and DetailHero · SectionHead and Eyebrow · CtaBand · FilterBar and ListingEmpty · Gallery · Testimonials · Timeline · StepsBand · AccordionBand · ChecklistPanel · FeaturePanel · PricingPanel · ProsePanel · Diagnostics · Differentiators · CredentialGrid · ClinicianGrid · LocationMap · NewsletterBand · HelpNote
A section arrives in Global/ on its second page group, not before, and it brings no page data with it — both callers pass their own strings as props. A Global/ section still reading one page’s config is only half promoted.
The listing band
Three pages draw the same filter band — the specialty grid, the clinician directory and the health library index — and it is one implementation: a search box, a row of selects, a row of shortcut chips, a live count, a grid of cards already in the DOM, and an empty state.
The data-* contract and the matching logic are in Sections/Global/_listing.ts, which is pure and checked by _listing.test.ts. _listingFilter.ts is the half that touches the document, split out because it imports ui/_client, which reads document at import time and so cannot load under plain Node.
Only the facets differ between the three pages. If you add a fourth listing, add its facets — do not copy the band.
Decorative paint
.decorative-glow reproduces the design’s mint glow — an ellipse at 24% under a blur — as a radial-gradient rather than an exported SVG. Same read, no asset, and it follows a rebrand because the color is still the token. It is pointer-events-none and -z-10; size and place it with normal utilities.
.main-text-gradient is the primary-to-mint gradient text used on accent headings and tags.