/* ===========================================================================
   Nirakkoot - the club's public site
   ---------------------------------------------------------------------------
   നിറക്കൂട്ട് means a blend of colours. The club is named after a palette, so
   the palette is the design: a set of five hues drawn from the club's own year
   - festival red, Onam marigold, the tea-green of the hills they walk in, the
   blue of the drive up, and the plum already carried by the logo. They appear
   as a blend at the top of every page and as a single mark beside each section
   heading. Nowhere else. Spread across backgrounds they would be noise; held
   to a rule and a dot they say the club's name without spelling it.

   Layered over bootstrap.css, which supplies the grid and the components.
   css/style.css is NOT loaded on these pages - it belongs to the member portal
   and the two are kept apart on purpose.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   1. Tokens
   --------------------------------------------------------------------------- */
:root {
	/* Ink and paper. Both carry a trace of the plum so the neutrals sit with
	   the brand rather than beside it. */
	--ink:        #1A1218;
	--ink-2:      #574A52;
	/* Was #8A7E86, which measured 3.8:1 on paper - under the 4.5:1 small text
	   needs. The eyebrows are set in 12px uppercase and were the worst of it. */
	--ink-3:      #6E636B;
	--paper:      #FFFCFC;
	--paper-2:    #F8F3F5;
	--paper-3:    #F1E9ED;
	--rule:       #E7DDE2;
	--rule-2:     #D6C7CE;

	/* The club's own colour, from the logo. */
	--plum:       #6B114D;
	--plum-deep:  #4A0B35;
	--plum-lift:  #8E1C68;
	--plum-wash:  #F7EDF3;

	/* The blend. Five hues, one year: the festival, the Onam sadya, the tea
	   hills, the road up, and the club itself. */
	--hue-red:    #C0402C;
	--hue-gold:   #C97F18;
	--hue-green:  #2C7A57;
	--hue-blue:   #2A5C86;
	--hue-plum:   #6B114D;

	/* Type */
	--display: "Fraunces", Georgia, "Times New Roman", serif;
	--body:    "Public Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
	--mal:     "Noto Sans Malayalam", "Public Sans", sans-serif;

	/* A type scale that steps rather than drifts. */
	--t-xs:   0.75rem;
	--t-sm:   0.875rem;
	--t-base: 1rem;
	--t-md:   1.125rem;
	--t-lg:   1.375rem;
	--t-xl:   1.875rem;
	--t-2xl:  2.5rem;
	--t-3xl:  3.25rem;

	/* One spacing scale, used everywhere, so the rhythm holds across pages. */
	--s1: 0.25rem;
	--s2: 0.5rem;
	--s3: 0.75rem;
	--s4: 1rem;
	--s5: 1.5rem;
	--s6: 2rem;
	--s7: 3rem;
	--s8: 4rem;
	--s9: 6rem;

	--radius:    6px;
	--radius-lg: 12px;
	--radius-xl: 20px;

	/* Shadows stay shallow. A club site is not a dashboard of floating cards. */
	--shadow-sm: 0 1px 2px rgba(26, 18, 24, 0.05);
	--shadow:    0 4px 16px rgba(26, 18, 24, 0.07);
	--shadow-lg: 0 18px 44px rgba(26, 18, 24, 0.13);

	--container: 1140px;
	--ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* ---------------------------------------------------------------------------
   2. Base
   --------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
	font-family: var(--body);
	font-size: var(--t-base);
	line-height: 1.65;
	color: var(--ink-2);
	background: var(--paper);
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
	overflow-x: hidden;
}

h1, h2, h3, h4, h5, h6 { color: var(--ink); font-family: var(--display); }

/* Fraunces is a variable face; asking for the display optical size keeps the
   serifs crisp at headline sizes instead of the softer text cut. */
h1, h2 { font-variation-settings: "opsz" 120, "SOFT" 0; }

a { color: var(--plum); text-decoration: none; transition: color 0.15s var(--ease); }
a:hover { color: var(--plum-lift); }

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

/* The club's name in its own script, wherever it appears. */
.mal, [lang="ml"] { font-family: var(--mal); }

/* A visible focus ring on everything that takes focus - the site is used by
   members of every age and not all of them use a mouse. */
:focus-visible {
	outline: 2px solid var(--plum);
	outline-offset: 3px;
	border-radius: 2px;
}

/* A finger is not a cursor. On touch, everything worth pressing is at least
   44px tall whatever size the type inside it is. */
@media (pointer: coarse) {
	.btn, .albumfilter__opt, .navbar-toggler {
		min-height: 44px;
		display: inline-flex;
		align-items: center;
		justify-content: center;
	}
	.form-control, .form-select { min-height: 44px; }
}

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

/* ---------------------------------------------------------------------------
   3. Layout
   --------------------------------------------------------------------------- */
.container { max-width: var(--container); padding-left: var(--s5); padding-right: var(--s5); }

/* One rhythm for every band on the page. Sections used to set their own
   padding with utility classes and no two agreed. */
