release: v0.20.0

This commit is contained in:
Ralksta
2026-10-02 18:14:23 +02:00
committed by GitHub
parent 81ce886b01
commit 5f831f719a
209 changed files with 13807 additions and 803 deletions

195
app/themes/birch.css Normal file
View File

@@ -0,0 +1,195 @@
/* ══════════════════════════════════════════════════════
THEME: Birch — Scandinavian daylight
══════════════════════════════════════════════════════
Birch-white and pine-night over green-tinted greys (tokens.css), pine
and lichen as the only accent, Albert Sans throughout. The signature is
what is missing: no uppercase and no letter-spacing anywhere in the
interface, where every other preset uses tracked caps. Corners come from
the theme radius (6px). */
/* ── Sentence case everywhere ─────────────────────── */
/* :is() takes its most specific argument, so one rule outranks every base
and hero-specific caps rule it lists. */
[data-preset='birch']
:is(
.header__nav-link,
.header__wordmark,
.hero__title,
.hero__subtitle,
.hero__nav-link,
.hero--stacked .hero__title,
.hero--stacked .hero__subtitle,
.hero--fullbleed .hero__subtitle,
.hero--mosaic .hero__title,
.hero--mosaic .hero__subtitle,
.hero--mosaic .hero__nav-link,
.hero__thumbnail-label,
.hero__thumbnail-index,
.hero__nav-index,
.section-label,
.album-header__title,
.album-header__meta,
.album-header__download,
.subpage-title,
.subpage-subtitle,
.subpage-section__title,
.subpage-section__desc,
.subpage-toc__num,
.subpage-toc__label,
.subpage-grid__item-title,
.subpage-grid__item-count,
.subpage-grid__item-badge,
.album-card__title,
.album-card__count,
.photo-grid__item-exif,
.footer__name,
.footer__legal-link,
.back-link
) {
text-transform: none;
letter-spacing: 0;
font-style: normal;
}
/* ── Header ───────────────────────────────────────── */
[data-preset='birch'] .header {
background: color-mix(in srgb, var(--bg-primary) 92%, transparent);
border-bottom-color: var(--border-subtle);
}
[data-preset='birch'] .header__nav-link {
font-size: 0.85rem;
font-weight: 500;
border-bottom-color: transparent;
}
[data-preset='birch'] .header__nav-link:hover {
border-bottom-color: transparent;
}
/* The active link sits in a soft pill rather than on an underline. */
[data-preset='birch'] .header__nav-link.active {
border-bottom-color: transparent;
background: var(--bg-card-hover);
border-radius: 999px;
}
/* ── Type ─────────────────────────────────────────── */
[data-preset='birch'] .hero__title,
[data-preset='birch'] .album-header__title,
[data-preset='birch'] .subpage-title {
font-weight: 500;
}
[data-preset='birch'] .section-label {
font-size: 0.85rem;
font-weight: 500;
color: var(--text-secondary);
}
/* ── Photo grid: soft corners, pill EXIF ──────────── */
[data-preset='birch'] .photo-grid {
--grid-gap: 10px;
}
[data-preset='birch'] .photo-grid__item img {
transition: filter 300ms ease;
}
[data-preset='birch'] .photo-grid__item:hover img {
transform: none;
filter: brightness(1.03);
}
[data-preset='birch'] .photo-grid__item-exif {
left: 10px;
right: auto;
bottom: 10px;
max-width: calc(100% - 20px);
padding: 4px 10px;
border-radius: 999px;
background: color-mix(in srgb, var(--bg-card) 88%, transparent);
color: var(--text-primary);
font-size: 0.7rem;
font-weight: 500;
transition-duration: 300ms;
}
/* ── Covers: soft corners, a 2px lift ─────────────── */
[data-preset='birch'] .subpage-grid {
--subpage-gap: 16px;
}
[data-preset='birch'] .subpage-grid__item,
[data-preset='birch'] .album-card {
border-radius: var(--radius-sm);
transition: transform 300ms ease;
}
[data-preset='birch'] .subpage-grid__item:hover,
[data-preset='birch'] .album-card:hover {
transform: translateY(-2px);
}
[data-preset='birch'] .subpage-grid__item:hover img {
transform: none;
filter: brightness(0.8);
}
[data-preset='birch'] .subpage-grid__item-title,
[data-preset='birch'] .album-card__title {
font-weight: 500;
}
/* ── Stacked hero: the photo inset with soft corners ─ */
[data-preset='birch'] .hero--stacked {
gap: 12px;
padding: 16px 24px 24px;
}
[data-preset='birch'] .hero__stacked-image {
border-radius: var(--radius-md);
overflow: hidden;
}
[data-preset='birch'] .hero--stacked .hero__title {
font-family: var(--font-serif);
font-weight: 500;
}
[data-preset='birch'] .hero--stacked .hero__subtitle {
font-size: 0.95rem;
color: rgba(255, 255, 255, 0.85);
}
[data-preset='birch'] .hero__thumbnail-strip {
gap: 8px;
background: none;
}
[data-preset='birch'] .hero__thumbnail-item {
padding: 10px 18px;
border-radius: 999px;
background: var(--bg-card);
border: 1px solid var(--border-subtle);
}
[data-preset='birch'] .hero__thumbnail-item:hover {
background: var(--bg-card-hover);
}
[data-preset='birch'] .hero__thumbnail-label {
font-size: 0.85rem;
font-weight: 500;
}
@media (max-width: 640px) {
[data-preset='birch'] .hero--stacked {
padding: 8px 12px 16px;
}
[data-preset='birch'] .hero__stacked-overlay {
padding: 32px 20px;
}
}

View File

