/* ============================================================
   CLIFF & MICHELLE — SAVE THE DATE

   One design: the designer's banner is the whole header, and the
   page below is set on the banner's own ground. Chosen from four
   directions on 2026-09-17; the review chrome that used to sit on
   top (tabs, date and palette toggles) is gone with the choice, so
   what follows is the page and nothing else.

   Ground is the deep faded green the couple picked. Every colour
   is a variable declared once, at :root — the palette has been
   swapped three times now, and each time the things that broke
   were the hexes written inline.
   ============================================================ */

:root{
  --paper:#363a31;            /* the ground. Desaturated and lifted from the
                                 first attempt at the couple's request
                                 (#2e3327 S 13% L 18% -> S 8% L 21%) */
  --cream:#3e4339;            /* lifted, for anything that needs to sit above */
  --ink:#e8e4d9;              /* cream type — 9.0:1 on the ground */
  --soft:#b9bdad;             /* muted — 5.9:1, and every use is small caps */
  --line:#e8e4d92e;           /* section rules */
  --field:#e8e4d94d;          /* form hairlines — heavier, because the flat
                                 form has no other structure left */
  --ph:#b9bdad99;             /* placeholder text */
  --accent:#c9cebe;           /* links — 7.2:1, still reads as an accent */
  --on-art:#5d6653;           /* the one colour that does NOT sit on the ground:
                                 the scroll cue is over the banner's pale paper.
                                 The muted cream above would be 1.2:1 there —
                                 it was, and the cue was all but invisible.
                                 Deep sage on #edefeb is 5.1:1. */
  --warn:#e8b4a0;             /* form errors — 6.4:1 on the ground. A soft clay
                                 rather than a signal red: it echoes the terracotta
                                 pressed flowers in the artwork, and nothing on a
                                 wedding RSVP is an emergency */
  --btn-bg:#e8e4d9; --btn-fg:#363a31;
  --btn-bg-hv:#ffffff; --btn-fg-hv:#363a31;
}

*,*::before,*::after{box-sizing:border-box}
html,body{max-width:100%}
html{
  background:var(--paper);    /* so overscroll matches the page, not the host */
  scroll-behavior:smooth;
  scroll-snap-type:y proximity;   /* proximity, not mandatory — lower sections stay free */
}
body{margin:0; background:var(--paper); color:var(--ink);
  -webkit-font-smoothing:antialiased}

/* cliffandmichelle.wedding@gmail.com is 34 unbreakable characters — on a 300px
   phone it ran past the edge in the FAQ and the footer */
a.mail,.pr-foot{overflow-wrap:anywhere}

.reveal{opacity:0; transform:translateY(14px); transition:opacity .7s ease, transform .7s ease}
.reveal.in{opacity:1; transform:none}
.done{display:none}
.done.on{display:block; animation:fade .5s ease both}
.hide{display:none !important}
@keyframes fade{from{opacity:0} to{opacity:1}}

/* the RSVP section is the snap-down target */
.snap-rsvp{scroll-snap-align:start; scroll-snap-stop:always;
  min-height:100vh; min-height:100svh;
  display:grid; align-content:center; align-content:safe center}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto; scroll-snap-type:none}
  .reveal{opacity:1; transform:none; transition:none}
}

/* ============================================================
   TYPE SYSTEM

   These are the `ar-` components — they began life in the Arches
   direction, which is gone, but renaming them across the markup,
   the build script and the shoot script would buy nothing.

   The couple's asks are baked in here rather than layered on as an
   override: heavier weights throughout ("bold font for non bolded
   words"), and a form that sits flat on the ground with no card,
   border or radius. Only weights actually requested from Google
   Fonts are used — an unloaded weight gets synthesised into a
   smear, which on this ground looks worse than the light one did.
   ============================================================ */
.ar{font-family:"Jost",ui-sans-serif,system-ui,sans-serif; font-weight:600;
  font-size:17px; line-height:1.85}
.ar-sec{padding:clamp(58px,8vw,104px) 0; text-align:center}
.ar-sec + .ar-sec{border-top:1px solid var(--line)}
.ar h2{font-family:"EB Garamond",Georgia,serif; font-weight:700;
  font-size:clamp(26px,3.7vw,39px); letter-spacing:.05em; margin:0 0 18px; text-wrap:balance}
.ar-eyebrow{font-size:11px; letter-spacing:.34em; text-transform:uppercase; color:var(--soft);
  margin:0 0 16px}
.ar p{margin:0 auto 1.1em; max-width:34em}

