/* ==========================================================================
   Kate Ming Photography
   Design tokens are all at the top — change them here, not further down.

   AFTER EDITING THIS FILE: bump the ?v= number on the stylesheet link in
   index.html AND the-archive/index.html. GitHub Pages tells browsers to hold
   assets for 10 minutes, so without a new ?v= a returning visitor keeps the
   old stylesheet and the page renders unstyled in places.
   ========================================================================== */

:root {
  /* Palette lifted from the design template */
  --bg:        #f7f7f7;   /* page surface            */
  --cream:     #f2f1ee;   /* hero button / hero type */
  --ink:       #1c1c1c;   /* headings                */
  --ink-2:     #2e2e2e;   /* body copy               */
  --ink-3:     #5f5f5f;   /* quiet labels            */
  --rule:      rgba(28, 28, 28, .22);

  --font-serif:  "Cormorant Garamond", Georgia, "Times New Roman", serif;
  --font-script: "Pinyon Script", "Cormorant Garamond", cursive;

  /* Layout */
  --wrap:    72rem;                          /* 1152px content column */
  --gutter:  clamp(1.25rem, 5vw, 4rem);
  --section: clamp(4.5rem, 10vw, 8.5rem);    /* vertical section rhythm */
  --header-h: 5rem;

  /* Type scale — mirrors the proportions of the 1024px-wide template */
  --fs-body:   clamp(1.0625rem, .95rem + .55vw, 1.25rem);
  --fs-small:  clamp(1rem, .94rem + .3vw, 1.125rem);
  --fs-h1:     clamp(2.75rem, 1.6rem + 5.4vw, 5.75rem);
  --fs-h2:     clamp(2rem, 1.35rem + 2.9vw, 3.5rem);
  --fs-h2-sm:  clamp(1.6rem, 1.25rem + 1.6vw, 2.35rem);
  --fs-h3:     clamp(1.35rem, 1.1rem + 1.15vw, 1.9rem);
  --fs-script: clamp(2.75rem, 1.5rem + 5.4vw, 4.75rem);
}

/* --------------------------------------------------------------- reset -- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 1rem);
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink-2);
  font-family: var(--font-serif);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: 1.75;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img { max-width: 100%; height: auto; display: block; }
h1, h2, h3, p, ul, figure { margin: 0; }
ul { list-style: none; padding: 0; }

a { color: inherit; }

:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

.skip-link {
  position: absolute;
  left: 50%;
  top: 0;
  transform: translate(-50%, -120%);
  z-index: 999;
  padding: .75rem 1.5rem;
  background: var(--ink);
  color: var(--bg);
  font-size: 1rem;
  letter-spacing: .12em;
  text-decoration: none;
}
.skip-link:focus { transform: translate(-50%, 0); }

/* ------------------------------------------------------------ primitives -- */

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section { padding-block: var(--section); }

.h2 {
  font-size: var(--fs-h2);
  font-weight: 500;
  line-height: 1.08;
  letter-spacing: -.005em;
  color: var(--ink);
}
.h2--sm { font-size: var(--fs-h2-sm); }

.script {
  font-family: var(--font-script);
  font-size: var(--fs-script);
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: .01em;
  color: var(--ink);
  /* Pinyon's swashes overshoot the em box in both directions. */
  padding-block: .12em;
}
.script--sm { font-size: clamp(2.5rem, 1.6rem + 3.6vw, 3.75rem); }

.rule {
  width: 5.5rem;
  height: 0;
  margin: 1.25rem 0 1.75rem;
  border: 0;
  border-top: 1px solid var(--ink);
}

/* The extracted brand marks are black artwork on transparency. */
.mark { width: auto; opacity: .92; }
.mark--lockup   { height: clamp(4rem, 6vw, 5.75rem); }
.mark--monogram { height: clamp(2.5rem, 3.4vw, 3.25rem); }

/* ---------------------------------------------------------------- button -- */