@@ -51,7 +51,7 @@
display: block;
margin-top: 20px;
font-size: 0.5rem;
color: var(--accent);
color: var(--accent-text);
letter-spacing: 0;
}
@@ -66,7 +66,7 @@
}
[data-preset='classic'] .hero__nav-link:hover {
color: var(--accent);
color: var(--accent-text);
border-bottom-color: transparent;
}
@@ -84,17 +84,6 @@
transform: scale(1.01);
}
/* Warm passepartout override */
[data-preset='classic'][data-photo-frame='passepartout'] .photo-grid__item {
background: #1a1816;
border-color: rgba(196, 154, 60, 0.12);
}
[data-preset='classic'][data-photo-frame='passepartout'][data-theme='light'] .photo-grid__item {
background: #fffdf5;
border-color: rgba(196, 154, 60, 0.2);
}
/* Album cards: warm rounded, gold hover */
[data-preset='classic'] .album-card {
border-radius: 12px;
@@ -135,12 +124,12 @@
[data-preset='classic'] .section-label::before {
content: '— ';
color: var(--accent);
color: var(--accent-text);
}
[data-preset='classic'] .section-label::after {
content: ' —';
color: var(--accent);
color: var(--accent-text);
}
/* Album & Subpage header: elegant serif */
@@ -177,7 +166,7 @@
[data-preset='classic'] .scroll-to-top:hover {
border-color: var(--accent);
color: var(--accent);
color: var(--accent-text);
}
/* Subpage grid: warm borders */
@@ -202,7 +191,7 @@
content: '◆';
padding: 0 14px;
font-size: 0.45rem;
color: var(--accent);
color: var(--accent-text);
}
[data-preset='classic'] .subpage-toc__num {
@@ -222,7 +211,7 @@
}
[data-preset='classic'] .subpage-toc__link:hover {
color: var(--accent);
color: var(--accent-text);
}
/* Section: ornamental centered divider rule */
@@ -259,5 +248,5 @@
content: '—◆—';
font-size: 0.55rem;
letter-spacing: 0.2em;
color: var(--accent);
color: var(--accent-text);
}

278
app/themes/cyanotype.css Normal file
View File