/* The one line it has to be: the sentence measures 34.9em, so the 34em above
   breaks it and drops "stay tuned!" alone onto a second line. 38em clears that
   with room for a font fallback, and still fits the 685px the narrowest
   desktop leaves inside .pr-wrap. Mobile keeps the 34em measure. */
@media (min-width:761px){
  #next p{max-width:38em}
}
.ar-cta{display:inline-block; padding:15px 44px; background:var(--btn-bg); color:var(--btn-fg);
  text-decoration:none; border:0; font:inherit; font-size:12px; cursor:pointer;
  letter-spacing:.28em; text-transform:uppercase; transition:background .22s, color .22s}
.ar-cta:hover{background:var(--btn-bg-hv); color:var(--btn-fg-hv)}

.ar-form{max-width:560px; margin:34px auto 0; display:grid; gap:22px; text-align:left;
  background:transparent; border:0; border-radius:0}
.ar-form label{display:block; font-size:11px; letter-spacing:.26em; text-transform:uppercase;
  color:var(--soft); margin:0 0 9px}
/* display:block is load-bearing, not tidying. Form controls are inline-block by
   default, so each one sits on its line's text baseline and leaves a phantom
   ~4px of descender space beneath it. The page shipped without a doctype until
   2026-09-23, and quirks mode hid that — adding the doctype made 10px of gap
   appear inside the RSVP section, spread under four fields. Blocking them out
   removes the baseline entirely, so the gaps are the ones the gap:22px grid
   actually specifies. */
.ar-form input,.ar-form textarea{display:block; width:100%; font:inherit; font-size:17px;
  font-weight:500; color:var(--ink); background:transparent; border:0;
  border-bottom:1px solid var(--field); padding:8px 2px; border-radius:0}
.ar-form input:focus,.ar-form textarea:focus{outline:0; border-bottom-color:var(--ink)}
.ar-form input::placeholder,.ar-form textarea::placeholder{color:var(--ph)}
/* Chrome repaints autofilled fields on a hard white ground, which would put
   cream type on near-white. The inset shadow is the only way to override it. */
.ar-form input:-webkit-autofill{
  -webkit-text-fill-color:var(--ink);
  -webkit-box-shadow:0 0 0 1000px var(--paper) inset;
  caret-color:var(--ink)}
/* `hidden` has to win. The two steps of the form are shown and hidden with the
   attribute, and .ar-suggest below sets display:flex — which outranks the UA
   sheet's [hidden]{display:none} and would leave the suggestions permanently on
   screen. */
[hidden]{display:none !important}

/* STEP ONE — the lookup. The button sits on the field's baseline on a wide
   screen and drops under it when there is no room, rather than squeezing the
   name field down to nothing. */
/* The instructions above the name field. Scoped inside .ar-form for the same
   reason the error messages are: `.ar p` sets `margin:0 auto` and a max-width,
   and in a grid that centres the text in its cell, away from the field. */
.ar-form .ar-lead{max-width:none; margin:0 0 26px; font-size:16px; line-height:1.65}
.ar-form .ar-hint{max-width:none; margin:9px 0 0; font-size:14px; line-height:1.55;
  color:var(--soft)}
.ar-form .ar-hint i{font-style:italic}
.ar-fieldset .ar-hint{margin:-8px 0 18px}

.ar-findrow{display:flex; align-items:flex-end; gap:14px; flex-wrap:wrap}
.ar-findrow input{flex:1 1 220px; width:auto}
.ar-go{flex:0 0 auto; padding:14px 30px}

.ar-link{appearance:none; background:transparent; border:0; cursor:pointer; font:inherit;
  padding:0; color:var(--soft); text-decoration:underline; text-underline-offset:3px}
.ar-link:hover{color:var(--ink)}

.ar-suggest{margin-top:14px; display:flex; flex-wrap:wrap; align-items:baseline; gap:8px 14px}
.ar-form .ar-suggest-lead{margin:0}
.ar-suggest-one{font-size:16px; color:var(--accent); text-decoration:underline;
  text-underline-offset:3px}
.ar-suggest-one:hover{color:var(--ink)}

/* STEP TWO — one row per person on the invitation. */
.ar-foundline{display:flex; flex-wrap:wrap; align-items:baseline; gap:6px 12px;
  font-size:14px; color:var(--soft)}
.ar-q{font-family:"EB Garamond",serif; font-size:21px; font-weight:700; line-height:1.4;
  margin:0 0 18px; color:var(--ink)}
