Set up petal_components in this Phoenix + Tailwind v4 app with the look I dialed in at http://playground.petal.build/c/typography?heading=fraunces&body=inter&mono=jetbrains-mono
1. Install petal_components per https://petal.build/petal-components/rules.md (hex dep, the @source/@import lines in assets/css/app.css, `use PetalComponents` in the web module, spread the bundled JS hooks).
2. Add this to assets/css/app.css:
:root { color-scheme: light; }
.dark { color-scheme: dark; }
@theme inline {
--color-primary-50: light-dark(var(--color-gray-50), var(--color-gray-900));
--color-primary-100: light-dark(var(--color-gray-100), var(--color-gray-700));
--color-primary-200: light-dark(var(--color-gray-200), var(--color-gray-800));
--color-primary-300: light-dark(var(--color-gray-300), var(--color-gray-300));
--color-primary-400: light-dark(var(--color-gray-400), var(--color-gray-600));
--color-primary-500: light-dark(var(--color-gray-600), var(--color-gray-400));
--color-primary-600: light-dark(var(--color-gray-900), var(--color-gray-50));
--color-primary-700: light-dark(var(--color-gray-800), var(--color-gray-200));
--color-primary-800: light-dark(var(--color-gray-700), var(--color-gray-300));
--color-primary-900: light-dark(var(--color-gray-900), var(--color-gray-100));
--color-primary-950: light-dark(var(--color-gray-950), var(--color-gray-50));
}
:root {
--pc-button-solid-fg: light-dark(#ffffff, var(--color-gray-900));
}
3. Self-host these fonts:
# fetch once, commit the files (Phoenix static_paths already serves /fonts;
# mix phx.digest fingerprints them; italics render synthetic)
curl -o priv/static/fonts/fraunces-latin-wght-normal.woff2 \
https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/files/fraunces-latin-wght-normal.woff2
curl -o priv/static/fonts/inter-latin-wght-normal.woff2 \
https://cdn.jsdelivr.net/npm/@fontsource-variable/inter@5.3.0/files/inter-latin-wght-normal.woff2
curl -o priv/static/fonts/jetbrains-mono-latin-wght-normal.woff2 \
https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/files/jetbrains-mono-latin-wght-normal.woff2
/* assets/css/app.css */
@font-face {
font-family: "Fraunces";
font-style: normal;
font-weight: 100 900;
font-display: swap;
src: url("/fonts/fraunces-latin-wght-normal.woff2") format("woff2-variations");
}
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 100 900;
font-display: swap;
src: url("/fonts/inter-latin-wght-normal.woff2") format("woff2-variations");
}
@font-face {
font-family: "JetBrains Mono";
font-style: normal;
font-weight: 100 800;
font-display: swap;
src: url("/fonts/jetbrains-mono-latin-wght-normal.woff2") format("woff2-variations");
}
/* body -> --font-sans reskins the whole app via preflight;
mono -> --font-mono reaches every pc mono surface */
@theme {
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
:root {
--pc-font-heading: "Fraunces", ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
}
/* optional: raw h1-h6 outside <.h1>..<.h5> follow the heading face too */
h1, h2, h3, h4, h5, h6 {
font-family: var(--pc-font-heading, inherit);
}
<%!-- root.html.heex, before the CSS link - preload the body face only --%>
<link rel="preload" href={~p"/fonts/inter-latin-wght-normal.woff2"} as="font" type="font/woff2" crossorigin="anonymous" />
Then start the server and confirm headings, body text and code render in the chosen look.