themes-editorial/style_css.go
Alex Dunmow 1d9a4c8ce6 initial: theme plugin editorial
Bootstrapped during the 2026-06-06 BlockNinja consolidation. Was previously
an unversioned directory inside ~/src/blockninja-themes/editorial.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 14:11:28 +08:00

366 lines
9.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
// editorialUtilityCSS is the theme's custom utility layer appended to the host
// Tailwind input. It is intentionally light: no @font-face rules (those are
// emitted by the host from the admin's font assignments per docs/FONTS.md), no
// hardcoded hex / rgb / named colours. Every colour goes through the shadcn
// HSL variable consumer pattern: `hsl(var(--token))`.
//
// What this CSS contracts to deliver (cross-checked against the UAT §13):
// - .prose-editorial: 64ch measure, indented continuation paragraphs.
// - .editorial-dropcap p:first-of-type::first-letter: oxblood accent,
// ≥ 3× body font-size.
// - .editorial-marginalia: italic Source Serif 4 12px right-rail asides.
// - .editorial-masthead-wordmark: Playfair Display 900 italic.
// - .editorial-pullquote: Playfair italic 38px in oxblood accent.
// - .editorial-section-label: uppercase + small-caps + hairline.
// - .editorial-hairline / hr.editorial-rule: 1px solid hsl(var(--border)).
// - .editorial-button: transparent fill, 1px border, hover → accent text.
// - .editorial-caption: Source Serif italic 14px with hairline above.
//
// All `font-family` declarations route through the three CSS variables
// (`--font-heading`, `--font-body`, `--font-mono`) the host exposes on :root,
// with fallback stacks derived from spec §3.
const editorialUtilityCSS = `
/* === Editorial theme — utility layer === */
:root {
--editorial-measure: 64ch;
--editorial-rule: 1px solid hsl(var(--border));
}
/* --- Narrow editorial column with indented continuation paragraphs --- */
.prose-editorial {
max-width: var(--editorial-measure);
margin-left: auto;
margin-right: auto;
font-family: var(--font-body, "Source Serif 4", "Source Serif Pro", Georgia, serif);
color: hsl(var(--foreground));
line-height: 1.65;
}
.prose-editorial p {
margin: 0 0 1em 0;
text-indent: 0;
}
.prose-editorial p + p {
text-indent: 1.5em;
}
.prose-editorial h1,
.prose-editorial h2,
.prose-editorial h3,
.prose-editorial h4 {
font-family: var(--font-heading, "Playfair Display", Georgia, serif);
font-weight: 700;
letter-spacing: -0.01em;
color: hsl(var(--foreground));
}
.prose-editorial a {
color: hsl(var(--accent));
text-decoration: underline;
text-decoration-thickness: 1px;
text-underline-offset: 2px;
}
/* --- Drop cap — oxblood accent first letter, ≥ 3x body size --- */
.editorial-dropcap p:first-of-type::first-letter {
font-family: var(--font-heading, "Playfair Display", Georgia, serif);
font-weight: 900;
font-style: italic;
color: hsl(var(--accent));
float: left;
font-size: 4.5em;
line-height: 0.85;
padding-right: 0.12em;
padding-top: 0.05em;
margin-bottom: -0.1em;
}
/* --- Marginalia rail (right-side italic notes) --- */
.editorial-marginalia {
font-family: var(--font-body, "Source Serif 4", "Source Serif Pro", Georgia, serif);
font-style: italic;
font-size: 12px;
line-height: 1.5;
color: hsl(var(--muted-foreground));
}
.editorial-marginalia aside {
margin: 0 0 1.5rem 0;
padding-left: 0.75rem;
border-left: var(--editorial-rule);
}
@media (max-width: 768px) {
.editorial-marginalia {
margin-top: 1.5rem;
border-top: var(--editorial-rule);
padding-top: 1rem;
}
}
/* --- Masthead wordmark --- */
.editorial-masthead-wordmark {
font-family: var(--font-heading, "Playfair Display", Georgia, serif);
font-weight: 900;
font-style: italic;
letter-spacing: -0.02em;
color: hsl(var(--foreground));
}
.editorial-masthead-kicker {
font-family: var(--font-mono, "JetBrains Mono", "SF Mono", ui-monospace, monospace);
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.15em;
color: hsl(var(--muted-foreground));
}
.editorial-masthead-rule {
border: 0;
border-top: var(--editorial-rule);
margin: 0.5rem 0 0 0;
}
/* --- Pull quote — Playfair italic in oxblood --- */
.editorial-pullquote {
font-family: var(--font-heading, "Playfair Display", Georgia, serif);
font-style: italic;
font-size: 38px;
line-height: 1.2;
color: hsl(var(--accent));
margin: 2.5rem auto;
max-width: var(--editorial-measure);
border: none;
}
.editorial-pullquote-attribution {
display: block;
margin-top: 1rem;
font-family: var(--font-body, "Source Serif 4", Georgia, serif);
font-style: normal;
font-size: 14px;
text-transform: uppercase;
letter-spacing: 0.12em;
color: hsl(var(--muted-foreground));
}
/* --- Section label — small-caps with hairline rule --- */
.editorial-section-label {
font-family: var(--font-body, "Source Serif 4", Georgia, serif);
text-transform: uppercase;
font-variant: small-caps;
font-feature-settings: "smcp";
letter-spacing: 0.15em;
font-size: 13px;
color: hsl(var(--foreground));
}
.editorial-section-label-rule {
border: 0;
border-top: var(--editorial-rule);
margin: 0.5rem 0 1.5rem 0;
}
/* --- Hairline rules --- */
hr.editorial-rule,
.editorial-hairline {
border: 0;
border-top: var(--editorial-rule);
margin: 1.5rem 0;
}
/* --- Byline --- */
.editorial-byline {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem 0;
border-top: var(--editorial-rule);
border-bottom: var(--editorial-rule);
}
.editorial-byline-photo {
width: 36px;
height: 36px;
border-radius: 50%;
background-color: hsl(var(--muted));
flex-shrink: 0;
object-fit: cover;
}
.editorial-byline-author {
font-family: var(--font-mono, "JetBrains Mono", monospace), var(--font-body, "Source Serif 4", Georgia, serif);
/* The spec calls for Inter for UI bylines. Fallback to Inter then system. */
font-family: var(--font-body, "Inter", -apple-system, sans-serif);
font-weight: 500;
font-size: 15px;
color: hsl(var(--foreground));
}
.editorial-byline-meta {
font-family: var(--font-body, "Inter", -apple-system, sans-serif);
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.1em;
color: hsl(var(--muted-foreground));
}
/* --- Override: heading (Playfair, tight tracking, optional small-caps kicker) --- */
.editorial-heading {
font-family: var(--font-heading, "Playfair Display", Georgia, serif);
font-weight: 700;
letter-spacing: -0.015em;
color: hsl(var(--foreground));
line-height: 1.15;
}
.editorial-heading-kicker {
display: block;
margin-bottom: 0.5rem;
font-family: var(--font-body, "Inter", -apple-system, sans-serif);
font-size: 12px;
text-transform: uppercase;
font-variant: small-caps;
font-feature-settings: "smcp";
letter-spacing: 0.18em;
color: hsl(var(--muted-foreground));
}
/* --- Override: text body (Source Serif, hanging quotes) --- */
.editorial-text {
font-family: var(--font-body, "Source Serif 4", "Source Serif Pro", Georgia, serif);
color: hsl(var(--foreground));
line-height: 1.7;
max-width: var(--editorial-measure);
}
.editorial-text p + p {
text-indent: 1.5em;
margin-top: 0;
}
.editorial-text blockquote {
hanging-punctuation: first;
font-style: italic;
border-left: var(--editorial-rule);
padding-left: 1rem;
margin-left: 0;
}
/* --- Override: button (hairline border, no fill, accent on hover) --- */
.editorial-button {
display: inline-block;
padding: 0.5rem 1rem;
font-family: var(--font-body, "Inter", -apple-system, sans-serif);
font-size: 13px;
text-transform: uppercase;
letter-spacing: 0.12em;
background-color: transparent;
color: hsl(var(--foreground));
border: 1px solid hsl(var(--border));
text-decoration: none;
cursor: pointer;
transition: color 150ms ease, border-color 150ms ease;
}
.editorial-button:hover,
.editorial-button:focus {
color: hsl(var(--accent));
border-color: hsl(var(--accent));
}
.editorial-button:focus-visible {
outline: 2px solid hsl(var(--ring));
outline-offset: 2px;
}
/* --- Override: image (Source Serif italic caption with hairline above) --- */
.editorial-figure {
margin: 1.5rem 0;
}
.editorial-figure img {
display: block;
width: 100%;
height: auto;
}
.editorial-figure figcaption {
margin-top: 0.75rem;
padding-top: 0.5rem;
border-top: var(--editorial-rule);
font-family: var(--font-body, "Source Serif 4", "Source Serif Pro", Georgia, serif);
font-style: italic;
font-size: 14px;
color: hsl(var(--muted-foreground));
}
/* --- Colophon --- */
.editorial-colophon {
border-top: var(--editorial-rule);
padding-top: 1.5rem;
font-family: var(--font-body, "Inter", -apple-system, sans-serif);
font-size: 13px;
color: hsl(var(--muted-foreground));
}
.editorial-colophon-issn {
font-family: var(--font-mono, "JetBrains Mono", monospace);
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.1em;
}
/* --- Page layout — narrow editorial column --- */
.editorial-column {
max-width: var(--editorial-measure);
margin-left: auto;
margin-right: auto;
padding-left: 1rem;
padding-right: 1rem;
}
.editorial-wide {
max-width: 96rem;
margin-left: auto;
margin-right: auto;
padding-left: 1rem;
padding-right: 1rem;
}
.editorial-article-grid {
display: grid;
grid-template-columns: 1fr;
gap: 1.5rem;
max-width: 80rem;
margin-left: auto;
margin-right: auto;
padding-left: 1rem;
padding-right: 1rem;
}
@media (min-width: 1024px) {
.editorial-article-grid {
grid-template-columns: minmax(0, 64ch) 16rem;
}
}
`