/* The template's signature double rule: outer border, gap, inner hairline.
   Both rules are hairlines — at button scale anything heavier reads as a slab
   rather than the engraved-stationery look the template is after.

   --btn-surface must be OPAQUE and match whatever sits behind the button. An
   inset box-shadow of `transparent` paints nothing, it does not mask the
   shadow beneath it, so a transparent gap collapses the two rules into one
   solid band. Over a photograph, drop the shadow entirely instead. */
.btn {
  --btn-face: transparent;
  --btn-surface: var(--bg);
  --btn-rule: 1px;
  --btn-gap: 3px;
  --btn-inner: calc(var(--btn-gap) + var(--btn-rule));

  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 3rem;
  padding: .55rem 3.25rem;
  background: var(--btn-face);
  color: var(--ink);
  border: var(--btn-rule) solid var(--ink);
  box-shadow:
    inset 0 0 0 var(--btn-gap) var(--btn-surface),
    inset 0 0 0 var(--btn-inner) var(--ink);
  font-family: var(--font-serif);
  font-size: clamp(1rem, .95rem + .25vw, 1.125rem);
  font-weight: 500;
  line-height: 1;
  letter-spacing: .14em;
  text-indent: .14em;              /* balance the trailing letter-space */
  text-decoration: none;
  transition: background-color .35s ease, color .35s ease, box-shadow .35s ease;
}

/* Inverts to a filled block, keeping the inner hairline as a light inset. */
.btn:hover,
.btn:focus-visible {
  --btn-face: var(--ink);
  --btn-surface: var(--ink);
  color: var(--bg);
  box-shadow:
    inset 0 0 0 var(--btn-gap) var(--ink),
    inset 0 0 0 var(--btn-inner) var(--bg);
}

.btn--sm {
  min-height: 2.75rem;
  padding: .4rem 1.75rem;
  font-size: 1rem;
}

/* "Read" sits in the script face in the template.

   Pinyon Script reserves a deep descender (~.39em) and "Read" has no descending
   letter, so `align-items: center` centres a line box whose lower third the word
   never fills, parking the ink ~.18em high. Measured at 1440px: 10px of space
   above the glyphs against 19.3px below. Asymmetric padding pushes it back onto
   the optical centre; in `em` so it tracks the clamped font size. */
.btn--read {
  min-width: min(13rem, 100%);
  padding-inline: 2rem;
  padding-block: calc(.55rem + .18em) calc(.55rem - .18em);
  font-family: var(--font-script);
  font-weight: 400;
  font-size: clamp(1.3rem, 1.15rem + .5vw, 1.6rem);
  letter-spacing: .02em;
  text-indent: 0;                  /* script face needs no optical nudge */
  line-height: 1;
}

.btn--hero {
  --btn-face: var(--cream);
  border-radius: 2px;
  box-shadow: none;
  min-width: min(17rem, 80vw);
}
.btn--hero:hover,
.btn--hero:focus-visible {
  --btn-face: var(--ink);
  color: var(--cream);
  box-shadow: none;
}

/* ---------------------------------------------------------------- header -- */

.header {
  position: fixed;
  inset: 0 0 auto;
  z-index: 100;
}

/* The solid header surface lives on a pseudo-element rather than on .header
   itself. backdrop-filter turns an element into a containing block for its
   position:fixed descendants — putting it on .header trapped the mobile drawer
   (.nav, inset:0) inside the 68px header strip instead of the viewport, so the
   links floated over the page with no background behind them. A pseudo-element
   cannot contain .nav, so the blur is safe here. */
.header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgba(247, 247, 247, .94);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  box-shadow: 0 1px 0 var(--rule);
  opacity: 0;
  transition: opacity .4s ease;
}

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  width: 100%;
  max-width: var(--wrap);
  min-height: var(--header-h);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.header__mark {
  position: relative;   /* keep the wordmark above the mobile drawer */
  z-index: 2;
  display: block;
}

/* The wordmark is wider than tall (KATE with the script M through it), so it
   is sized by height and given a little more of it than a plain script mark. */
.header__mark img {
  height: clamp(2.35rem, 3.8vw, 3rem);
  width: auto;
  transition: filter .4s ease;
}

/* Over the photograph the black artwork and links flip to cream. The gradient
   travels with the header so the links stay legible whatever is underneath. */