.ar-people{display:grid; gap:20px}
.ar-person{display:grid; gap:10px}
.ar-person-name{font-family:"EB Garamond",serif; font-size:20px; font-weight:700;
  line-height:1.3; color:var(--ink)}
@media (min-width:560px){
  .ar-person{grid-template-columns:1fr 252px; align-items:center; gap:18px}
}
.ar-person-yn{display:grid; grid-template-columns:1fr 1fr; gap:10px}
.ar-person-yn label{margin:0; display:block; cursor:pointer}
.ar-person-yn input{position:absolute; opacity:0; width:0; height:0}
.ar-person-yn span{display:block; text-align:center; padding:12px 6px; border:1px solid var(--field);
  font-size:10px; letter-spacing:.18em; text-transform:uppercase; color:var(--soft);
  transition:background .2s, color .2s, border-color .2s}
.ar-person-yn input:focus-visible + span{outline:2px solid var(--ink); outline-offset:2px}
.ar-person-yn input:checked + span{background:var(--ink); border-color:var(--ink);
  color:var(--paper)}
.ar-done{max-width:560px; margin:34px auto 0; background:transparent; border:0; border-radius:0;
  padding:34px 0}
.ar-done h3{font-family:"EB Garamond",serif; font-weight:700; font-size:25px; margin:0 0 8px}
.ar-done p{margin:0; color:var(--ink)}
/* gap, not a margin on dd: the pairs used to sit flush against each other, so
   the next question began on the line after the previous answer and the list
   read as one block of text. The gap has to stay clear of the dt's own bottom
   margin, or the blank line inside a pair reads the same as the break between
   two of them and the grouping is lost again. */
.ar-faq{max-width:34em; margin:0 auto; text-align:left; display:grid; gap:48px}
/* The address answer runs 47.2em set on one line, and .pr-wrap gives at most
   852px of content — so it only fits from 940px up, where the wrapper is at
   full width. Below that the 34em measure is kept rather than widened into a
   column that is wider than everything else on the page and still wraps. */
@media (min-width:940px){
  .ar-faq{max-width:50em}
}
.ar-faq dt{font-family:"EB Garamond",serif; font-weight:700; font-size:21px; margin:0 0 22px}
/* 400, against the 600 the rest of .ar runs at: the question is the bold half
   of the pair, and an answer at the same weight makes the list one grey wall. */
.ar-faq dd{margin:0; color:var(--ink); font-weight:400}
.ar a.mail{color:var(--accent); text-decoration:underline; text-underline-offset:3px}

/* ============================================================
   FORM STATE — errors, the honeypot, and the submit lifecycle.
   Added 2026-09-23, when the form stopped being a visual prop.
   ============================================================ */

/* An empty message is an absent message. site.js sets textContent and this
   rule does the showing, so there is no `hidden` attribute to keep in sync
   with the text — the bug where the message is cleared but the gap remains
   cannot happen. */
.ar-err:empty,.ar-note:empty{display:none}
/* Scoped to .ar-form to outrank `.ar p` (0,1,1), which sets `margin:0 auto` and
   `max-width:34em` on every paragraph in the page. A bare `.ar-err` (0,1,0)
   loses that fight, and because .ar-form is a grid, `margin:0 auto` centres the
   message in its cell: on desktop every error sat indented ~40px from the field
   it belongs to, pointing at nothing. Caught in a screenshot, not by any
   assertion — the messages were present, correct and in the DOM. */
.ar-form .ar-err,.ar-form .ar-note,.ar-form .ar-suggest-lead,
.ar-form .ar-foundline,.ar-form .ar-prev{max-width:none; margin-left:0; margin-right:0}
.ar-form .ar-err{margin-top:9px; margin-bottom:0; font-size:14px; font-weight:500;
  line-height:1.5; color:var(--warn)}
.ar-form .ar-err-form{margin-top:16px}
.ar-form .ar-note{margin-top:14px; margin-bottom:0; font-size:13px; line-height:1.6;
  color:var(--soft)}

/* Mark the field as well as writing the message. On a form this long the
   message alone is easy to scroll past, and colour alone is not enough on its
   own either — hence both, plus aria-describedby in the markup. */
.ar-form input.bad,.ar-form textarea.bad{border-bottom-color:var(--warn)}
.ar-person.bad .ar-person-yn span{border-color:var(--warn)}