.band { padding-top: var(--s9); padding-bottom: var(--s9); }
.band--tight { padding-top: var(--s8); padding-bottom: var(--s8); }
.band--tinted { background: var(--paper-2); }
.band--edged { border-top: 1px solid var(--rule); }

/*
* Two untinted bands in a row have nothing between them but their own padding,
* which doubles into a gap twice the size of the rhythm everywhere else. A
* change of background earns the full gap; a continuation of the same paper
* does not.
*/
.band:not(.band--tinted) + .band:not(.band--tinted) { padding-top: 0; }

/* ---------------------------------------------------------------------------
   4. The blend - this site's signature
   ---------------------------------------------------------------------------
   The club's name, drawn. It sits above the header on every page and is the
   one piece of decoration the design allows itself.
   --------------------------------------------------------------------------- */
.blendrule {
	height: 4px;
	width: 100%;
	background: linear-gradient(
		90deg,
		var(--hue-red)   0%,   var(--hue-red)   20%,
		var(--hue-gold)  20%,  var(--hue-gold)  40%,
		var(--hue-green) 40%,  var(--hue-green) 60%,
		var(--hue-blue)  60%,  var(--hue-blue)  80%,
		var(--hue-plum)  80%,  var(--hue-plum)  100%
	);
}

/* An eyebrow above a section heading, carrying one hue of the blend. The
   colour is set per section so the page walks through the palette top to
   bottom - the same blend, unrolled. */
.eyebrow {
	display: inline-flex;
	align-items: flex-start;
	gap: var(--s2);
	font-family: var(--body);
	font-size: var(--t-xs);
	font-weight: 700;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--ink-3);
	margin-bottom: var(--s3);
}
.eyebrow::before {
	content: "";
	flex-shrink: 0;
	width: 22px;
	height: 3px;
	border-radius: 2px;
	background: var(--eyebrow-hue, var(--plum));
	/* Sits against the first line, so a label that wraps to two does not leave
	   the rule floating in the middle of them. */
	margin-top: 0.55em;
}
.eyebrow--red   { --eyebrow-hue: var(--hue-red); }
.eyebrow--gold  { --eyebrow-hue: var(--hue-gold); }
.eyebrow--green { --eyebrow-hue: var(--hue-green); }
.eyebrow--blue  { --eyebrow-hue: var(--hue-blue); }
.eyebrow--plum  { --eyebrow-hue: var(--hue-plum); }

/* ---------------------------------------------------------------------------
   5. Type roles
   --------------------------------------------------------------------------- */
.title-xl {
	font-family: var(--display);
	font-size: clamp(2.25rem, 5.2vw, var(--t-3xl));
	font-weight: 600;
	line-height: 1.06;
	letter-spacing: -0.02em;
	color: var(--ink);
	margin: 0;
}
.title-lg {
	font-family: var(--display);
	font-size: clamp(1.875rem, 3.6vw, var(--t-2xl));
	font-weight: 600;
	line-height: 1.14;
	letter-spacing: -0.018em;
	color: var(--ink);
	margin: 0;
}
.title-md {
	font-family: var(--display);
	font-size: var(--t-lg);
	font-weight: 600;
	line-height: 1.28;
	color: var(--ink);
	margin: 0;
}

/* One measure for running text. Long lines are the commonest reason a page
   built on a 12-column grid reads as unfinished. */
.lede {
	font-size: var(--t-md);
	line-height: 1.68;
	color: var(--ink-2);
	max-width: 58ch;
}
.prose { max-width: 62ch; }
.prose p { margin-bottom: var(--s4); }
.prose p:last-child { margin-bottom: 0; }

/* ---------------------------------------------------------------------------
   6. Header
   --------------------------------------------------------------------------- */
.siteheader {
	position: sticky;
	top: 0;
	z-index: 1030;
	background: rgba(255, 252, 252, 0.92);
	backdrop-filter: saturate(160%) blur(12px);
	border-bottom: 1px solid var(--rule);
}
.siteheader .navbar { padding-top: var(--s3); padding-bottom: var(--s3); }
.siteheader .navbar-brand img { max-height: 46px; width: auto; display: block; }

.sitenav { gap: var(--s1); }
.sitenav .nav-link {
	position: relative;
	font-family: var(--body);
	font-size: var(--t-sm);
	font-weight: 600;
	letter-spacing: 0.04em;
	color: var(--ink-2);
	padding: var(--s2) var(--s3);
	border-radius: var(--radius);
	transition: color 0.15s var(--ease), background-color 0.15s var(--ease);
}
.sitenav .nav-link:hover { color: var(--plum); background: var(--plum-wash); }
.sitenav .nav-link.is-current { color: var(--plum); }
/* The current page is marked under the word rather than by colour alone. */
.sitenav .nav-link.is-current::after {
	content: "";
	position: absolute;
	left: var(--s3);
	right: var(--s3);
	bottom: 2px;
	height: 2px;
	border-radius: 2px;
	background: var(--plum);
}
.navbar-toggler { border: 1px solid var(--rule-2); padding: 0.35rem 0.55rem; }
.navbar-toggler:focus { box-shadow: none; }