.header[data-over-hero] {
  background: linear-gradient(to bottom, rgba(0, 0, 0, .42), rgba(0, 0, 0, 0));
}
.header[data-over-hero] .header__mark img { filter: brightness(0) invert(1); }
.header[data-over-hero] .nav__list a,
.header[data-over-hero] .btn { color: var(--cream); }
/* Over the photograph there is no opaque surface to draw the gap in, so the
   nav button is a single cream hairline rather than the double rule. */
.header[data-over-hero] .btn {
  border-color: var(--cream);
  box-shadow: none;
}
.header[data-over-hero] .btn:hover,
.header[data-over-hero] .btn:focus-visible {
  background: var(--cream);
  color: var(--ink);
  box-shadow:
    inset 0 0 0 var(--btn-gap) var(--cream),
    inset 0 0 0 var(--btn-inner) var(--ink);
}
.header[data-over-hero] .header__bars,
.header[data-over-hero] .header__bars::before,
.header[data-over-hero] .header__bars::after { background: var(--cream); }

.header:not([data-over-hero])::before { opacity: 1; }

.nav {
  display: flex;
  align-items: center;
  gap: clamp(1.5rem, 3vw, 2.75rem);
}

.nav__list {
  display: flex;
  align-items: center;
  gap: clamp(1.25rem, 2.6vw, 2.5rem);
}

.nav__list a {
  position: relative;
  display: inline-block;
  padding-block: .65rem;      /* comfortable hit target, not just the glyphs */
  font-size: 1.0625rem;
  font-weight: 500;
  letter-spacing: .08em;
  text-decoration: none;
  white-space: nowrap;
}

.nav__list a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: .35rem;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .35s ease;
}
.nav__list a:hover::after,
.nav__list a:focus-visible::after,
.nav__list a[aria-current="page"]::after { transform: scaleX(1); }

/* Hamburger — hidden until the nav no longer fits */
.header__toggle {
  display: none;
  position: relative;
  z-index: 2;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
}

.header__bars,
.header__bars::before,
.header__bars::after {
  position: absolute;
  left: 50%;
  width: 1.5rem;
  height: 1px;
  margin-left: -.75rem;
  background: var(--ink);
  transition: transform .3s ease, opacity .2s ease;
}
.header__bars { top: 50%; }
.header__bars::before { content: ""; left: 0; margin: 0; top: -.4rem; }
.header__bars::after  { content: ""; left: 0; margin: 0; top:  .4rem; }

/* ------------------------------------------------------------------ hero -- */

.hero {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 100svh;
  padding: calc(var(--header-h) + 2rem) var(--gutter) 3rem;
  isolation: isolate;
  overflow: hidden;
}

.hero__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 46%;
  z-index: -2;
}

/* Just enough scrim to hold the cream type at AA on a high-key photograph. */
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(to bottom, rgba(0, 0, 0, .22), rgba(0, 0, 0, 0) 24%),
    linear-gradient(to top,    rgba(0, 0, 0, .28), rgba(0, 0, 0, 0) 26%),
    radial-gradient(62% 52% at 50% 50%, rgba(0, 0, 0, .34), rgba(0, 0, 0, .04) 100%);
}

.hero__inner { text-align: center; max-width: 54rem; }

.hero__title {
  font-size: var(--fs-h1);
  font-weight: 400;
  line-height: 1.04;
  letter-spacing: -.01em;
  color: var(--cream);
  text-shadow: 0 1px 24px rgba(0, 0, 0, .28);
}

.hero__sub {
  margin-top: clamp(1rem, 2vw, 1.6rem);
  font-size: var(--fs-small);
  font-weight: 400;
  letter-spacing: .04em;
  color: var(--cream);
  text-shadow: 0 1px 16px rgba(0, 0, 0, .35);
}

.btn--hero { margin-top: clamp(1.75rem, 3vw, 2.5rem); }

/* ----------------------------------------------------------------- about -- */

/* Portrait in column one; mark + heading, copy, then button stacked in column
   two. Rows are pinned so the mobile block can rearrange them into the
   portrait-beside-heading layout Kate uses on her live site. */