@@ -0,0 +1,278 @@
/* ══════════════════════════════════════════════════════
THEME: Cyanotype — a Prussian-blue print, set like a drawing sheet
══════════════════════════════════════════════════════
Ink-blue night in dark mode; in light mode every piece of text is
Prussian ink on cool paper (tokens.css). Jost for type, DM Mono 300 for
numbers and EXIF, ruled title blocks, registration marks, and sheets
indexed A-01, A-02. */
[data-preset='cyanotype'] {
/* Registration marks sit on the photo, so they are light in both modes. */
--cy-reg: rgba(255, 255, 255, 0.75);
}
/* ── Header: one ruled line ───────────────────────── */
[data-preset='cyanotype'] .header {
background: color-mix(in srgb, var(--bg-primary) 94%, transparent);
border-bottom: 1px solid var(--border-hover);
}
[data-preset='cyanotype'] .header__nav-link {
font-size: 0.68rem;
font-weight: 500;
letter-spacing: 0.16em;
text-transform: uppercase;
border-bottom-color: transparent;
}
[data-preset='cyanotype'] .header__nav-link:hover {
border-bottom-color: transparent;
}
[data-preset='cyanotype'] .header__nav-link.active {
color: var(--accent-text, var(--accent));
border-bottom-color: transparent;
text-decoration: underline;
text-decoration-thickness: 1px;
text-underline-offset: 6px;
}
/* ── Type ─────────────────────────────────────────── */
[data-preset='cyanotype'] .hero__title,
[data-preset='cyanotype'] .album-header__title,
[data-preset='cyanotype'] .subpage-title {
font-weight: 300;
letter-spacing: -0.01em;
text-transform: none;
}
[data-preset='cyanotype'] .hero__subtitle,
[data-preset='cyanotype'] .subpage-subtitle {
font-style: normal;
}
[data-preset='cyanotype'] .section-label,
[data-preset='cyanotype'] .subpage-section__desc {
font-size: 0.68rem;
font-weight: 500;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--text-secondary);
}
/* Title block: the album metadata as a ruled cell, in DM Mono. */
[data-preset='cyanotype'] .album-header__meta {
display: inline-flex;
flex-wrap: wrap;
border: 1px solid var(--border-hover);
font-family: var(--font-caption);
font-size: 0.7rem;
font-weight: 300;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--text-secondary);
}
[data-preset='cyanotype'] .album-header__meta > span {
padding: 6px 12px;
}
[data-preset='cyanotype'] .album-header__meta > span + span {
border-left: 1px solid var(--border-hover);
}
/* ── Photo grid: the architectural module ─────────── */
[data-preset='cyanotype'] .photo-grid {
--grid-gap: 24px;
}
[data-preset='cyanotype'] .photo-grid__item:hover img {
transform: none;
filter: none;
}
/* Registration marks: four 12px corner ticks, faded in on hover and focus.
::after belongs to the grain overlay, so they use ::before. */
[data-preset='cyanotype'] .photo-grid__item::before {
content: '';
position: absolute;
inset: 8px;
z-index: 2;
pointer-events: none;
opacity: 0;
transition: opacity var(--transition-fast);
background:
linear-gradient(var(--cy-reg), var(--cy-reg)) left top / 12px 1px no-repeat,
linear-gradient(var(--cy-reg), var(--cy-reg)) left top / 1px 12px no-repeat,
linear-gradient(var(--cy-reg), var(--cy-reg)) right top / 12px 1px no-repeat,
linear-gradient(var(--cy-reg), var(--cy-reg)) right top / 1px 12px no-repeat,
linear-gradient(var(--cy-reg), var(--cy-reg)) left bottom / 12px 1px no-repeat,
linear-gradient(var(--cy-reg), var(--cy-reg)) left bottom / 1px 12px no-repeat,
linear-gradient(var(--cy-reg), var(--cy-reg)) right bottom / 12px 1px no-repeat,
linear-gradient(var(--cy-reg), var(--cy-reg)) right bottom / 1px 12px no-repeat;
}
[data-preset='cyanotype'] .photo-grid__item:hover::before,
[data-preset='cyanotype'] .photo-grid__item:focus-visible::before {
opacity: 1;
}
[data-preset='cyanotype'] .photo-grid__item-exif {
font-family: var(--font-caption);
font-size: 0.65rem;
font-weight: 300;
letter-spacing: 0.04em;
text-transform: uppercase;
transition-duration: 200ms;
}
/* ── Covers: sheets with a caption bar ────────────── */
[data-preset='cyanotype'] .subpage-grid {
--subpage-gap: 24px;
}
[data-preset='cyanotype'] .subpage-grid__item {
aspect-ratio: auto;
border: 1px solid var(--border-subtle);
background: var(--bg-card);
transition: border-color var(--transition-fast);
}
[data-preset='cyanotype'] .subpage-grid__item:hover {
border-color: var(--border-hover);
}
[data-preset='cyanotype'] .subpage-grid__item-media {
aspect-ratio: 3 / 2;
height: auto;
}
[data-preset='cyanotype'] .subpage-grid__item:hover img {
transform: none;
filter: none;
}
[data-preset='cyanotype'] .subpage-grid__item-overlay,
[data-preset='cyanotype'] .subpage-grid__item-badge {
display: none;
}
[data-preset='cyanotype'] .subpage-grid__item-caption {
display: flex;
align-items: baseline;
gap: 14px;
padding: 12px 16px;
border-top: 1px solid var(--border-subtle);
}
[data-preset='cyanotype'] .subpage-grid__item-index,
[data-preset='cyanotype'] .subpage-grid__item-caption-count {
font-family: var(--font-caption);
font-size: 0.68rem;
font-weight: 400;
letter-spacing: 0.04em;
text-transform: uppercase;
white-space: nowrap;
}
[data-preset='cyanotype'] .subpage-grid__item-index {
color: var(--accent-text, var(--accent));
}
[data-preset='cyanotype'] .subpage-grid__item-index::before,
[data-preset='cyanotype'] .hero__nav-index::before {
content: 'A-';
}
[data-preset='cyanotype'] .subpage-grid__item-caption-title {
font-size: 0.95rem;
font-weight: 400;
color: var(--text-primary);
}
[data-preset='cyanotype'] .subpage-grid__item-caption-count {
margin-left: auto;
color: var(--text-muted);
}
[data-preset='cyanotype'] .album-card {
border: 1px solid var(--border-subtle);
}
[data-preset='cyanotype'] .album-card:hover {
transform: none;
border-color: var(--border-hover);
}
/* ── Split hero: sheet list and title block ───────── */
[data-preset='cyanotype'] .hero--split .hero__content {
text-align: left;
}
[data-preset='cyanotype'] .hero--split .hero__nav {
align-items: stretch;
gap: 0;
border-top: 1px solid var(--border-hover);
}
[data-preset='cyanotype'] .hero--split .hero__nav-link {
display: flex;
align-items: baseline;
gap: 16px;
padding: 10px 0;
border-bottom: 1px solid var(--border-subtle);
font-weight: 400;
text-decoration: none;
}
[data-preset='cyanotype'] .hero--split .hero__nav-link:hover {
color: var(--accent-text, var(--accent));
}
[data-preset='cyanotype'] .hero .hero__nav-index {
display: inline-block;
font-family: var(--font-caption);
font-size: 0.68rem;
font-weight: 300;
color: var(--accent-text, var(--accent));
}
/* The hero EXIF chip, drawn as a cell of a drawing's title block. */
[data-preset='cyanotype'] .hero--split .hero__exif-chip {
position: absolute;
left: 24px;
bottom: 24px;
z-index: 3;
display: inline-flex;
max-width: calc(100% - 96px);
padding: 6px 10px;
border: 1px solid var(--border-hover);
background: var(--bg-primary);
color: var(--text-secondary);
font-family: var(--font-caption);
font-size: 0.68rem;
font-weight: 300;
letter-spacing: 0.04em;
text-transform: uppercase;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
pointer-events: none;
}
[data-preset='cyanotype'] .footer {
border-top: 1px solid var(--border-hover);
}
@media (max-width: 640px) {
[data-preset='cyanotype'] .photo-grid {
--grid-gap: 12px;
}
[data-preset='cyanotype'] .hero--split .hero__exif-chip {
left: 12px;
bottom: 12px;
max-width: calc(100% - 80px);
}
}

View File

@@ -47,7 +47,7 @@
}
[data-preset='editorial'] .hero__nav-link:hover {
color: var(--accent);
color: var(--accent-text);
border-bottom-color: transparent;
}
@@ -213,7 +213,7 @@
}
[data-preset='editorial'] .subpage-toc__link:hover {
color: var(--accent);
color: var(--accent-text);
}
/* Section: pull-quote accent border, large cinematic title */

370
app/themes/kunsthalle.css Normal file
View File

