/*
 * The studio's landing page.
 *
 * ── Where the look comes from ───────────────────────────────────────
 *
 * Two briefs meeting. The palette, the type and the one inviolable
 * rule are the wedding page's, because a couple who follows a link
 * from here to reserve a date should not arrive at a different studio.
 * The layout is Pic-Time's gallery: a full-bleed cover, then a
 * three-column masonry of photographs with an eight-pixel gutter and
 * almost no chrome, because that is the language photographers and
 * their clients already read as "portfolio".
 *
 * The rule survives the move: nothing sits on top of a photograph. No
 * scrim, no gradient, no tint, no type. Pic-Time sets the couple's
 * names over the cover; this does not. The cover is a photograph, and
 * the words sit on paper beneath it — which is also why the cover can
 * be a bright, busy frame without anybody having to find a dark corner
 * to put a sentence in. The wedding page allows itself one exception —
 * a studio mark in the hero's corner — and this page does not even take
 * that one: the masthead sits directly above the cover with the mark
 * already in it, so a second would be the same logo twice.
 *
 * ── The graphic language (September 2026) ───────────────────────────
 *
 * The first build of this page was correct and quiet, and the studio
 * said so: it did not make anyone stop. What it lacked was not colour —
 * the palette is theirs and stays — but a graphic language with a
 * point of view. The one it has now is taken from the studio's own
 * mark: a brushed gold monogram with the word TIMELESS set on an arc
 * beneath it. Unfolded across a page that becomes
 *
 *   · rings and arcs of type — the "now booking" ring beside the
 *     headline, the arched line under the contact address;
 *   · gold hairlines doing structural work — folio rules, corner
 *     marks around figures like a contact sheet, a seam under the
 *     cover — rather than decorating;
 *   · flat blush fields that photographs stand on or hang over,
 *     always behind them, never on them;
 *   · Fraunces italic as an accent inside roman headlines, and
 *     numerals set large where they mean something (a price, a date,
 *     a frame number).
 *
 * Everything decorative is vector or type, drawn in the page's own
 * three colours. There is no second hue and no image used as ornament.
 * Motion is the same restraint: things arrive by rising a little onto
 * the page, the colour blocks drift a few pixels against the scroll,
 * the ring turns slowly. Nothing bounces, and all of it stops for a
 * reader who has asked for less movement.
 *
 * ── The measurement the layout is built around ──────────────────────
 *
 * Every photograph in "Website photos" and "Christmas Website Photos"
 * is 1024 pixels on its long edge, so it is honest to 512 CSS pixels
 * and invented past it. Three columns inside a container capped at
 * 1345px makes each one 443 CSS pixels — 886 on a retina screen,
 * inside what a 1024 can actually carry. That cap is not a taste
 * decision and must not be raised: widen the container and every
 * photograph in the grid goes soft at once, on the only screens
 * anybody would notice it on.
 *
 * The eighteen photographs with verified full-resolution originals may
 * span two columns (894px), and one of them is the cover. Nothing else
 * may ever be drawn larger than one column — including every Christmas
 * frame, none of which has a full-resolution original at all.
 *
 * Committed to a single light theme, like the wedding page: the
 * photographs are graded for one, and a page that flips under a system
 * setting would show two different studios depending on the hour.
 *
 * ── The phone (September 2026, second pass) ─────────────────────────
 *
 * Nearly everyone who opens this page opens it on a phone, so the rules
 * under `max-width: 39.99rem` are not the fallback; they are the
 * design, and the wide layout is what it becomes with room. What
 * changes on a phone, and why:
 *
 *   · the first screen is photograph, then the blush field with the
 *     turning ring standing under it, then the first line of the
 *     headline — the desktop's composition in the phone's order, with
 *     the one call to book sitting where a thumb rests;
 *   · every section opens with its photograph and the words follow,
 *     because on a narrow screen a section that opens with a heading
 *     is a screen of type before the reason for it;
 *   · the Christmas frames and the journal cards become strips that
 *     scroll sideways, a gesture a phone already knows, in place of
 *     rows of two that ran for screens;
 *   · everything that can be tapped is at least 44px tall, buttons run
 *     the width of the page, and the menu is a full sheet of paper.
 *
 * None of it puts anything on a photograph, and none of it touches the
 * wide layout, which was signed off before this pass.
 */

@font-face {
  font-family: 'Fraunces';
  src: url('/site/fonts/fraunces.woff2') format('woff2');
  font-weight: 100 900;
  font-display: swap;
}
@font-face {
  font-family: 'Fraunces';
  src: url('/site/fonts/fraunces-italic.woff2') format('woff2');
  font-weight: 100 900;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: 'Karla';
  src: url('/site/fonts/karla.woff2') format('woff2');
  font-weight: 200 800;
  font-display: swap;
}

:root {
  /* The wedding page's palette, unchanged. Blush is a ground and never
     type; gold below 18px uses --gold-ink. Both of those are contrast
     arithmetic rather than preference — #C98B84 reads 2.71:1 on this
     paper and the brand gold 3.0:1, which is enough to fill a button
     and not enough to set a caption. */
  --ground: #FDFBFA;
  --raised: #FAF2F0;
  --line: #EEE0DC;
  --ink: #241C1C;
  --ink-soft: #5A4E4C;
  --muted: #7A6A68;
  --gold: #B08D57;
  --gold-soft: #9A7742;
  --gold-ink: #856334;
  --blush: #C98B84;
  --blush-wash: #F5E2DF;
  --blush-block: #EFD3CE;

  /* Two tints derived from the same blush, not new hues. --blush-field
     is the deeper ground the hero's ring stands on: ink reads 11.5:1
     on it and --ink-soft 5.2:1, but --gold-ink only 3.5:1, which is
     why small labels on any blush ground are set in ink rather than
     gold. --line-strong is the form's underline, one step firmer than
     --line so an empty field still shows where to write. */
  --blush-field: #E9C7C0;
  --line-strong: #DCC6C0;

  /* Pic-Time's gutter, measured off their own gallery. Tight on
     purpose: the photographs should read as one field rather than as a
     set of separate cards. */
  --gutter: 8px;
  /* Three 443px columns plus two gutters. See the note above before
     changing it. */
  --grid-max: 1345px;
  --pad: 1rem;

  /* How far a colour block may bleed past the photograph it sits
     behind. Always less than --pad, so a block bleeding toward the
     viewport edge stops inside the page margin and never gives a phone
     a horizontal scrollbar. */
  --bleed: 0.75rem;
  /* Corner marks sit this far outside a figure's edges — on the paper
     around the photograph, not on it. */
  --mk: 10px;

  --ease: cubic-bezier(.2, .6, .2, 1);
}

@media (min-width: 40rem) { :root { --pad: 1.5rem; --bleed: 1.25rem; } }
@media (min-width: 64rem) { :root { --pad: 3rem; --bleed: 2rem; } }

*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: 'Karla', system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

img { display: block; max-width: 100%; }
a { color: inherit; }

/* One focus style for everything that can take focus. Gold at 2px is
   plenty visible on paper and on blush, and the offset keeps it off
   the element's own edge so it never reads as part of the design. */
:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }

/* A larger place to tap than the text itself occupies. Small text
   links — the phone number, the footer, the link under the ring — are
   twenty pixels tall, and a thumb is not. The pseudo-element extends
   the hit area to about 44px without moving anything on the page,
   which is the one thing padding could not promise inside a grid with
   gaps. It is on the link's own layer, so it never covers a neighbour
   that also needs tapping. */
.tap { position: relative; }
.tap::after { content: ''; position: absolute; inset: -0.85rem -0.35rem; }