.about__grid {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  align-items: center;
  column-gap: clamp(2.5rem, 6vw, 5.5rem);
  row-gap: 1.5rem;
}

.about__figure {
  grid-area: 1 / 1 / 4 / 2;
  width: min(24rem, 100%);
  justify-self: end;
}
.about__figure img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
}

.about__intro {
  grid-area: 1 / 2;
  display: grid;
  justify-items: start;
  gap: 1.5rem;
}
.about__intro .h2 { margin-top: -.35rem; }

/* Kate's primary mark. Sized by height, and shorter than the stacked lockup
   it replaced because this one is wide rather than square. */
.about__mark {
  height: clamp(2.75rem, 4.4vw, 4rem);
  width: auto;
  opacity: .92;
}

.about__copy { grid-area: 2 / 2; }
.about__copy p { max-width: 44ch; }
.about__copy p + p { margin-top: 1.35em; }

.about__cta { grid-area: 3 / 2; justify-self: start; margin-top: .75rem; }

/* ------------------------------------------------------------ experience -- */

.experience__title { margin-bottom: clamp(2.25rem, 4.5vw, 3.5rem); }

.experience__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr);
  column-gap: clamp(2.5rem, 6vw, 5rem);
  row-gap: clamp(2.5rem, 5vw, 4rem);
  align-items: start;
}

.experience__lead { grid-column: 1; }
.experience__lead p + p { margin-top: 1.25em; }

.press {
  grid-column: 2;
  justify-self: end;
  text-align: left;
  max-width: 16rem;
}
.press .mark { margin-bottom: .75rem; }
.press__label { color: var(--ink-3); }
.press__list li { white-space: nowrap; }

/* Photographs are deliberately small against the white space, as in the
   template — the column is wide, the picture is not. */
.experience__figure {
  grid-column: 1;
  align-self: start;
  width: min(19rem, 100%);
}
.experience__figure img {
  width: 100%;
  aspect-ratio: 2 / 3;
  object-fit: cover;
}

.experience__body { grid-column: 2; }
.experience__body p + p { margin-top: 1.25em; }

/* ----------------------------------------------------------- collections -- */

.collections__inner {
  display: grid;
  justify-items: center;
  text-align: center;
  gap: clamp(1.5rem, 3vw, 2.25rem);
}

.collections__note {
  font-size: var(--fs-small);
  letter-spacing: .05em;
  color: var(--ink);
}

.collections__figure { width: min(19rem, 70vw); }
.collections__figure img {
  width: 100%;
  aspect-ratio: 2 / 3;
  object-fit: cover;
}

.collections__title { margin-top: .5rem; }

/* -------------------------------------------------------------- packages -- */

.package { padding-block: clamp(3.25rem, 7vw, 6rem); }

.package__grid {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  gap: clamp(2.5rem, 6vw, 5rem);
}

.package--reverse .package__figure { order: -1; }

.package__body { display: grid; justify-items: start; gap: .35rem; text-align: left; }

.package__body .script { margin-bottom: .35rem; }

.package__price {
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: .02em;
  color: var(--ink);
  margin-bottom: .6rem;
}

.package__list {
  display: grid;
  gap: .28em;
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--ink);
}

.package__body .btn { margin-top: 1.75rem; }

.package__figure {
  width: min(20rem, 100%);
  justify-self: center;
}
.package__figure img {
  width: 100%;
  aspect-ratio: 2 / 3;
  object-fit: cover;
}
.package--wide .package__figure { width: min(30rem, 100%); }
.package--wide .package__figure img { aspect-ratio: 3 / 2; }

/* Kate's accent ciphers. On desktop they sit quietly in the outer margin; the
   mobile block below turns them into a grid item flanking the photograph. */
.package__accent {
  position: absolute;
  width: auto;
  opacity: .5;
  pointer-events: none;
}
.package__accent--script { height: clamp(1.75rem, 2.6vw, 2.5rem); }
.package__accent--oval   { height: clamp(2.75rem, 4.2vw, 4rem); }