@@ -0,0 +1,370 @@
/* ══════════════════════════════════════════════════════
THEME: Kunsthalle — photographs hung on a grey gallery wall
══════════════════════════════════════════════════════
The grey surround (tokens.css) is the point: lighter than every dark
preset, darker than every light one, as in an ISO 3664 viewing booth.
Everything else is a museum signage system: one family (Libre Franklin),
sentence-case titles, small tracked labels, and petrol reserved for
wayfinding — links and hover, never decoration. */
[data-preset='kunsthalle'] {
/* The hung shadow: a tight contact shadow plus a soft drop below. */
--kh-hang: 0 1px 2px rgba(0, 0, 0, 0.14), 0 14px 28px -14px rgba(0, 0, 0, 0.28);
--kh-hang-hover: 0 2px 4px rgba(0, 0, 0, 0.18), 0 20px 36px -16px rgba(0, 0, 0, 0.36);
}
[data-preset='kunsthalle'][data-theme='light'] {
--kh-hang: 0 1px 2px rgba(0, 0, 0, 0.1), 0 14px 28px -16px rgba(0, 0, 0, 0.22);
--kh-hang-hover: 0 2px 4px rgba(0, 0, 0, 0.12), 0 20px 36px -16px rgba(0, 0, 0, 0.3);
}
/* ── Header: wall colour, no rule ─────────────────── */
[data-preset='kunsthalle'] .header {
background: color-mix(in srgb, var(--bg-primary) 94%, transparent);
border-bottom-color: transparent;
}
[data-preset='kunsthalle'] .header__wordmark {
display: flex;
align-items: center;
margin-right: 24px;
font-family: var(--font-serif);
font-size: 0.9rem;
font-weight: 600;
color: var(--text-primary);
white-space: nowrap;
}
[data-preset='kunsthalle'] .header__nav-link {
font-size: 0.8rem;
font-weight: 400;
letter-spacing: 0;
text-transform: none;
}
[data-preset='kunsthalle'] .header__nav-link:hover {
color: var(--accent-text, var(--accent));
border-bottom-color: transparent;
}
[data-preset='kunsthalle'] .header__nav-link.active {
color: var(--text-primary);
border-bottom-color: var(--text-primary);
}
/* ── Titles: sentence case, Franklin 500 ──────────── */
[data-preset='kunsthalle'] .hero__title,
[data-preset='kunsthalle'] .album-header__title,
[data-preset='kunsthalle'] .subpage-title {
font-weight: 500;
letter-spacing: -0.01em;
text-transform: none;
}
[data-preset='kunsthalle'] .hero__subtitle,
[data-preset='kunsthalle'] .album-header__meta,
[data-preset='kunsthalle'] .subpage-subtitle {
font-style: normal;
letter-spacing: 0;
text-transform: none;
}
/* Labels: the small caps line on a wall text. */
[data-preset='kunsthalle'] .section-label,
[data-preset='kunsthalle'] .subpage-section__desc {
font-size: 0.68rem;
font-weight: 600;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--text-secondary);
}
/* ── Photo grid: hung works with wall between them ── */
/* Each photo hangs with a wall label below it: PhotoGrid's figcaption
(.photo-grid__label), in flow under the tile, so a long caption pushes the
next row down instead of running into it. The rows and columns between the
works are wall: at least 16px even when settings.yaml sets a tighter
grid.gap, which lands inline and beats the preset's 56px. */
[data-preset='kunsthalle'] .photo-grid {
--grid-gap: 56px;
row-gap: max(var(--grid-gap), 16px);
}
[data-preset='kunsthalle'] .photo-grid .photo-grid__item {
margin-bottom: 0;
transition: box-shadow var(--transition-fast);
}
/* Masonry: the work and its label stay together in one column, and the
wall below them is the figure's, not the tile's. */
[data-preset='kunsthalle'] .photo-grid--masonry > .fade-in {
break-inside: avoid;
margin-bottom: max(var(--grid-gap), 16px);
}
/* Justified: the tile keeps the row height and the label hangs below it,
so the figure grows rather than the photo shrinking. */
[data-preset='kunsthalle'] .photo-grid--justified > .fade-in {
height: auto;
}
[data-preset='kunsthalle'] .photo-grid--justified .photo-grid__item {
height: var(--grid-row-height);
}
/* The shadow frame, retuned from a soft halo to a hung shadow. */
[data-preset='kunsthalle'][data-photo-frame='shadow'] .photo-grid__item {
box-shadow: var(--kh-hang);
}
[data-preset='kunsthalle'][data-photo-frame='shadow'] .photo-grid__item:hover {
box-shadow: var(--kh-hang-hover);
}
/* Still photos: no zoom, no dimming. */
[data-preset='kunsthalle'] .photo-grid__item:hover img {
transform: none;
filter: none;
}
/* The EXIF line moves from the photo to the wall label. Under passepartout
it stays printed on the mat (that frame's rule outranks this one), and the
label drops its copy below. */
[data-preset='kunsthalle'] .photo-grid__item-exif {
display: none;
}
[data-preset='kunsthalle'][data-photo-frame='passepartout'] .photo-grid__label-exif {
display: none;
}
/* Wall label: catalogue number, the photo's caption when the site publishes
one, then camera and lens, in small Franklin on the wall. */
[data-preset='kunsthalle'] .photo-grid__label {
display: flex;
flex-direction: column;
gap: 2px;
/* As wide as the photo and never wider: a filmstrip frame sizes to its
content, and a long caption must not stretch it. */
width: 0;
min-width: 100%;
padding-top: 12px;
font-family: var(--font-caption);
font-size: 0.68rem;
font-weight: 400;
letter-spacing: 0.01em;
line-height: 1.45;
color: var(--text-muted);
transition: color var(--transition-fast);
}
[data-preset='kunsthalle'] .photo-grid__label-no {
font-weight: 600;
letter-spacing: 0.04em;
font-variant-numeric: tabular-nums;
color: var(--text-secondary);
}
[data-preset='kunsthalle'] .photo-grid__label-no::before {
content: 'No. ';
}
/* The caption reads as the work's title; three lines at most on the wall,
the lightbox has the rest. */
[data-preset='kunsthalle'] .photo-grid__label-title {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
line-clamp: 3;
overflow: hidden;
overflow-wrap: anywhere;
font-size: 0.8rem;
font-weight: 500;
letter-spacing: 0;
color: var(--text-primary);
}
[data-preset='kunsthalle'] .photo-grid__item:is(:hover, :focus-visible) + .photo-grid__label {
color: var(--text-secondary);
}
/* ── Album covers: hung, with a wall label below ──── */
[data-preset='kunsthalle'] .subpage-grid {
--subpage-gap: 40px;
}
[data-preset='kunsthalle'] .subpage-grid__item {
aspect-ratio: auto;
overflow: visible;
}
[data-preset='kunsthalle'] .subpage-grid__item-media {
aspect-ratio: 3 / 2;
height: auto;
box-shadow: var(--kh-hang);
transition: box-shadow var(--transition-fast);
}
[data-preset='kunsthalle'] .subpage-grid__item:hover .subpage-grid__item-media {
box-shadow: var(--kh-hang-hover);
}
[data-preset='kunsthalle'] .subpage-grid__item:hover img {
transform: none;
filter: none;
}
[data-preset='kunsthalle'] .subpage-grid__item-overlay,
[data-preset='kunsthalle'] .subpage-grid__item-badge {
display: none;
}
[data-preset='kunsthalle'] .subpage-grid__item-caption {
display: grid;
grid-template-columns: auto 1fr;
gap: 0 12px;
padding: 14px 0 0;
line-height: 1.4;
}
[data-preset='kunsthalle'] .subpage-grid__item-index {
grid-row: span 2;
font-size: 0.68rem;
font-weight: 600;
letter-spacing: 0.04em;
color: var(--text-muted);
font-variant-numeric: tabular-nums;
}
[data-preset='kunsthalle'] .subpage-grid__item-index::before {
content: 'No. ';
}
[data-preset='kunsthalle'] .subpage-grid__item-caption-title {
font-size: 0.9rem;
font-weight: 500;
color: var(--text-primary);
transition: color var(--transition-fast);
}
[data-preset='kunsthalle'] .subpage-grid__item:hover .subpage-grid__item-caption-title {
color: var(--accent-text, var(--accent));
}
[data-preset='kunsthalle'] .subpage-grid__item-caption-count {
font-size: 0.72rem;
color: var(--text-muted);
}
/* Standalone album cards on the home page */
[data-preset='kunsthalle'] .album-card {
border: none;
box-shadow: var(--kh-hang);
}
[data-preset='kunsthalle'] .album-card:hover {
transform: none;
box-shadow: var(--kh-hang-hover);
}
[data-preset='kunsthalle'] .album-card:hover .album-card__image {
transform: none;
}
/* ── Mosaic hero: a wall of works, the title below ── */
[data-preset='kunsthalle'] .hero--mosaic {
min-height: 0;
}
[data-preset='kunsthalle'] .hero__mosaic-grid {
gap: 28px;
min-height: 0;
height: clamp(360px, 64vh, 760px);
padding: 40px 40px 0;
max-width: var(--max-width);
margin: 0 auto;
}
[data-preset='kunsthalle'] .hero__mosaic-cell {
box-shadow: var(--kh-hang);
}
[data-preset='kunsthalle'] .hero__mosaic-overlay {
position: static;
transform: none;
max-width: var(--max-width);
margin: 0 auto;
padding: 32px 40px 72px;
text-align: left;
background: none;
backdrop-filter: none;
-webkit-backdrop-filter: none;
border: none;
border-radius: 0;
}
[data-preset='kunsthalle'] .hero--mosaic .hero__title {
font-size: clamp(1.75rem, 3vw, 2.5rem);
font-weight: 500;
letter-spacing: -0.01em;
text-transform: none;
color: var(--text-primary);
}
[data-preset='kunsthalle'] .hero--mosaic .hero__subtitle {
font-size: 0.85rem;
font-weight: 400;
letter-spacing: 0;
text-transform: none;
color: var(--text-muted);
margin-bottom: 20px;
}
[data-preset='kunsthalle'] .hero--mosaic .hero__nav {
justify-content: flex-start;
gap: 8px 24px;
}
[data-preset='kunsthalle'] .hero--mosaic .hero__nav-link {
font-size: 0.85rem;
letter-spacing: 0;
text-transform: none;
color: var(--text-secondary);
}
[data-preset='kunsthalle'] .hero--mosaic .hero__nav-link:hover {
color: var(--accent-text, var(--accent));
border-bottom-color: var(--accent);
}
/* The other hero styles keep their own layout; only the type follows. */
[data-preset='kunsthalle'] .hero__nav-link {
text-decoration-color: var(--border-hover);
}
/* ── Footer ───────────────────────────────────────── */
[data-preset='kunsthalle'] .footer {
border-top-color: transparent;
}
@media (max-width: 640px) {
[data-preset='kunsthalle'] .header__wordmark {
display: none;
}
[data-preset='kunsthalle'] .photo-grid {
--grid-gap: 44px;
}
[data-preset='kunsthalle'] .hero__mosaic-grid {
gap: 16px;
height: 72vh;
height: 72svh;
padding: 24px 20px 0;
}
[data-preset='kunsthalle'] .hero__mosaic-overlay {
padding: 24px 20px 56px;
}
}