/* Every photograph is an AVIF-first <picture>, and a <picture> is an
   inline box that would otherwise sit between the layout and the image
   it wraps — the image would size against the wrapper rather than
   against the grid cell. `display: contents` removes that box, so the
   <img> lays out as a direct child of whatever holds it. */
picture { display: contents; }

/* And with that box gone, the <source> elements inside become children
   of the layout too. They draw nothing, but in a grid they still take a
   cell each: every photograph is one <img> behind two <source>s, so the
   Christmas strip laid out three items per photograph and scattered
   five pictures across fifteen cells with holes between them. A source
   is never rendered, so removing it from layout entirely costs nothing
   and cannot affect which file the browser picks — resource selection
   happens before any of this. */
picture > source { display: none; }

/* ── Type ───────────────────────────────────────────────────────────
   Fraunces for display, Karla for everything that has to be read at
   length. The display sizes are set in clamp() rather than at
   breakpoints because the cover's headline is the one piece of type
   that has to hold a whole screen at every width.

   Fraunces is a variable font with an optical-size axis, so at these
   sizes the browser draws the high-contrast display cut rather than a
   scaled-up text face. That is where the hairline serifs come from;
   nothing here is faked with weight. */

.display {
  font-family: 'Fraunces', Georgia, serif;
  font-weight: 300;
  font-size: clamp(2.5rem, 6.2vw, 5.75rem);
  line-height: 1.02;
  letter-spacing: -0.025em;
  margin: 0;
  /* No single word stranded on the last line: at tablet width the
     hero's headline left "felt." alone under three full lines.
     Browsers that do not know the value simply wrap as before. */
  text-wrap: pretty;
}

.display-sm {
  font-family: 'Fraunces', Georgia, serif;
  font-weight: 300;
  font-size: clamp(1.9rem, 4.2vw, 3.2rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin: 0;
  text-wrap: pretty;
}

/* The accent inside a headline: one phrase in italic, same weight, so
   the line reads as a single voice changing register rather than as
   two fonts. */
.display em, .display-sm em { font-style: italic; font-weight: 300; }

.lede {
  font-size: clamp(1rem, 1.6vw, 1.15rem);
  line-height: 1.7;
  color: var(--ink-soft);
  max-width: 34em;
  margin: 1.25rem 0 0;
}

p { margin: 1rem 0 0; color: var(--ink-soft); }

/* Small caps labels. Never gold above 11px without --gold-ink; see the
   palette note. On a blush ground the same label is set in ink-soft
   (the .on-blush rule below), because gold-ink falls to 3.5:1 there. */
.eyebrow {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--gold-ink);
  margin: 0 0 1rem;
}
.on-blush .eyebrow { color: var(--ink-soft); }

.rule {
  height: 1px;
  background: var(--gold);
  opacity: 0.55;
  border: 0;
  margin: 0;
}

/* The hand-drawn underline. An inline SVG stroke under one word, drawn
   in when the headline arrives (the dash offset runs to zero once the
   `.in` class lands on an ancestor). One word only: it is inline-block
   so the stroke spans exactly the word, and a phrase would refuse to
   wrap on a phone. */
.u { position: relative; display: inline-block; font-style: italic; }
.u svg {
  position: absolute;
  left: -2%;
  bottom: -0.06em;
  width: 104%;
  height: 0.24em;
  overflow: visible;
  pointer-events: none;
}
.u path {
  fill: none;
  stroke: var(--gold);
  stroke-width: 2.5;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: 320;
  stroke-dashoffset: 320;
  transition: stroke-dashoffset 1.3s var(--ease) 0.55s;
}
.in .u path { stroke-dashoffset: 0; }

/* ── Folios ─────────────────────────────────────────────────────────
   Every section opens like a magazine page: a numeral in italic, a
   short gold rule, the label. The numeral is 24px, which is large text
   by the accessibility arithmetic, so --gold-soft (3.9:1 on paper,
   3.2:1 on blush) is allowed where --gold-ink would be required at
   caption size. */
.folio {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin: 0 0 1.25rem;
}
.folio .no {
  font-family: 'Fraunces', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: 1.5rem;
  line-height: 1;
  color: var(--gold-soft);
}
.folio .folio-rule { width: 36px; height: 1px; background: var(--gold); }
.folio .eyebrow { margin: 0; }

/* ── The masthead ───────────────────────────────────────────────────
   Sits above the cover on paper rather than over the photograph. It
   scrolls away with the page: a fixed bar over a full-bleed cover
   would be chrome on top of a picture, which is the one thing this
   page does not do. */

.masthead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 1.1rem var(--pad);
  background: var(--ground);
}
/* A little tighter on a phone, where every pixel above the fold is one
   the photograph does not get. */
@media (max-width: 39.99rem) { .masthead { padding-block: 0.8rem; gap: 0.75rem; } }

.masthead-mark { width: 84px; height: auto; }
@media (min-width: 40rem) { .masthead-mark { width: 100px; } }
@media (min-width: 64rem) { .masthead-mark { width: 116px; } }

.masthead-nav {
  display: none;
  gap: 2rem;
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
@media (min-width: 56rem) { .masthead-nav { display: flex; } }
.masthead-nav a { text-decoration: none; padding-bottom: 2px; border-bottom: 1px solid transparent; }
.masthead-nav a:hover { border-bottom-color: var(--gold); color: var(--ink); }

/* The booking, beside the menu on a phone. The nav is hidden there,
   and a page whose whole purpose is the reservation should not make a
   reader open a menu, let alone scroll to the bottom, to find it. */
.masthead-tools { display: flex; align-items: center; gap: 0.5rem; flex: none; }
.masthead-cta { flex: none; }
/* Drawn 36px tall so it sits lightly beside the mark, and tappable
   over 44 through the .tap pseudo-element, which here extends only up
   and down: sideways it would overlap the menu button. */
@media (max-width: 39.99rem) {
  .masthead-cta {
    display: inline-flex; align-items: center; min-height: 36px;
    padding: 0.4rem 0.75rem; font-size: 11px; letter-spacing: 0.14em;
  }
  .masthead-cta.tap::after { inset: -5px 0; }
}
/* The mark never shrinks to make room; it is the one thing on the row
   that must look the same on every phone. Under 23rem the button loses
   its object instead. */
.masthead > a:first-child { flex: none; }
.cta-short { display: none; }
@media (max-width: 22.99rem) {
  .masthead-tools { gap: 0.25rem; }
  .cta-long { display: none; }
  .cta-short { display: inline; }
}

/* ── The menu ───────────────────────────────────────────────────────
   Under 56rem the nav has nowhere to go, so a button opens it as a
   full sheet of paper: opaque, because a scrim over the page would be
   something on top of a photograph. The pages are set as a numbered
   table of contents in the display face; the booking button and the
   direct lines to the studio sit at the bottom, in reach of a thumb. */
.menu-button {
  display: none;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
  min-width: 44px;
  margin: 0;
  padding: 0.5rem 0.25rem 0.5rem 0.5rem;
  border: 0;
  background: none;
  font-family: inherit;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink);
  cursor: pointer;
}
.menu-button svg { width: 20px; height: 20px; fill: none; stroke: var(--gold-ink); stroke-width: 1.4; stroke-linecap: round; }
/* The Close button inside the sheet is always drawn: an open sheet
   must be closable whatever the window has become. */
@media (max-width: 55.99rem) { .menu-button { display: inline-flex; } }
.menu .menu-button { display: inline-flex; }