.package:not(.package--reverse) .package__accent { top: -2.5rem; right: 0; }
.package--reverse .package__accent { top: 40%; left: 0; }

/* --------------------------------------------------- archive (the-archive) -- */

/* The archive hero photograph is high-key, so it carries a heavier scrim
   than the homepage's. */
.hero--archive::after {
  background:
    linear-gradient(to bottom, rgba(0, 0, 0, .30), rgba(0, 0, 0, 0) 24%),
    linear-gradient(to top,    rgba(0, 0, 0, .34), rgba(0, 0, 0, 0) 26%),
    radial-gradient(64% 54% at 50% 50%, rgba(0, 0, 0, .44), rgba(0, 0, 0, .12) 100%);
}
.hero--archive .hero__img { object-position: 50% 42%; }

.entry { padding-block: clamp(3.5rem, 8vw, 6.5rem); }
.entry + .entry { border-top: 1px solid var(--rule); }

/* Couple's name treatment from page 2 of the template: the name flanked by
   the dove pair, wedding location beneath. */
.entry__head {
  text-align: center;
  margin-bottom: clamp(2.5rem, 5vw, 4rem);
}

.entry__name {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(1rem, 3.5vw, 3rem);
}

.entry__name .script { font-size: clamp(2.25rem, 1.3rem + 4.4vw, 4.25rem); }

.entry__dove {
  flex: none;
  width: clamp(3.25rem, 8vw, 9.5rem);
  height: auto;
  opacity: .8;
}
.entry__dove--flip { transform: scaleX(-1); }

.entry__place {
  margin-top: .5rem;
  font-size: var(--fs-small);
  letter-spacing: .05em;
  color: var(--ink-2);
}

.entry__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  align-items: center;   /* excerpts vary in length; keep the pair balanced */
  gap: clamp(2.5rem, 6vw, 5rem);
}

.entry__figure {
  width: min(22rem, 100%);
  justify-self: center;
}
.entry__figure img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
}
.entry__figure figcaption {
  display: flex;
  justify-content: center;
  margin-top: 1.5rem;
}

/* ----------------------------------------------- wedding story (post page) -- */

.post__head {
  padding-block: calc(var(--header-h) + clamp(2.5rem, 6vw, 4.5rem))
                clamp(2rem, 4vw, 3rem);
  text-align: center;
}

.post__back {
  display: inline-block;
  margin-bottom: clamp(1.75rem, 4vw, 3rem);
  font-size: var(--fs-small);
  letter-spacing: .12em;
  text-decoration: none;
  color: var(--ink-3);
  transition: color .3s ease;
}
.post__back:hover { color: var(--ink); }

.post__head .script { font-size: clamp(2.25rem, 1.3rem + 4.4vw, 4.75rem); }

/* --- opening carousel --- */

.carousel { padding-bottom: clamp(2.5rem, 5vw, 4rem); }

.carousel__track {
  --carousel-gap: clamp(.75rem, 1.6vw, 1.35rem);
  --carousel-visible: 3;

  display: grid;
  grid-auto-flow: column;
  /* N across, minus the gaps between them */
  grid-auto-columns: calc(
    (100% - (var(--carousel-visible) - 1) * var(--carousel-gap)) / var(--carousel-visible));
  gap: var(--carousel-gap);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  scrollbar-width: none;                 /* the arrows are the affordance */
  padding-bottom: 2px;                   /* room for the focus ring */
}
.carousel__track::-webkit-scrollbar { display: none; }

.carousel__slide { scroll-snap-align: start; }
.carousel__slide img {
  width: 100%;
  aspect-ratio: 2 / 3;
  object-fit: cover;
}

.carousel__controls {
  display: flex;
  justify-content: center;
  gap: 1rem;
  margin-top: clamp(1.25rem, 2.5vw, 1.75rem);
}

.carousel__arrow {
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  padding: 0;
  background: none;
  color: var(--ink);
  border: 1px solid var(--ink);
  cursor: pointer;
  transition: background-color .3s ease, color .3s ease, opacity .3s ease;
}
.carousel__arrow svg { width: 1.15rem; height: 1.15rem; }
.carousel__arrow:hover { background: var(--ink); color: var(--bg); }

