/* Fotoessay (Essay-01) — the layout-independent photo-essay renderer.
 *
 * Pairs with templates/portfolio/_photolog_essay.html and is loaded by BOTH
 * project shells: Journal renders every project with it, the classic shell
 * renders `preset == 'essay-01'` with it. Same policy as photolog_group.css
 * and photolog_carousel.css — a component that has to survive on very
 * different page designs gets a file of its own rather than a copy inside
 * each layout's stylesheet, so a fix lands once.
 *
 * These rules grew inside journal.css (as .jr-photolog) and were lifted out
 * unchanged in behaviour. Two things had to change to make them free-standing:
 *
 *   1. TOKENS. Journal set --jr-* on body.jr. Every value is restated here as
 *      --pfe-* with the Journal value as its fallback, so on a Journal page
 *      the component still inherits the site's own scale, and on any other
 *      page it brings sensible numbers of its own.
 *   2. RESET. The rules relied on `.jr figure { margin: 0 }`, `.jr * {
 *      box-sizing: border-box }` and `.jr img { display: block }` existing.
 *      A classic page has none of those (and styles.css adds `img { padding:
 *      0 1.5pt }`), so the component states them for its own subtree.
 *
 * The `.pf-essay .pf-essay__…` specificity doubles are load-bearing wherever
 * they appear, exactly as the `.jr .jr-photolog__…` doubles were: they must
 * beat the element-level reset directly above them (0-1-1), and on classic
 * they must beat styles.css.
 */

