/* ===========================================================================
   Aquarelle (watercolor) — the reference invitation, as a theme.

   Paper-white pages, calligraphic names in deep olive ink, and watercolor
   countryside scenes borrowed from the printed invitation:

     /img/watercolor-landscape.png  — the château & vineyard painting. It is
        the home hero's banner: anchored to the BOTTOM of the hero, it rises
        up from under the paper field so the invitation text is surrounded
        by the scene (see the hero section below). Its top 300px (≈40% of
        the height, the faintest part — the distant hills) fade out in alpha,
        so the scene emerges from the page paper exactly where the reference
        invitation's does, with no visible edge.
     /img/watercolor-hills.png      — the panoramic hills strip, the footer
        backdrop of every page (home included): all pages end on the same
        quiet strip, so the château painting stays unique to the home hero.
        Its white sky was faded to transparent in the asset (whiteness-based
        alpha), so it melts into the page paper with no hard white edge.
     /img/watercolor-hills-field.png — derived from the strip by
        scripts/make_footer_field.js (the same alpha system as the hero's
        watercolor-landscape-field.png): a paper-alpha mask cut along the
        strip's own ink, so the footer's paper/hills boundary follows the
        watercolour's ridgeline instead of a rectangular fade.

   The hero "photo" (a media item in the CMS) used to be the invitation's
   transparent floral frame; it is now hidden — the hero is the calligraphy
   on the paper, with the painting rising from the bottom. A real photograph
   set in the CMS is likewise hidden by this theme.

   Type (self-hosted, SIL OFL — see /fonts/):
     Great Vibes          — the invitation's script, for the names only.
     Cormorant Garamond   — the invitation's serif, for headings & body.
   The faces load only for this theme (base.css is untouched), so the other
   themes never pay their download cost.

   Parallax: the existing [data-parallax] drift in site.js is reused. The
   hero media overhangs the hero bottom by 110px (clipped by overflow:hidden)
   so ±8% of travel never opens a gap. The footer art layers overhang the
   footer bottom by 12% — always more than the ±8% drift (which is computed
   from the footer's own height), so the page's last edge is always artwork.
   Both artworks fade to transparent at their top, so the drift can never
   turn a feathered edge into a hard line.
   =========================================================================== */