/* --- the story itself --- */

.post__body {
  /* A measure that stays readable; figures break out of it deliberately. */
  --measure: 40rem;
  padding-bottom: clamp(2.5rem, 5vw, 4rem);
}

.post__body > p {
  max-width: var(--measure);
  margin-inline: auto;
}
.post__body > p + p { margin-top: 1.35em; }

.post__deck {
  max-width: var(--measure);
  margin: 0 auto clamp(2rem, 4vw, 3rem);
  font-size: var(--fs-h2-sm);
  font-weight: 500;
  line-height: 1.2;
  text-align: center;
  color: var(--ink);
}

.post__lede {
  font-size: clamp(1.15rem, 1rem + .7vw, 1.4rem);
  line-height: 1.65;
  color: var(--ink);
}

/* Standing credit where an associate photographer shot the wedding. */
.post__note {
  font-style: italic;
  text-align: center;
  color: var(--ink-3);
}
.post__body > p.post__note { margin-bottom: 1.6em; }

/* The one-line beat in the middle of the story ("And then there was Finn!!!") */
.post__aside {
  font-size: clamp(1.35rem, 1.1rem + 1.1vw, 1.9rem);
  font-style: italic;
  text-align: center;
  color: var(--ink);
}
.post__body > p.post__aside { margin-block: 1.6em; }

/* Each paragraph after the lede is paired with one photograph, and the pair
   alternates sides down the page: text left / picture right, then picture
   left / text right. Rows are the only <div>s in .post__body, so nth-of-type
   drives the alternation — keep it that way, or add an explicit modifier. */
.post__row {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: clamp(2.5rem, 5vw, 4.5rem);
  align-items: center;
  margin-block: clamp(3rem, 6vw, 5rem);
}

.post__row:nth-of-type(even) .post__figure { order: -1; }

.post__row .post__text > p + p { margin-top: 1.35em; }

.post__figure img {
  width: 100%;
  aspect-ratio: 2 / 3;
  object-fit: cover;
}

/* --- vendor team --- */

.post__vendors {
  padding-block: clamp(3rem, 7vw, 5.5rem);
  border-top: 1px solid var(--rule);
  text-align: center;
}
.post__vendors .h2 { margin-bottom: clamp(1.75rem, 3.5vw, 2.5rem); }

.vendors {
  display: grid;
  gap: .5rem;
  max-width: 30rem;
  margin: 0 auto;
  font-size: var(--fs-small);
}
.vendors__row {
  display: flex;
  justify-content: center;
  gap: .5ch;
}
.vendors dt { color: var(--ink-3); }
.vendors dt::after { content: " ·"; }
.vendors dd { margin: 0; color: var(--ink); }
.vendors a { text-decoration-thickness: 1px; text-underline-offset: .2em; }

.post__more { margin-top: clamp(2.5rem, 5vw, 3.5rem); }

/* --------------------------------------------------------------- contact -- */

/* Three columns: details, the pitch centred on screen, doves alongside it.
   The outer columns are equal, which is what puts the pitch dead centre.
   The doves come first in the DOM so they stack as a divider on mobile;
   explicit column placement moves them to the right here. */
.contact__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.5fr) minmax(0, 1fr);
  column-gap: clamp(2rem, 4.5vw, 3.5rem);
  row-gap: clamp(2.5rem, 5vw, 4rem);
  align-items: center;
}

/* Row is pinned explicitly: the doves come first in the DOM but belong in the
   third column, and sparse auto-placement would otherwise refuse to backtrack
   and drop the other two onto a second row. */
.contact__details { grid-area: 1 / 1; align-self: start; }
.contact__pitch   { grid-area: 1 / 2; }
.contact__doves   { grid-area: 1 / 3; }

.contact__doves {
  justify-self: start;
  width: clamp(6.5rem, 11vw, 9.5rem);
  height: auto;
  opacity: .85;
  pointer-events: none;
}