.ar-fieldset{border:0; padding:0; margin:8px 0 0; min-width:0}
.ar-submit{margin:8px 0 0}
.ar-party{display:grid; gap:22px}
.ar-foundline{margin:0}
/* Says a reply is already on file. Accent rather than warn: changing your mind
   is a normal thing to do here, not a mistake to be corrected. */
.ar-prev:empty{display:none}
.ar-form .ar-prev{margin:0; padding:12px 16px; font-size:14px; line-height:1.6;
  color:var(--ink); border-left:2px solid var(--accent); background:rgba(255,255,255,.04)}

/* Off-screen rather than display:none, and out of the tab order. A bot worth
   stopping reads the DOM and fills what it finds; a guest can neither see nor
   reach it. */
.ar-hp{position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden}

.ar-cta[disabled]{opacity:.55; cursor:progress}

/* Every interactive thing needs a visible focus ring, not just the yes/no
   pair that happened to get one. */
.ar-cta:focus-visible,.ar-link:focus-visible{
  outline:2px solid var(--ink); outline-offset:3px}

/* The confirmation panel and the form-level error are focused programmatically
   (tabindex=-1) so a screen reader lands on the new content instead of being
   left where the submit button used to be. Nobody tabbed there, so Chrome's
   default ring is noise — and it is bright blue, the one colour nowhere else on
   this page. :focus-visible keeps a real ring for anyone who does reach them by
   keyboard. */
.ar-done:focus,.ar-err-form:focus,.ar-foundline:focus{outline:none}
.ar-done:focus-visible,.ar-err-form:focus-visible{
  outline:2px solid var(--ink); outline-offset:3px}

/* ============================================================
   THE HERO — the designer's artwork, full width.
   It already carries the names, "Save the Date", the city and the
   date, so nothing is typeset on top of it.
   ============================================================ */
.pr{background:var(--paper); color:var(--ink)}
.pr-hero{
  position:relative;
  /* The designer's pressed-flower banner, inline and split across background
     LONGHANDS. That is not a style choice: Blink stores any declaration
     CONTAINING var() as CSSVariableData, which is capped at 2MiB and discarded
     SILENTLY past that — no console error, the declaration simply never applies
     and the hero renders as blank paper. Measured cap: 1,779,610 chars kept,
     2,252,364 dropped. This image is 3.6MB of base64, so it must sit in a
     declaration with no var() in it at all; `background:var(--paper) url(...)`
     was dropped exactly like the custom property it replaced. Hence
     background-color (which may use the variable) and background-image (which
     may not) are set separately. build-preview.sh splits this into a file. */
  background-color:var(--paper);
  background-image:url("./banner.841c4c0de5.jpg");
  background-position:center;
  background-size:cover;
  background-repeat:no-repeat;
  scroll-snap-align:start;

  /* ── THE RULE ──────────────────────────────────────────────
     This is now the production rule outright: with the review bar
     gone there is no chrome eating the viewport, so svh means what
     it says and the height needs no adjustment term.

     Given a 3.42:1 canvas whose ink is a narrow centre column
     (1981 x 3425 of 14010 x 4096):

       the image is always wider than the viewport, so `cover`
       scales by HEIGHT alone — which makes the on-screen artwork
       width 0.4836 x this height, whatever the viewport width.

       170vw  phone guard. Without it the designer's `100svh` makes
              that column WIDER than the phone: at 390x844 the
              artwork lands 408px across in a 390px screen and the
              ends of "Save the Date" and "MISSISSAUGA, ONTARIO"
              are cut. With it the artwork sits at 82% of the width.
       86svh  leaves a sliver of the next section showing.
       880px  stop growing on large desktops.
       29.3vw ultra-wide guard (100/3.42). Below this, cover starts
              scaling by WIDTH and crops the top.

     ── on the 2026-09-17 artwork ──────────────────────────────
     The replacement master is 14010x6409 (2.19:1), NOT the 3.42:1
     of the one it replaced. The ink island is the same size —
     14.14% of canvas width against 14.29% before — but the paper
     around it grew: 23.3% margin above and below, where the old
     one had 6.6% and 9.8%. Dropped in whole, `cover` would have
     rendered the artwork about a third smaller at every width,
     because cover scales by canvas height and the ink no longer
     fills it. So the master is cropped vertically, centred, to
     14010x4096 — which restores the old ink-to-canvas ratio
     (0.8362, matched exactly) and keeps every term below valid.
     `cover` would crop that paper at run time on any wide hero
     anyway; doing it in the asset just stops us shipping the
     bytes. The uncropped master is assets/banner-source-2026-09-17.png.

     Revised master, same day 14:58 — the designer re-cropped the
     photograph inside the polaroid (the couple sits larger and
     better placed). Canvas, ink bounding box, centring and margins
     are identical to the hour, so nothing below needed changing;
     only the asset and the flat band's measured colour. The
     predecessor is assets/banner-source-2026-09-17-v1.png.
     ───────────────────────────────────────────────────────── */
  height:clamp(29.3vw, min(86svh, 170vw), 880px)}