.pf-essay {
  --pfe-margin: var(--jr-margin, clamp(20px, 6vw, 80px));
  --pfe-section: var(--jr-section, clamp(72px, 12vw, 160px));
  --pfe-measure: var(--jr-measure, 68ch);
  --pfe-ink: var(--jr-ink, #1a1c1c);
  --pfe-ink-muted: var(--jr-ink-muted, #4c4546);
  /* The widest the photo column ever gets. The one-sided-bleed margins below
     read it as a token (they used to hardcode 1400px), which is what lets a
     variant narrow the column without the bleed geometry drifting out of
     step with it. */
  --pfe-maxw: 1400px;
  /* The beat. One token for the space between blocks AND for the space above
     the first one — a flex `gap` applies only BETWEEN children, so with
     padding-top:0 the opening block sat flush against whatever the shell put
     above it (usually a full-bleed hero). It read as a caption that had come
     loose. The essay now opens on the same beat it keeps. */
  --pfe-beat: clamp(56px, 9vw, 120px);

  padding: var(--pfe-beat) var(--pfe-margin) var(--pfe-section);
  display: flex;
  flex-direction: column;
  gap: var(--pfe-beat);
}

/* --- reset, scoped to the component (see header note 2) --- */
.pf-essay,
.pf-essay *,
.pf-essay *::before,
.pf-essay *::after { box-sizing: border-box; }
.pf-essay figure,
.pf-essay p { margin: 0; }
.pf-essay img { display: block; max-width: 100%; padding: 0; }

/* Prose takes the SAME box as a photograph: the content column, centred, with
 * --pfe-wcap available for the owner's width lever exactly as on a figure.
 * (Until 2026-08 it was capped at --pfe-measure instead, which left every
 * paragraph starting well inside the line the photographs made and read as an
 * accident rather than a decision. The measure now lives on the CHILDREN, so
 * the text still breaks at a readable line length — it just does it inside the
 * photo column rather than instead of it.)
 *
 * width:100% is load-bearing beside `margin: 0 auto`: see the note at the
 * essay-02 rules — an auto cross-axis margin on a flex item suppresses
 * `align-items: stretch`, so max-width alone shrink-wraps the box around the
 * longest line and the alignment classes below would have nothing to move. */
.pf-essay__text {
  --pfe-wcap: 100%;
  width: 100%;
  max-width: min(var(--pfe-maxw), var(--pfe-wcap));
  margin: 0 auto;
  font-size: 1.0625rem;
  line-height: 1.7;
  color: var(--pfe-ink-muted);
  text-wrap: pretty;
}
.pf-essay__text > * { max-width: var(--pfe-measure); }
.pf-essay__text p { margin: 0 0 1.1em; }
.pf-essay__text > *:last-child { margin-bottom: 0; }
/* Two columns ARE the measure — each column is already narrow — so the
 * per-paragraph cap would fight the column width and win, leaving two thin
 * ribbons in a wide box. */
.pf-essay__text--2col > * { max-width: none; }

/* --- Prose levers: alignment, width, typeface, size --- */
/* Every one of these is opt-in and emits nothing when unset (see
 * _photolog_text_block.html), so a text block written before they existed
 * renders exactly the HTML it always did.
 *
 * Left/right pin the box to the CONTENT COLUMN's edge, not the page's — the
 * same max(0px, half the leftover) recipe the one-sided bleeds use further
 * down. Below --pfe-maxw the term collapses to 0 and the block simply fills
 * the column, which is what a phone should do. */
.pf-essay .pf-essay__text--left {
  margin-left: max(0px, calc((100% - var(--pfe-maxw)) / 2));
  margin-right: auto;
}
.pf-essay .pf-essay__text--right {
  margin-right: max(0px, calc((100% - var(--pfe-maxw)) / 2));
  margin-left: auto;
}

/* Prose ATTACHED to a photograph (flow: beside / overlay) is an ordinary
 * paragraph under it until the desktop rules take over, so it needs the same
 * breathing room a caption gets. The desktop block resets this to 0 when it
 * moves the prose into the column or onto the picture. */
.pf-essay__sidetext,
.pf-essay__overlaytext { margin-top: 18px; }

/* --pfe-wcap is the owner's per-photo width cap, as ONE token every width rule
 * below just min()s against. 100% means "no cap" — what the layout would do
 * anyway. The inline --pf-w (from display_width) replaces it on desktop only;
 * see the media query further down for why a phone ignores it. It has to be
 * declared on the FIGURE, not on .pf-essay: var(--pf-w) only sees the inline
 * value on the element carrying it. */
.pf-essay .pf-essay__figure {
  --pfe-wcap: 100%;
  margin: 0 auto;
  width: 100%;
  max-width: var(--pfe-maxw);
}
/* …but not when the essay's OWN head is directly above it. The head already
   carries a generous bottom padding, and head + beat stacked to ~184px on the
   classic shell — the two are one unit, so the head owns the space between
   them. When there is no head (Journal, where a hero or .jr-project-head sits
   above instead, or a project whose head is entirely suppressed), the sibling
   never matches and the beat applies as normal. */
.pf-essay-head + .pf-essay { padding-top: 0; }

.pf-essay__media { width: 100%; }
/* width:100% + the template's inline max-width cap = fill the column, but
 * never upscale past the photo's natural size. */
/* A lone photograph spans the column at its natural height. ⚠️ Deliberately
   NOT the carousel's media: photolog_carousel.css manages its own slides
   (height: 100%, object-fit: contain in a fixed frame), and this blanket rule
   outweighs it — (0,3,1) vs (0,2,0), loaded later besides. Its `height: auto`
   once neutered `contain` here: a portrait slide rendered at full frame WIDTH,
   grew past the frame and was clipped — indistinguishable from `cover`
   cropping, invisible on slides that happen to match the frame ratio, and
   only on essay layouts (found on /projekt/wien/, 2026-08-29). */
.pf-essay .pf-essay__figure img:not(.pf-carousel__img):not(.pf-carousel__fill) {
  width: 100%; height: auto; cursor: zoom-in;
}
/* Full-width figures shrink-wrap to the photo and centre as one unit, so a
 * photo narrower than the content box doesn't strand at the left edge on wide
 * monitors — and its caption stays aligned with the image edge. min-width
 * keeps captions of very small photos readable. */
.pf-essay .pf-essay__figure--full {
  width: fit-content;
  /* fit-content alone shrink-wraps to the WIDER of photo and caption, so a
   * long caption under a small photograph made the figure wider than the
   * picture and the caption ran past its right edge. Capping at the photo's
   * own pixels is what makes the box the photograph's box. */
  max-width: min(var(--pfe-maxw), var(--pf-nat, var(--pfe-maxw)), var(--pfe-wcap));
  /* min-width outranks max-width in CSS, so the readability floor needs the
   * same clamp — otherwise a 200px photo still gets a 320px caption line
   * hanging off its edge. */
  min-width: min(320px, var(--pf-nat, 320px), var(--pfe-wcap), 100%);
}

.pf-essay__caption {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  margin-top: 14px;
  font-size: 0.75rem;
  line-height: 1.4;
  color: var(--pfe-ink-muted);
}
.pf-essay__caption-title {
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--pfe-ink);
}
.pf-essay__caption-text { max-width: 48rem; }

/* Side-aligned figures: photo on its side, caption in the free column —
 * bottom-aligned so it reads like a label anchored to the image base, and
 * mirrored so the text always hugs the photograph across the gap. Mobile
 * stacks naturally. */
@media (min-width: 768px) {
  /* Below this breakpoint every figure is one stacked column at full width,
   * which is also why --pf-w is honoured only from here up: a percentage of a
   * phone screen only makes a photograph too small to read. */
  .pf-essay .pf-essay__figure { --pfe-wcap: var(--pf-w, 100%); }
  /* Prose gets the identical lever, on the identical terms: the owner's width
   * on desktop, the full column on a phone. A paragraph and a photograph mean
   * the same thing by the same control — which is the entire point of giving
   * text blocks the photo vocabulary instead of inventing margins for them. */
  .pf-essay .pf-essay__text { --pfe-wcap: var(--pf-w, 100%); }

  .pf-essay__figure--left,
  .pf-essay__figure--right {
    /* One token, used by both the gap and the media share: 3fr of
     * (100% - gap) is what `minmax(0, 3fr)` used to resolve to, and writing it
     * out is what lets min() clamp it by the photograph. */
    --pfe-side-gap: clamp(24px, 3.5vw, 48px);
    --pfe-media-share: calc(75% - 0.75 * var(--pfe-side-gap));
    /* A caption beside a photograph is a label, not a column of prose. Once
     * the media track started following the picture, the old `1fr` caption
     * track swallowed every pixel the photo did not use — a 420px photo in a
     * 1400px figure left a 932px caption, wider than the thing it describes.
     * A fifth of the essay column is the cap; the percentage sits in
     * grid-template-columns precisely because a percentage THERE resolves
     * against the figure, so "20 %" means a fifth of the row and not a fifth
     * of the leftovers (a max-width on the caption itself would resolve
     * against its own track and mean nothing stable). max() keeps the 180px
     * floor that stops a label from being crushed on a small desktop. */
    --pfe-caption-max: max(180px, 20%);
    /* The floor, as a token rather than a literal, for exactly one reason: a
     * figure carrying PROSE in this column needs a bigger one (a 180px column
     * is a label's width, not a paragraph's). Same value as the literal it
     * replaced — the --sidetext rules below are the only thing that moves it. */
    --pfe-caption-min: 180px;
    display: grid;
    /* The photograph carries the row: 3:1 in favour of the media, with a
     * floor on the caption so it never gets crushed on small desktops.
     * Was `minmax(0, 3fr)` — but an fr track is sized by the ROW, not by the
     * picture, so the caption column started where the photo would have ended
     * had it been big enough. minmax(0, min(…)) keeps the track shrinkable, so
     * the 180px caption floor still wins, while never growing past the photo's
     * own pixels or the owner's width. */
    grid-template-columns:
      minmax(0, min(var(--pfe-media-share),
                    var(--pf-nat, var(--pfe-media-share)),
                    var(--pfe-wcap)))
      minmax(var(--pfe-caption-min), var(--pfe-caption-max));
    gap: var(--pfe-side-gap);
    align-items: end;
  }
  .pf-essay__figure--left .pf-essay__media { grid-column: 1; grid-row: 1; }
  .pf-essay__figure--left .pf-essay__caption {
    grid-column: 2;
    grid-row: 1;
    margin-top: 0;
    flex-direction: column;
    align-items: flex-start;
  }

  .pf-essay__figure--right {
    /* Neither track is `1fr` any more, so they no longer fill the row and the
     * leftover space has to be told where to go. Pushing the pair to the end
     * is what keeps a right-aligned photograph on the right edge — without
     * this it would drift into the middle of the row as soon as the caption
     * hit its cap. (The --bleed overrides below restore fr tracks, which fill
     * exactly, so this is inert for them.) */
    justify-content: end;
    grid-template-columns:
      minmax(180px, var(--pfe-caption-max))
      minmax(0, min(var(--pfe-media-share),
                    var(--pf-nat, var(--pfe-media-share)),
                    var(--pfe-wcap)));
  }
  .pf-essay__figure--right .pf-essay__media { grid-column: 2; grid-row: 1; }
  /* Right edge meets the container edge, aligned with full-width photos. */
  .pf-essay__figure--right .pf-essay__media img { display: block; margin-left: auto; }
  .pf-essay__figure--right .pf-essay__caption {
    grid-column: 1;
    grid-row: 1;
    margin-top: 0;
    flex-direction: column;
    align-items: flex-end;
    text-align: right;
  }

  /* There used to be a pull-up here: a full figure's caption carried
   * `margin-bottom: calc(-14px - 1.4em)` so the caption would not add to the
   * gap and the rhythm would read photograph-to-photograph. It measured a
   * SINGLE line, which is the only case it got right — a caption wrapping to
   * three lines had one line removed and left the next block 54px further
   * away than everywhere else (measured at 1600px: 174px instead of 120px).
   * Shrink-wrapping full figures to the photograph made wrapped captions
   * commoner, not rarer, so the exception got louder.
   *
   * The rule now is the one with no exceptions: EVERY block — text, photo,
   * photo with caption — is separated from its neighbours by the flex gap,
   * measured from what the eye can actually see. A caption is part of its
   * block and takes its own room, exactly like a paragraph does. This is also
   * what mobile always did, so the two now agree instead of diverging at
   * 768px. */

  .pf-essay__text--2col { columns: 2; column-gap: clamp(32px, 5vw, 72px); }

  /* --- flow: beside — prose in the column the photograph already leaves ----
   * A side-aligned figure has always had a free column; until now only a
   * caption lived there, and the track was sized for a label (20 %, floor
   * 180px). Prose needs a paragraph's width, so the --sidetext figure re-cuts
   * the row closer to 60/40 and raises the floor to something a sentence can
   * survive in.
   *
   * The row also gains a SECOND track. Stacking text and caption in one cell
   * (align-self: start / end) was the obvious move and it is wrong: nothing
   * stops a long text from running down into its caption, and the failure is
   * silent — overlapping type, on a customer's published page. Two rows make
   * the collision impossible. Prose starts at the top of its column, the
   * caption stays pinned to the bottom where a label belongs, and the
   * photograph spans both so its base still lines up with the caption. When
   * the prose outgrows the photograph the row simply gets taller, which is
   * the one outcome that still reads as composed.
   *
   * Below 768px none of this applies: the figure is one stacked column, so
   * media, prose and caption fall into source order by themselves. */
  .pf-essay__figure--sidetext {
    --pfe-media-share: calc(62% - 0.62 * var(--pfe-side-gap));
    --pfe-caption-max: max(280px, 38%);
    --pfe-caption-min: 240px;
    grid-template-rows: 1fr auto;
  }
  .pf-essay__figure--left.pf-essay__figure--sidetext .pf-essay__media,
  .pf-essay__figure--right.pf-essay__figure--sidetext .pf-essay__media {
    grid-row: 1 / -1;
  }
  .pf-essay__figure--left.pf-essay__figure--sidetext .pf-essay__sidetext {
    grid-column: 2;
  }
  .pf-essay__figure--right.pf-essay__figure--sidetext .pf-essay__sidetext {
    grid-column: 1;
  }
  .pf-essay__figure--sidetext .pf-essay__sidetext {
    grid-row: 1;
    align-self: start;
    /* The page-level levers are the PAGE's; inside a figure the column decides
     * the width, so a width or an alignment set on this block earlier does not
     * follow it in here and leave prose floating in its own column. */
    --pfe-wcap: 100%;
    max-width: 100%;
    margin: 0;
    font-size: clamp(0.9375rem, 0.9rem + 0.2vw, 1.0625rem);
    line-height: 1.62;
  }
  .pf-essay__figure--sidetext .pf-essay__sidetext > * { max-width: none; }
  /* Two columns inside a 40 %-wide side column would be two ribbons. Attached
   * prose is single-column whatever the block's own setting says. */
  .pf-essay__figure--sidetext .pf-essay__sidetext,
  .pf-essay__overlaytext { columns: auto; }
  .pf-essay__figure--left.pf-essay__figure--sidetext .pf-essay__caption,
  .pf-essay__figure--right.pf-essay__figure--sidetext .pf-essay__caption {
    grid-row: 2;
    align-self: end;
    margin-top: 18px;
  }

  /* --- flow: overlay — prose ON the photograph ----------------------------
   * Desktop only, and the scrim is why. White type straight onto an unknown
   * photograph is a coin toss: it lands on a bright sky and disappears. The
   * gradient guarantees the bottom of the frame is dark enough to read
   * against, whatever the owner uploaded, and it fades out well before the
   * middle so it never reads as a filter over the picture.
   *
   * On a phone this whole rule set is absent and the text renders as an
   * ordinary paragraph under the photograph (see the base rules): a phone
   * screen has no room to spare a third of the frame to type, and a
   * photograph small enough to fit in a hand should not be covered. */
  .pf-essay__figure--overlay .pf-essay__media { position: relative; }
  .pf-essay__figure--overlay .pf-essay__media::after {
    content: "";
    position: absolute;
    inset: auto 0 0 0;
    height: 62%;
    background: linear-gradient(to top,
                                rgb(0 0 0 / 0.66),
                                rgb(0 0 0 / 0.28) 42%,
                                rgb(0 0 0 / 0));
    pointer-events: none;
  }
  .pf-essay__overlaytext {
    position: absolute;
    left: clamp(20px, 4.5%, 56px);
    right: clamp(20px, 4.5%, 56px);
    bottom: clamp(18px, 4%, 48px);
    /* Above the scrim: a ::after paints after every child, so without this the
     * gradient would sit on top of the very text it exists to make readable. */
    z-index: 1;
    width: auto;
    max-width: min(52ch, 62%);
    margin: 0;
    color: #fff;
    /* Belt to the scrim's braces, for the thin strokes at the top of the
     * block where the gradient has already faded. */
    text-shadow: 0 1px 12px rgb(0 0 0 / 0.45);
    font-size: clamp(1rem, 0.94rem + 0.3vw, 1.1875rem);
    line-height: 1.55;
  }
  .pf-essay__overlaytext > * { max-width: none; }
  /* A right-aligned photograph reads right-to-left, so its overlay hugs the
   * same edge the picture does rather than drifting to the far side. */
  .pf-essay__figure--right.pf-essay__figure--overlay .pf-essay__overlaytext {
    margin-left: auto;
    text-align: right;
  }
}

/* --- Randlos (full-bleed) figures --- */
/* .pf-essay owns the page's side padding (--pfe-margin) and spans the full
 * width, so a figure reaches the true page edge with a negative margin of
 * exactly that padding — no vw units, no scrollbar overflow. width:auto is
 * load-bearing: a block with width:100% only SHIFTS under a negative margin;
 * auto stretches to fill the containing block plus the margins. Placed after
 * the figure/--full rules so the equal-specificity overrides win by order. */
.pf-essay .pf-essay__figure--bleed { max-width: none; width: auto; }
/* Defeat the inline natural-width cap: randlos always fills, upscaling. */
.pf-essay .pf-essay__figure--bleed .pf-essay__media img {
  max-width: 100% !important;
  width: 100%;
}

/* Vollbild randlos: both edges out (undoes --full's fit-content shrink-wrap);
 * the caption keeps the page indent. */
.pf-essay .pf-essay__figure--full.pf-essay__figure--bleed {
  width: auto;
  min-width: 0;
  margin-left: calc(-1 * var(--pfe-margin));
  margin-right: calc(-1 * var(--pfe-margin));
}
.pf-essay .pf-essay__figure--full.pf-essay__figure--bleed .pf-essay__caption {
  padding: 0 var(--pfe-margin);
}

/* Links/Rechts randlos: ONLY the aligned edge pulls to the page edge; the
 * opposite edge stays pinned on the normal content-column line — the
 * percentage margin re-creates the centering the max-width cap provided.
 * Explicit margins on both sides also remove the auto centering. Applies at
 * every width — stacked mobile figures bleed one side too. */
.pf-essay .pf-essay__figure--left.pf-essay__figure--bleed {
  margin-left: calc(-1 * var(--pfe-margin));
  margin-right: max(0px, calc((100% - var(--pfe-maxw)) / 2));
}
.pf-essay .pf-essay__figure--right.pf-essay__figure--bleed {
  margin-left: max(0px, calc((100% - var(--pfe-maxw)) / 2));
  margin-right: calc(-1 * var(--pfe-margin));
}
@media (min-width: 768px) {
  /* Randlos claims proportionally more of the row for the photograph: 4:1
   * instead of the normal 3:1 — on top of the extra width the bleed itself
   * adds to the figure. */
  .pf-essay .pf-essay__figure--left.pf-essay__figure--bleed {
    grid-template-columns: minmax(0, 4fr) minmax(180px, 1fr);
  }
  .pf-essay .pf-essay__figure--right.pf-essay__figure--bleed {
    grid-template-columns: minmax(180px, 1fr) minmax(0, 4fr);
  }
}
@media (max-width: 767px) {
  /* Stacked: the caption under a one-sided bleed keeps the page indent on
   * the bled side (the other side already sits on the content line). */
  .pf-essay .pf-essay__figure--left.pf-essay__figure--bleed .pf-essay__caption {
    padding-left: var(--pfe-margin);
  }
  .pf-essay .pf-essay__figure--right.pf-essay__figure--bleed .pf-essay__caption {
    padding-right: var(--pfe-margin);
  }
}

/* ------------------------------------------------------- essay header -- */
/* The classic shell has no head of its own for an essay project (Journal
   brings .jr-hero / .jr-project-head), so the essay carries one: title, the
   Ort/Zeitraum pair, and the lede. Rendered by _photolog_essay_header.html,
   which is included only where the shell needs it. */
.pf-essay-head {
  padding: clamp(48px, 8vw, 96px) var(--jr-margin, clamp(20px, 6vw, 80px)) clamp(32px, 5vw, 64px);
  max-width: 1400px;
  margin: 0 auto;
  color: var(--jr-ink, #1a1c1c);
}
.pf-essay-head__title {
  margin: 0;
  font-family: var(--jr-font-display, "Iowan Old Style", Georgia, serif);
  font-weight: 500;
  font-size: clamp(2rem, 5vw, 3.5rem);
  line-height: 1.1;
  letter-spacing: -0.01em;
}
.pf-essay-head__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 32px;
  margin: 20px 0 0;
  font-size: 0.75rem;
  line-height: 1.4;
  color: var(--jr-ink-muted, #4c4546);
}
.pf-essay-head__meta-row { display: flex; gap: 8px; margin: 0; }
.pf-essay-head__meta dt {
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.pf-essay-head__meta dd { margin: 0; }
.pf-essay-head__lede {
  max-width: var(--jr-measure, 68ch);
  margin: 24px 0 0;
  font-size: 1.0625rem;
  line-height: 1.7;
  color: var(--jr-ink-muted, #4c4546);
  text-wrap: pretty;
}


/* ------------------------------------------------ Essay fallback header -- */
/* The sticky nav _essay_header.html renders on a CLASSIC essay project whose
   owner turned the site nav off. Unrelated to the essay body above — it lives
   here only because this file is the one stylesheet an essay page is
   guaranteed to load. Journal pages render their own nav and never emit this
   markup. */

.essay-header {
  position: sticky;
  top: 0;
  z-index: 20;
  background: rgba(255, 255, 255, 0.9);
  backdrop-filter: saturate(180%) blur(8px);
  border-bottom: 1px solid #ececec;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
.essay-header__inner {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 clamp(24px, 5vw, 64px);
  height: 60px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
}
.essay-header__brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  color: #191c1d;
  font-weight: 600;
  font-size: 1.05rem;
  text-decoration: none;
  white-space: nowrap;
}
.essay-header__brand:hover { color: #191c1d; text-decoration: none; opacity: 0.7; }
.essay-header__brand i { font-size: 0.85rem; color: #9aa0a6; }
.essay-header__nav { display: flex; align-items: center; gap: clamp(1rem, 3vw, 2rem); }
.essay-header__link {
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  font: inherit;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #5c5c61;
  text-decoration: none;
  transition: color 0.15s ease;
  white-space: nowrap;
}
.essay-header__link:hover { color: #191c1d; text-decoration: none; }
.essay-header__link i { font-size: 0.6rem; margin-left: 0.15rem; }

.essay-header__dropdown { position: relative; }
.essay-header__menu {
  display: none;
  position: absolute;
  top: 100%;
  right: 0;
  margin-top: 0.6rem;
  min-width: 200px;
  max-height: 60vh;
  overflow-y: auto;
  background: #fff;
  border: 1px solid #ececec;
  border-radius: 8px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.1);
  padding: 0.4rem;
}
.essay-header__dropdown:hover .essay-header__menu,
.essay-header__dropdown:focus-within .essay-header__menu { display: block; }
.essay-header__menu a {
  display: block;
  padding: 0.5rem 0.65rem;
  font-size: 0.9rem;
  color: #374151;
  text-decoration: none;
  border-radius: 5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.essay-header__menu a:hover { background: #f4f6fb; color: #191c1d; text-decoration: none; }

@media (max-width: 600px) {
  .essay-header__brand span { max-width: 40vw; overflow: hidden; text-overflow: ellipsis; }
}

/* The feedback strip when it sits in the essay head: quiet ink pills under the
   lede, matching the head's muted metadata tone. (Moved here from project.css
   — the head is the essay's, and project.css is a classic-only stylesheet.) */
.pf-essay-head .pf-strip { margin-top: 1.75rem; }
.pf-essay-head .pf-strip__item {
  border-color: #d9d9d9;
  color: #4a4a4a;
}
.pf-essay-head .pf-strip__item:hover { border-color: #9a9a9a; color: #1c1c1c; }
.pf-essay-head .pf-strip__like.is-liked { border-color: #1c1c1c; color: #1c1c1c; }

/* ===========================================================================
   VARIANTS
   ===========================================================================
   Four presets, one renderer, one stylesheet. They differ on the only axis a
   photo essay really has: HOW THE PROSE AND THE PHOTOGRAPHS RELATE. Everything
   above is the shared machine (sequence, alignment, bleed, caption geometry);
   everything below is voice.

   The class comes from PortfolioProject.essay_variant, so `simple` projects on
   a Journal site — which render through this partial regardless of preset —
   land on essay-01 and are untouched by any of this.

     essay-01   photographs lead, prose is a narrow centred aside.
                FROZEN: it is live on published customer sites, and its prose
                deliberately keeps inheriting the shell's body font. Nothing
                below targets it. Do not "improve" it here — that is what
                essay-01b exists for.
     essay-01b  the same composition, with prose that owns its typography.
     essay-02   "Archiv" — the prose stops apologising and squares up to the
                photo column.
     essay-03   "Lesebuch" — inverted: the prose leads and the photographs are
                set into its measure.

   Why the prose needed owning at all: .pf-essay__text sets a size, a leading
   and a colour but no font-family, so on a classic site it spoke Nunito and on
   a Journal site Hanken Grotesk, while the essay's own head spoke Playfair
   Display. The photographs had a voice and the headline had a voice; the prose
   borrowed one. And it was set in --pfe-ink-muted while a caption TITLE got
   full --pfe-ink, so the label out-ranked the essay it labelled. */

/* --- essay-01b — Essay-01, with the prose given a voice -------------------
   Same composition, same colours, same caption vocabulary. Three changes, all
   typographic: the prose is pinned to one face instead of inheriting the
   shell's, it is set in full ink instead of muted, and the measure is stated
   in the reading face's own characters rather than inherited from whatever
   font happened to win. Hanken Grotesk pairs with the Playfair head on a
   structure axis (serif display / humanist sans body) and is already the
   Journal body face, so a Journal page changes only in weight of ink. */
.pf-essay--essay-01b {
  --pfe-measure: 66ch;
}
.pf-essay--essay-01b .pf-essay__text {
  font-family: "Hanken Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI",
               Roboto, sans-serif;
  /* One step up from 1.0625rem, fluid: at this measure the old size read as a
     long caption rather than as the essay's own voice. */
  font-size: clamp(1.0625rem, 1rem + 0.3vw, 1.1875rem);
  line-height: 1.68;
  color: var(--pfe-ink);
  letter-spacing: -0.003em;
}
/* Paragraph rhythm: space between, never space AND indent. */
.pf-essay--essay-01b .pf-essay__text p { margin: 0 0 1.15em; }

/* --- essay-02 "Archiv" ----------------------------------------------------
   Reference object: a picture archive's typed caption strip. One grotesque for
   everything — Archivo is drawn for print captions and highlight text, so it
   holds up small without the neutral-UI blankness — with hierarchy carried by
   weight and size, not by a second family.

   The composition move: the prose is no longer centred. Its box is the SAME
   box as a photograph (--pfe-maxw, centred), and the paragraphs are capped at
   the reading measure INSIDE that box. So the prose's left edge lands exactly
   on every photograph's left edge, and the two grids finally line up — which
   is the thing that made the centred prose read as a caption adrift. */
.pf-essay--essay-02 {
  --pfe-ink: #16181a;
  --pfe-ink-muted: #4a4f55;
  --pfe-measure: 64ch;
}
.pf-essay--essay-02 .pf-essay__text {
  /* width:100% is load-bearing next to the auto margins, and is exactly the
     recipe .pf-essay__figure already uses. An auto cross-axis margin on a flex
     item SUPPRESSES align-items:stretch, so `max-width + margin:0 auto` alone
     left the box shrink-wrapped around the paragraph and centred — the very
     thing this variant exists to stop. With a definite width it spans the
     photo column and the paragraph sits at its left edge. */
  width: 100%;
  max-width: var(--pfe-maxw);
  margin: 0 auto;
  font-family: "Archivo", -apple-system, BlinkMacSystemFont, "Segoe UI",
               Roboto, sans-serif;
  font-size: clamp(1rem, 0.95rem + 0.3vw, 1.125rem);
  line-height: 1.62;
  color: var(--pfe-ink);
}
.pf-essay--essay-02 .pf-essay__text > * { max-width: var(--pfe-measure); }
.pf-essay--essay-02 .pf-essay__text p { margin: 0 0 1.1em; }
/* Two columns keep the photo box, so a 2-col text block spans the picture
   column exactly rather than a measure of its own. */
.pf-essay--essay-02 .pf-essay__text--2col { width: 100%; max-width: var(--pfe-maxw); }
.pf-essay--essay-02 .pf-essay__text--2col > * { max-width: none; }

/* Captions: same family, no tracked-uppercase label. The small-caps-with-
   letterspacing tell belongs to the editorial lane essay-01 lives in; here the
   caption is a typed archive note, so the title is simply the heavier word at
   the front of it. */
.pf-essay--essay-02 .pf-essay__caption {
  font-family: "Archivo", -apple-system, BlinkMacSystemFont, "Segoe UI",
               Roboto, sans-serif;
  font-size: 0.8125rem;
  line-height: 1.45;
}
.pf-essay--essay-02 .pf-essay__caption-title {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 600;
}
.pf-essay-head--essay-02 .pf-essay-head__title {
  font-family: "Archivo", -apple-system, BlinkMacSystemFont, "Segoe UI",
               Roboto, sans-serif;
  font-weight: 700;
  /* -0.02em: firm, and well clear of the -0.04em floor where letters touch. */
  letter-spacing: -0.02em;
}
.pf-essay-head--essay-02 .pf-essay-head__meta {
  font-family: "Archivo", -apple-system, BlinkMacSystemFont, "Segoe UI",
               Roboto, sans-serif;
}

/* --- essay-03 "Lesebuch" --------------------------------------------------
   Reference object: a small-press photobook. The inversion: the PROSE leads.
   The photo column narrows to the book's page (900px) so photographs sit
   inside the text's world rather than the text floating in theirs, and the
   beat tightens to match a page rather than a gallery wall.

   Which makes `full_bleed` mean something it could not mean before: in this
   variant it is the deliberate escape from the reading measure — the one
   photograph allowed to leave the page. The bleed margins read --pfe-maxw as a
   token now, so they follow the narrower column without any variant-specific
   geometry.

   Literata is a reading face (drawn for long-form on screen, slightly slabbed,
   warm) rather than a display serif — which is what keeps this out of the
   display-serif-plus-mono-labels editorial lane it would otherwise fall into. */
.pf-essay--essay-03 {
  --pfe-maxw: 900px;
  --pfe-measure: 62ch;
  --pfe-beat: clamp(44px, 6vw, 84px);
  --pfe-ink: #1b1a18;
  --pfe-ink-muted: #4a4642;
}
.pf-essay--essay-03 .pf-essay__text {
  /* One spine. The head and every photograph sit at the page's left edge, so
     the prose does too — it is the leading voice here, not a centred inset.
     Same recipe as essay-02 (width:100% beside the auto margins, paragraphs
     capped at the measure inside), at book width instead of gallery width. */
  width: 100%;
  max-width: var(--pfe-maxw);
  margin: 0 auto;
  font-family: "Literata", "Iowan Old Style", Georgia, "Times New Roman", serif;
  font-size: clamp(1.0625rem, 1rem + 0.4vw, 1.25rem);
  line-height: 1.64;
  color: var(--pfe-ink);
}
.pf-essay--essay-03 .pf-essay__text > * { max-width: var(--pfe-measure); }
.pf-essay--essay-03 .pf-essay__text--2col > * { max-width: none; }
.pf-essay--essay-03 .pf-essay__text p { margin: 0 0 1.2em; }
/* The photograph is a guest on the page, not the room: it is held to the
   book's page width, a little wider than the text block it sits between, and
   both are centred on the same spine. A photograph only leaves the page when
   the owner says so — that is what `full_bleed` means here. */
.pf-essay--essay-03 .pf-essay__figure { max-width: var(--pfe-maxw); }
.pf-essay--essay-03 .pf-essay__caption {
  font-family: "Literata", "Iowan Old Style", Georgia, "Times New Roman", serif;
  font-size: 0.8125rem;
  line-height: 1.5;
}
.pf-essay--essay-03 .pf-essay__caption-title {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 600;
}
.pf-essay-head--essay-03 {
  max-width: 900px;
}
.pf-essay-head--essay-03 .pf-essay-head__title {
  font-family: "Literata", "Iowan Old Style", Georgia, serif;
  font-weight: 600;
  font-size: clamp(1.75rem, 3.5vw, 2.75rem);
  letter-spacing: -0.012em;
}
.pf-essay-head--essay-03 .pf-essay-head__meta {
  font-family: "Literata", "Iowan Old Style", Georgia, serif;
}

/* =============================================================================
   PER-BLOCK TYPOGRAPHY — the owner's own voice for one text block
   =============================================================================
   Deliberately the LAST thing in this file. A variant's prose rule
   (`.pf-essay--essay-02 .pf-essay__text`, 0-2-0) and a font class
   (`.pf-essay .pf-essay__text--font-archivo`, 0-3-0) both target the same
   element; the class already wins on specificity, and sitting last means it
   still wins if either selector is ever loosened. A block that picked nothing
   emits no class at all and keeps the variant's voice — which is the point:
   this is an override, not a default.

   The vocabulary is closed and lives in PortfolioProjectTextBlock.TEXT_FONTS.
   Adding a face is that dict plus one rule here; the <link> follows from the
   dict on its own (_photolog_text_fonts.html), so nothing else learns a name.

   Five faces, chosen as five different DECISIONS rather than five flavours of
   the same one — a picker whose options a reader cannot tell apart is a picker
   that wastes the owner's time:

     hanken     humanist sans. Open, quiet, contemporary. (essay-01b's voice)
     archivo    grotesque sans. Tighter, squarer, more newsprint. (essay-02's)
     literata   book serif. Sturdy, low contrast, made for screen reading.
                (essay-03's)
     spectral   literary serif. Finer strokes, more contrast than Literata —
                a gallery catalogue rather than a paperback.
     courier    typewriter. For prose that wants to read as an annotation
                pinned beside the picture, not as the essay's own voice.

   Every stack ends in a real system fallback: a webfont that fails to load
   must degrade to the same CATEGORY, or a serif block silently becomes a sans
   one and the owner's decision is quietly reversed. */

.pf-essay .pf-essay__text--font-hanken {
  font-family: "Hanken Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI",
               Roboto, sans-serif;
  letter-spacing: -0.003em;
}
.pf-essay .pf-essay__text--font-archivo {
  font-family: "Archivo", -apple-system, BlinkMacSystemFont, "Segoe UI",
               Roboto, sans-serif;
}
.pf-essay .pf-essay__text--font-literata {
  font-family: "Literata", "Iowan Old Style", Georgia, "Times New Roman", serif;
}
.pf-essay .pf-essay__text--font-spectral {
  font-family: "Spectral", "Iowan Old Style", Georgia, "Times New Roman", serif;
  /* Spectral runs a touch small and light for its point size next to the
     others; a hair more leading is what keeps its finer strokes from looking
     crowded at essay width. */
  line-height: 1.72;
}
.pf-essay .pf-essay__text--font-courier {
  font-family: "Courier Prime", "Courier New", ui-monospace, monospace;
  /* A monospaced face sets far fewer characters per line, so the measure has
     to come down with it or the block runs to the width of a page and stops
     scanning. Leading up, because Courier's small x-height leaves the lines
     looking further apart than they measure. */
  line-height: 1.66;
}
.pf-essay .pf-essay__text--font-courier > * { max-width: 58ch; }

/* --- Size steps ----------------------------------------------------------
   Four steps, not a slider. A free size control produces 17.3px prose and
   pages where every block is a slightly different size; steps produce a page
   that still reads as one document. The ratio between steps is ~1.15 at the
   small end and ~1.25 at the large — close enough to read as a scale, far
   enough apart that picking the next step is visibly a decision.

   All four are fluid: the same block should not be shouting on a phone. XL is
   the pull-quote step and is where the reading measure starts to matter, so it
   tightens its own tracking rather than letting big type sprawl. */
.pf-essay .pf-essay__text--size-s  { font-size: clamp(0.9375rem, 0.91rem + 0.14vw, 1rem); }
.pf-essay .pf-essay__text--size-m  { font-size: clamp(1.0625rem, 1rem + 0.3vw, 1.1875rem); }
.pf-essay .pf-essay__text--size-l  { font-size: clamp(1.1875rem, 1.11rem + 0.4vw, 1.375rem); }
.pf-essay .pf-essay__text--size-xl {
  font-size: clamp(1.375rem, 1.24rem + 0.66vw, 1.75rem);
  line-height: 1.42;
  letter-spacing: -0.012em;
  color: var(--pfe-ink);
}