.contact__details .script { margin-bottom: -.25rem; }
.contact__line { margin-top: 1.5rem; }
.contact__line a { text-decoration-thickness: 1px; text-underline-offset: .2em; }

.contact__pitch {
  display: grid;
  justify-items: center;
  gap: 2rem;
}
.contact__pitch p { text-align: justify; hyphens: auto; }

/* ---------------------------------------------------------------- footer -- */

.footer {
  padding-block: var(--section);
  border-top: 1px solid var(--rule);
}

.footer__inner {
  display: grid;
  justify-items: center;
  text-align: center;
  gap: 2rem;
}

/* Inner pages skip the homepage manifesto. */
.footer--slim { padding-block: clamp(3rem, 6vw, 5rem); }

.footer__mark { opacity: 1; }

/* Carries the manifesto's closing line only — the rest lives in .experience,
   which is why this is sized as a closing statement rather than as prose:
   narrower than the 60rem it needed at seven paragraphs, and at body size so it
   doesn't read as fine print. `balance` evens the lines out at every width; a
   hand-placed <br> read well at 1440px but stranded "felt," alone on a line at
   390px. The p + p rule stays in case copy ever comes back. */
.footer__manifesto {
  max-width: 42rem;
  font-size: var(--fs-body);
  line-height: 1.7;
}
.footer__manifesto p { text-wrap: balance; }
.footer__manifesto p + p { margin-top: 1.15em; }

.footer__nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1rem 2rem;
  margin-top: 1rem;
}
.footer__nav a {
  font-size: 1.0625rem;
  font-weight: 500;
  letter-spacing: .08em;
  text-decoration: none;
}
.footer__nav a:hover { text-decoration: underline; text-underline-offset: .25em; }

.footer__legal {
  font-size: .95rem;
  letter-spacing: .04em;
  color: var(--ink-3);
}

/* ================================ responsive ============================== */

