Alex Dunmow 11c6c8c63e initial: theme plugin coffee
Bootstrapped during the 2026-06-06 BlockNinja consolidation. Was previously
an unversioned directory inside ~/src/blockninja-themes/coffee.

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

152 lines
6.2 KiB
CSS

/* Coffee theme styles
*
* Uses the 19 shadcn-style HSL token CSS variables (--background,
* --foreground, --primary, --accent, --border, --muted, --card, ...) via
* `hsl(var(--token))`. Font families are resolved through the BlockNinja font
* variables (--font-heading, --font-body, --font-mono) with fallback stacks
* derived from the spec §3 typography list.
*/
/* --- Font-family fallbacks ---------------------------------------------
*
* Templates use the variable form; the second argument is the fallback the
* site shows before the admin assigns fonts via the typography picker.
*/
:root {
--coffee-heading-fallback: "Fraunces", "Playfair Display", Georgia, "Times New Roman", serif;
--coffee-body-fallback: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
--coffee-mono-fallback: "JetBrains Mono", "Fira Code", Menlo, Consolas, monospace;
}
/* --- Paper grain background --------------------------------------------
*
* Inline SVG noise overlay applied as the body background. Keeps file size
* tiny and palette-neutral so it works with all three presets.
*/
body.coffee-paper {
background-color: hsl(var(--background));
background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160' viewBox='0 0 160 160'%3E%3Cfilter id='paper-grain'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.18 0 0 0 0 0.13 0 0 0 0 0.09 0 0 0 0.07 0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23paper-grain)'/%3E%3C/svg%3E");
background-repeat: repeat;
}
/* --- Headings ----------------------------------------------------------- */
.coffee-display {
font-family: var(--font-heading, var(--coffee-heading-fallback));
font-feature-settings: "liga" 1, "dlig" 1;
letter-spacing: -0.01em;
}
.coffee-body {
font-family: var(--font-body, var(--coffee-body-fallback));
line-height: 1.65;
}
.coffee-mono {
font-family: var(--font-mono, var(--coffee-mono-fallback));
}
/* --- Doodle underline (heading override) -------------------------------- */
.coffee-doodle-underline {
background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 12' preserveAspectRatio='none'%3E%3Cpath d='M2 8 Q 20 2 40 7 T 80 6 T 118 7' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' opacity='0.55'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: 0 100%;
background-size: 100% 0.5em;
padding-bottom: 0.18em;
}
/* --- Drop-cap (text override / article body) ---------------------------- */
.coffee-dropcap > p:first-of-type::first-letter {
font-family: var(--font-heading, var(--coffee-heading-fallback));
font-size: 4em;
line-height: 0.85;
float: left;
padding: 0.05em 0.12em 0 0;
color: hsl(var(--primary));
}
/* --- Kraft-tag button --------------------------------------------------- */
.kraft-tag {
position: relative;
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.55rem 1.1rem;
background-color: hsl(var(--primary));
color: hsl(var(--primary-foreground));
border: 1px solid hsl(var(--border));
border-radius: 0.25rem;
font-family: var(--font-body, var(--coffee-body-fallback));
font-weight: 500;
letter-spacing: 0.02em;
box-shadow: 0 1px 0 hsl(var(--border));
transition: transform 120ms ease, box-shadow 120ms ease;
cursor: pointer;
}
.kraft-tag:hover {
transform: rotate(-1.2deg);
box-shadow: 0 2px 0 hsl(var(--border));
}
.kraft-tag:focus-visible {
outline: 2px solid hsl(var(--ring));
outline-offset: 3px;
}
/* --- Torn-edge utility -------------------------------------------------- */
.coffee-torn-top {
-webkit-mask-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 12' preserveAspectRatio='none'%3E%3Cpath d='M0 12 L0 6 Q 5 2 10 5 T 20 4 T 30 6 T 40 3 T 50 5 T 60 4 T 70 5 T 80 3 T 90 5 T 100 4 L100 12 Z' fill='black'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 12' preserveAspectRatio='none'%3E%3Cpath d='M0 12 L0 6 Q 5 2 10 5 T 20 4 T 30 6 T 40 3 T 50 5 T 60 4 T 70 5 T 80 3 T 90 5 T 100 4 L100 12 Z' fill='black'/%3E%3C/svg%3E");
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
}
.coffee-torn-bottom {
-webkit-mask-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 12' preserveAspectRatio='none'%3E%3Cpath d='M0 0 L100 0 L100 6 Q 95 10 90 7 T 80 8 T 70 6 T 60 9 T 50 7 T 40 8 T 30 7 T 20 9 T 10 7 T 0 8 Z' fill='black'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 12' preserveAspectRatio='none'%3E%3Cpath d='M0 0 L100 0 L100 6 Q 95 10 90 7 T 80 8 T 70 6 T 60 9 T 50 7 T 40 8 T 30 7 T 20 9 T 10 7 T 0 8 Z' fill='black'/%3E%3C/svg%3E");
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
}
/* --- Coffee surfaces ---------------------------------------------------- */
.coffee-card {
background-color: hsl(var(--card));
color: hsl(var(--card-foreground));
border: 1px solid hsl(var(--border));
border-radius: 0.5rem;
}
.coffee-frame {
border: 1px solid hsl(var(--border));
background-color: hsl(var(--card));
}
.coffee-pencil-rule {
border-color: hsl(var(--border));
border-style: solid;
}
/* --- Today highlight ---------------------------------------------------- */
.coffee-hours-today {
background-color: hsl(var(--accent) / 0.15);
color: hsl(var(--accent-foreground));
border-left: 3px solid hsl(var(--accent));
padding-left: 0.75rem;
}
/* --- Price typography --------------------------------------------------- */
.coffee-price {
font-family: var(--font-mono, var(--coffee-mono-fallback));
font-variant-numeric: tabular-nums;
color: hsl(var(--accent));
}
/* --- Doodle pin overlay for location card ------------------------------- */
.coffee-pin {
color: hsl(var(--accent));
}