/* --- Typefaces (SIL Open Font License) ------------------------------------ */
@font-face {
  font-family: 'Great Vibes';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/great-vibes-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Great Vibes';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/great-vibes-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Cormorant Garamond';
  font-style: normal;
  font-weight: 300 700;          /* variable */
  font-display: swap;
  src: url('/fonts/cormorant-garamond-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Cormorant Garamond';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('/fonts/cormorant-garamond-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Cormorant Garamond';
  font-style: italic;
  font-weight: 300 700;
  font-display: swap;
  src: url('/fonts/cormorant-garamond-italic-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Cormorant Garamond';
  font-style: italic;
  font-weight: 300 700;
  font-display: swap;
  src: url('/fonts/cormorant-garamond-italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* --- Palette & type tokens -------------------------------------------------- */
:root {
  --bg: #fbfaf5;                  /* watercolor paper */
  --surface: #ffffff;
  --text: #454b3b;                /* olive ink, softened for body text */
  --muted: #7d8272;               /* sage gray */
  --ink: #333b20;                 /* the invitation's deep olive */
  --accent: #6b7a4e;              /* foliage olive */
  --accent-strong: #4f5c37;
  --accent-soft: rgba(107, 122, 78, 0.13);
  --gold: #a38d58;                /* the invitation's muted gilt line */
  --border: #e4e2d5;
  --font-script: 'Great Vibes', 'Snell Roundhand', 'Segoe Script', cursive;
  --font-serif: 'Cormorant Garamond', Georgia, 'Times New Roman', serif;
  --font-display: var(--font-serif);
  /* Cormorant runs small, so the body step is nudged up from 16px. */
  --font-body: 'Cormorant Garamond', Georgia, 'Times New Roman', serif;
  --shadow: none;
  --shadow-soft: none;
}

body { font-size: 1.09375rem; line-height: 1.75; }

h1, h2, h3, h4 {
  font-family: var(--font-serif);
  font-weight: 500;
  letter-spacing: 0;
  color: var(--ink);
}

a { color: var(--accent-strong); }
a:hover { color: var(--ink); }
::selection { background: var(--accent-soft); }

/* --- Header / navigation ---------------------------------------------------- */
/* The paper is white, so the unscrolled bar keeps dark ink (no light-on-
   photo treatment) and a whisper of warm tint instead of blur. */
.site-header {
  --hdr-text: var(--ink);
  --hdr-muted: #6a705c;
  background: color-mix(in srgb, var(--bg) 84%, transparent);
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
.site-header.is-scrolled {
  background: color-mix(in srgb, var(--bg) 95%, transparent);
  border-bottom-color: var(--border);
}
body.has-hero .site-header:not(.is-scrolled) {
  --hdr-text: var(--ink);
  --hdr-muted: #6a705c;
  background: linear-gradient(180deg, color-mix(in srgb, var(--bg) 90%, transparent), rgba(251, 250, 245, 0));
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
/* Serif capitals: a touch larger than the sans default, since Cormorant's
   capitals are light on the stroke. */
.main-nav a { font-size: .92rem; font-weight: 600; letter-spacing: .16em; }

.lang-flag.active { background: var(--surface); border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }

/* --- The invitation (hero) ---------------------------------------------------
   Desktop layout: the invitation text sits on a paper field cut out of
   the scene. The .hero-field layer is masked by the painting's own
   visible ink (public/img/watercolor-landscape-field.png, derived by
   scripts/make_hero_field.js): paper stays opaque where the wash is
   faint, recedes along the watercolour's edges (the château's roofline,
   the woodlines), and is gone where the painting is strong — so the
   paper/painting boundary follows the artwork instead of fading like a
   rectangle, while the text keeps the paper under it. The hero carries
   extra bottom padding below the field, so the painting (bottom-anchored,
   or roofline-pinned on wide windows — see below) rises up into a
   full-width banner under the RSVP button — the
   invitation sits surrounded by its scene. The media layer overhangs the
   hero bottom by 110px (clipped) so the parallax drift can never expose
   a gap at the bottom edge; the scrim's bottom fade keeps the painting's
   cut edge hidden under the hero's lower edge at every scroll position.
   The field shares the media layer's parallax host, so the cut stays
   locked to the scene while it drifts.
----------------------------------------------------------------------------- */
.block-hero {
  min-height: max(94vh, 720px);
  align-items: flex-start;
  color: var(--ink);
  background: var(--bg);
  /* Static (pre-parallax) y from the hero's top where the château's
     roofline should sit — offset just BELOW the RSVP button (CTA bottom
     ≈ 603–618px at the reference width) so the button and the location
     line stay on near-full paper at every resolution. The media layer and
     the .hero-field mask share this pin so the paper cut holds at every
     viewport width. Retune here to raise or lower the scene. */
  --roofline-y: 710px;
}
/* The painting scales by WIDTH (not cover): the reference's white/painting
   ratio holds on every screen width, and the band's top just continues the
   page paper (the painting's top rows fade to transparent in the asset).
   Its POSITION is pinned to the roofline, not to the bottom: at
   `100% auto` the asset's height is proportional to the viewport width, so
   a bottom anchor would drag the roofline up into (and above) the text on
   wide windows and let it sink into the band on narrow ones.
   max(roofline pin, 100%) anchors the roofline — where the ink reaches
   ~30%, 17vw of the scaled height (0.296 × 742/1297) — at --roofline-y
   whenever the asset is tall enough to reach, and falls back to the
   classic bottom anchor (100%) when it is short. .hero-field's mask
   repeats the exact expression, so the paper edge stays glued to the
   artwork at every resolution. Repeated with .no-image to keep rank over
   base.css's higher-specificity fallback — this theme ignores the CMS
   hero photo either way. */
.block-hero .hero-media,
.block-hero.no-image .hero-media {
  inset: 0 0 -110px 0;
  background: var(--bg) url('/img/watercolor-landscape.png') no-repeat;
  background-size: 100% auto;
  background-position: 50% max(calc(var(--roofline-y) - 17vw), 100%);
}
/* The floral frame (and any other CMS hero photo) is hidden: the invitation
   is the calligraphy on the paper, with the painting rising from the bottom.
   The media layer keeps data-parallax, so the painting still drifts. */
.hero-img { display: none; }
/* The admin's hero colour lays a flat tint over photo heroes; over watercolour
   it would muddy the scene, so this theme drops it. */
.block-hero .hero-media::after { background: none; }
/* Bottom fade to the page paper: the painting is bottom-anchored in the
   *drifting* media layer, so its cut edge would slide under the hero's lower
   edge as you scroll — the scrim is fixed to the hero, so the cut stays
   hidden in this fade at every scroll position. The upper text zone is the
   .hero-field paper layer. */
.hero-scrim {
  background: linear-gradient(0deg, var(--bg) 0%, rgba(251, 250, 245, 0) 12%);
}
.hero-content {
  padding: calc(var(--header-h) + 58px) 24px 0;
  max-width: none; /* full-bleed paper field on desktop (see below) */
}
/* The paper field, cut along the painting's own lines. It is a dedicated
   layer (not the content's background) masked by the derived inverse-ink
   asset, boxed and positioned exactly like the painting (same inset, and
   the same max(roofline pin, 100%) position with 100% auto sizing), so
   the paper edge aligns with the artwork at every hero height AND width
   — and with data-parallax on the same host (.block-hero) it receives
   the media layer's drift, so the cut stays locked to the scene while it
   parallaxes. z-index 1 puts it above the painting and scrim, below the
   text (z 2). Desktop only — the stacked mobile layout already sits on
   bare paper. */
@media (min-width: 721px) {
  /* Room for the banner: below the field the painting shows in a
     full-width band, so the hero ends on the scene instead of on paper. */
  .block-hero { padding-bottom: 200px; }
  .hero-content {
    width: 100%;
    padding-bottom: 140px;
  }
  .hero-field {
    display: block;
    position: absolute;
    inset: 0 0 -110px 0; /* the painting layer's box, so the mask aligns */
    z-index: 1;
    background: var(--bg);
    -webkit-mask-image: url('/img/watercolor-landscape-field.png');
            mask-image: url('/img/watercolor-landscape-field.png');
    -webkit-mask-repeat: no-repeat;
            mask-repeat: no-repeat;
    /* Identical expression to the media layer's background-position, so
       the mask and the painting always share one top edge. */
    -webkit-mask-position: 50% max(calc(var(--roofline-y) - 17vw), 100%);
            mask-position: 50% max(calc(var(--roofline-y) - 17vw), 100%);
    -webkit-mask-size: 100% auto;
            mask-size: 100% auto;
    will-change: transform;
    pointer-events: none;
  }
}
/* Countdown under the date: ink on the paper field. */
.hero-countdown .cd-val { color: var(--ink); }
.hero-countdown .cd-unit { color: var(--muted); margin-top: 8px; }
/* The invitation's small italic intro line. */
.hero-kicker {
  font-family: var(--font-serif); font-style: italic; font-weight: 500;
  text-transform: none; letter-spacing: .05em; font-size: 1.3rem;
  color: #767c66; padding-left: 0; margin-bottom: 16px;
}
/* The calligraphic names — the heart of the reference. */
.hero-names {
  font-family: var(--font-script); font-weight: 400;
  font-size: clamp(3.2rem, 9.5vw, 6.6rem); line-height: 1.12; letter-spacing: 0;
  color: var(--ink); margin-bottom: .3em; text-shadow: none;
}
.hero-date {
  font-family: var(--font-serif); font-weight: 600;
  font-size: clamp(1rem, 2.6vw, 1.25rem); letter-spacing: .18em;
  color: var(--ink); padding-left: .18em; margin-bottom: 18px;
}
.hero-rule { width: 72px; margin-bottom: 20px; }
.hero-loc {
  font-family: var(--font-serif); font-style: italic;
  font-size: 1.15rem; color: #5c6350; margin-bottom: 30px;
}
.hero-cta {
  padding: 12px 36px;
  font-family: var(--font-serif); font-weight: 600; font-size: .95rem;
  letter-spacing: .24em; color: var(--accent-strong);
  border: 1px solid var(--accent);
  background: color-mix(in srgb, var(--bg) 82%, transparent);
}
.hero-cta:hover { background: var(--accent); color: #fff; border-color: var(--accent); }
.hero-scroll::after { background: linear-gradient(rgba(51, 59, 32, 0), var(--ink)); }

/* --- Section headings & blocks ---------------------------------------------- */
.block-heading h2 {
  font-size: clamp(2.2rem, 5.5vw, 3.2rem);
  font-weight: 500; letter-spacing: 0;
}
/* A watercolor hairline instead of a solid accent bar. */
.block-heading h2::before {
  width: 78px; height: 1px; border-radius: 0;
  background: linear-gradient(90deg, transparent, var(--accent) 30% 70%, transparent);
  margin-bottom: 24px;
}

.block-text p { color: var(--text); line-height: 1.85; }

/* Images, maps & gallery get a white matte + hairline frame, like prints. */
.block-image img {
  aspect-ratio: 16 / 9;
  padding: 10px; background: var(--surface);
  border: 1px solid var(--border); border-radius: 1px; box-shadow: none;
}
.block-image figcaption, .block-map figcaption {
  font-family: var(--font-serif); font-style: italic; font-size: 1rem;
}
.block-map iframe { border: 1px solid var(--border); border-radius: 1px; box-shadow: none; }

.block-gallery .gallery-grid { gap: 16px; }
.block-gallery a {
  padding: 9px; background: var(--surface);
  border: 1px solid var(--border); border-radius: 1px; box-shadow: none;
}
.block-gallery img { border-radius: 0; }

/* --- Schedule ---------------------------------------------------------------- */
.block-schedule li { border-bottom-color: #e7e5d9; }
.schedule-time {
  font-family: var(--font-serif); font-weight: 600; font-size: 1.6rem;
  color: var(--accent-strong); letter-spacing: 0;
}
.schedule-body h3 { font-family: var(--font-serif); font-weight: 600; font-size: 1.28rem; letter-spacing: 0; }
.schedule-body p { font-size: 1.06rem; }

/* --- Forms & RSVP -------------------------------------------------------------- */
.form-field label {
  font-family: var(--font-serif); font-size: .95rem; font-weight: 600;
  letter-spacing: .09em;
}
.field-help { font-size: .95rem; }
input[type='text'], input[type='email'], input[type='password'], input[type='number'],
input[type='date'], select, textarea {
  font-size: 1.05rem; border-radius: 1px;
}
textarea { line-height: 1.6; }

.btn {
  font-family: var(--font-serif); font-weight: 600; font-size: .95rem;
  letter-spacing: .14em;
}
.btn-small { font-size: .85rem; }

.auth-card { border-radius: 2px; }
.auth-card h1 { font-family: var(--font-serif); font-weight: 500; font-size: 2rem; color: var(--ink); }
.auth-card .lead { font-size: 1.05rem; }

.family-head h1 {
  font-family: var(--font-script); font-weight: 400;
  font-size: clamp(2.4rem, 6vw, 3.4rem); color: var(--ink); margin-bottom: 12px;
}
.family-head p { font-family: var(--font-serif); font-size: 1.1rem; }

.person-name { font-family: var(--font-serif); font-size: 1.15rem; font-weight: 600; color: var(--ink); }
.person-chip .fillin-name { font-size: 1.1rem; }
.person-chip { box-shadow: none; }
.person-chip label.seg {
  font-family: var(--font-serif); font-size: 1rem; font-weight: 600;
  letter-spacing: .03em;
}
.child-flag { font-family: var(--font-serif); font-size: .95rem; }

.footer-note { font-family: var(--font-serif); font-style: italic; font-size: 1.05rem; }

/* --- Footer: every page ends on the hills strip ----------------------------------
   All pages — home included — close on the same panoramic hills strip, so
   the château painting is not repeated on the home page. Same alpha system
   as the home hero: the strip (.footer-art) is a bottom-anchored,
   width-scaled background in a parallax layer that overhangs the footer
   bottom by 12% (clipped by overflow:hidden) — the drift is ±8% of the
   footer's own height, so the last edge of the page is always artwork —
   and a paper field (.footer-field) is masked by the strip's own visible
   ink (watercolor-hills-field.png, derived by scripts/make_footer_field.js),
   so the paper/hills boundary runs along the watercolour's ridgeline (the
   tall left hill, the low valley under the line, the pale dune on the
   right) instead of fading like a rectangle. Both layers share one box and
   one parallax host, so the cut stays locked to the strip while it drifts.
   The footer's height is derived from --hills-y (the static y, from the
   footer's top, where the tallest hilltop sits): the strip's ink band is
   66% of its height (0.66 × 18.56vw at 100% auto) and the art box overhangs
   the footer by 12%, so (hills-y + 12.25vw) / 1.12 lands the hilltops
   exactly at --hills-y — the gap between the footer line and the scene is a
   fixed number of pixels at every width. The strip's own sky (faded to
   transparent in the asset) melts into the page paper where the field is
   thin.
----------------------------------------------------------------------------- */
.site-footer {
  position: relative;
  overflow: hidden;
  background: var(--bg);
  /* Static (pre-parallax) y from the footer's top where the tallest
     hilltop (the left ridge) should sit — close under the footer line so
     the scene feels like it belongs to it. The art and the field are
     bottom-anchored and the min-height below is derived from this knob, so
     the hilltops hold this y at every width. Note the shared parallax
     drifts the scene up by 8% of the footer's height at rest (the footer
     can never scroll past the bottom of the page), so the gap the visitor
     sees is a little larger than this static value. Retune here to raise
     or lower the scene (the clear-paper gap under the line is this value
     minus ≈94px of text zone, before that drift). */
  --hills-y: 90px;
  min-height: max(190px, calc((var(--hills-y) + 12.25vw) / 1.12));
}
.footer-art {
  position: absolute;
  inset: 0 0 -12% 0; /* overset: absorbs the ±8% parallax drift at any width */
}
.footer-art-hills {
  display: block; /* base.css hides .footer-art for every other theme */
  background: var(--bg) url('/img/watercolor-hills.png') 50% 100% / 100% auto no-repeat;
}
/* The paper field, cut along the strip's own lines — the footer's twin of
   .hero-field. Boxed exactly like the art (same inset, 100% auto, bottom
   anchored), so the mask and the strip share one bottom edge at every
   width; the paper is opaque where the wash is faint, recedes along the
   ridgeline, and is gone over the strong ink. data-parallax on the same
   host (.site-footer) gives it the art's drift, so the cut stays locked to
   the scene. Aquarelle only — base.css hides it for every other theme. */
.footer-field {
  display: block;
  position: absolute;
  inset: 0 0 -12% 0;
  z-index: 1;
  background: var(--bg);
  -webkit-mask-image: url('/img/watercolor-hills-field.png');
          mask-image: url('/img/watercolor-hills-field.png');
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-size: 100% auto;
          mask-size: 100% auto;
  -webkit-mask-position: 50% 100%;
          mask-position: 50% 100%;
  will-change: transform;
  pointer-events: none;
}
.footer-inner {
  position: relative; /* above the drifting art and field */
  z-index: 2;
  padding: 72px 24px 0;
  font-family: var(--font-serif); font-style: italic;
  font-size: 1.05rem; letter-spacing: .02em; color: var(--ink);
}
.footer-inner a { color: var(--accent-strong); }

/* --- Responsive ------------------------------------------------------------------ */
@media (max-width: 1080px) {
  .main-nav a { font-size: .85rem; letter-spacing: .12em; }
}
@media (max-width: 720px) {
  /* The reference's own mobile layout is sequential: the invitation text on
     the first screen, the painting below it. So the hero stacks, the photo
     becomes a framed print under the text, and the parallax drift is
     disarmed (an in-flow element must not be translated by site.js). */
  .block-hero {
    min-height: 0;
    flex-direction: column; align-items: stretch;
  }
  .hero-content {
    order: 1;
    padding: calc(var(--header-h) + 52px) 22px 0;
    max-width: none;
  }
  /* Both base selectors, matched exactly: they carry the desktop roofline
     pin in their background-position, and .no-image (0,3,0) outranks a bare
     .block-hero .hero-media (0,2,0) — losing this re-anchor would paint the
     in-flow card 500+px out of its own box. */
  .block-hero .hero-media,
  .block-hero.no-image .hero-media {
    order: 2;
    position: relative;
    inset: auto;
    margin-top: 48px;
    transform: none !important;
    /* The frame image no longer defines this layer's height, so the painting
       card keeps the artwork's own ratio (1297×742): at 100% width it fills
       the card exactly, feathered top and all. The base rule's viewport
       roofline-pin targets the absolute desktop layer — this in-flow card
       is filled edge to edge, so re-anchor it plainly. */
    aspect-ratio: 1297 / 742;
    background-position: 50% 100%;
  }
  /* Stacked layout: the text already sits on bare paper, so the desktop
     paper field does not apply (it is scoped to ≥721px) and only the
     scrim's bottom fade melts the painting card into the next block. */
  .hero-scroll { display: none; }
  .hero-names { font-size: clamp(2.9rem, 13vw, 4.4rem); }
}