.menu {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: var(--ground);
  color: var(--ink);
  overflow: auto;
  overscroll-behavior: contain;
}
.menu::backdrop { background: transparent; }
.menu[open] {
  display: flex;
  flex-direction: column;
  min-height: 100%;
  animation: menu-in 360ms var(--ease);
}
@keyframes menu-in { from { opacity: 0; translate: 0 10px; } }
/* The page behind the sheet stays where it was. */
html.menu-open { overflow: hidden; }

.menu-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.8rem var(--pad);
  border-bottom: 1px solid var(--line);
}
.menu-pages { padding: 0.5rem var(--pad) 0; }
.menu-pages ol { list-style: none; margin: 0; padding: 0; }
.menu-pages li { border-bottom: 1px solid var(--line); }
.menu-pages a {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding: 1rem 0;
  font-family: 'Fraunces', Georgia, serif;
  font-weight: 300;
  font-size: clamp(1.9rem, 8vw, 2.5rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
  text-decoration: none;
  color: var(--ink);
}
.menu-pages .no {
  font-style: italic;
  font-size: 1rem;
  line-height: 1;
  color: var(--gold-soft);
  min-width: 1.6em;
}
.menu-pages svg {
  width: 20px; height: 20px; align-self: center; margin-left: auto;
  fill: none; stroke: var(--gold-ink); stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round;
}
.menu-foot {
  margin-top: auto;
  padding: 2rem var(--pad) 1.5rem;
  display: grid;
  gap: 1rem;
}
.menu-now {
  margin: 0;
  font-family: 'Fraunces', Georgia, serif;
  font-style: italic;
  font-weight: 300;
  font-size: 1.35rem;
  line-height: 1.2;
  color: var(--ink);
}
.menu-direct {
  display: flex;
  justify-content: space-between;
  gap: 0.5rem;
  margin: 0.25rem 0 0;
  padding-top: 0.5rem;
  border-top: 1px solid var(--line);
}
.menu-direct a {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink);
}
.menu-direct a + a { border-left: 1px solid var(--line); }

/* ── The cover ──────────────────────────────────────────────────────
   Full-bleed, and the only photograph on the page allowed past one
   grid column. `svh` rather than `vh` because on a phone `vh` is the
   height the viewport has when the browser's chrome is hidden, which
   it is not when the page first paints — the cover would be taller
   than the screen and the headline beneath it would start below the
   fold on the one screen that has to sell the studio.

   Shorter than it was. At 88svh the first screen was the photograph
   alone and every word was below the fold; at 76svh the eyebrow and the
   first line of the headline show under it, with the top of the blush
   field beside them, so the photograph visibly hands off to something
   rather than simply ending. */

.cover {
  position: relative;
  width: 100%;
  height: min(72svh, 720px);
  overflow: hidden;
  background: var(--raised);
  /* The seam: a gold hairline where the photograph meets the paper.
     A border, so it is drawn outside the image box and not on it. */
  border-bottom: 1px solid var(--gold);
}
@media (min-width: 64rem) { .cover { height: min(76svh, 820px); } }
/* On a phone the cover is 58svh: with the masthead above it and the
   blush field with the ring below, that puts the field's whole height
   and the first line of the headline on the first screen. At 72svh the
   first screen was the photograph and a strip of blank paper, and the
   one thing to tap was at the top of the page. The photograph loses
   nothing: a 3:2 landscape in a 390 by 490 box shows more of its width
   than it did in a 390 by 608 one. */
@media (max-width: 39.99rem) { .cover { height: min(58svh, 720px); } }

/* Named rather than written as the bare `.cover img` it started as.
   That selector — a class plus an element — out-specifies any plain
   class on an image inside the cover, so when the studio mark was still
   here it inherited `width: 100%` and was drawn the full width of the
   photograph: a logo the size of the cover, on the first screen. The
   mark has since gone, but the next thing put inside .cover would meet
   exactly the same trap. */
.cover img.cover-photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--focal, 50% 42%);
}

/* ── The hero: the words under the cover ────────────────────────────
   A spread rather than a caption. On a wide screen the headline takes
   the left of the page and a blush field runs down the right, touching
   the cover's bottom edge so the photograph appears to stand on it;
   the "now booking" ring turns slowly in that field and is the page's
   first call to book. On a phone the field becomes a band under the
   words, ring on the left, the same sentence on the right. */

.hero { position: relative; display: grid; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 64rem) {
  .hero { grid-template-columns: minmax(0, 1fr) clamp(300px, 30vw, 460px); }
}

.hero-say {
  padding: clamp(2.5rem, 5vw, 4.5rem) var(--pad) clamp(2.5rem, 5vw, 4rem);
  max-width: 70rem;
}
.hero-say .display { max-width: 13.5em; }
@media (min-width: 64rem) {
  .hero-say { padding-left: calc(var(--pad) + 1.5rem); }
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 2rem;
  margin-top: 2rem;
}

/* The phone's first screen. On a wide screen the blush field runs down
   the right of the headline and touches the cover, so the photograph
   stands on it; a phone has no right, so the field goes under the
   photograph instead and the headline follows it. That is the same
   composition in the phone's order — picture, field, words — and it
   puts the ring, the page's first call to book, in the bottom third of
   the first screen, which is where a thumb already is. The sentence
   reads first, at the left, and the ring stands at the right under the
   thumb. */
@media (max-width: 39.99rem) {
  .hero-aside { order: -1; }
  .hero-say { padding-top: 2.25rem; }
  .hero-actions { flex-direction: column; align-items: stretch; gap: 0.75rem; }
  .hero-actions .btn-link { justify-content: center; }
}

/* A text link with a small arrow, for the second action in a pair:
   the button books, this one just scrolls. */
.btn-link {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 44px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink);
  padding: 0.4rem 0;
}
.btn-link svg { width: 16px; height: 16px; fill: none; stroke: var(--gold-ink); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; transition: transform 400ms var(--ease); }
.btn-link:hover svg { transform: translateY(3px); }

/* The rotated label in the left margin. Only where there is a margin
   to put it in: under 64rem the page padding is too narrow and it
   would sit on the words. */
.hero-side { display: none; }
@media (min-width: 64rem) {
  .hero-side {
    position: absolute;
    left: 1.1rem;
    top: 3.25rem;
    bottom: 3.25rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.25rem;
    pointer-events: none;
  }
  .hero-side span {
    writing-mode: vertical-rl;
    rotate: 180deg;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.3em;
    text-transform: uppercase;
    color: var(--gold-ink);
    white-space: nowrap;
  }
  .hero-side::after { content: ''; flex: 1; width: 1px; background: var(--gold); opacity: 0.6; }
}

.hero-aside {
  --ring: 150px;
  background: var(--blush-field);
  display: flex;
  align-items: center;
  gap: 1.5rem;
  padding: 1.5rem var(--pad);
}
@media (max-width: 39.99rem) {
  .hero-aside { --ring: 164px; justify-content: space-between; gap: 1rem; padding: 1.25rem var(--pad); }
  .hero-aside .ring { order: 2; }
  .hero-aside .aside-say { gap: 0.6rem; }
}
/* On a 320px screen the sentence's link is 137px wide and cannot
   break, so the ring gives up the room: 124px is the widest that fits
   beside it inside the page margins. */
@media (max-width: 22.99rem) {
  .hero-aside { --ring: 124px; gap: 0.75rem; }
}
/* On a wide screen the ring sits at the top of the field rather than
   in the middle of it, level with the headline, so its upper edge shows
   above the fold under the cover: a slowly turning thing at the edge of
   the first screen is the scroll cue, and it needs no arrow. */