243
app/themes/ma.css Normal file
View File

@@ -0,0 +1,243 @@
/* ══════════════════════════════════════════════════════
THEME: Ma — negative space as the material
══════════════════════════════════════════════════════
Washi-grey paper (light) or sumi (dark), one vermilion seal. Space does
the work: two columns, 64px between photos, an asymmetric offset, slow
fades and no hover transforms. The only Japanese device is tategaki —
the hero subtitle set vertically on desktop. */
/* ── Header: transparent, no rule ─────────────────── */
[data-preset='ma'] .header {
background: color-mix(in srgb, var(--bg-primary) 92%, transparent);
border-bottom-color: transparent;
}
/* The hanko: the header dot as a small square seal. */
[data-preset='ma'][data-header-dot='true'] .header__nav::before {
width: 9px;
height: 9px;
border-radius: 0;
margin-right: 14px;
}
[data-preset='ma'] .header__nav-link {
font-size: 0.78rem;
font-weight: 300;
letter-spacing: 0.08em;
text-transform: none;
border-bottom-color: transparent;
}
[data-preset='ma'] .header__nav-link:hover,
[data-preset='ma'] .header__nav-link.active {
border-bottom-color: transparent;
}
/* The active link carries the seal instead of an underline. */
[data-preset='ma'] .header__nav-link.active::before {
content: '';
display: inline-block;
width: 5px;
height: 5px;
margin-right: 8px;
vertical-align: 0.15em;
background: var(--accent);
}
/* ── Type ─────────────────────────────────────────── */
[data-preset='ma'] body {
line-height: 1.8;
}
[data-preset='ma'] .hero__title,
[data-preset='ma'] .album-header__title,
[data-preset='ma'] .subpage-title {
font-weight: 300;
letter-spacing: 0;
text-transform: none;
}
[data-preset='ma'] .album-header__title,
[data-preset='ma'] .subpage-title {
font-size: clamp(2.2rem, 4vw, 3.2rem);
line-height: 1.05;
}
[data-preset='ma'] .hero__subtitle,
[data-preset='ma'] .album-header__meta,
[data-preset='ma'] .subpage-subtitle {
font-style: normal;
font-weight: 300;
text-transform: none;
}
[data-preset='ma'] .section-label,
[data-preset='ma'] .subpage-section__desc {
font-size: 0.68rem;
font-weight: 400;
letter-spacing: 0.12em;
color: var(--text-secondary);
}
/* Light mode: a faint paper fibre on the page, never on the photos. */
[data-preset='ma'][data-theme='light'] body {
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.025'/%3E%3C/svg%3E");
background-size: 256px 256px;
}
/* ── Photo grid: air, stillness ───────────────────── */
[data-preset='ma'] .photo-grid {
--grid-gap: 64px;
}
[data-preset='ma'] .fade-in {
transition-duration: 900ms;
transition-timing-function: ease-out;
}
[data-preset='ma'] .photo-grid__item img {
transition: opacity 900ms ease-out;
}
[data-preset='ma'] .photo-grid__item:hover img {
transform: none;
filter: none;
opacity: 0.94;
}
/* Captions belong to the lightbox; the grid stays silent. */
[data-preset='ma'] .photo-grid__item-exif {
display: none;
}
/* ── Covers ───────────────────────────────────────── */
[data-preset='ma'] .subpage-grid {
--subpage-gap: 48px;
}
[data-preset='ma'] .subpage-grid__item:hover img,
[data-preset='ma'] .album-card:hover .album-card__image {
transform: none;
filter: brightness(0.9);
}
[data-preset='ma'] .subpage-grid__item-title,
[data-preset='ma'] .album-card__title {
font-family: var(--font-serif);
font-weight: 400;
letter-spacing: 0.02em;
text-transform: none;
}
[data-preset='ma'] .album-card {
border: none;
}
[data-preset='ma'] .album-card:hover {
transform: none;
}
[data-preset='ma'] .footer {
border-top-color: transparent;
}
/* ── Desktop: asymmetry and tategaki ──────────────── */
@media (min-width: 1025px) {
/* Album and subpage content sits right of centre, a sixth of the width
left empty. The home hero is full width and keeps its own layout. */
[data-preset='ma'] .main:not(:has(.hero)) {
padding-left: max(40px, 14vw);
}
}
@media (min-width: 641px) {
/* Split hero: a narrow text column, the title set low, the photo inset
into the paper rather than running to the edges. */
[data-preset='ma'] .hero--split {
grid-template-columns: 1fr 2fr;
}
[data-preset='ma'] .hero--split .hero__left {
align-items: flex-end;
justify-content: flex-start;
padding: 64px 40px 96px max(40px, 6vw);
}
[data-preset='ma'] .hero--split .hero__content {
text-align: left;
}
[data-preset='ma'] .hero--split .hero__title {
font-size: clamp(2.6rem, 4.6vw, 4rem);
line-height: 0.98;
margin-bottom: 20px;
}
[data-preset='ma'] .hero--split .hero__nav {
align-items: flex-start;
}
[data-preset='ma'] .hero--split .hero__right {
margin: 56px 56px 56px 0;
}
/* Tategaki: the subtitle runs down a column of its own beside the title
and the links. Each line of the hero text sits in a FadeIn wrapper whose
transform would capture an absolutely positioned subtitle, so this is a
grid, not a position. */
[data-preset='ma'] .hero--split .hero__content {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
column-gap: 40px;
align-items: start;
}
[data-preset='ma'] .hero--split .hero__content > * {
grid-column: 1;
}
[data-preset='ma'] .hero--split .hero__content > :has(> .hero__subtitle) {
grid-column: 2;
grid-row: 1 / span 2;
}
[data-preset='ma'] .hero--split .hero__subtitle {
margin: 0;
writing-mode: vertical-rl;
white-space: nowrap;
font-size: 0.7rem;
letter-spacing: 0.3em;
color: var(--text-muted);
}
[data-preset='ma'] .hero--split .hero__subtitle::before {
content: '';
display: inline-block;
width: 7px;
height: 7px;
margin-bottom: 12px;
background: var(--accent);
}
}
[data-preset='ma'] .hero__nav-link {
font-size: 0.85rem;
font-weight: 300;
letter-spacing: 0.06em;
text-transform: none;
}
[data-preset='ma'] .hero__nav-link:hover {
border-bottom-color: transparent;
}
@media (max-width: 640px) {
[data-preset='ma'] .photo-grid {
--grid-gap: 24px;
}
[data-preset='ma'] .subpage-grid {
--subpage-gap: 32px;
}
}