/* ---------------------------------------------------------------------------
   7. Buttons
   --------------------------------------------------------------------------- */
.btn {
	font-family: var(--body);
	font-weight: 600;
	font-size: var(--t-sm);
	letter-spacing: 0.01em;
	border-radius: 999px;
	padding: 0.6rem 1.4rem;
	transition: transform 0.15s var(--ease), box-shadow 0.15s var(--ease),
	            background-color 0.15s var(--ease), color 0.15s var(--ease);
}
.btn-lg { font-size: var(--t-base); padding: 0.8rem 1.9rem; }
.btn-sm { font-size: var(--t-xs); padding: 0.45rem 1.1rem; }

.btn-plum {
	background: var(--plum);
	border: 1px solid var(--plum);
	color: #fff;
}
.btn-plum:hover, .btn-plum:focus {
	background: var(--plum-deep);
	border-color: var(--plum-deep);
	color: #fff;
	transform: translateY(-1px);
	box-shadow: var(--shadow);
}

.btn-ghost {
	background: transparent;
	border: 1px solid var(--rule-2);
	color: var(--ink);
}
.btn-ghost:hover, .btn-ghost:focus {
	border-color: var(--plum);
	color: var(--plum);
	background: var(--plum-wash);
}

/* On a dark or photographic ground. */
.btn-ondark {
	background: #fff;
	border: 1px solid #fff;
	color: var(--plum);
}
.btn-ondark:hover, .btn-ondark:focus {
	background: var(--paper-3);
	border-color: var(--paper-3);
	color: var(--plum-deep);
	transform: translateY(-1px);
}
.btn-ondark-ghost {
	background: rgba(255, 255, 255, 0.08);
	border: 1px solid rgba(255, 255, 255, 0.55);
	color: #fff;
}
.btn-ondark-ghost:hover, .btn-ondark-ghost:focus {
	background: rgba(255, 255, 255, 0.16);
	border-color: #fff;
	color: #fff;
}

/* ---------------------------------------------------------------------------
   8. Hero
   ---------------------------------------------------------------------------
   The photographs are of members, taken on club trips, and they are the point
   of the page - so the type is laid over a scrim that darkens only where the
   words fall, instead of dimming the whole picture the way a blanket
   brightness filter does.
   --------------------------------------------------------------------------- */
.hero { position: relative; background: var(--ink); }
.hero .carousel-item {
	height: clamp(460px, 74vh, 680px);
	background: var(--ink);
}
.hero .carousel-item > img,
.hero .carousel-item > video {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}
.hero .carousel-item::after {
	content: "";
	position: absolute;
	inset: 0;
	background:
		linear-gradient(to top, rgba(18, 10, 16, 0.86) 0%, rgba(18, 10, 16, 0.42) 42%, rgba(18, 10, 16, 0.10) 68%, rgba(18, 10, 16, 0.28) 100%),
		linear-gradient(to right, rgba(18, 10, 16, 0.62) 0%, rgba(18, 10, 16, 0.12) 58%, transparent 100%);
	pointer-events: none;
}

.hero__caption {
	position: absolute;
	inset: auto 0 0 0;
	z-index: 3;
	padding-bottom: clamp(var(--s7), 9vh, var(--s9));
	text-align: left;
}
.hero__inner { max-width: 640px; }

.hero__tag {
	display: inline-flex;
	align-items: center;
	gap: var(--s2);
	background: rgba(255, 255, 255, 0.14);
	border: 1px solid rgba(255, 255, 255, 0.34);
	backdrop-filter: blur(6px);
	color: #fff;
	font-size: var(--t-xs);
	font-weight: 700;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	padding: 0.3rem 0.85rem;
	border-radius: 999px;
	margin-bottom: var(--s4);
}
.hero__tag::before {
	content: "";
	width: 7px; height: 7px;
	border-radius: 50%;
	background: var(--tag-hue, var(--hue-gold));
}
.hero__tag--red   { --tag-hue: var(--hue-red); }
.hero__tag--gold  { --tag-hue: var(--hue-gold); }
.hero__tag--green { --tag-hue: var(--hue-green); }
.hero__tag--blue  { --tag-hue: var(--hue-blue); }

.hero__title {
	font-family: var(--display);
	font-size: clamp(2.4rem, 6vw, 4.25rem);
	font-weight: 600;
	line-height: 1.02;
	letter-spacing: -0.025em;
	color: #fff;
	margin: 0 0 var(--s4);
}
.hero__lede {
	font-size: clamp(var(--t-base), 1.5vw, var(--t-md));
	line-height: 1.6;
	color: rgba(255, 255, 255, 0.9);
	max-width: 46ch;
	margin: 0 0 var(--s5);
}

/* Bootstrap's default arrows sit on the photo with nothing behind them. */
.hero .carousel-control-prev,
.hero .carousel-control-next { width: 8%; opacity: 0; transition: opacity 0.2s var(--ease); }
.hero:hover .carousel-control-prev,
.hero:hover .carousel-control-next,
.hero .carousel-control-prev:focus-visible,
.hero .carousel-control-next:focus-visible { opacity: 0.85; }