@media (min-width: 64rem) {
  .hero-aside {
    --ring: 224px;
    flex-direction: column;
    justify-content: flex-start;
    gap: 1.5rem;
    padding: 3.25rem 2rem 2.5rem;
  }
}

.aside-say { margin: 0; display: grid; gap: 0.4rem; color: var(--ink); }
.aside-title {
  font-family: 'Fraunces', Georgia, serif;
  font-style: italic;
  font-weight: 300;
  font-size: clamp(1.2rem, 4.6vw, 1.5rem);
  line-height: 1.2;
  letter-spacing: -0.01em;
}
.aside-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink);
  border-bottom: 1px solid var(--gold);
  width: max-content;
  padding-bottom: 2px;
}
.aside-link svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
/* On a wide screen the ring already says the sentence; keep only the
   short link beneath it. */
@media (min-width: 64rem) { .aside-title { display: none; } .aside-say { text-align: center; justify-items: center; } }

/* ── The ring ───────────────────────────────────────────────────────
   The studio's mark sets TIMELESS on an arc; this is the same idea
   closed into a circle and set turning. Type on a path in an inline
   SVG, a gold hairline circle inside it, and a solid gold disc with an
   arrow at the centre. The whole thing is one link. It stops turning
   under the pointer, so it can be read, and for anyone who has asked
   for reduced motion it never starts. */