View File

@@ -81,6 +81,27 @@
color: var(--text-primary);
}
/* Over the photo the dimmed links sit on dark glass in both modes, so they
cannot take the page colours: half-opacity white came out near 3:1, and in
light mode the hover turned them --text-primary black on the dark glass.
Near-white on a denser glass (0.55 keeps 4.5:1 even over a white sky),
with the hover marked by an underline instead. */
[data-preset='minimal'] .hero--fullbleed .hero__nav {
background: rgba(0, 0, 0, 0.55);
}
[data-preset='minimal'] .hero--fullbleed .hero__nav-link {
opacity: 1;
color: rgba(255, 255, 255, 0.92);
}
[data-preset='minimal'] .hero--fullbleed .hero__nav-link:hover {
color: #fff;
text-decoration: underline;
text-decoration-color: currentColor;
text-underline-offset: 4px;
}
[data-preset='minimal'] .hero__right {
grid-column: 1;
grid-row: 1;

View File

@@ -329,10 +329,6 @@
opacity: 1;
}
[data-photo-frame='passepartout'] .photo-grid__item {
padding: 6px 6px 18px;
}
/* Minimal: adjust fullbleed hero for mobile */
[data-preset='minimal'] .hero__left {
padding: 20px 24px;

View File

@@ -45,6 +45,11 @@
box-shadow: inset 0 0 60px rgba(0, 0, 0, 0.4);
}
/* Under passepartout the vignette darkens the photo, not the mat. */
[data-preset='noir'][data-photo-frame='passepartout'] .photo-grid .photo-grid__item::before {
inset: var(--photo-mat) var(--photo-mat) var(--photo-mat-caption);
}
/* Film-edge EXIF labels */
[data-preset='noir'] .photo-grid__item-exif {
font-family: var(--font-caption);
@@ -123,7 +128,7 @@
font-family: var(--font-caption);
font-size: 0.55rem;
letter-spacing: 0.12em;
color: var(--accent);
color: var(--accent-text);
text-transform: uppercase;
}
@@ -140,7 +145,7 @@
}
[data-preset='noir'] .subpage-toc__link:hover {
color: var(--accent);
color: var(--accent-text);
}
/* Section: amber hairline rule */

