Files
immich-folio/app/[...path]/essay.css
Ralksta 89a8fac564 release: v0.17.0 (#677)
See CHANGELOG.md, section [0.17.0] — 2026-09-23.
2026-09-23 12:09:08 +02:00

287 lines
6.5 KiB
CSS

/* Photo Essay & Storytelling Mode Styles */
.essay-container {
/*
* One shared measure for every block, so headings, prose and figures line up
* on the same left edge. Deliberately in rem, not the `68ch` this replaces:
* `ch` is relative to each element's own font, so a serif heading resolved to
* a wider column than the body text and started further left. 40rem matches
* what 68ch produced for the body font. Custom properties are substituted as
* raw tokens, so a `ch` value here would be re-resolved per element and bring
* the bug straight back — keep this font-independent.
*
* `--essay-bleed` / `--essay-wide` are viewport-based by default and get
* overridden where the essay renders inside a narrower box (e.g. the admin
* Journal Studio preview pane).
*/
--essay-measure: 40rem;
--essay-wide: 1100px;
--essay-bleed: 100vw;
width: 100%;
max-width: 100%;
margin: 0 auto;
padding: 2rem 1.5rem 6rem 1.5rem;
}
/* Header & Cover */
.essay-header {
max-width: var(--essay-measure);
margin: 0 auto 3.5rem auto;
text-align: center;
}
.essay-header__title {
font-family: var(--font-serif, serif);
font-size: clamp(2.2rem, 5vw, 3.8rem);
font-weight: 700;
line-height: 1.15;
margin-bottom: 1rem;
letter-spacing: -0.02em;
}
.essay-header__subtitle {
font-family: var(--font-sans, sans-serif);
font-size: clamp(1.1rem, 2.5vw, 1.4rem);
opacity: 0.8;
line-height: 1.5;
margin-bottom: 1.5rem;
}
.essay-header__meta {
font-family: var(--font-caption, monospace);
font-size: 0.85rem;
opacity: 0.6;
text-transform: uppercase;
letter-spacing: 0.05em;
}
/* Reading column */
.essay-prose {
max-width: var(--essay-measure);
margin: 0 auto 2.5rem auto;
font-family: var(--font-sans, sans-serif);
font-size: clamp(1.05rem, 2vw, 1.2rem);
line-height: 1.75;
color: var(--text-primary, rgba(255, 255, 255, 0.92));
}
.essay-prose p {
margin-bottom: 1.75rem;
}
.essay-heading {
font-family: var(--font-serif, serif);
max-width: var(--essay-measure);
margin: 3.5rem auto 1.5rem auto;
font-weight: 600;
line-height: 1.25;
}
.essay-heading--1 {
font-size: clamp(1.8rem, 3.5vw, 2.5rem);
}
.essay-heading--2 {
font-size: clamp(1.5rem, 3vw, 2rem);
}
.essay-heading--3 {
font-size: clamp(1.25rem, 2.5vw, 1.6rem);
}
/* Pullquote */
.essay-quote {
max-width: var(--essay-measure);
margin: 3.5rem auto;
padding: 1.5rem 2rem;
border-left: 3px solid var(--accent, #e60012);
background: var(--bg-card, rgba(255, 255, 255, 0.03));
border-radius: 0 8px 8px 0;
font-family: var(--font-serif, serif);
font-style: italic;
font-size: clamp(1.15rem, 2.2vw, 1.35rem);
line-height: 1.6;
}
.essay-quote__author {
display: block;
margin-top: 0.75rem;
font-family: var(--font-caption, monospace);
font-style: normal;
font-size: 0.85rem;
opacity: 0.7;
text-transform: uppercase;
}
/* Essay Photos & Layout Modes */
.essay-figure {
margin: 3.5rem auto;
width: 100%;
}
.essay-figure--contained {
max-width: var(--essay-measure);
}
.essay-figure--wide {
max-width: var(--essay-wide);
}
/*
* `width` has to be set too, not just max-width: .essay-figure is width: 100%,
* which over-constrains the box so the negative right margin is dropped and only
* the left side bleeds.
*/
.essay-figure--fullbleed {
width: var(--essay-bleed);
max-width: var(--essay-bleed);
margin-left: calc(-0.5 * var(--essay-bleed) + 50%);
margin-right: calc(-0.5 * var(--essay-bleed) + 50%);
}
.essay-image-wrapper {
position: relative;
width: 100%;
overflow: hidden;
border-radius: var(--radius-md, 0px);
max-height: 80vh;
}
.essay-image-wrapper img {
object-fit: cover;
width: 100%;
height: auto;
max-height: 80vh;
display: block;
transition: transform 0.4s ease;
}
.essay-image-wrapper:hover img {
transform: scale(1.015);
}
.essay-figcaption {
max-width: var(--essay-measure);
margin: 0.75rem auto 0 auto;
text-align: center;
font-family: var(--font-caption, monospace);
font-size: 0.85rem;
opacity: 0.75;
}
/* Side by side photo pair */
/*
* Justified row: each photo keeps its own aspect ratio, and its width is given
* by `flex-grow: <aspect ratio>` (set inline from the asset). Since width ∝ ratio
* and height = width / ratio, both photos end up exactly the same height without
* a single pixel being cropped — a shared baseline instead of one portrait
* towering over a landscape.
*/
.essay-pair-grid {
display: flex;
gap: 1.5rem;
width: 100%;
max-width: var(--essay-wide);
margin: 3.5rem auto;
}
.essay-pair-grid > .essay-image-wrapper {
flex-basis: 0;
min-width: 0;
}
@media (max-width: 640px) {
/* Stacked: full width each, height from the photo's own ratio. */
.essay-pair-grid {
flex-direction: column;
gap: 1.5rem;
}
.essay-pair-grid > .essay-image-wrapper {
flex: none;
}
}
/* Map: the entry's geotagged photos as pins, a story-sized Leaflet map. */
.essay-map {
width: 100%;
height: 420px;
border-radius: var(--radius-sm, 0);
overflow: hidden;
border: 1px solid var(--border-subtle, rgba(128, 128, 128, 0.15));
background: var(--bg-secondary, #222);
}
@media (max-width: 640px) {
.essay-map {
height: 300px;
}
}
/* Facts: a short definition list in the text column — distance, venue, date. */
.essay-facts {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1rem 2rem;
max-width: var(--essay-contained, 680px);
margin: 2.5rem auto;
padding: 1.25rem 0;
border-top: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.12));
border-bottom: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.12));
}
.essay-facts__item {
margin: 0;
}
.essay-facts__label {
font-family: var(--font-caption);
font-size: 0.7rem;
letter-spacing: 0.15em;
text-transform: uppercase;
color: var(--text-muted);
margin-bottom: 0.25rem;
}
.essay-facts__value {
margin: 0;
font-family: var(--font-sans);
font-size: 1rem;
color: var(--text-primary);
}
@media (max-width: 640px) {
.essay-facts {
grid-template-columns: 1fr;
}
}
/* Grid: rows of up to three, each row justified exactly like a pair. */
.essay-grid {
display: flex;
flex-direction: column;
gap: 1.5rem;
width: 100%;
max-width: var(--essay-wide);
margin: 3.5rem auto;
}
.essay-grid-row {
display: flex;
gap: 1.5rem;
}
.essay-grid-row > .essay-image-wrapper {
flex-basis: 0;
min-width: 0;
}
@media (max-width: 640px) {
.essay-grid-row {
flex-direction: column;
}
.essay-grid-row > .essay-image-wrapper {
flex: none;
}
}