/* ==========================================================================
   Tata's Party
   An engraved invitation. Ivory stock, aubergine ink, one metal.

   Two rules hold the whole thing together:
     - purple is the ink and the two dark bands, never a field of colour;
     - gold is the only metal, and it is reserved for hairlines, the crest
       and the fleuron. Nothing else is allowed to shine.

   Set large and high-contrast on purpose - a good share of this guest list
   is in its eighties.
   ========================================================================== */

:root {
	/* Stock */
	--paper:        #F7F3EC;
	--paper-2:      #F1EAE0;
	--paper-3:      #E8DFD1;

	/* Ink */
	--ink:          #2A2033;
	--ink-soft:     #5A4C66;

	/* The purple, in three weights */
	--aubergine:      #3B2347;
	--aubergine-deep: #2C1936;
	--amethyst:       #6B4A86;
	--amethyst-deep:  #543A6B;
	--lilac:          #EDE4F2;
	--lilac-text:     #E4DAEC;

	/* The metal.

	   Two golds, and the difference matters: --gold is for hairlines, the
	   crest and the fleuron, where nothing has to be read. Gold type on ivory
	   only reaches 3.1:1, so anything gold that is a *word* uses --gold-ink,
	   which clears 4.5:1 on both stocks. */
	--gold:      #A98449;
	--gold-ink:  #85642F;
	--gold-lt:   #C9AE72;
	--gold-hair: rgba(169, 132, 73, .42);

	/* Correction, used only when a reply cannot be accepted */
	--brick:     #8E3B34;
	--brick-bg:  #F6E7E4;

	--font-display: "Cormorant Garamond", Garamond, Georgia, "Times New Roman", serif;
	--font-body:    "Lora", Georgia, "Times New Roman", serif;
	--font-script:  "Pinyon Script", "Snell Roundhand", cursive;

	--wrap:   1140px;
	--gutter: 26px;
}

/* --------------------------------------------------------------------------
   Reset-ish
   -------------------------------------------------------------------------- */

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

html {
	-webkit-text-size-adjust: 100%;
	scroll-behavior: smooth;
}

body {
	margin: 0;
	background: var(--paper);
	color: var(--ink);
	font-family: var(--font-body);
	font-size: 19px;
	line-height: 1.78;
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
	overflow-x: hidden;
}

h1, h2, h3, p, dl, dd, figure, ul { margin: 0; }
ul { padding: 0; list-style: none; }

img, svg, canvas { max-width: 100%; }
img { height: auto; }

a { color: var(--amethyst); }
a:hover { color: var(--amethyst-deep); }

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

/* --------------------------------------------------------------------------
   Utilities
   -------------------------------------------------------------------------- */