246
app/themes/salon.css Normal file
View File

@@ -0,0 +1,246 @@
/* ══════════════════════════════════════════════════════
THEME: Salon — the oxblood picture gallery, done quietly
══════════════════════════════════════════════════════
Velvet-dark and plaster-rose walls (tokens.css), Gloock titles that are
never italic, Work Sans text, and a fine fillet floating 6px outside each
photo. An outline is not clipped by the item's `overflow: hidden`, so
the fillet needs no extra markup. */
/* ── Header ───────────────────────────────────────── */
[data-preset='salon'] .header {
background: color-mix(in srgb, var(--bg-primary) 94%, transparent);
border-bottom-color: var(--border-subtle);
}
[data-preset='salon'] .header__wordmark {
display: flex;
align-items: center;
margin-right: 28px;
font-family: var(--font-serif);
font-size: 1.1rem;
font-weight: 400;
color: var(--text-primary);
white-space: nowrap;
}
[data-preset='salon'] .header__nav-link {
font-size: 0.72rem;
font-weight: 300;
letter-spacing: 0.04em;
text-transform: none;
border-bottom-color: transparent;
}
[data-preset='salon'] .header__nav-link:hover {
border-bottom-color: transparent;
}
[data-preset='salon'] .header__nav-link.active {
color: var(--accent-text, var(--accent));
border-bottom-color: transparent;
}
/* ── Type: Gloock, never italic ───────────────────── */
[data-preset='salon'] .hero__title,
[data-preset='salon'] .album-header__title,
[data-preset='salon'] .subpage-title,
[data-preset='salon'] .subpage-section__title {
font-family: var(--font-serif);
font-weight: 400;
font-style: normal;
letter-spacing: 0;
text-transform: none;
}
[data-preset='salon'] .album-header__title,
[data-preset='salon'] .subpage-title {
font-size: clamp(2rem, 3.6vw, 3rem);
line-height: 1.08;
}
[data-preset='salon'] .hero__subtitle,
[data-preset='salon'] .album-header__meta,
[data-preset='salon'] .subpage-subtitle {
font-style: normal;
}
[data-preset='salon'] .section-label,
[data-preset='salon'] .subpage-section__desc {
font-family: var(--font-caption);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--text-secondary);
}
/* ── Photo grid: the fillet ───────────────────────── */
[data-preset='salon'] .photo-grid {
--grid-gap: 24px;
}
[data-preset='salon'] .photo-grid__item {
outline: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
outline-offset: 6px;
transition: outline-color 600ms ease;
}
[data-preset='salon'] .photo-grid__item:hover {
outline-color: var(--accent);
}
/* Only the fillet reacts. */
[data-preset='salon'] .photo-grid__item:hover img {
transform: none;
filter: none;
}
/* Captions stay out of the grid. */
[data-preset='salon'] .photo-grid__item-exif {
display: none;
}
/* ── Covers: Gloock titles beneath ────────────────── */
[data-preset='salon'] .subpage-grid {
--subpage-gap: 32px;
}
[data-preset='salon'] .subpage-grid__item {
aspect-ratio: auto;
overflow: visible;
}
[data-preset='salon'] .subpage-grid__item-media {
aspect-ratio: 4 / 3;
height: auto;
outline: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
outline-offset: 6px;
transition: outline-color 600ms ease;
}
[data-preset='salon'] .subpage-grid__item:hover .subpage-grid__item-media {
outline-color: var(--accent);
}
[data-preset='salon'] .subpage-grid__item:hover img {
transform: none;
filter: none;
}
[data-preset='salon'] .subpage-grid__item-overlay,
[data-preset='salon'] .subpage-grid__item-badge,
[data-preset='salon'] .subpage-grid__item-index {
display: none;
}
[data-preset='salon'] .subpage-grid__item-caption {
display: flex;
flex-direction: column;
gap: 4px;
padding: 20px 0 0;
}
[data-preset='salon'] .subpage-grid__item-caption-title {
font-family: var(--font-serif);
font-size: 1.25rem;
line-height: 1.2;
color: var(--text-primary);
}
[data-preset='salon'] .subpage-grid__item-caption-count {
font-family: var(--font-caption);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--text-muted);
}
[data-preset='salon'] .album-card {
border: none;
overflow: visible;
outline: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
outline-offset: 6px;
transition: outline-color 600ms ease;
}
[data-preset='salon'] .album-card:hover {
transform: none;
outline-color: var(--accent);
}
[data-preset='salon'] .album-card__title {
font-family: var(--font-serif);
font-weight: 400;
letter-spacing: 0;
text-transform: none;
}
/* ── Fullbleed hero: a scrim tinted from the wall ─── */
[data-preset='salon'] .hero__fullbleed-overlay {
align-items: flex-start;
justify-content: flex-end;
text-align: left;
padding: 64px clamp(24px, 5vw, 72px);
background: linear-gradient(
0deg,
color-mix(in srgb, var(--bg-primary) 94%, transparent) 0%,
color-mix(in srgb, var(--bg-primary) 70%, transparent) 28%,
color-mix(in srgb, var(--bg-primary) 20%, transparent) 55%,
transparent 75%
);
}
[data-preset='salon'] .hero--fullbleed .hero__title {
color: var(--text-primary);
font-size: clamp(2.25rem, 6vw, 4.5rem);
line-height: 1.02;
text-shadow: none;
}
[data-preset='salon'] .hero--fullbleed .hero__subtitle {
color: var(--text-secondary);
font-weight: 300;
letter-spacing: 0.04em;
text-transform: none;
text-shadow: none;
margin-bottom: 24px;
}
[data-preset='salon'] .hero--fullbleed .hero__nav {
flex-direction: row;
flex-wrap: wrap;
gap: 6px 24px;
align-items: baseline;
padding: 0;
background: none;
backdrop-filter: none;
-webkit-backdrop-filter: none;
border: none;
border-radius: 0;
}
[data-preset='salon'] .hero--fullbleed .hero__nav-link {
color: var(--text-secondary);
text-decoration-color: color-mix(in srgb, var(--accent) 50%, transparent);
}
[data-preset='salon'] .hero--fullbleed .hero__nav-link:hover {
color: var(--accent-text, var(--accent));
text-decoration-color: var(--accent);
}
[data-preset='salon'] .footer {
border-top-color: var(--border-subtle);
}
@media (max-width: 640px) {
[data-preset='salon'] .header__wordmark {
display: none;
}
[data-preset='salon'] .photo-grid {
--grid-gap: 18px;
}
}