.ring {
  position: relative;
  display: grid;
  place-items: center;
  flex: none;
  width: var(--ring, 200px);
  height: var(--ring, 200px);
  border-radius: 50%;
  color: var(--ink);
  text-decoration: none;
  /* Clipped to its own circle. The type is inscribed in it, so nothing
     visible is cut; what the clip removes is the empty corners of the
     turning square, whose bounding box otherwise swings up to 34px
     past the ring, and on a phone, where the ring stands 16px from the
     screen's edge, gave the whole page a sideways scroll that came and
     went with the rotation. */
  overflow: clip;
}
.ring-text {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  transform-origin: 50% 50%;
  animation: spin 34s linear infinite;
}
.ring-text text {
  font-family: 'Karla', system-ui, sans-serif;
  font-size: 14.5px;
  font-weight: 600;
  letter-spacing: 0.2em;
  fill: var(--ink);
}
.ring-core {
  width: 36%;
  height: 36%;
  border-radius: 50%;
  background: var(--gold);
  display: grid;
  place-items: center;
  transition: transform 500ms var(--ease), background-color 200ms ease;
}
.ring-core svg { width: 42%; height: 42%; fill: none; stroke: #fff; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.ring:hover .ring-core { transform: scale(1.08); background: var(--gold-soft); }
.ring:hover .ring-text { animation-play-state: paused; }
.ring:focus-visible { outline-offset: 8px; }

@keyframes spin { to { transform: rotate(1turn); } }

/* ── The ribbon ─────────────────────────────────────────────────────
   Between the words and the work: the places these photographs were
   made, in italic, sliding by at reading pace. The list is doubled in
   the markup and the track travels exactly half its width, which is
   what makes the loop seamless. The clip fades the ends so names enter
   and leave rather than being cut; that is a mask on type, not on a
   photograph. */
.ribbon {
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 1.1rem 0;
  overflow: hidden;
}
.ribbon-clip {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.ribbon-track { display: flex; width: max-content; animation: ribbon 64s linear infinite; }
.ribbon:hover .ribbon-track { animation-play-state: paused; }
.ribbon-run { display: flex; flex: none; }
.ribbon-item {
  display: inline-flex;
  align-items: center;
  gap: 1.6rem;
  padding-right: 1.6rem;
  font-family: 'Fraunces', Georgia, serif;
  font-style: italic;
  font-weight: 300;
  font-size: clamp(1.15rem, 2vw, 1.55rem);
  line-height: 1;
  color: var(--ink-soft);
  white-space: nowrap;
}
.ribbon-item svg { width: 7px; height: 7px; fill: var(--gold); flex: none; }
@keyframes ribbon { to { transform: translateX(-50%); } }

/* ── Buttons ────────────────────────────────────────────────────────
   Gold fills the primary because at 3:1 it can carry a large word and
   not a small one. The outline version sets its label in ink for the
   same reason. */

.btn {
  display: inline-block;
  padding: 0.9rem 1.6rem;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  border: 1px solid var(--gold);
  border-radius: 2px;
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}
.btn-primary { background: var(--gold); color: #fff; }
.btn-primary:hover { background: var(--gold-soft); }
.btn-ghost { background: transparent; color: var(--ink); }
.btn-ghost:hover { background: var(--raised); }
/* On a phone a button is the width of the page: a gold bar under a
   paragraph is easier to hit with either thumb than a pill at the
   left, and it ends a section the way a rule does. The masthead's is
   the exception, since it shares its row. */
@media (max-width: 39.99rem) {
  .btn:not(.masthead-cta) { display: flex; justify-content: center; width: 100%; padding-block: 1rem; text-align: center; }
}

/* ── Sections ───────────────────────────────────────────────────────*/

.section { padding: clamp(3.5rem, 8vw, 6.5rem) var(--pad); }
.section-wide { padding-left: 0; padding-right: 0; }
.wrap { max-width: var(--grid-max); margin: 0 auto; }
.wrap-narrow { max-width: 46rem; margin: 0 auto; }

.section-head { margin-bottom: clamp(2rem, 4vw, 3rem); }
.section-head .rule { width: 64px; margin-bottom: 1.5rem; }

/* A section head with a note set against it on the right, italic, the
   way a magazine sets a standfirst beside a title. */
.head-split {
  display: grid;
  gap: 1.25rem;
  align-items: end;
  margin-bottom: clamp(2rem, 4vw, 3rem);
}
@media (min-width: 60rem) {
  .head-split { grid-template-columns: minmax(0, 8fr) minmax(0, 4fr); gap: 4rem; }
}
.head-note {
  font-family: 'Fraunces', Georgia, serif;
  font-style: italic;
  font-weight: 300;
  font-size: 1.2rem;
  line-height: 1.5;
  color: var(--ink-soft);
  margin: 0;
  max-width: 24em;
  padding-bottom: 0.35rem;
}
@media (min-width: 60rem) { .head-note { justify-self: end; text-align: right; } }

/* ── The portfolio masonry ──────────────────────────────────────────
   Positions come from JavaScript, because every photograph's aspect
   ratio is known from the manifest and a column-packed masonry with
   two-column features cannot be expressed in CSS alone. The container
   is given an explicit height by the same code.

   Each tile keeps its own aspect ratio, so nothing is cropped and
   nothing shifts when the photograph arrives. */

.grid { position: relative; margin: 0 auto; max-width: var(--grid-max); }

.grid-item {
  position: absolute;
  overflow: hidden;
  background: var(--raised);
}

.grid-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 900ms var(--ease);
}
/* The only hover on a photograph, and it does not put anything on top
   of one — it moves the picture, it does not tint it. */
@media (hover: hover) {
  .grid-item:hover img { transform: scale(1.03); }
}

/* ── Figures with a colour block behind them ────────────────────────
   The wedding page's graphic device carried across and generalised: a
   flat blush rectangle the photograph overlaps, offset toward one
   corner. The block is a pseudo-element under the image (z-index 0
   against the image's 1), so by construction it can never be on top of
   the photograph. Which corner it sits at is a class; how far it
   bleeds is --bleed, which is always inside the page margin.

   `--dy` is written by the scroll handler and moves the block, and
   only the block, a few pixels against the scroll. The photograph
   itself never moves. */

.fig { position: relative; margin: 0; }
.fig img { position: relative; z-index: 1; width: 100%; height: auto; }
.fig::before {
  content: '';
  position: absolute;
  z-index: 0;
  background: var(--blush-block);
  inset: var(--b-top, auto) var(--b-right, auto) var(--b-bottom, auto) var(--b-left, auto);
  width: var(--b-w, 72%);
  height: var(--b-h, 66%);
  translate: 0 calc(var(--dy, 0) * 1px);
}
.fig-br { --b-right: calc(-1 * var(--bleed)); --b-bottom: calc(-1 * var(--bleed)); }
.fig-bl { --b-left: calc(-1 * var(--bleed)); --b-bottom: calc(-1 * var(--bleed)); }
.fig-tr { --b-right: calc(-1 * var(--bleed)); --b-top: calc(-1 * var(--bleed)); }
.fig-tl { --b-left: calc(-1 * var(--bleed)); --b-top: calc(-1 * var(--bleed)); }
.fig-deep::before { background: var(--blush-field); }

/* The caption under a figure, and the same caption set vertically up a
   figure's side where there is room for it. */
.caption {
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin-top: 0.75rem;
}
.fig .caption { position: relative; z-index: 1; }

/* Corner marks: four small gold brackets just outside a figure's
   corners, the way a contact sheet or a proof is marked up. They are
   empty <i> elements offset outward by --mk, so they sit on the paper
   (or on the blush block) and never on the picture. */
.marks > i {
  position: absolute;
  z-index: 2;
  width: 14px;
  height: 14px;
  border: 0 solid var(--gold);
  pointer-events: none;
}
.marks > i:nth-of-type(1) { top: calc(-1 * var(--mk)); left: calc(-1 * var(--mk)); border-top-width: 1px; border-left-width: 1px; }
.marks > i:nth-of-type(2) { top: calc(-1 * var(--mk)); right: calc(-1 * var(--mk)); border-top-width: 1px; border-right-width: 1px; }
.marks > i:nth-of-type(3) { bottom: calc(-1 * var(--mk)); left: calc(-1 * var(--mk)); border-bottom-width: 1px; border-left-width: 1px; }
.marks > i:nth-of-type(4) { bottom: calc(-1 * var(--mk)); right: calc(-1 * var(--mk)); border-bottom-width: 1px; border-right-width: 1px; }
/* When a figure has a caption the marks should frame the photograph,
   not the caption under it; the bottom pair moves up by the caption's
   height, which is set on the figure by the markup. */
.marks.has-caption > i:nth-of-type(3),
.marks.has-caption > i:nth-of-type(4) { bottom: calc(var(--cap-h, 2rem) - var(--mk)); }

/* ── The Christmas minis ────────────────────────────────────────────
   A blush ground so the section reads as its own thing without
   introducing a second hue: the photographs are already full of red,
   green and gold, and a red panel behind red photographs would be the
   loudest thing on the page. The gold rules do the seasonal work.

   Set like an invitation: the title large with its second half in
   italic, then the facts as a key/value list with the numbers that
   matter — the dates, the price — set big in Fraunces. */

.season { background: var(--blush-wash); }

.season-grid {
  display: grid;
  gap: clamp(2.5rem, 5vw, 3.5rem);
  align-items: center;
}
@media (min-width: 60rem) {
  .season-grid { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: clamp(3rem, 7vw, 6rem); }
}
.season-title { max-width: 11em; }
/* On a phone the photograph opens the section and the invitation
   follows it. A reader arriving from the portfolio sees a family among
   Christmas trees on blush and knows what the section is before a
   word of it; the title, the dates and the price then land in the
   thumb's reach, with the button under them. */
@media (max-width: 39.99rem) {
  .season-grid > .season-figure { order: -1; }
}

/* Capped at 450px, and this is arithmetic rather than composition.
   Not one of the ten Christmas exports has a full-resolution original
   on the drive, so every one of them is a 1024 and stops being honest
   past 450 CSS pixels. This figure was laid out at 40vw — 576px on a
   desktop, 847px on a tablet — and the audit caught it asking a 900px
   file to fill 1,694 device pixels. If the studio re-exports a
   Christmas frame at 2,500px or more, this cap can be lifted for that
   one photograph and not before. */
.season-figure { max-width: 450px; width: 100%; justify-self: center; }
@media (min-width: 60rem) { .season-figure { justify-self: end; } }

/* The facts. Numbers first, because a reader scanning for "when" and
   "how much" should find both without reading a sentence. */
.kv {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.5rem 2rem;
  margin: 2rem 0 0;
  padding: 1.5rem 0 0;
  border-top: 1px solid var(--gold);
}
/* Two across at every width, like the facts on a ticket. It used to
   fall to one column on a phone because "Oct 1 to Dec 22" broke after
   "Dec"; now the dates are set on two lines there on purpose, "Oct 1
   to" over "Dec 22" (a phone-only <br> in the markup), which reads like
   a poster and lets all four numerals stay at 24px in half a row. Four
   facts in two rows instead of a stack a screen and a half tall. */
@media (max-width: 39.99rem) { .kv { gap: 1.4rem 1rem; } }
/* Markup that exists only on a phone: a <br> is inline there and
   nothing anywhere else. */
.phone-only { display: none; }
@media (max-width: 39.99rem) { .phone-only { display: initial; } }
.nb { white-space: nowrap; }
.kv dt {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.kv dd { margin: 0.3rem 0 0; font-size: 0.95rem; line-height: 1.5; color: var(--ink-soft); }
.kv strong {
  display: block;
  font-family: 'Fraunces', Georgia, serif;
  font-weight: 300;
  font-size: clamp(1.7rem, 3vw, 2.3rem);
  line-height: 1.05;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin-bottom: 0.25rem;
}
.kv strong em { font-style: italic; font-size: 0.6em; letter-spacing: 0; color: var(--ink-soft); padding: 0 0.15em; }
/* 24px on a phone: still large text by the contrast arithmetic below,
   and "Oct 1 to" fits half a 320px row. After the base rule, because
   the two share a specificity and the later one wins. */
@media (max-width: 39.99rem) { .kv strong { font-size: 1.5rem; } }
/* The price is large text (over 24px), where --gold-soft clears 3:1 on
   the blush ground. */
.kv .price { color: var(--gold-soft); }
.fine { font-size: 0.9rem; line-height: 1.6; color: var(--ink-soft); max-width: 36em; }

/* The strip of Christmas frames, set as a contact sheet: eight frames
   with a little air between them and a frame number under each, every
   second frame hung a step lower so the row has a rhythm rather than a
   ruler edge. Two columns, then four — never three or five. Eight
   divides by two and by four exactly; odd counts left a row with a
   hole in it, which on a page made almost entirely of photographs
   reads as a missing photograph rather than as spacing. */
.sheet {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2rem 0.75rem;
  margin-top: clamp(3rem, 6vw, 5rem);
}
@media (min-width: 48rem) { .sheet { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 2.5rem 1.25rem; } }
.sheet-frame { margin: 0; }
@media (min-width: 48rem) { .sheet-frame:nth-child(even) { margin-top: 2.5rem; } }

/* On a phone the sheet is a strip: one row of frames that scrolls
   sideways and snaps frame to frame, bleeding to both edges of the
   screen so the next frame shows at the right and says there is more.
   Four rows of two ran for a screen and a half; a strip is one gesture
   the phone already knows, and flipping through prints is what a
   contact sheet is for. Each frame is 62% of the screen and never
   wider than 300px, which is what a 900px file can carry on a 3x
   screen; the second frame hangs a step lower, as on the wide sheet.
   The scrollbar is hidden because the peeking frame is the cue, and
   the strip takes keyboard focus (app.jsx) so it still moves for
   someone who cannot swipe. */
@media (max-width: 39.99rem) {
  .sheet {
    display: flex;
    gap: 0.75rem;
    margin-inline: calc(-1 * var(--pad));
    padding: 0.25rem var(--pad) 0.5rem;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--pad);
    scrollbar-width: none;
  }
  .sheet::-webkit-scrollbar { display: none; }
  .sheet-frame { flex: 0 0 min(62vw, 300px); scroll-snap-align: start; }
  .sheet-frame:nth-child(even) { margin-top: 1.25rem; }
}
.sheet-frame .ph { overflow: hidden; background: var(--raised); }
.sheet-frame img { width: 100%; height: auto; aspect-ratio: 2 / 3; object-fit: cover; transition: transform 900ms var(--ease); }
@media (hover: hover) { .sheet-frame:hover img { transform: scale(1.03); } }
.frame-no {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: 0.65rem;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.2em;
  color: var(--ink-soft);
}
.frame-no::before { content: ''; width: 18px; height: 1px; background: var(--gold); }

/* ── Editorial two-column blocks (weddings, films, families) ─────────
   Asymmetric on purpose: five parts of words to seven of picture, and
   the picture pushed to the outer edge with its colour block bleeding
   toward the margin. A portrait figure is held to 540px so it stays a
   picture beside a paragraph rather than a wall the paragraph leans
   on; the full-resolution originals behind these figures carry that
   width twice over on a retina screen. */

.split {
  display: grid;
  gap: clamp(2.5rem, 5vw, 3.5rem);
  align-items: center;
}
@media (min-width: 60rem) {
  .split { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: clamp(3rem, 7vw, 6rem); }
  .split-flip { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
  .split-flip > :first-child { order: 2; }
  .split > .fig { justify-self: end; width: 100%; }
  .split-flip > .fig { justify-self: start; }
  .split .fig-portrait { max-width: 540px; }
}
.split figure { margin: 0; }
.split figure img { width: 100%; height: auto; }
/* On a phone the photograph comes first in each of these sections and
   the words follow it: the picture is the reason for the section, and
   a heading arriving before it is a screen of type between two
   photographs. The folio and the heading then sit under the picture
   like a caption that grew, and the button lands lowest, nearest the
   thumb. */
@media (max-width: 39.99rem) {
  .split > .fig { order: -1; }
}

/* ── About ──────────────────────────────────────────────────────────
   Two photographs on one blush field, never touching: a landscape of
   the morning of a wedding and, hung lower and to the right, a small
   portrait of the details. Beside them the names, with the ampersand
   between them set enormous in italic gold — a husband and wife team,
   drawn as type. */

.about-grid {
  display: grid;
  gap: clamp(2.5rem, 5vw, 3.5rem);
  align-items: center;
}
@media (min-width: 60rem) {
  .about-grid { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: clamp(3rem, 7vw, 6rem); }
}

.about-pics {
  position: relative;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem var(--gutter);
  padding-bottom: 1.5rem;
}
.about-pics::before {
  content: '';
  position: absolute;
  z-index: 0;
  left: 10%;
  right: calc(-1 * var(--bleed));
  top: 14%;
  bottom: 0;
  background: var(--blush-block);
  translate: 0 calc(var(--dy, 0) * 1px);
}
.about-main { grid-column: 1 / -1; margin: 0; position: relative; z-index: 1; }
.about-inset { grid-column: 2; justify-self: end; width: 86%; margin: 0; position: relative; z-index: 1; }
.about-pics img { width: 100%; height: auto; }
@media (min-width: 60rem) {
  .about-pics { grid-template-columns: 64fr 4fr 32fr; gap: 0; padding-bottom: clamp(2.5rem, 6vw, 5rem); }
  .about-main { grid-column: 1; grid-row: 1; align-self: start; }
  /* Hung a step lower than the row it lays out in; the padding on the
     container is what makes room for the drop. */
  .about-inset { grid-column: 3; grid-row: 1; align-self: end; width: 100%; translate: 0 clamp(2.5rem, 6vw, 5rem); }
}

.about-names {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0 0.1em;
  font-family: 'Fraunces', Georgia, serif;
  font-weight: 300;
  font-size: clamp(2.6rem, 6vw, 4.5rem);
  line-height: 1;
  letter-spacing: -0.03em;
  margin: 0 0 1.5rem;
  color: var(--ink);
}
.about-tag {
  font-family: 'Fraunces', Georgia, serif;
  font-style: italic;
  font-weight: 300;
  font-size: clamp(1.3rem, 2.1vw, 1.55rem);
  line-height: 1.3;
  color: var(--ink);
  margin: 0;
}
.about-names .amp {
  font-style: italic;
  font-weight: 200;
  font-size: 1.9em;
  line-height: 0.6;
  color: var(--gold);
  margin: 0 0.02em 0 0.04em;
  position: relative;
  top: 0.1em;
}

/* ── The journal cards ──────────────────────────────────────────────
   Post cards, and the reading column a story sits in. The gallery
   underneath is the same masonry as the portfolio, for the same reason:
   these are the studio's 1024 exports and a column of the grid is the
   widest they can honestly be drawn. */

.cards {
  display: grid;
  gap: clamp(2rem, 3vw, 2.5rem) clamp(1.5rem, 3vw, 2.25rem);
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 64rem) { .cards { grid-template-columns: repeat(3, 1fr); } }

/* Two across on a phone too, where the journal's twenty five cards
   stacked one wide were fourteen thousand pixels of scrolling; at
   171px a card is still a photograph with a name under it, and the
   page reads like a wall of small prints. The type steps down with
   the frame. */
@media (max-width: 39.99rem) {
  .cards { gap: 1.75rem 0.75rem; }
  .cards .card-frame { margin-bottom: 0.75rem; }
  .cards .card-title { font-size: 1.05rem; }
  .cards .card-meta { font-size: 10px; gap: 0.5rem; }
  .cards .card-meta .no::after { width: 12px; margin-left: 0.5rem; }
}

/* Three cards at the end of the landing page and under a story are a
   strip on a phone, for the same reasons as the Christmas frames: one
   row to swipe, bleeding to the edges, the next card peeking. Cards
   are 72% of the screen, never wider than 300px. */
@media (max-width: 39.99rem) {
  .cards-strip {
    display: flex;
    gap: 0.75rem;
    margin-inline: calc(-1 * var(--pad));
    padding: 0.25rem var(--pad) 0.5rem;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--pad);
    scrollbar-width: none;
  }
  .cards-strip::-webkit-scrollbar { display: none; }
  .cards-strip > .card { flex: 0 0 min(72vw, 300px); scroll-snap-align: start; }
  .cards-strip .card-title { font-size: 1.25rem; }
}

.card { text-decoration: none; display: block; }

/* A fixed frame so a row of cards keeps one baseline whatever shape the
   photographs are. The picture is cropped to the frame rather than the
   frame stretched to the picture. */
.card-frame {
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--raised);
  margin-bottom: 1.1rem;
}
.card-frame img { width: 100%; height: 100%; object-fit: cover; transition: transform 900ms var(--ease); }
@media (hover: hover) { .card:hover .card-frame img { transform: scale(1.04); } }

.card-meta {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--gold-ink);
}
.card-meta .no {
  font-family: 'Fraunces', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: 1.1rem;
  line-height: 1;
  letter-spacing: 0;
  text-transform: none;
  color: var(--gold-soft);
}
.card-meta .no::after { content: ''; display: inline-block; width: 18px; height: 1px; background: var(--gold); vertical-align: middle; margin-left: 0.75rem; }
.card-title {
  font-family: 'Fraunces', Georgia, serif;
  font-weight: 300;
  font-size: 1.45rem;
  line-height: 1.2;
  letter-spacing: -0.015em;
  margin: 0.5rem 0 0;
  color: var(--ink);
  transition: color 200ms ease;
}
@media (hover: hover) { .card:hover .card-title { color: var(--gold-ink); } }