.hero .carousel-indicators { margin-bottom: var(--s5); z-index: 4; }
.hero .carousel-indicators [data-bs-target] {
	width: 26px;
	height: 3px;
	border-radius: 2px;
	border: 0;
	background: rgba(255, 255, 255, 0.42);
	opacity: 1;
	transition: background-color 0.2s var(--ease), width 0.2s var(--ease);
}
.hero .carousel-indicators .active { background: #fff; width: 42px; }

/* ---------------------------------------------------------------------------
   9. Cards
   --------------------------------------------------------------------------- */
.tile {
	background: var(--paper);
	border: 1px solid var(--rule);
	border-radius: var(--radius-lg);
	padding: var(--s5);
	height: 100%;
	transition: border-color 0.18s var(--ease), transform 0.18s var(--ease), box-shadow 0.18s var(--ease);
}
.tile:hover {
	border-color: var(--rule-2);
	transform: translateY(-3px);
	box-shadow: var(--shadow);
}
.tile__icon {
	width: 44px;
	height: 44px;
	border-radius: var(--radius);
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 1.15rem;
	margin-bottom: var(--s4);
	background: var(--tile-wash, var(--plum-wash));
	color: var(--tile-hue, var(--plum));
}
.tile--red   { --tile-hue: var(--hue-red);   --tile-wash: #FAEEEB; }
.tile--gold  { --tile-hue: var(--hue-gold);  --tile-wash: #FBF2E2; }
.tile--green { --tile-hue: var(--hue-green); --tile-wash: #E9F3EE; }
.tile--blue  { --tile-hue: var(--hue-blue);  --tile-wash: #EAF0F6; }
/* Reserves exactly two lines, so a tile whose month wraps ("August /
   September") keeps its title level with the tiles beside it. The line-height
   is pinned here so the reserved height and the real height agree. */
.tile .eyebrow { line-height: 1.3; min-height: 2.6em; }
.tile h3, .tile h5 { font-size: var(--t-base); font-weight: 600; margin: 0 0 var(--s2); font-family: var(--body); color: var(--ink); }
.tile p { font-size: var(--t-sm); color: var(--ink-2); margin: 0; }

/* Photographs of the club's own events. */
.shot {
	position: relative;
	display: block;
	border-radius: var(--radius-lg);
	overflow: hidden;
	background: var(--ink);
	aspect-ratio: 4 / 3;
	/* Everything inside sits on a photograph, so white is the default here
	   rather than the page's link colour - plum on a dark image is unreadable
	   and would only show if a caption ever forgot to set its own colour. */
	color: #fff;
}
.shot img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	transition: transform 0.6s var(--ease);
}
.shot:hover img, .shot:focus-visible img { transform: scale(1.045); }
.shot__veil {
	position: absolute;
	inset: 0;
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	padding: var(--s4);
	color: #fff;
	background: linear-gradient(to top, rgba(18, 10, 16, 0.88) 0%, rgba(18, 10, 16, 0.30) 46%, transparent 72%);
}
.shot__kind {
	align-self: flex-start;
	display: inline-flex;
	align-items: center;
	gap: var(--s2);
	font-size: var(--t-xs);
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.92);
	margin-bottom: var(--s2);
}
.shot__kind::before {
	content: "";
	width: 7px; height: 7px; border-radius: 50%;
	background: var(--kind-hue, var(--hue-gold));
}
.shot__kind--red   { --kind-hue: var(--hue-red); }
.shot__kind--gold  { --kind-hue: var(--hue-gold); }
.shot__kind--green { --kind-hue: var(--hue-green); }
.shot__kind--blue  { --kind-hue: var(--hue-blue); }
.shot__title { font-family: var(--body); font-size: var(--t-base); font-weight: 600; color: #fff; margin: 0 0 2px; }
.shot__note { font-size: var(--t-sm); color: rgba(255, 255, 255, 0.76); margin: 0; }

/* ---------------------------------------------------------------------------
   9b. The club's year
   ---------------------------------------------------------------------------
   A genuine sequence - the year runs in this order - so it is drawn as one,
   on a rule, with each fixture taking its own colour from the blend. The one
   coming next is called out, which is the question a visitor actually has.
   --------------------------------------------------------------------------- */
.yearline {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: var(--s5);
	position: relative;
}
/* The rule the year runs along. */
.yearline::before {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	top: 5px;
	height: 1px;
	background: var(--rule-2);
}
.yearline__item { position: relative; padding-top: var(--s5); }
.yearline__item::before {
	content: "";
	position: absolute;
	top: 0;
	left: 0;
	width: 11px;
	height: 11px;
	border-radius: 50%;
	background: var(--paper-2);
	border: 3px solid var(--year-hue, var(--plum));
}
.yearline__item--red   { --year-hue: var(--hue-red); }
.yearline__item--gold  { --year-hue: var(--hue-gold); }
.yearline__item--green { --year-hue: var(--hue-green); }
.yearline__item--blue  { --year-hue: var(--hue-blue); }

.yearline__when {
	display: block;
	font-size: var(--t-xs);
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--ink-3);
	margin-bottom: var(--s2);
}
.yearline__title {
	font-family: var(--display);
	font-size: var(--t-md);
	font-weight: 600;
	color: var(--ink);
	margin: 0;
	line-height: 1.25;
}
.yearline__item.is-next::before { background: var(--year-hue); }
.yearline__flag {
	display: inline-block;
	margin-top: var(--s3);
	font-size: var(--t-xs);
	font-weight: 700;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--year-hue);
	border: 1px solid currentColor;
	border-radius: 999px;
	padding: 0.15rem 0.6rem;
}

@media (max-width: 767.98px) {
	/* On a phone the year reads down the page, so the rule turns with it. */
	.yearline { grid-template-columns: 1fr; gap: var(--s5); padding-left: var(--s5); }
	.yearline::before { left: 5px; right: auto; top: 0; bottom: 0; width: 1px; height: auto; }
	.yearline__item { padding-top: 0; padding-left: var(--s5); }
	.yearline__item::before { top: 4px; left: -22px; }
}

/* ---------------------------------------------------------------------------
   10. Page banner - the head of an inner page
   ---------------------------------------------------------------------------
   Replaces a Bootstrap .bg-gradient whose background-image carries !important
   and quietly swallowed the brand gradient, leaving white text on white.
   --------------------------------------------------------------------------- */
.pagebanner {
	position: relative;
	background: linear-gradient(135deg, var(--plum-deep) 0%, var(--plum) 55%, #8E1C68 100%);
	color: #fff;
	padding-top: var(--s8);
	padding-bottom: var(--s8);
	overflow: hidden;
}
.pagebanner::after {
	content: "";
	position: absolute;
	inset: auto 0 0 0;
	height: 4px;
	background: linear-gradient(90deg,
		var(--hue-red) 0%, var(--hue-red) 20%,
		var(--hue-gold) 20%, var(--hue-gold) 40%,
		var(--hue-green) 40%, var(--hue-green) 60%,
		var(--hue-blue) 60%, var(--hue-blue) 80%,
		#8E1C68 80%, #8E1C68 100%);
}
.pagebanner h1 { color: #fff; }
.pagebanner .eyebrow { color: rgba(255, 255, 255, 0.78); }
.pagebanner .eyebrow::before { background: rgba(255, 255, 255, 0.65); }
.pagebanner .lede { color: rgba(255, 255, 255, 0.86); margin-left: auto; margin-right: auto; }

/* ---------------------------------------------------------------------------
   11. Celebration banner - a member's day, on the club's front page
   --------------------------------------------------------------------------- */
.celebrate {
	position: relative;
	border-radius: var(--radius-xl);
	overflow: hidden;
	background: linear-gradient(135deg, #7A1A54 0%, #B0472B 100%);
	color: #fff;
	padding: clamp(var(--s5), 4vw, var(--s7));
	box-shadow: var(--shadow-lg);
}
.celebrate--anniversary { background: linear-gradient(135deg, #5B1440 0%, #A8442F 60%, #C97F18 100%); }
.celebrate::before {
	content: "";
	position: absolute;
	inset: 0;
	background-size: cover;
	background-position: center;
	opacity: 0.22;
	mix-blend-mode: screen;
}
.celebrate--birthday::before    { background-image: url('../nirakkoot/assets/img/birthday-bg.jpg'); }
.celebrate--anniversary::before { background-image: url('../nirakkoot/assets/img/anniversary-bg.jpg'); }
.celebrate__body { position: relative; z-index: 2; }
.celebrate__portrait {
	width: clamp(140px, 20vw, 190px);
	height: clamp(140px, 20vw, 190px);
	border-radius: 50%;
	object-fit: cover;
	border: 4px solid rgba(255, 255, 255, 0.9);
	box-shadow: 0 12px 30px rgba(0, 0, 0, 0.3);
}
.celebrate__kicker {
	display: inline-flex;
	align-items: center;
	gap: var(--s2);
	font-size: var(--t-xs);
	font-weight: 700;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.88);
	margin-bottom: var(--s2);
}
.celebrate__name {
	font-family: var(--display);
	font-size: clamp(1.875rem, 4.4vw, 3rem);
	font-weight: 600;
	line-height: 1.06;
	color: #fff;
	margin: 0 0 var(--s2);
}
.celebrate__wish { font-size: var(--t-md); font-weight: 600; color: #FFD9A3; margin: 0 0 var(--s2); }
.celebrate__note { color: rgba(255, 255, 255, 0.82); margin: 0; font-size: var(--t-sm); }

/* ---------------------------------------------------------------------------
   12. Portal invitation
   --------------------------------------------------------------------------- */
.invite {
	position: relative;
	border-radius: var(--radius-xl);
	background: linear-gradient(135deg, var(--plum-deep) 0%, var(--plum) 58%, #8E1C68 100%);
	color: #fff;
	padding: clamp(var(--s6), 5vw, var(--s8));
	text-align: center;
	overflow: hidden;
}
.invite::before {
	content: "";
	position: absolute;
	inset: 0 0 auto 0;
	height: 4px;
	background: linear-gradient(90deg,
		var(--hue-red) 0%, var(--hue-red) 20%,
		var(--hue-gold) 20%, var(--hue-gold) 40%,
		var(--hue-green) 40%, var(--hue-green) 60%,
		var(--hue-blue) 60%, var(--hue-blue) 80%,
		#8E1C68 80%, #8E1C68 100%);
}
.invite h2 { color: #fff; }
/* Narrow enough that centred lines break evenly instead of dropping a single
   word onto a line of its own. */
.invite p { color: rgba(255, 255, 255, 0.85); max-width: 44ch; margin-left: auto; margin-right: auto; }
.invite .lede { max-width: 44ch; }

/* ---------------------------------------------------------------------------
   13. Forms
   --------------------------------------------------------------------------- */
.field-label {
	display: block;
	font-size: var(--t-sm);
	font-weight: 600;
	color: var(--ink);
	margin-bottom: var(--s2);
}
.form-control, .form-select {
	font-family: var(--body);
	font-size: var(--t-base);
	color: var(--ink);
	background: var(--paper);
	border: 1px solid var(--rule-2);
	border-radius: var(--radius);
	padding: 0.65rem 0.85rem;
	transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.form-control:focus, .form-select:focus {
	border-color: var(--plum);
	box-shadow: 0 0 0 3px var(--plum-wash);
	outline: none;
}
.form-control::placeholder { color: var(--ink-3); }

.formcard {
	background: var(--paper);
	border: 1px solid var(--rule);
	border-radius: var(--radius-lg);
	padding: clamp(var(--s5), 4vw, var(--s7));
}

/* Sits out of sight and out of the tab order, but is not display:none - some
   bots skip anything hidden that way, which defeats the point. */
.trapfield {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

.notice {
	display: flex;
	gap: var(--s3);
	align-items: flex-start;
	padding: var(--s4);
	border-radius: var(--radius);
	border: 1px solid;
	font-size: var(--t-sm);
	margin-bottom: var(--s5);
}
.notice i { margin-top: 0.15rem; }
.notice--good { background: #EDF6F1; border-color: #BFDECE; color: #1F5E42; }
.notice--bad  { background: #FBEEEC; border-color: #EBC7C0; color: #8E2E1C; }

/* ---------------------------------------------------------------------------
   13b. Gallery
   --------------------------------------------------------------------------- */
.albumfilter {
	display: flex;
	flex-wrap: wrap;
	gap: var(--s2);
	justify-content: center;
	margin-bottom: var(--s7);
}
.albumfilter__opt {
	border: 1px solid var(--rule-2);
	background: var(--paper);
	color: var(--ink-2);
	font-family: var(--body);
	font-size: var(--t-sm);
	font-weight: 600;
	padding: 0.45rem 1.1rem;
	border-radius: 999px;
	transition: all 0.15s var(--ease);
}
.albumfilter__opt:hover { border-color: var(--plum); color: var(--plum); }
.albumfilter__opt.is-active {
	background: var(--plum);
	border-color: var(--plum);
	color: #fff;
}

/* The photographs on the gallery page open larger, so each one is a button. */
.shot--button {
	border: 0;
	padding: 0;
	cursor: zoom-in;
	text-align: left;
}
.shot__zoom {
	position: absolute;
	top: var(--s3);
	right: var(--s3);
	width: 34px;
	height: 34px;
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
	background: rgba(18, 10, 16, 0.55);
	backdrop-filter: blur(4px);
	color: #fff;
	font-size: var(--t-sm);
	opacity: 0;
	transform: translateY(-4px);
	transition: opacity 0.18s var(--ease), transform 0.18s var(--ease);
}
.shot--button:hover .shot__zoom,
.shot--button:focus-visible .shot__zoom { opacity: 1; transform: translateY(0); }

.shotmodal {
	background: #140E12;
	border: 0;
	border-radius: var(--radius-lg);
	color: #fff;
}
.shotmodal .modal-header { border-bottom: 1px solid rgba(255, 255, 255, 0.12); }
.shotmodal .modal-title { color: #fff; }
.shotmodal .modal-body { padding: var(--s5); text-align: center; }
.shotmodal img { max-height: 76vh; width: auto; max-width: 100%; border-radius: var(--radius); }

/* A video keeps its shape at any width rather than being given a fixed height. */
.shotmodal__frame {
	position: relative;
	width: 100%;
	aspect-ratio: 16 / 9;
	border-radius: var(--radius);
	overflow: hidden;
	background: #000;
}
.shotmodal__frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* Marks a tile as a film rather than a photograph. Unlike the zoom badge this
   one is always visible - it is telling you what the thing is, not offering an
   action on hover. */
.shot__play {
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	width: 54px;
	height: 54px;
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
	background: rgba(18, 10, 16, 0.55);
	border: 2px solid rgba(255, 255, 255, 0.85);
	backdrop-filter: blur(4px);
	color: #fff;
	font-size: 1.1rem;
	padding-left: 4px;
	transition: transform 0.18s var(--ease), background-color 0.18s var(--ease);
}
.shot--button:hover .shot__play,
.shot--button:focus-visible .shot__play {
	transform: translate(-50%, -50%) scale(1.08);
	background: var(--hue-red);
}

/* The offer to play whatever album is on show, sitting under the filter. */
.slideshowcue { text-align: center; margin: 0 0 var(--s7); }
/* Under a filter it belongs with it, not a whole band away. */
.albumfilter + .slideshowcue { margin-top: calc(var(--s4) - var(--s7)); }
.slideshowcue i { margin-right: 0.5rem; }
.slideshowcue__count { opacity: 0.75; font-weight: 500; }
.slideshowcue .btn[disabled] { opacity: 0.45; box-shadow: none; transform: none; }

/* ---------------------------------------------------------------------------
   13c. Slideshow

   Full screen and its own ground, because a photograph shown one at a time is
   the only thing on the page worth looking at. The picture takes the whole
   overlay and the chrome floats over it on a gradient: a line of type at the
   top, two steps at the sides, the caption and one control at the foot.

   Laid out as stacked rows instead - which is how this began - the chrome took
   a third of a phone held upright and left the photograph a band across the
   middle. Floating it costs nothing on a desktop and gives a phone back the
   whole screen.
   --------------------------------------------------------------------------- */
.slideshow {
	position: fixed;
	inset: 0;
	/* A phone's layout viewport is taller than what you can actually see - the
	   address bar sits over the bottom of it. dvh is the visible height, and it
	   follows the bar in and out and the device through a rotation. vh first,
	   for anything that has not heard of dvh. */
	height: 100vh;
	height: 100dvh;
	z-index: 1080;              /* above Bootstrap's modal layer */
	background: #0F0A0D;
	color: #fff;
	overflow: hidden;
}
.slideshow[hidden] { display: none; }

/* The picture, given the entire overlay. Contained rather than cropped: these
   are group photographs and the person on the end is the one who gets cut. */
.slideshow__stage {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	/* Clear of a notch or a rounded corner, whichever way round the phone is. */
	padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px)
	         env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px);
}
.slideshow__stage img {
	max-width: 100%;
	max-height: 100%;
	object-fit: contain;
	opacity: 0;
	transition: opacity 0.35s var(--ease);
}
.slideshow__stage img.is-shown { opacity: 1; }

/* Chrome sits on a gradient so the type holds against whatever is behind it,
   and the shadow carries it over the bright end of a photograph. */
.slideshow__bar,
.slideshow__foot {
	position: absolute;
	left: 0;
	right: 0;
	z-index: 2;
	text-shadow: 0 1px 4px rgba(0, 0, 0, 0.7);
}
.slideshow__bar {
	top: 0;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--s4);
	padding: calc(var(--s3) + env(safe-area-inset-top, 0px))
	         calc(var(--s3) + env(safe-area-inset-right, 0px))
	         var(--s7)
	         calc(var(--s3) + env(safe-area-inset-left, 0px));
	background: linear-gradient(to bottom, rgba(10, 6, 9, 0.82), rgba(10, 6, 9, 0));
}
.slideshow__where {
	margin: 0;
	display: flex;
	align-items: baseline;
	gap: var(--s3);
	min-width: 0;
}
.slideshow__album {
	font-family: var(--display);
	font-size: var(--t-md);
	font-weight: 600;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.slideshow__count {
	font-size: var(--t-sm);
	color: rgba(255, 255, 255, 0.82);
	white-space: nowrap;
}

.slideshow__foot {
	bottom: 0;
	display: flex;
	flex-direction: column;
	gap: var(--s3);
	padding: var(--s7)
	         calc(var(--s3) + env(safe-area-inset-right, 0px))
	         calc(var(--s3) + env(safe-area-inset-bottom, 0px))
	         calc(var(--s3) + env(safe-area-inset-left, 0px));
	background: linear-gradient(to top, rgba(10, 6, 9, 0.86), rgba(10, 6, 9, 0));
}
.slideshow__caption {
	margin: 0;
	text-align: center;
	font-size: var(--t-sm);
	color: rgba(255, 255, 255, 0.88);
}
.slideshow__controls { display: flex; align-items: center; gap: var(--s4); }

/* One shape for every control on the overlay, at the 44px a finger needs
   whatever the pointer turns out to be. */
.slideshow__icon {
	flex-shrink: 0;
	width: 44px;
	height: 44px;
	border-radius: 50%;
	border: 1px solid rgba(255, 255, 255, 0.32);
	background: rgba(18, 10, 16, 0.45);
	backdrop-filter: blur(4px);
	color: #fff;
	display: flex;
	align-items: center;
	justify-content: center;
	transition: background-color 0.15s var(--ease), border-color 0.15s var(--ease);
}
.slideshow__icon:hover, .slideshow__icon:focus-visible {
	background: rgba(255, 255, 255, 0.22);
	border-color: #fff;
}

.slideshow__step {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	z-index: 2;
}
.slideshow__step--prev { left: calc(var(--s3) + env(safe-area-inset-left, 0px)); }
.slideshow__step--next { right: calc(var(--s3) + env(safe-area-inset-right, 0px)); }

/* How long is left on this photograph. Decoration, so it is hidden from
   assistive technology and from anyone who asked for less movement. */
.slideshow__meter {
	flex: 1 1 auto;
	height: 3px;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.24);
	overflow: hidden;
}
.slideshow__meter > span {
	display: block;
	height: 100%;
	width: 0;
	background: var(--hue-gold);
}

/* A phone held upright: the picture wants every pixel of the width, so the
   side steps stand down and a thumb moves the reel instead. */
@media (max-width: 575.98px) {
	.slideshow__step { display: none; }
}

/* A phone turned on its side. There is barely any height to spend, so the
   gradients pull in and the chrome sits as close to the edges as it can. */
@media (max-height: 480px) {
	.slideshow__bar  { padding-bottom: var(--s6); }
	.slideshow__foot { padding-top: var(--s6); gap: var(--s2); }
	.slideshow__album { font-size: var(--t-base); }
	.slideshow__caption { font-size: var(--t-xs); }
}

@media (prefers-reduced-motion: reduce) {
	.slideshow__stage img { opacity: 1; }
	.slideshow__meter { visibility: hidden; }
}

/* ---------------------------------------------------------------------------
   14. Contact details
   --------------------------------------------------------------------------- */
.contactline { display: flex; gap: var(--s4); align-items: flex-start; padding: var(--s4) 0; border-bottom: 1px solid var(--rule); }
.contactline:last-child { border-bottom: 0; }
.contactline__icon {
	flex-shrink: 0;
	width: 40px; height: 40px;
	border-radius: var(--radius);
	display: flex; align-items: center; justify-content: center;
	background: var(--plum-wash);
	color: var(--plum);
}
/* The label names the line and the value answers it, so they stack rather than
   running together as one sentence. */
.contactline__label {
	display: block;
	font-size: var(--t-xs);
	font-weight: 700;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--ink-3);
	margin: 0 0 2px;
}
.contactline__value { display: block; font-size: var(--t-base); color: var(--ink); margin: 0; }

/* ---------------------------------------------------------------------------
   15. Footer
   --------------------------------------------------------------------------- */
.sitefooter {
	background: var(--ink);
	color: rgba(255, 255, 255, 0.62);
	padding-top: var(--s8);
	padding-bottom: var(--s5);
	font-size: var(--t-sm);
}
.sitefooter h4, .sitefooter h5 { color: #fff; }
.sitefooter__mark { font-family: var(--display); font-size: var(--t-lg); font-weight: 600; color: #fff; margin: 0 0 var(--s3); }
.sitefooter__head {
	font-family: var(--body);
	font-size: var(--t-xs);
	font-weight: 700;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.5);
	margin: 0 0 var(--s4);
}
.sitefooter a { color: rgba(255, 255, 255, 0.78); }
.sitefooter a:hover { color: #fff; }
.sitefooter ul { list-style: none; margin: 0; padding: 0; }
.sitefooter li { padding: var(--s1) 0; }
.sitefooter__where { font-style: normal; margin: 0; color: rgba(255, 255, 255, 0.55); }
.sitefooter__rule { border: 0; border-top: 1px solid rgba(255, 255, 255, 0.12); margin: var(--s6) 0 var(--s4); }
/* 0.45 white measured close to the floor against the footer's ink. */
.sitefooter__fine { font-size: var(--t-xs); color: rgba(255, 255, 255, 0.62); }

/* ---------------------------------------------------------------------------
   16. Narrow screens
   --------------------------------------------------------------------------- */
@media (max-width: 991.98px) {
	:root { --s9: 4rem; --s8: 3rem; }

	.siteheader .navbar-collapse {
		padding: var(--s4) 0 var(--s2);
		border-top: 1px solid var(--rule);
		margin-top: var(--s3);
	}
	.sitenav .nav-link { padding: var(--s3) var(--s2); }
	.sitenav .nav-link.is-current::after { left: var(--s2); right: auto; width: 22px; }
	.siteheader .navbar-collapse .btn { width: 100%; margin-top: var(--s3); }

	.hero .carousel-item { height: clamp(420px, 62vh, 540px); }
	.hero__caption { text-align: left; }
}

@media (max-width: 575.98px) {
	.container { padding-left: var(--s4); padding-right: var(--s4); }

	/* A Bootstrap row pulls itself outwards by half its gutter. At g-5 that is
	   24px a side, wider than the container's padding on a phone, so the grid
	   hung 8px past the screen. Capping the gutter keeps every row inside its
	   container instead of relying on the body to clip the overspill. */
	.row { --bs-gutter-x: 1.5rem; }
	.hero .carousel-item { height: 78vh; min-height: 400px; }
	.hero__title { font-size: clamp(2rem, 9vw, 2.6rem); }
	.hero .carousel-control-prev, .hero .carousel-control-next { display: none; }
	.tile { padding: var(--s4); }
	.celebrate { padding: var(--s5) var(--s4); }
}