View File

@@ -227,7 +227,7 @@
}
[data-preset='studio-modern'] .hero .hero__nav-link:hover {
color: var(--sm-accent);
color: var(--accent-text);
border-bottom-color: var(--border-subtle);
}
@@ -246,7 +246,7 @@
}
[data-preset='studio-modern'] .hero .hero__nav-link:first-child .hero__nav-index {
color: var(--sm-accent);
color: var(--accent-text);
}
[data-preset='studio-modern'] .hero .hero__nav-count {
@@ -353,7 +353,8 @@
}
[data-preset='studio-modern'] .hero--fullbleed .hero__nav-link:hover {
color: var(--sm-accent);
/* Dark glass in both modes, so the dark-mode text accent. */
color: var(--accent-text-dark, var(--accent-text));
}
[data-preset='studio-modern'] .hero--fullbleed .hero__nav-index {
@@ -362,7 +363,8 @@
}
[data-preset='studio-modern'] .hero--fullbleed .hero__nav-link:first-child .hero__nav-index {
color: var(--sm-accent);
/* Dark glass in both modes, so the dark-mode text accent. */
color: var(--accent-text-dark, var(--accent-text));
}
[data-preset='studio-modern'] .hero--fullbleed .hero__nav-count {
@@ -404,7 +406,7 @@
}
[data-preset='studio-modern'] .hero--minimal .hero__nav-link:hover {
color: var(--sm-accent);
color: var(--accent-text);
border-bottom-color: var(--sm-accent);
}
@@ -462,7 +464,7 @@
}
[data-preset='studio-modern'] .hero__thumbnail-item:hover .hero__thumbnail-label {
color: var(--sm-accent);
color: var(--accent-text);
}
[data-preset='studio-modern'] .hero__thumbnail-index {
@@ -473,7 +475,7 @@
}
[data-preset='studio-modern'] .hero__thumbnail-item:first-child .hero__thumbnail-index {
color: var(--sm-accent);
color: var(--accent-text);
}
[data-preset='studio-modern'] .hero__thumbnail-label {
@@ -588,7 +590,7 @@
[data-preset='studio-modern'] .subpage-header__kicker {
display: flex;
color: var(--sm-accent);
color: var(--accent-text);
margin-bottom: 16px;
}
@@ -657,7 +659,7 @@
font-family: var(--font-caption);
font-size: 0.6875rem;
letter-spacing: 0.06em;
color: var(--sm-accent);
color: var(--accent-text);
}
[data-preset='studio-modern'] .subpage-grid__item-caption-title {
@@ -685,7 +687,7 @@
[data-preset='studio-modern'] .subpage-toc__num {
font-family: var(--font-caption);
color: var(--sm-accent);
color: var(--accent-text);
}
[data-preset='studio-modern'] .subpage-toc__label {
@@ -745,7 +747,7 @@
}
[data-preset='studio-modern'] .album-header__back:hover {
color: var(--sm-accent);
color: var(--accent-text);
}
[data-preset='studio-modern'] .album-header__back svg {
@@ -820,10 +822,12 @@
transform: none;
}
/* EXIF-Chip statt Verlaufsband */
/* EXIF-Chip statt Verlaufsband. A block, not a flex row: text-overflow only
applies to a block container, and as flex the line was cut off mid-letter
on narrow tiles instead of ending in an ellipsis. The dot is inline-block
and vertically centred on its own (.photo-grid__item-exif::before). */
[data-preset='studio-modern'] .photo-grid__item-exif {
display: flex;
align-items: center;
display: block;
padding: 8px 12px;
background: var(--sm-chip-bg);
backdrop-filter: blur(8px);
@@ -862,7 +866,7 @@
}
[data-preset='studio-modern'] .footer__legal-link:hover {
color: var(--sm-accent);
color: var(--accent-text);
}
[data-preset='studio-modern'] .footer__link {
@@ -955,7 +959,7 @@
content: counter(sm-gear, decimal-leading-zero);
font-family: var(--font-caption);
font-size: 0.625rem;
color: var(--sm-accent);
color: var(--accent-text);
}
/* ── Map ────────────────────────────────────────────────────── */
@@ -1081,7 +1085,7 @@
font-size: 0.6875rem;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--sm-accent);
color: var(--accent-text);
}
/* ── Admin ──────────────────────────────────────────────────── */