/* ── Contact ────────────────────────────────────────────────────────
   The last page of the invitation. The whole section on blush, the
   address set large in Fraunces with a gold line under it, an arc of
   type beneath that echoing the mark, and the form on a sheet of paper
   with corner marks and a block of deeper blush showing at its edge. */

.contact { background: var(--blush-wash); }

.contact-grid { display: grid; gap: clamp(2.5rem, 5vw, 4rem); }
@media (min-width: 60rem) {
  .contact-grid { grid-template-columns: minmax(0, 6fr) minmax(0, 6fr); gap: clamp(3rem, 7vw, 6rem); align-items: start; }
}

.contact-email {
  display: inline-block;
  margin-top: 2rem;
  font-family: 'Fraunces', Georgia, serif;
  font-weight: 300;
  font-size: clamp(1.35rem, 5.2vw, 2.5rem);
  line-height: 1.2;
  letter-spacing: -0.015em;
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid var(--gold);
  transition: border-color 200ms ease, color 200ms ease;
}
.contact-email:hover { color: var(--gold-ink); }

/* The arc. Same gesture as TIMELESS under the monogram: the studio's
   four kinds of work set on the lower curve of a circle. Type in an
   SVG, sized by the SVG, so it scales with the column. */
.arc { width: min(78%, 340px); height: auto; margin-top: 2rem; overflow: visible; }
.arc text {
  font-family: 'Karla', system-ui, sans-serif;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.22em;
  fill: var(--ink-soft);
}
.arc .arc-line { fill: none; stroke: var(--gold); stroke-width: 0.75; }
/* The initials above the arc, in the italic, gold. At this size (over
   50px on screen) the brand gold is well past 3:1 for large text. */