/* The hero meets the first section with a crisp edge, at the couple's request —
   it used to fade, to hide a seam. There is no seam to hide now: the ground is
   deep green and the banner's paper is pale, so the boundary reads as a
   deliberate edge rather than a mismatch. */

/* The cue has to fit inside the artwork's bottom margin — 81px at 768x1024. The
   shared 34px tick plus its 22px offset needed 78px and sat on top of the
   artwork's date line. Word only, closer to the edge. */
.hdr-cue{position:absolute; left:0; right:0; bottom:12px; z-index:4;
  display:grid; justify-items:center; text-decoration:none; text-transform:uppercase;
  color:var(--on-art); font-size:9.5px; letter-spacing:.24em}
.pr-wrap{max-width:940px; margin:0 auto; padding:0 clamp(20px,5vw,44px)}
/* the artwork's own lettering is a sparse serif caps — echo it, don't compete */
.pr h2{font-family:"EB Garamond",Georgia,serif; font-weight:700;
  font-size:clamp(25px,3.5vw,37px); letter-spacing:.06em}
.pr .ar-eyebrow{letter-spacing:.3em}
.pr-foot{border-top:1px solid var(--line); margin-top:clamp(40px,6vw,72px);
  padding:34px 0 46px; text-align:center; font-size:15px; color:var(--soft);
  line-height:2}
.pr-foot b{font-weight:600; color:var(--ink); letter-spacing:.14em;
  text-transform:uppercase; font-size:13px}

/* The date and the names are baked into the artwork, so they are plain text
   below it and there is no date-format control: it could only contradict the
   picture. The 2026-09-17 artwork also reversed the names back to
   "Cliff & Michelle", and the copy below follows the artwork. */

/* ============================================================
   MOBILE — 760px and below.
   ============================================================ */
@media (max-width:760px){
  /* Snapping off. On touch, scroll-snap-stop:always fights momentum scrolling
     and feels like the page is grabbing back. */
  html{scroll-snap-type:none}
  .pr-hero,.snap-rsvp{scroll-snap-align:none; scroll-snap-stop:normal}
  .snap-rsvp{min-height:0}

  /* ---- "open up the splash vertically" — the couple, 2026-09-17.
     On a phone the 170vw guard pins the hero to 663px at 390 wide, and the
     artwork's ink is 83.6% of the canvas height, so only ~8% of paper was left
     above "Save the Date" and below the date. It read cramped.

     The fix is NOT a taller hero on its own: `cover` scales the artwork with
     the hero's height, so more height means a bigger artwork, and the guard
     exists because a bigger artwork gets its ends clipped. Instead the image is
     sized explicitly to the height it has today — so the artwork is pixel-for-
     pixel unchanged — and the hero grows past it, with flat paper filling the
     bands above and below.

     A phone only ever shows the centre ~17-25% of the canvas (the image is
     drawn 2268px wide behind a 390px viewport), and across that strip the paper
     is uniform: top edge averages #efeeed, bottom #ecedea, with only texture
     noise between. #ededeb sits between the two, so neither band shows a seam.
     That is a measured value and only holds for this crop of this artwork —
     re-measure if the banner is replaced again.

     94svh, not 100: the sliver of ground left at the bottom is the only cue a
     phone gets that the RSVP is down there. ---- */
  .pr-hero{
    height:94svh;
    background-size:auto min(86svh, 170vw);   /* exactly today's hero height */
    background-color:#ededeb}
  /* there is room for the cue now, and it lands on the flat paper band */
  .hdr-cue{bottom:max(12px, 3svh)}

  .pr h2{font-size:clamp(24px,5.4vw,32px)}
  .ar-sec{padding:clamp(44px,8vw,64px) 0}

  /* form: fill the screen, bump text, 17px keeps iOS from zooming */
  .ar-form{max-width:none; gap:18px}
  .ar-form input,.ar-form textarea{font-size:17px}
  .ar-form label{font-size:13px}
  .ar-q{font-size:19px}
  .ar-add{font-size:14px}
  .ar-cta{width:100%; text-align:center}
}