.screen-reader-text,
.seal__label {
	position: absolute !important;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.skip-link {
	position: absolute;
	left: -9999px;
	top: 0;
	z-index: 300;
	background: var(--aubergine);
	color: var(--paper);
	font-family: var(--font-body);
	font-size: 17px;
	padding: 14px 22px;
	text-decoration: none;
}
.skip-link:focus {
	left: 16px;
	top: 16px;
	color: var(--paper);
}

.placeholder-bar {
	background: repeating-linear-gradient(135deg, #F5E9CF 0 14px, #EFDFBE 14px 28px);
	border-bottom: 1px solid var(--gold-hair);
	color: var(--ink);
	font-size: 15px;
	line-height: 1.6;
	padding: 12px 22px;
	text-align: center;
}
.placeholder-bar code {
	font-size: 13px;
	background: rgba(42, 32, 51, .07);
	padding: 2px 5px;
}

/* A hairline with the fleuron set into it. The only divider on the site. */
.rule {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 18px;
	color: var(--gold);
	max-width: 420px;
	margin: 38px auto;
}
.rule::before,
.rule::after {
	content: "";
	flex: 1 1 auto;
	height: 1px;
	opacity: .55;
	background: linear-gradient(90deg, transparent, currentColor);
}
.rule::after { background: linear-gradient(90deg, currentColor, transparent); }

.fleuron {
	flex: 0 0 auto;
	display: block;
	width: 64px;
	height: auto;
}
.fleuron--gold { color: var(--gold); }

/* The crest. The ring is drawn; the letter is real type, so it scales with
   the page rather than being baked into a viewBox at one size. */
.crest {
	position: relative;
	display: inline-grid;
	place-items: center;
	width: 86px;
	height: 86px;
	color: var(--gold);
}
.crest__ring {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
}
.crest__letter {
	font-family: var(--font-display);
	font-weight: 600;
	font-size: 40px;
	line-height: 1;
	color: var(--gold);
	transform: translateY(2px);
}
.crest--rsvp { width: 62px; height: 62px; }
.crest--rsvp .crest__letter { font-size: 29px; }
.crest--footer { width: 56px; height: 56px; color: var(--gold-lt); }
.crest--footer .crest__letter { font-size: 26px; color: var(--gold-lt); }
.crest--placeholder { width: 84px; height: 84px; opacity: .55; }

.section-title {
	font-family: var(--font-display);
	font-weight: 500;
	font-size: 38px;
	line-height: 1.2;
	letter-spacing: .01em;
	color: var(--ink);
	text-align: center;
}
.section-title::after {
	content: "";
	display: block;
	width: 54px;
	height: 1px;
	margin: 18px auto 0;
	background: var(--gold);
	opacity: .65;
}
.section-title--onDark { color: var(--paper); }
.section-title--onDark::after { background: var(--gold-lt); }

.btn {
	display: inline-block;
	font-family: var(--font-body);
	font-weight: 500;
	font-size: 18px;
	line-height: 1;
	letter-spacing: .04em;
	color: var(--paper);
	background: var(--amethyst-deep);
	border: 1px solid var(--amethyst-deep);
	border-radius: 2px;
	padding: 21px 46px;
	text-decoration: none;
	transition: background .16s ease, border-color .16s ease, box-shadow .16s ease;
}
.btn:hover,
.btn:focus-visible {
	color: var(--paper);
	background: var(--aubergine);
	border-color: var(--aubergine);
	box-shadow: 0 0 0 3px rgba(107, 74, 134, .18);
}

.link-quiet {
	color: var(--amethyst);
	text-decoration: none;
	border-bottom: 1px solid var(--gold-hair);
	padding-bottom: 1px;
}
.link-quiet:hover { border-bottom-color: var(--amethyst); }

/* --------------------------------------------------------------------------
   The sealed state

   .tata-sealed is put on <html> by an inline script in the head, before the
   first paint, and taken off again when the envelope has been opened. With no
   JavaScript it is never added at all, so the page below is simply the page.
   -------------------------------------------------------------------------- */

.sheet {
	opacity: 1;
	transition: opacity .85s ease;
}

html.tata-sealed,
html.tata-sealed body { overflow: hidden; }

/* The transition stays declared here. Killing it while sealed would mean the
   page had no transition running at the moment the class comes off, and it
   would snap in rather than fade. */
html.tata-sealed .sheet {
	opacity: 0;
	visibility: hidden;
}
.sheet:focus { outline: none; }
html.tata-sealed .placeholder-bar { display: none; }

.gilding {
	position: fixed;
	inset: 0;
	width: 100%;
	height: 100%;
	pointer-events: none;
	z-index: 120;
}

/* --------------------------------------------------------------------------
   The envelope
   -------------------------------------------------------------------------- */

.seal-stage { display: none; }

html.tata-sealed .seal-stage {
	display: grid;
	place-items: center;
	position: fixed;
	inset: 0;
	z-index: 200;
	padding: 24px;
	overflow: hidden;
	background:
		radial-gradient(120% 92% at 50% 34%, #4C2F5E 0%, #33203F 52%, #1E1026 100%);
	opacity: 1;
	transition: opacity .75s ease;
}
html.tata-sealed .seal-stage.is-dissolving { opacity: 0; }

.seal-stage__inner {
	display: flex;
	flex-direction: column;
	align-items: center;
	width: 100%;
	max-width: 520px;
	text-align: center;
}

.envelope {
	position: relative;
	width: 100%;
	aspect-ratio: 142 / 100;
	/* Pushed down the stage so the card has somewhere to rise into. Any more
	   and the sealed envelope reads as having fallen to the bottom of the
	   screen; any less and the card's top edge is clipped on a short window. */
	margin-top: 30%;
	perspective: 1300px;
	cursor: pointer;
}

/* The back of the envelope: panel, two side flaps, the bottom flap. */
.envelope__pocket {
	position: absolute;
	inset: 0;
	z-index: 3;
	filter: drop-shadow(0 26px 44px rgba(0, 0, 0, .45));
}
.envelope__pocket svg {
	display: block;
	width: 100%;
	height: 100%;
}

/* The card inside. Starts tucked in behind the pocket. */
.envelope__card {
	position: absolute;
	left: 9%;
	right: 9%;
	bottom: 6%;
	z-index: 2;
	aspect-ratio: 1 / .74;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 2%;
	padding: 4% 8%;
	background: var(--paper);
	border: 1px solid rgba(169, 132, 73, .6);
	box-shadow: 0 -12px 30px rgba(0, 0, 0, .3);
	transform: translateY(0);
	transition: transform 1.05s cubic-bezier(.19, .84, .25, 1), opacity .55s ease;
}
.envelope.is-rising .envelope__card { transform: translateY(-88%); }
.envelope.is-leaving .envelope__card {
	transform: translateY(-88%) scale(1.06);
	opacity: 0;
}

.envelope__card .fleuron { width: 52px; color: var(--gold); }

.envelope__card-kicker {
	font-family: var(--font-display);
	font-style: italic;
	font-size: 17px;
	line-height: 1.3;
	color: var(--ink-soft);
}
.envelope__card-name {
	font-family: var(--font-display);
	font-weight: 500;
	font-size: 27px;
	line-height: 1.15;
	letter-spacing: .09em;
	text-transform: uppercase;
	color: var(--aubergine);
}
.envelope__card-alias {
	font-family: var(--font-script);
	font-size: 26px;
	line-height: 1.1;
	color: var(--gold-ink);
	margin-top: -2px;
}
.envelope__card-when {
	font-family: var(--font-display);
	font-size: 16px;
	line-height: 1.3;
	color: var(--ink-soft);
	border-top: 1px solid var(--gold-hair);
	padding-top: 3%;
	margin-top: 1%;
}

/* The top flap. Two faces back to back, so the underside that swings into
   view is the paper liner and not the outside of the envelope mirrored.
   Each face carries its own clip-path: the liner's triangle is flipped,
   because rotateX(180deg) mirrors the shape along with the element. */
.envelope__flap {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	height: 56%;
	z-index: 5;
	transform-origin: top center;
	transform-style: preserve-3d;
	transform: rotateX(0deg);
	transition: transform 1s cubic-bezier(.62, .02, .3, 1);
}
.envelope.is-rising .envelope__flap { z-index: 1; }
.envelope.is-open .envelope__flap { transform: rotateX(-172deg); }

.envelope__flap-face {
	position: absolute;
	inset: 0;
	backface-visibility: hidden;
}
/* A clipped element cannot carry a border, and the two edges that need to be
   seen are the diagonals. drop-shadow traces the clip path's own silhouette,
   so a one-pixel gold shadow underneath it draws the fold line the border
   cannot. */
.envelope__flap-face--out {
	clip-path: polygon(0 0, 100% 0, 50% 100%);
	background: linear-gradient(172deg, #573A69 0%, #472C56 58%, #3E2650 100%);
	filter:
		drop-shadow(0 1px 0 rgba(201, 174, 114, .5))
		drop-shadow(0 10px 18px rgba(0, 0, 0, .42));
}
.envelope__flap-face--in {
	clip-path: polygon(0 100%, 100% 100%, 50% 0);
	transform: rotateX(180deg);
	background: linear-gradient(180deg, var(--paper-3) 0%, var(--paper-2) 100%);
	filter: drop-shadow(0 -1px 0 rgba(169, 132, 73, .55));
}

.seal {
	position: absolute;
	left: 50%;
	top: 56%;
	z-index: 6;
	width: 26%;
	aspect-ratio: 1;
	transform: translate(-50%, -50%);
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: none;
	cursor: pointer;
	transition: transform .45s cubic-bezier(.3, 1.3, .5, 1), opacity .4s ease;
}
.seal:hover { transform: translate(-50%, -50%) scale(1.04); }
.seal:focus-visible {
	outline: 2px solid var(--gold-lt);
	outline-offset: 7px;
}
.envelope.is-open .seal {
	transform: translate(-50%, -62%) scale(1.3) rotate(-9deg);
	opacity: 0;
	pointer-events: none;
}

.seal__disc {
	position: relative;
	display: grid;
	place-items: center;
	width: 100%;
	height: 100%;
	filter: drop-shadow(0 4px 10px rgba(0, 0, 0, .45));
}
.seal__wax {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
}
.seal__letter {
	position: relative;
	font-family: var(--font-display);
	font-weight: 600;
	font-size: 44px;
	line-height: 1;
	color: #E5D2A8;
	text-shadow: 0 1px 1px rgba(0, 0, 0, .4);
	transform: translateY(2px);
}

.seal-stage__to {
	font-family: var(--font-script);
	font-size: 34px;
	line-height: 1.3;
	color: var(--gold-lt);
	margin-top: 34px;
}
.seal-stage__hint {
	font-family: var(--font-body);
	font-size: 15px;
	letter-spacing: .09em;
	color: #C6B7D2;
	margin-top: 8px;
}

/* --------------------------------------------------------------------------
   The invitation
   -------------------------------------------------------------------------- */

.hero {
	position: relative;
	padding: 86px var(--gutter) 78px;
	text-align: center;
}

/* Two hairlines inset from the edge, the way a bordered card is printed. */
.hero::before,
.hero::after {
	content: "";
	position: absolute;
	pointer-events: none;
	border: 1px solid var(--gold);
}
.hero::before { inset: 22px; opacity: .42; }
.hero::after  { inset: 28px; opacity: .2; }

.hero__inner {
	position: relative;
	max-width: 760px;
	margin: 0 auto;
}

.hero .crest--hero { margin-bottom: 26px; }

.hero__kicker {
	font-family: var(--font-display);
	font-style: italic;
	font-weight: 400;
	font-size: 26px;
	line-height: 1.4;
	color: var(--ink-soft);
}

.hero__name { margin-top: 14px; }

.hero__name-full {
	display: block;
	font-family: var(--font-display);
	font-weight: 500;
	font-size: 62px;
	line-height: 1.1;
	letter-spacing: .1em;
	text-transform: uppercase;
	color: var(--aubergine);
	/* uppercase tracking adds a trailing space the optical centre does not want */
	text-indent: .1em;
}
.hero__name-alias {
	display: block;
	font-family: var(--font-script);
	font-weight: 400;
	font-size: 54px;
	line-height: 1.2;
	letter-spacing: 0;
	text-transform: none;
	color: var(--gold-ink);
	margin-top: 4px;
}

.hero__occasion {
	font-family: var(--font-display);
	font-style: italic;
	font-size: 27px;
	line-height: 1.4;
	color: var(--ink-soft);
	margin-top: 10px;
}

.rule--hero { margin: 36px auto; }

.hero__facts > * + * { margin-top: 6px; }

.hero__when {
	font-family: var(--font-display);
	font-weight: 500;
	font-size: 31px;
	line-height: 1.3;
	color: var(--ink);
}
.hero__year {
	font-family: var(--font-display);
	font-weight: 400;
	font-size: 24px;
	line-height: 1.3;
	color: var(--ink-soft);
}
.hero__time {
	font-family: var(--font-body);
	font-size: 18px;
	color: var(--ink-soft);
	margin-top: 12px !important;
}
.hero__venue {
	font-family: var(--font-display);
	font-weight: 500;
	font-size: 27px;
	line-height: 1.35;
	color: var(--ink);
	margin-top: 26px !important;
}
.hero__address {
	font-family: var(--font-body);
	font-size: 17px;
	color: var(--ink-soft);
}
.hero__map { font-size: 16px; margin-top: 12px !important; }

.hero__cta { margin-top: 4px; }

.hero__by {
	font-family: var(--font-display);
	font-style: italic;
	font-size: 21px;
	color: var(--ink-soft);
	margin-top: 22px;
}
/* The date is the only part of this line anyone has to act on, so it comes
   out of the italic and up to full ink while "kindly reply by" stays the
   quiet lead-in. Roman against italic does most of the work; the tracking
   and the hairline finish it. Nothing here is a new colour - the rule is the
   same gold hairline the fleuron and the crest are drawn in. */
.hero__by-date {
	display: inline-block;
	font-style: normal;
	font-size: 23px;
	letter-spacing: .03em;
	color: var(--ink);
	/* the date is one thought - never let it break across two lines */
	white-space: nowrap;
	border-bottom: 1px solid var(--gold);
	padding-bottom: 3px;
}
.hero__countdown {
	font-family: var(--font-body);
	font-style: italic;
	font-size: 15px;
	letter-spacing: .02em;
	color: var(--ink-soft);
	opacity: .8;
	margin-top: 6px;
}

/* --------------------------------------------------------------------------
   The note from the family
   -------------------------------------------------------------------------- */

.note {
	padding: 6px var(--gutter) 92px;
}

.note__frame {
	position: relative;
	max-width: 720px;
	margin: 0 auto;
	padding: 54px 58px 46px;
	background: var(--paper-2);
	border: 1px solid var(--gold-hair);
	text-align: center;
}
.note__frame::before {
	content: "";
	position: absolute;
	inset: 8px;
	border: 1px solid var(--gold);
	opacity: .22;
	pointer-events: none;
}

.note__frame .section-title { font-size: 31px; }

.note__body {
	font-size: 19px;
	line-height: 1.85;
	color: var(--ink);
	max-width: 52ch;
	margin: 26px auto 0;
}

.note__sign {
	font-family: var(--font-script);
	font-size: 38px;
	line-height: 1.3;
	color: var(--gold-ink);
	margin-top: 26px;
}

.note__postscript {
	font-family: var(--font-display);
	font-style: italic;
	font-size: 21px;
	line-height: 1.6;
	color: var(--ink-soft);
	max-width: 50ch;
	margin: 34px auto 0;
	padding-top: 28px;
	border-top: 1px solid var(--gold-hair);
}

/* --------------------------------------------------------------------------
   The particulars — only whatever party.php actually has to add
   -------------------------------------------------------------------------- */

.particulars {
	padding: 0 var(--gutter) 92px;
}

.particulars__list {
	max-width: 720px;
	margin: 36px auto 0;
}

.particulars__row {
	display: grid;
	grid-template-columns: 180px 1fr;
	gap: 28px;
	padding: 24px 0;
	border-top: 1px solid var(--gold-hair);
	text-align: left;
}
.particulars__row:last-child { border-bottom: 1px solid var(--gold-hair); }

.particulars__label {
	font-family: var(--font-display);
	font-style: italic;
	font-size: 22px;
	line-height: 1.5;
	color: var(--gold-ink);
	text-align: right;
}
.particulars__body {
	margin: 0;
	font-size: 18px;
	line-height: 1.7;
	color: var(--ink);
}

/* --------------------------------------------------------------------------
   The album wall

   Everything in this band sits on aubergine, so every text element states its
   own colour. Inheritance is not enough once a stylesheet grows element rules.
   -------------------------------------------------------------------------- */

.gallery {
	/* The rail is the distance from the window edge to the first photograph.
	   It is a variable because the scroller has to snap to it as well as pad
	   by it - without the matching scroll-padding, a photograph the script
	   scrolls to lands with its gutter and then the native snap yanks it
	   flush against the window edge. */
	--rail: max(var(--gutter), calc((100vw - var(--wrap)) / 2));
	background: var(--aubergine);
	padding: 84px 0 76px;
	text-align: center;
}
/* Only the copy that actually sits on the aubergine. A figcaption does not:
   it is printed on the ivory mat inside the frame, and naming it here made
   .gallery figcaption (0,1,1) outrank .photo__caption (0,1,0), which painted
   every caption near-white on paper at 1.22:1. It went unseen for as long as
   every caption was empty. */
.gallery p { color: var(--lilac-text); }

.gallery__lede {
	font-size: 18px;
	line-height: 1.7;
	color: var(--lilac-text);
	max-width: 52ch;
	margin: 22px auto 0;
	padding: 0 var(--gutter);
}

.gallery__stage {
	position: relative;
	margin-top: 44px;
}

.gallery__viewport {
	overflow-x: auto;
	overflow-y: hidden;
	/* proximity, not mandatory: the last photo has no snap point of its own -
	   there is not a scrollport's worth of line to its right - and mandatory
	   drags the strip back off the end so photo thirty can never be seen whole */
	scroll-snap-type: x proximity;
	scroll-padding-left: var(--rail);
	-webkit-overflow-scrolling: touch;
	scrollbar-width: thin;
	scrollbar-color: var(--gold-lt) rgba(255, 255, 255, .1);
}
.gallery__viewport:focus-visible {
	outline: 2px solid var(--gold-lt);
	outline-offset: -2px;
}
.gallery__viewport::-webkit-scrollbar { height: 8px; }
.gallery__viewport::-webkit-scrollbar-track { background: rgba(255, 255, 255, .08); }
.gallery__viewport::-webkit-scrollbar-thumb { background: var(--gold-lt); border-radius: 4px; }

.gallery__track {
	display: flex;
	gap: 30px;
	margin: 0;
	padding: 10px var(--rail) 26px;
	transition: opacity .2s ease;
}
.gallery__track.is-wrapping { opacity: 0; }

.photo {
	flex: 0 0 auto;
	width: 320px;
	scroll-snap-align: start;
}

.photo__frame {
	margin: 0;
	padding: 13px;
	background: var(--paper);
	border: 1px solid rgba(169, 132, 73, .55);
	box-shadow: 0 18px 38px rgba(0, 0, 0, .3);
}
.photo__img {
	display: block;
	width: 100%;
	aspect-ratio: 1;
	object-fit: cover;
}
.photo__placeholder {
	display: grid;
	place-items: center;
	width: 100%;
	aspect-ratio: 1;
	background: var(--ground, var(--lilac));
}
.photo__caption {
	font-family: var(--font-display);
	font-style: italic;
	font-size: 17px;
	line-height: 1.45;
	color: var(--ink-soft);
	padding-top: 12px;
}
/* A credit is not a caption. It says who sent the photograph in, not what is
   in it, so it sits back a step. */
.photo__caption--credit {
	font-size: 15px;
	letter-spacing: .02em;
	/* One step back from a caption, and no further: at .82 this lands on
	   4.58:1 against the mat, which passes and leaves nothing spare for
	   fifteen-pixel italic. */
	color: rgba(90, 76, 102, .92);
}

.gallery__controls {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 14px;
	margin-top: 8px;
}
.gallery__btn {
	display: grid;
	place-items: center;
	width: 46px;
	height: 46px;
	padding: 0;
	color: var(--gold-lt);
	background: none;
	border: 1px solid rgba(201, 174, 114, .55);
	border-radius: 50%;
	cursor: pointer;
	transition: background .15s ease, border-color .15s ease;
}
.gallery__btn:hover {
	background: rgba(201, 174, 114, .14);
	border-color: var(--gold-lt);
}
.gallery__btn:focus-visible {
	outline: 2px solid var(--gold-lt);
	outline-offset: 3px;
}
.gallery__btn svg { width: 20px; height: 20px; }

/* One button, two faces: whichever one the current state is not. */
.gallery__icon--play { display: none; }
.gallery__stage.is-paused .gallery__icon--pause { display: none; }
.gallery__stage.is-paused .gallery__icon--play { display: block; }

.gallery__count {
	font-family: var(--font-body);
	font-size: 15px;
	letter-spacing: .04em;
	color: var(--lilac-text);
	margin-left: 10px;
}

.gallery__progress {
	width: min(340px, 60vw);
	height: 1px;
	margin: 22px auto 0;
	background: rgba(255, 255, 255, .16);
}
.gallery__progress-bar {
	display: block;
	width: 4%;
	height: 100%;
	background: var(--gold-lt);
	transition: width .3s ease;
}

.gallery__note {
	font-size: 16px;
	line-height: 1.7;
	color: var(--lilac-text);
	max-width: 52ch;
	margin: 34px auto 0;
	padding: 0 var(--gutter);
}
.gallery__note a {
	color: var(--gold-lt);
	text-decoration: underline;
	text-underline-offset: 3px;
}
.gallery__note a:hover { color: var(--paper); }

/* --------------------------------------------------------------------------
   The reply card
   -------------------------------------------------------------------------- */

.rsvp {
	padding: 92px var(--gutter) 100px;
}

.rsvp__card {
	position: relative;
	max-width: 800px;
	margin: 0 auto;
	padding: 52px 62px 58px;
	background: var(--paper-2);
	border: 1px solid var(--gold);
	text-align: center;
}
.rsvp__card::before {
	content: "";
	position: absolute;
	inset: 9px;
	border: 1px solid var(--gold);
	opacity: .3;
	pointer-events: none;
}

.rsvp__card .crest--rsvp { margin-bottom: 18px; }

.rsvp__lede {
	font-size: 18px;
	line-height: 1.75;
	color: var(--ink-soft);
	max-width: 50ch;
	margin: 22px auto 0;
}
/* Quieter than the hero's - this one sits mid-sentence, and a rule under it
   would cut the line in half. Full ink and a little weight is enough. */
.rsvp__by-date {
	font-weight: 600;
	color: var(--ink);
	white-space: nowrap;
}

.rsvp__form {
	position: relative;
	margin-top: 40px;
	text-align: left;
}

/* --------------------------------------------------------------------------
   Gravity Forms, re-dressed

   Scoped to .tata-form, which both forms on the page carry: the reply card and
   the album upload. It used to be scoped to .rsvp__form, and that scope still
   exists for the reply card own layout - but the dressing itself is shared,
   because two forms on one sheet of stationery have to be the same piece of
   stationery.
   -------------------------------------------------------------------------- */

.tata-form .gform_wrapper { margin: 0; }
.tata-form .gform_wrapper form { margin: 0; }
.tata-form .gform_heading { display: none; }

/* Gravity Forms lays its fields out as a <ul> on a twelve-column grid and
   defends it with high-specificity selectors, so every rule below carries the
   .gform_wrapper.gravity-theme prefix to out-weigh GF's own.

   We replace the twelve columns with two. Borrowing GF's grid does not work:
   a column gap on a twelve-column track is charged eleven times, which on a
   phone is more gap than there is card to put it in, and every field spills
   out the side. Two columns, two gaps, no arithmetic traps. */

.tata-form .gform_wrapper.gravity-theme .gform_fields {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 28px 26px;
	list-style: none;
	margin: 0;
	padding: 0;
}
.tata-form .gform_wrapper.gravity-theme .gform_fields .gfield {
	grid-column: 1 / -1;
	min-width: 0;
	margin: 0;
	padding: 0;
	/* the fields are <li>; GF's conditional logic owns `display`, so kill the
	   marker with list-style instead of fighting it over the display value */
	list-style: none;
}
.tata-form .gform_wrapper.gravity-theme .gform_fields .rsvp-half {
	grid-column: span 1;
}

/* GF wraps choice fields in a fieldset, which arrives with browser furniture. */
.tata-form fieldset {
	margin: 0;
	padding: 0;
	border: 0;
	min-width: 0;
}
.tata-form legend {
	display: block;
	width: 100%;
	padding: 0;
	float: left;   /* keeps Safari from ignoring width on a legend */
}
.tata-form legend + * { clear: both; }

.tata-form .gfield_label,
.tata-form .gform-field-label {
	display: block;
	font-family: var(--font-body);
	font-weight: 500;
	font-size: 18px;
	line-height: 1.4;
	color: var(--ink);
	margin: 0 0 8px;
}
.tata-form .gfield_required {
	color: var(--amethyst);
	font-style: italic;
	margin-left: 5px;
}
.tata-form .gfield_required_text {
	font-family: var(--font-display);
	font-size: 17px;
	font-weight: 400;
}

.tata-form .gfield_description,
.tata-form .gform-field-label--type-sub {
	font-family: var(--font-display);
	font-style: italic;
	font-size: 17px;
	line-height: 1.5;
	color: var(--ink-soft);
	padding: 7px 0 0;
}

.tata-form input[type="text"],
.tata-form input[type="email"],
.tata-form input[type="tel"],
.tata-form input[type="number"],
.tata-form textarea {
	width: 100%;
	font-family: var(--font-body);
	font-size: 18px;
	line-height: 1.5;
	color: var(--ink);
	background: var(--paper);
	border: 1px solid rgba(42, 32, 51, .3);
	border-radius: 2px;
	padding: 14px 16px;
	transition: border-color .14s ease, box-shadow .14s ease;
	-webkit-appearance: none;
	appearance: none;
}
.tata-form textarea { min-height: 124px; resize: vertical; }
.tata-form .rsvp-message textarea { min-height: 160px; }

.tata-form input:hover,
.tata-form textarea:hover { border-color: rgba(42, 32, 51, .5); }

.tata-form input:focus,
.tata-form textarea:focus {
	outline: none;
	border-color: var(--amethyst);
	box-shadow: 0 0 0 3px rgba(107, 74, 134, .16);
}

.tata-form input::placeholder,
.tata-form textarea::placeholder { color: rgba(90, 76, 102, .6); }

/* The yes/no pair, as two things you can actually hit with a thumb --------- */

.tata-form .gform_wrapper.gravity-theme .ginput_container_radio .gfield_radio {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 16px;
	list-style: none;
	margin: 0;
	padding: 0;
}
/* GF's own .gchoice is a flex row, which leaves the label sized to its text
   and the two answers different widths. Both are meant to be the same slab. */
.tata-form .gform_wrapper.gravity-theme .gchoice {
	position: relative;
	display: block;
	margin: 0;
	padding: 0;
}
.tata-form .gform_wrapper.gravity-theme .gchoice input[type="radio"] {
	position: absolute;
	opacity: 0;
	width: 1px;
	height: 1px;
	margin: 0;
}
.tata-form .gform_wrapper.gravity-theme .gchoice label {
	display: flex;
	align-items: center;
	gap: 14px;
	width: 100%;
	max-width: none;
	min-height: 78px;
	margin: 0;
	padding: 18px 20px;
	font-family: var(--font-body);
	font-weight: 500;
	font-size: 17px;
	line-height: 1.4;
	color: var(--ink);
	background: var(--paper);
	border: 1px solid rgba(42, 32, 51, .3);
	border-radius: 2px;
	cursor: pointer;
	transition: border-color .14s ease, background .14s ease, color .14s ease;
}
.tata-form .gform_wrapper.gravity-theme .gchoice label::before {
	content: "";
	display: block;
	flex: 0 0 22px;
	width: 22px;
	height: 22px;
	border: 1px solid rgba(42, 32, 51, .45);
	border-radius: 50%;
	background: transparent;
	transition: box-shadow .14s ease, border-color .14s ease;
}
.tata-form .gform_wrapper.gravity-theme .gchoice label:hover {
	border-color: var(--amethyst);
}
.tata-form .gform_wrapper.gravity-theme .gchoice input:focus-visible + label {
	outline: 2px solid var(--amethyst);
	outline-offset: 3px;
}
.tata-form .gform_wrapper.gravity-theme .gchoice:has(input:checked) label,
.tata-form .gform_wrapper.gravity-theme .gchoice.is-picked label {
	background: var(--aubergine);
	border-color: var(--aubergine);
	color: var(--paper);
}
.tata-form .gform_wrapper.gravity-theme .gchoice:has(input:checked) label::before,
.tata-form .gform_wrapper.gravity-theme .gchoice.is-picked label::before {
	border-color: var(--gold-lt);
	box-shadow: inset 0 0 0 5px var(--gold-lt);
}

/* Honeypot and GF furniture we do not want ------------------------------- */

.tata-form .gform_validation_container,
.tata-form .gfield--type-honeypot { display: none !important; }

/* GF prints its own "Please enter a number from 1 to 20" under the headcount
   field, right above ours. One hint is enough. */
.tata-form .gfield--type-number .instruction { display: none; }

/* Validation --------------------------------------------------------------- */

.tata-form .gform_validation_errors {
	background: var(--brick-bg);
	border: 1px solid var(--brick);
	border-radius: 2px;
	padding: 20px 24px;
	margin: 0 0 30px;
}
.tata-form .gform_validation_errors h2,
.tata-form .gform_submission_error {
	font-family: var(--font-display);
	font-weight: 500;
	font-size: 24px;
	line-height: 1.35;
	color: var(--brick);
	margin: 0;
}
.tata-form .gform_validation_errors ol {
	margin: 10px 0 0 18px;
	font-size: 16px;
	color: var(--ink);
}

.tata-form .gfield_error input,
.tata-form .gfield_error textarea {
	border-color: var(--brick);
	background: var(--brick-bg);
}

.tata-form .validation_message,
.tata-form .gfield_validation_message {
	font-family: var(--font-body);
	font-size: 16px;
	color: var(--brick);
	background: none;
	border: 0;
	padding: 8px 0 0;
}

/* Submit ------------------------------------------------------------------- */

.tata-form .gform_footer {
	margin: 36px 0 0;
	padding: 0;
	display: flex;
	justify-content: center;
}
.tata-form .gform_button,
.tata-form button.gform_button,
.tata-form input[type="submit"] {
	font-family: var(--font-body);
	font-weight: 500;
	font-size: 18px;
	line-height: 1;
	letter-spacing: .04em;
	color: var(--paper);
	background: var(--amethyst-deep);
	border: 1px solid var(--amethyst-deep);
	border-radius: 2px;
	padding: 21px 48px;
	cursor: pointer;
	transition: background .16s ease, border-color .16s ease, box-shadow .16s ease;
	-webkit-appearance: none;
	appearance: none;
}
.tata-form .gform_button:hover {
	background: var(--aubergine);
	border-color: var(--aubergine);
	box-shadow: 0 0 0 3px rgba(107, 74, 134, .18);
}

.tata-form .gform_ajax_spinner {
	width: 28px;
	height: 28px;
	margin-left: 16px;
	align-self: center;
}

/* Thank you ---------------------------------------------------------------- */

.rsvp__card.is-replied .rsvp__lede,
.rsvp__card.is-replied .section-title { display: none; }

.tata-form .gform_confirmation_wrapper { text-align: center; }
.rsvp-thanks { padding: 24px 10px 10px; }
.rsvp-thanks__big {
	font-family: var(--font-display);
	font-weight: 500;
	font-size: 44px;
	line-height: 1.15;
	letter-spacing: .01em;
	color: var(--aubergine);
	margin: 0 0 18px;
}
.rsvp-thanks__body {
	font-size: 18px;
	line-height: 1.75;
	color: var(--ink);
	max-width: 46ch;
	margin: 0 auto;
}

.rsvp-missing {
	font-family: var(--font-display);
	font-style: italic;
	font-size: 20px;
	color: var(--ink-soft);
	text-align: center;
}

/* --------------------------------------------------------------------------
   Add to the album

   Kept deliberately quiet. It sits between the wall and the reply card, and
   the reply card is the thing that actually has to be filled in - so this one
   gets no crest, no ruled frame and no ground of its own. It reads as a line
   under the photographs rather than a second card.
   -------------------------------------------------------------------------- */

.photos {
	padding: 72px var(--gutter) 6px;
	background: var(--paper);
	text-align: center;
}

.photos__inner {
	max-width: 620px;
	margin: 0 auto;
}

.photos__title { font-size: 30px; }

.photos__lede {
	font-size: 17px;
	line-height: 1.7;
	color: var(--ink-soft);
	max-width: 46ch;
	margin: 20px auto 0;
}

.photos__form {
	margin-top: 30px;
	text-align: left;
}

.photos__noscript {
	font-family: var(--font-display);
	font-style: italic;
	font-size: 18px;
	color: var(--ink-soft);
	margin-top: 24px;
}
.photos__noscript a { color: var(--amethyst); }

/* The upload control ------------------------------------------------------- */

/* The rules line Gravity Forms prints for itself - accepted types, ceiling,
   count. It is mechanical where the field description is the explanation, so
   it is set quieter than one. */
.tata-form .gform_fileupload_rules {
	display: block;
	font-family: var(--font-body);
	font-style: normal;
	font-size: 14px;
	letter-spacing: .02em;
	color: rgba(90, 76, 102, .85);
	padding-top: 8px;
}

.tata-form .gform_drop_area {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: 8px 14px;
	padding: 34px 24px;
	background: var(--paper);
	/* dashed, because the whole point of the shape is that something can be
	   dropped into it - a solid rule would read as one more field */
	border: 1px dashed rgba(42, 32, 51, .38);
	border-radius: 2px;
	text-align: center;
	transition: border-color .14s ease, background .14s ease;
}
.tata-form .gform_drop_area:hover { border-color: var(--amethyst); }

.tata-form .gform_drop_instructions {
	font-family: var(--font-display);
	font-style: italic;
	font-size: 19px;
	color: var(--ink-soft);
}

.tata-form .gform_button_select_files {
	font-family: var(--font-body);
	font-weight: 500;
	font-size: 17px;
	line-height: 1;
	color: var(--paper);
	background: var(--amethyst-deep);
	border: 1px solid var(--amethyst-deep);
	border-radius: 2px;
	/* a thumb, not a mouse pointer: this is the one control a guest has to hit
	   before anything else on this form can happen */
	padding: 16px 30px;
	min-height: 52px;
	cursor: pointer;
	transition: background .16s ease, border-color .16s ease;
	-webkit-appearance: none;
	appearance: none;
}
.tata-form .gform_button_select_files:hover {
	background: var(--aubergine);
	border-color: var(--aubergine);
}
.tata-form .gform_button_select_files:focus-visible {
	outline: 2px solid var(--amethyst);
	outline-offset: 3px;
}

/* What has been picked so far --------------------------------------------- */

.tata-form .ginput_preview_list { margin: 0; padding: 0; }

.tata-form .ginput_preview {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 6px 14px;
	font-size: 15px;
	color: var(--ink);
	padding: 12px 2px;
	border-bottom: 1px solid var(--gold-hair);
}
.tata-form .gfield_fileupload_filename {
	flex: 1 1 12ch;
	min-width: 0;
	overflow-wrap: anywhere;
}
.tata-form .gfield_fileupload_filesize {
	font-size: 14px;
	color: var(--ink-soft);
}
.tata-form .gfield_fileupload_progress { flex: 0 0 110px; }
.tata-form .gfield_fileupload_progressbar {
	display: block;
	height: 3px;
	background: var(--paper-3);
}
.tata-form .gfield_fileupload_progressbar_progress {
	display: block;
	height: 100%;
	background: var(--gold);
	transition: width .2s ease;
}
.tata-form .gfield_fileupload_percent {
	font-size: 13px;
	letter-spacing: .04em;
	color: var(--ink-soft);
}

.tata-form .gform_delete_file,
.tata-form .gfield_fileupload_cancel {
	font-family: var(--font-body);
	font-size: 14px;
	color: var(--brick);
	background: none;
	border: 1px solid rgba(142, 59, 52, .4);
	border-radius: 2px;
	padding: 7px 12px;
	min-height: 36px;
	cursor: pointer;
	text-decoration: none;
	line-height: 1;
}
.tata-form .gform_delete_file:hover,
.tata-form .gfield_fileupload_cancel:hover {
	background: var(--brick-bg);
	border-color: var(--brick);
}
/* Dashicons is an admin stylesheet and is not reliably on the front end. When
   it is missing the trash button is an empty box with a screen-reader label
   and nothing a sighted guest can read, so the word is drawn here instead. */
.tata-form .gform_delete_file .dashicons { display: none; }
.tata-form .gform_delete_file::before { content: "Remove"; }

/* The other remove control. Once a file has finished uploading, Gravity Forms
   swaps in a bare <img> with an onclick instead of the button above, so it
   gets a tap target of its own - party.js gives it the role and the tab stop
   that make the focus ring worth drawing. */
.tata-form img.gform_delete {
	flex: 0 0 auto;
	width: 20px;
	height: 20px;
	/* 20 + 24 = a 44px target, which is the smallest thing worth asking a
	   thumb to hit. The icon itself stays 20px. */
	padding: 12px;
	box-sizing: content-box;
	cursor: pointer;
	border-radius: 2px;
	order: 9;
}
.tata-form img.gform_delete:hover { background: var(--brick-bg); }
.tata-form img.gform_delete:focus-visible {
	outline: 2px solid var(--amethyst);
	outline-offset: 2px;
}

/* The HEIC warning, revealed by party.js when one is picked --------------- */

.photos__heic {
	font-size: 16px;
	line-height: 1.6;
	color: var(--brick);
	background: var(--brick-bg);
	border: 1px solid rgba(142, 59, 52, .45);
	border-radius: 2px;
	padding: 16px 18px;
	margin-top: 18px;
	text-align: left;
}
.photos__heic[hidden] { display: none; }

/* Thank you ---------------------------------------------------------------- */

.photos-added { text-align: center; padding: 18px 0 4px; }

.photos-thanks__big {
	font-family: var(--font-display);
	font-weight: 500;
	font-size: 34px;
	line-height: 1.2;
	color: var(--aubergine);
	margin: 0 0 14px;
}
.photos-thanks__body,
.photos-thanks__note {
	font-size: 17px;
	line-height: 1.7;
	color: var(--ink);
	max-width: 44ch;
	margin: 0 auto;
}
.photos-thanks__note {
	font-family: var(--font-display);
	font-style: italic;
	color: var(--brick);
	margin-top: 12px;
}
.photos-thanks__again {
	font-size: 16px;
	margin-top: 20px;
}
.photos-thanks__again a {
	color: var(--amethyst);
	text-decoration: underline;
	text-underline-offset: 3px;
}

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

.footer {
	background: var(--aubergine-deep);
	padding: 62px var(--gutter) 58px;
	text-align: center;
}
.footer p { color: var(--lilac-text); }

.footer .crest--footer { margin-bottom: 22px; }

.footer__line {
	font-family: var(--font-display);
	font-size: 22px;
	line-height: 1.6;
	color: var(--lilac-text);
	max-width: 44ch;
	margin: 0 auto;
}
.footer__line strong { color: var(--paper); font-weight: 500; }

.footer__contact {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 8px 26px;
	font-size: 16px;
	margin-top: 14px;
}
.footer__contact a {
	color: var(--gold-lt);
	text-decoration: underline;
	text-underline-offset: 3px;
}
.footer__contact a:hover { color: var(--paper); }

.footer__sign {
	font-family: var(--font-display);
	font-style: italic;
	font-size: 18px;
	color: rgba(228, 218, 236, .72);
	margin-top: 32px;
}

/* --------------------------------------------------------------------------
   Smaller screens
   -------------------------------------------------------------------------- */

@media (max-width: 1023px) {
	.hero__name-full { font-size: 50px; }
	.hero__name-alias { font-size: 46px; }
	.photo { width: 288px; }
}

@media (max-width: 767px) {
	:root { --gutter: 20px; }

	body { font-size: 18px; }

	.hero { padding: 58px var(--gutter) 56px; }
	.hero::before { inset: 12px; }
	.hero::after  { inset: 17px; }

	.hero .crest--hero { width: 70px; height: 70px; margin-bottom: 20px; }
	.hero .crest--hero .crest__letter { font-size: 32px; }

	.hero__kicker   { font-size: 21px; }
	.hero__name-full { font-size: 33px; letter-spacing: .07em; }
	.hero__name-alias { font-size: 38px; }
	.hero__occasion { font-size: 22px; }
	.hero__when     { font-size: 24px; }
	.hero__year     { font-size: 20px; }
	.hero__venue    { font-size: 22px; }
	.hero__time     { font-size: 16px; }
	/* Street on one line, town on the next: at 390px the whole address is
	   exactly as wide as the ruled frame it sits inside. */
	.hero__address  { font-size: 16px; max-width: 26ch; margin-left: auto; margin-right: auto; }
	.hero__by       { font-size: 19px; }
	.hero__by-date  { font-size: 21px; }

	.rule { max-width: 280px; margin: 28px auto; }
	.fleuron { width: 52px; }

	.section-title { font-size: 29px; }

	.note { padding-bottom: 66px; }
	.note__frame { padding: 36px 24px 32px; }
	.note__frame .section-title { font-size: 26px; }
	.note__body { font-size: 18px; }
	.note__sign { font-size: 32px; }
	.note__postscript { font-size: 19px; }

	.particulars { padding-bottom: 66px; }
	.particulars__row {
		grid-template-columns: 1fr;
		gap: 6px;
		text-align: center;
	}
	.particulars__label { text-align: center; }

	.gallery { padding: 60px 0 56px; }
	.photo { width: 76vw; }
	.gallery__track { gap: 20px; }
	.photo__frame { padding: 10px; }

	.photos { padding: 54px var(--gutter) 4px; }
	.photos__title { font-size: 25px; }
	.photos__form { margin-top: 24px; }
	.tata-form .gform_drop_area { padding: 24px 16px; }
	.tata-form .gform_button_select_files { width: 100%; }
	.photos-thanks__big { font-size: 28px; }

	.rsvp { padding: 62px var(--gutter) 70px; }
	.rsvp__card { padding: 34px 22px 38px; }
	.rsvp__card::before { inset: 6px; }
	.rsvp__form { margin-top: 30px; }

	.tata-form .gform_wrapper.gravity-theme .gform_fields { gap: 24px; }
	.tata-form .gform_wrapper.gravity-theme .gform_fields .rsvp-half {
		grid-column: 1 / -1;
	}
	.tata-form .gform_wrapper.gravity-theme .ginput_container_radio .gfield_radio {
		grid-template-columns: 1fr;
	}
	.tata-form .gform_button { width: 100%; }

	.rsvp-thanks__big { font-size: 34px; }

	.seal-stage__to { font-size: 27px; margin-top: 26px; }
	.envelope__card-name { font-size: 19px; letter-spacing: .07em; }
	.envelope__card-alias { font-size: 19px; }
	.envelope__card-kicker { font-size: 13px; }
	.envelope__card-when { font-size: 12px; }
	.seal__letter { font-size: 30px; }

	.footer { padding: 48px var(--gutter) 46px; }
	.footer__line { font-size: 20px; }
}

/* A short window - a laptop with a lot of browser chrome, or a phone in
   landscape - has to fit the whole envelope plus the card standing out of it. */
@media (max-height: 780px) {
	.seal-stage__inner { max-width: 430px; }
	.seal-stage__to { font-size: 28px; margin-top: 24px; }
}
@media (max-height: 640px) {
	.seal-stage__inner { max-width: 340px; }
	.seal-stage__to { font-size: 23px; margin-top: 18px; }
	.seal-stage__hint { font-size: 14px; }
}

/* --------------------------------------------------------------------------
   Reduced motion

   The envelope still opens - it is the way in, not an ornament - but it does
   it by cutting rather than swinging, and nothing falls when a reply lands.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
	html { scroll-behavior: auto; }

	.sheet,
	.seal,
	.seal-stage,
	.envelope__card,
	.envelope__flap,
	.gallery__track,
	.gallery__progress-bar {
		transition-duration: .01ms !important;
	}

	.envelope.is-open .envelope__flap { transform: rotateX(-172deg); }
}