.arc .arc-mono {
  font-family: 'Fraunces', Georgia, serif;
  font-style: italic;
  font-weight: 300;
  font-size: 58px;
  letter-spacing: -0.04em;
  fill: var(--gold);
}

.paper { position: relative; }
/* The deeper block behind the sheet, offset down and to the right. It
   is a pseudo-element of the wrapper and the sheet is a positioned
   child above it, which is the only arrangement that actually puts a
   block under a background: a negative z-index child paints above its
   own parent's background, not below it, and the first cut of this
   drew the form on blush with an L of paper showing at two edges. */
.paper::before {
  content: '';
  position: absolute;
  z-index: 0;
  inset: var(--bleed) calc(-1 * var(--bleed)) calc(-1 * var(--bleed)) var(--bleed);
  background: var(--blush-block);
  translate: 0 calc(var(--dy, 0) * 1px);
}
.paper-sheet {
  position: relative;
  z-index: 1;
  background: var(--ground);
  padding: clamp(1.5rem, 3.5vw, 2.75rem);
}
.paper .form-title {
  font-family: 'Fraunces', Georgia, serif;
  font-weight: 300;
  font-size: 1.5rem;
  line-height: 1.2;
  margin: 0 0 1.5rem;
  color: var(--ink);
}

.field { display: grid; gap: 0.35rem; margin-bottom: 1.35rem; }
.field label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
/* Underlined fields rather than boxes: a line to write on, like a
   card. Focus doubles the line and turns it gold; the global outline
   is switched off here because a rectangle around an underline reads
   as a mistake. */
.field input, .field textarea {
  font-family: inherit;
  /* Never under 16px: iOS zooms the page into any smaller field the
     moment it takes focus, and does not zoom back out. */
  font-size: 1.05rem;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--line-strong);
  border-radius: 0;
  padding: 0.6rem 0;
  min-height: 44px;
  /* A field is as wide as its column and no wider. Left to itself an
     <input> is twenty characters wide whatever its column is, and two
     of them in a row on a phone pushed the sheet past the edge of the
     screen and gave the whole page a sideways scroll. */
  width: 100%;
  min-width: 0;
  transition: border-color 150ms ease, box-shadow 150ms ease;
}
.field input:focus-visible, .field textarea:focus-visible {
  outline: none;
  border-bottom-color: var(--gold);
  box-shadow: 0 1px 0 0 var(--gold);
}
.field textarea { min-height: 6.5rem; resize: vertical; }
/* Name and phone share a row from 20rem: at 320px each field is still
   140px, which is a name, and the form is one line shorter on the
   screen where its length matters. */
.field-row { display: grid; gap: 0 1.5rem; }
@media (min-width: 20rem) { .field-row { grid-template-columns: 1fr 1fr; } }

.detail-list { display: grid; gap: 1.25rem; margin: 2rem 0 0; padding: 0; list-style: none; }
@media (min-width: 32rem) { .detail-list { grid-template-columns: 1fr 1fr; } }
.detail-list dt {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.detail-list dd { margin: 0.25rem 0 0; font-size: 1.05rem; }
.detail-list a { text-decoration: none; border-bottom: 1px solid var(--line-strong); }
.detail-list a:hover { border-bottom-color: var(--gold); }

/* ── Footer ─────────────────────────────────────────────────────────
   The name, once, large. The mark has been at the top of every page;
   the bottom gets the words. */

.footer {
  padding: clamp(3rem, 6vw, 5rem) var(--pad) 2rem;
  border-top: 1px solid var(--line);
}
.footer-word {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0 0.35em;
  margin: 0;
  font-family: 'Fraunces', Georgia, serif;
  font-weight: 300;
  font-size: clamp(2.4rem, 7vw, 5.5rem);
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--ink);
}
/* "Timeless" beside the name, in the italic and at roughly half the
   size — still over 24px at every width, so --gold-soft clears 3:1. */
.footer-word em { font-style: italic; font-size: 0.5em; letter-spacing: 0; color: var(--gold-soft); }
.footer-row {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem 2.5rem;
  align-items: center;
  justify-content: space-between;
  margin-top: 2.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}
.footer a { text-decoration: none; }
.footer a:hover { color: var(--ink); }
.footer-social { display: flex; gap: 1.5rem; }

/* The phone-only "view all" under the grid. */
.grid-more { margin: 1.5rem 0 0; text-align: center; }

/* Any figure holding a 1024 export rather than a full-resolution
   original. Same 450px ceiling as the Christmas figure, and the same
   reason: half of what the file actually has. */
.figure-capped { max-width: 450px; }

/* ── The journal pages ──────────────────────────────────────────────*/

.post-head { padding-bottom: clamp(2rem, 4vw, 3rem); }
.post-para { font-size: 1.05rem; line-height: 1.75; margin-top: 1.25rem; }
.post-head .wrap-narrow > .display { margin-bottom: 0; }
/* A story's first photograph, under its title on a phone (app.jsx
   decides when). The width of the page inside its padding, which is
   the width the grid below draws its own full rows at, so the frame
   reads as the first of the set rather than as a banner. */
.post-lead { margin: 1.75rem 0 0; }
.post-lead img { width: 100%; height: auto; }
.post-lead + .lede, .post-lead + .post-para { margin-top: 1.75rem; }
@media (max-width: 39.99rem) {
  .post-head { padding-bottom: 1.5rem; }
  .post-para { font-size: 1rem; }
}

/* ── Motion ─────────────────────────────────────────────────────────
   `.rv` is anything that arrives: it starts a little below its place
   and slightly transparent, and the `.in` class (added by an
   IntersectionObserver in app.jsx as it scrolls into view) lets it
   rise. `translate` rather than `transform`, so an element that is
   also rotated or scaled keeps that. `--i` staggers siblings. */