@media (max-width: 60rem) {
  :root { --header-h: 4.25rem; }

  .header__toggle { display: block; }

  .nav {
    position: fixed;
    inset: 0;
    flex-direction: column;
    justify-content: center;
    gap: 2.5rem;
    background: var(--bg);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-1rem);
    transition: opacity .35s ease, transform .35s ease, visibility .35s;
  }

  .nav__list {
    flex-direction: column;
    gap: 1.75rem;
    text-align: center;
  }
  .nav__list a { font-size: 1.5rem; }

  /* Menu open: panel visible, links always dark on the solid panel. */
  .header.is-open .nav {
    opacity: 1;
    visibility: visible;
    transform: none;
  }
  .header.is-open[data-over-hero] .nav__list a,
  .header.is-open[data-over-hero] .btn { color: var(--ink); }
  /* Drawer open: the panel is opaque again, so the double rule comes back. */
  .header.is-open[data-over-hero] .btn {
    border-color: var(--ink);
    box-shadow:
      inset 0 0 0 var(--btn-gap) var(--bg),
      inset 0 0 0 var(--btn-inner) var(--ink);
  }
  .header.is-open[data-over-hero] .header__mark img { filter: none; }
  .header.is-open[data-over-hero] .header__bars::before,
  .header.is-open[data-over-hero] .header__bars::after { background: var(--ink); }

  .header.is-open .header__bars { background: transparent !important; }
  .header.is-open .header__bars::before { transform: translateY(.4rem) rotate(45deg); }
  .header.is-open .header__bars::after  { transform: translateY(-.4rem) rotate(-45deg); }

  /* The hero is a band rather than a full screen, so the next section shows. */
  .hero { min-height: min(64svh, 30rem); }

  /* The homepage hero drops its button on small screens — the nav already
     carries one a thumb's reach away. The Archive hero keeps its own. */
  .hero--home .btn--hero { display: none; }
  .hero--home .hero__sub { margin-bottom: 0; }

  /* Two-column layouts collapse to a single readable column. */
  .experience__grid,
  .entry__grid,
  .contact__grid {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Standalone photographs sit inset from the gutters rather than spanning
     the full column, so they read at a similar size to the paired ones. */
  .experience__figure,
  .entry__figure,
  .collections__figure,
  .post__figure {
    width: min(20rem, 74%);
    justify-self: center;
    margin-inline: auto;
  }

  /* ---- About: portrait on the left, mark + heading + button to its right,
     copy full width beneath. Mirrors Kate's live mobile layout. ---- */
  .about__grid {
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: clamp(1rem, 4vw, 1.75rem);
    row-gap: clamp(1.25rem, 3.5vw, 1.75rem);
  }
  .about__figure {
    grid-area: 1 / 1 / 3 / 2;
    width: clamp(7rem, 37vw, 12rem);
    justify-self: start;
  }
  .about__intro { grid-area: 1 / 2; align-self: end; gap: 1rem; }
  .about__cta   { grid-area: 2 / 2; align-self: start; margin-top: 0; }
  .about__copy  { grid-area: 3 / 1 / 4 / 3; }
  .about__copy p { max-width: none; }

  /* ---- Packages: a smaller photograph with the accent cipher opposite it,
     text beneath. The wider column always holds the photograph. ---- */
  .package__grid {
    grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
    column-gap: clamp(1rem, 4vw, 2rem);
  }
  .package--reverse .package__grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.55fr);
  }

  .package__figure,
  .package--wide .package__figure {
    grid-area: 1 / 1 / 2 / 2;
    width: 100%;
    margin-inline: 0;
  }
  .package--reverse .package__figure,
  .package--reverse.package--wide .package__figure { grid-area: 1 / 2 / 2 / 3; }

  .package__accent {
    position: static;
    grid-area: 1 / 2 / 2 / 3;
    align-self: center;
    justify-self: center;
  }
  .package--reverse .package__accent { grid-area: 1 / 1 / 2 / 2; }

  .package__body { grid-area: 2 / 1 / 3 / 3; }

  .experience__lead,
  .experience__body,
  .press { grid-column: 1; }

  .press { justify-self: start; max-width: none; }

  /* Source order: heading, lead, photo, body, press */
  .experience__lead    { order: 1; }
  .experience__figure  { order: 2; }
  .experience__body    { order: 3; }
  .press               { order: 4; }

  /* Stacked: the doves come first and sit centred, reading as a divider
     between the page content above and the contact block below. */
  .contact__details,
  .contact__pitch,
  .contact__doves { grid-area: auto; }   /* stack in DOM order: doves first */

  .contact__doves {
    justify-self: center;
    width: clamp(7rem, 24vw, 10rem);
    margin-inline: auto;
  }
  .contact__pitch { justify-items: start; }

  /* Two photographs at a time reads better than three on a tablet. */
  .carousel__track { --carousel-visible: 2; }

  /* Stacked: text then its photograph, every row the same way round. */
  .post__row {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(1.75rem, 5vw, 2.5rem);
  }
  .post__row:nth-of-type(even) .post__figure { order: 0; }
  /* width comes from the shared inset rule above */
}

@media (max-width: 40rem) {
  /* Below this the doves crowd the couple's name off its line. */
  .entry__dove { display: none; }

  /* One slide at a time, inset to the same width as every other photograph on
     the page (see the shared standalone-figure rule above). Narrowing the
     track rather than the slide keeps scroll-snap landing on whole frames. */
  .carousel__track {
    --carousel-visible: 1;
    width: min(20rem, 74%);
    margin-inline: auto;
  }

  .contact__pitch p { text-align: left; }
  .btn { padding-inline: 2.25rem; width: 100%; max-width: 22rem; }
  .package__body,
  .contact__pitch { justify-items: stretch; }
}

/* ============================ motion & reveal ============================= */

.reveal {
  opacity: 0;
  transform: translateY(1.25rem);
  transition: opacity .9s cubic-bezier(.22, .61, .36, 1),
              transform .9s cubic-bezier(.22, .61, .36, 1);
}
.reveal.is-visible { opacity: 1; transform: none; }

/* No JS? Never leave content invisible. */
.no-js .reveal { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .reveal { opacity: 1; transform: none; }
}

@media print {
  .header, .btn, .contact__doves { display: none; }
  body { background: #fff; }
}