.rv {
  opacity: 0;
  translate: 0 28px;
  transition: opacity 1s var(--ease), translate 1.1s var(--ease);
  transition-delay: calc(var(--i, 0) * 110ms);
}
.rv.in { opacity: 1; translate: 0 0; }
/* Quicker on a phone, where a flick covers a screen in a moment and a
   second-long rise means arriving at a photograph before it has. */
@media (max-width: 39.99rem) {
  .rv { translate: 0 18px; transition-duration: 0.65s, 0.75s; transition-delay: calc(var(--i, 0) * 70ms); }
}

/* Respect a reader who has asked for less movement: nothing rises,
   nothing turns, nothing slides, nothing drifts, the menu simply
   appears, the strips jump rather than glide, and the underline is
   simply there. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
  html { scroll-behavior: auto; }
  .rv { opacity: 1; translate: none; transition: none; }
  .ring-text, .ribbon-track { animation: none !important; }
  .menu[open] { animation: none; }
  .sheet, .cards-strip { scroll-behavior: auto; }
  .fig::before, .about-pics::before, .paper::before { translate: none !important; }
  .u path { stroke-dashoffset: 0; transition: none; }
}

/* The honeypot, and the note under the form.
   `.trap` is taken out of the layout entirely rather than moved off
   screen with a huge negative offset, because some bots check for that
   trick specifically. It is also aria-hidden and out of the tab order,
   so nobody using a screen reader or a keyboard ever lands on it. */
.trap { position: absolute; width: 1px; height: 1px; overflow: hidden;
        clip-path: inset(50%); white-space: nowrap; }
.form-note { font-size: 0.9rem; line-height: 1.6; margin-top: 1rem; min-height: 1.6em; }
.form-note a { text-decoration: underline; text-underline-offset: 3px; }
.btn[disabled] { opacity: 0.6; cursor: default; }

/* ── The Christmas season, while it is on ───────────────────────────
   Christmas minis are the studio's most valuable booking window and
   the nav gave them one word in five, set exactly like the other four.
   Everything here is switched by one date in app.jsx and goes quiet on
   its own the day after the season.

   No red. The photographs in that section are already full of it, and
   a red bar on blush paper beside gold would be the first thing on
   this site to look like a template. The emphasis is the page's own
   gold, used solid instead of as a hairline. */

.ribbon {
  display: flex;
  align-items: stretch;
  background: var(--gold);
  color: #fff;
}
.ribbon-main {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.7rem var(--pad);
  text-decoration: none;
  color: inherit;
  min-height: 44px;
}
/* Pinned to the first line rather than centred, because on a phone the
   ribbon wraps to two lines and a vertically centred mark then floats
   in the gutter between them, attached to neither. */
.ribbon-star { flex: none; opacity: 0.95; align-self: center; }
@media (max-width: 40rem) { .ribbon-star { align-self: flex-start; margin-top: 0.25rem; } }
.ribbon-say { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.2rem 0.7rem; }
.ribbon-say strong {
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}
/* The dates in italic Fraunces, which is the page's own accent voice
   and stops the bar reading as a system notification. */
.ribbon-dates {
  font-family: 'Fraunces', Georgia, serif;
  font-style: italic;
  font-size: 0.95rem;
  opacity: 0.92;
}
.ribbon-go {
  margin-left: auto;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  border-bottom: 1px solid rgba(255,255,255,0.55);
  padding-bottom: 1px;
  white-space: nowrap;
}
@media (max-width: 40rem) {
  /* On a phone the verb goes and the whole bar becomes the target, so
     the words are not competing with a second tappable thing inside a
     bar that is itself one. */
  .ribbon-go { display: none; }
}
.ribbon-close {
  flex: none;
  width: 44px;
  background: none;
  border: 0;
  color: #fff;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.75;
}
.ribbon-close:hover { opacity: 1; }
.ribbon-main:focus-visible, .ribbon-close:focus-visible {
  outline: 2px solid #fff;
  outline-offset: -4px;
}

/* The nav item, filled rather than tinted. Gold as small type does not
   clear contrast on this paper; white on gold does, comfortably. */
.masthead-nav a.nav-lit {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  background: var(--gold);
  color: #fff;
  padding: 0.45rem 0.8rem;
  border-radius: 999px;
  border-bottom-color: transparent;
}
.masthead-nav a.nav-lit:hover { background: var(--gold-soft); border-bottom-color: transparent; }
.nav-star { opacity: 0.95; }

/* The phone menu's version. A rule down the side rather than a fill,
   because a solid pill in a list of six plain rows reads as a button
   somebody has dropped in the wrong place. */
.menu-lit .menu-label { color: var(--gold-ink); }
.menu-lit { border-left: 2px solid var(--gold); padding-left: 0.75rem; margin-left: -0.75rem; }
.menu-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin-left: 0.6rem;
  font-family: 'Karla', system-ui, sans-serif;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold-ink);
  vertical-align: middle;
}

/* ── The service pages ──────────────────────────────────────────────
   Four pages built out of the parts the landing page already uses, so
   there is very little here: the questions block, the links out to the
   other three, and the row of them in the footer. */

/* A link inside a sentence. `.u` is the drawn underline and needs the
   Underline component's svg inside it, so a bare <a className="u"> gets
   the italic and no line at all. */
.prose-link {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 3px;
  transition: text-decoration-color 200ms ease;
}
.prose-link:hover { text-decoration-color: var(--gold); }

/* The questions couples ask, answered on the page. A definition list
   rather than an accordion: the answers are three lines each, and an
   answer folded away is one Google will not count as being on the page
   at all, which is the opposite of the point. */
.faq { margin: 0; padding: 0; }
.faq-item { padding: 1.75rem 0; border-top: 1px solid var(--line); }
.faq-item:last-child { border-bottom: 1px solid var(--line); }
.faq dt {
  font-family: 'Fraunces', Georgia, serif;
  font-weight: 400;
  font-size: clamp(1.15rem, 2.4vw, 1.4rem);
  line-height: 1.35;
  color: var(--ink);
}
.faq dd { margin: 0.75rem 0 0; font-size: 1.02rem; line-height: 1.7; color: var(--ink-soft); }

/* The other three services, as a list of rules rather than as buttons:
   a page of its own deserves a line, not a chip. */
.service-links { list-style: none; margin: 2.5rem 0 0; padding: 0; display: grid; }
.service-links li { border-top: 1px solid var(--line); }
.service-links li:last-child { border-bottom: 1px solid var(--line); }
.service-links a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.25rem 0;
  font-family: 'Fraunces', Georgia, serif;
  font-size: clamp(1.15rem, 2.4vw, 1.5rem);
  color: var(--ink);
  text-decoration: none;
}
/* Sized and stroked here, like every other arrow on the site. These
   icons carry no width, height or fill of their own, so an svg given
   only a colour fills its box with a solid black triangle the height of
   the row. */
.service-links a svg {
  width: 18px;
  height: 18px;
  flex: none;
  fill: none;
  stroke: var(--gold-ink);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 400ms var(--ease);
}
.service-links a:hover svg { transform: translateX(6px); }

/* The same four in the footer of every page. 12px, so the label colour
   has to be --muted at the lightest; --gold at this size is 3:1 and
   unreadable, which is the whole reason --gold-ink exists. */
.footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 2rem;
  margin-top: 2.5rem;
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.footer-links a { color: var(--muted); text-decoration: none; }
.footer-links a:hover { color: var(--ink); }
