/**
 * 1020 Events Core — structural styles.
 *
 * Intentionally brand-neutral. Everything colour/type related reads from custom
 * properties, so once brand direction is signed off you set these four or five values
 * once (in Beaver Builder > Global Styles, or a child theme) and every block follows.
 *
 * Cosmetics (colour, type, padding, radius) are intentionally low-specificity so Beaver
 * Builder and the theme can override them freely.
 *
 * Layout is not. See the STRUCTURAL LOCK block at the bottom of this file — the theme's
 * global button/input rules would otherwise dismantle the filter bar.
 */

:root {
	--tt-ink:        #16181c;
	--tt-muted:      #5f6672;
	--tt-line:       #e2e5ea;
	--tt-surface:    #ffffff;
	--tt-surface-2:  #f6f7f9;
	--tt-accent:     #16181c; /* replace with 1020 primary */
	--tt-accent-ink: #ffffff;
	--tt-radius:     6px;
	--tt-gap:        1.25rem;
	--tt-shadow:     0 1px 2px rgba( 16, 20, 28, .06 ), 0 4px 12px rgba( 16, 20, 28, .04 );
	--tt-shadow-lift:0 2px 4px rgba( 16, 20, 28, .07 ), 0 12px 28px rgba( 16, 20, 28, .10 );

	/* Motion. One easing curve and three durations for the whole component - shared values
	   are what make separate interactions feel like one system rather than several. */
	--tt-ease:   cubic-bezier( .2, .8, .2, 1 );  /* fast out, gentle settle */
	--tt-ease-in:cubic-bezier( .4, 0, .6, 1 );   /* for things leaving */
	--tt-fast:   120ms;
	--tt-base:   200ms;
	--tt-slow:   340ms;
}

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

.tt-btn {
	display: inline-block;
	padding: .7em 1.35em;
	border: 1.5px solid var( --tt-accent );
	border-radius: var( --tt-radius );
	background: var( --tt-accent );
	color: var( --tt-accent-ink );
	font-size: .8125rem;
	font-weight: 600;
	letter-spacing: .04em;
	text-transform: uppercase;
	text-decoration: none;
	line-height: 1.2;
	text-align: center;
	transition: opacity .15s ease, background-color .15s ease, color .15s ease;
}

.tt-btn:hover,
.tt-btn:focus { opacity: .85; color: var( --tt-accent-ink ); }

.tt-btn--ghost {
	background: transparent;
	color: var( --tt-accent );
}

.tt-btn--ghost:hover,
.tt-btn--ghost:focus {
	background: var( --tt-accent );
	color: var( --tt-accent-ink );
	opacity: 1;
}

.tt-btn--lg { padding: 1em 2.25em; font-size: .9375rem; }

.tt-chip {
	display: inline-block;
	padding: .35em .8em;
	border: 1px solid var( --tt-line );
	border-radius: 99px;
	background: var( --tt-surface );
	color: var( --tt-muted );
	font-size: .6875rem;
	font-weight: 600;
	letter-spacing: .04em;
	text-transform: uppercase;
	line-height: 1.3;
	white-space: nowrap;
}

.tt-chip--series { border-style: dashed; }
.tt-chip--past   { opacity: .7; }

button.tt-chip { cursor: pointer; font-family: inherit; }

/* Filter chips and view toggles are the same pill, styled by button.tt-chip above.
   Declared explicitly so the JS hooks are visible in the stylesheet too. */
.tt-chip--filter,
.tt-view { user-select: none; }

.tt-chip--filter:focus-visible,
.tt-view:focus-visible { outline: 2px solid var( --tt-accent ); outline-offset: 2px; }

button.tt-chip.is-on,
button.tt-chip[aria-pressed="true"] {
	background: var( --tt-accent );
	border-color: var( --tt-accent );
	color: var( --tt-accent-ink );
}

/* ---------------------------------------------------------- status badge */

/*
 * Four states, styled as genuinely distinct signals rather than four grey pills. This is
 * the element that makes a schedule read as live rather than archival, so the colours are
 * the one place in this file that is NOT brand-neutral - they need to stay semantic
 * (green = go, amber = caution, grey = done) even after brand is applied.
 */
.tt-status {
	display: inline-flex;
	align-items: center;
	gap: .45em;
	padding: .35em .8em;
	border-radius: 99px;
	font-size: .6875rem;
	font-weight: 700;
	letter-spacing: .05em;
	text-transform: uppercase;
	line-height: 1.3;
	white-space: nowrap;
}

.tt-status__dot {
	width: .5em;
	height: .5em;
	border-radius: 99px;
	background: currentColor;
	flex: none;
}

.tt-status--open        { background: #e7f6ec; color: #12683a; }
.tt-status--waitlist    { background: #fdf3e0; color: #8a5a00; }
.tt-status--closed      { background: #fdeaea; color: #96201d; }
.tt-status--coming-soon { background: var( --tt-surface-2 ); color: var( --tt-muted ); }
.tt-status--complete    { background: var( --tt-surface-2 ); color: var( --tt-muted ); }

/* --- on a photographic hero -------------------------------------------------
 *
 * The pale-tint-plus-dark-text pair is right on a white card and wrong on a dark hero: the
 * pill stays pale, and any inherited white text on top of it disappears. Inverted here to a
 * saturated fill with white text, which reads on photography and keeps the signal.
 *
 * The fills are the same hues as the text colours above, so green still means open. Each is
 * dark enough for white text to clear 4.5:1 on its own, independent of whatever is behind it.
 * The hairline lifts the pill off a busy photograph without needing a shadow.
 */
.tt-status--on-dark {
	border: 1px solid rgba( 255, 255, 255, .28 );
	color: #fff;
}

.tt-status--on-dark.tt-status--open        { background: #12683a; }
.tt-status--on-dark.tt-status--waitlist    { background: #8a5a00; }
.tt-status--on-dark.tt-status--closed      { background: #96201d; }

/* No hue for the two neutral states, so they read as absence of a signal rather than a
   fourth colour nobody has to learn. */
.tt-status--on-dark.tt-status--coming-soon,
.tt-status--on-dark.tt-status--complete {
	background: rgba( 255, 255, 255, .16 );
	color: #fff;
}

/* Only the live state pulses, and only if the visitor hasn't asked us not to. */
@media ( prefers-reduced-motion: no-preference ) {
	.tt-status--open .tt-status__dot { animation: tt-pulse 2.4s ease-in-out infinite; }
}

@keyframes tt-pulse {
	0%, 100% { opacity: 1; }
	50%      { opacity: .35; }
}

.tt-pending {
	display: inline-block;
	font-size: .8125rem;
	color: var( --tt-muted );
	font-style: italic;
}

/* Visually-hidden label text. Named to match core so themes style it consistently. */
.screen-reader-text {
	position: absolute !important;
	width: 1px; height: 1px;
	margin: -1px; padding: 0;
	overflow: hidden;
	clip: rect( 0 0 0 0 );
	white-space: nowrap;
	border: 0;
}

/* ---------------------------------------------------------------- info bar */

.tt-infobar {
	display: grid;
	grid-template-columns: repeat( 4, minmax( 0, 1fr ) );
	gap: var( --tt-gap );
	padding: 1.15rem 0;
	border-top: 1px solid var( --tt-line );
	border-bottom: 1px solid var( --tt-line );
}

.tt-infobar__cell { display: flex; flex-direction: column; gap: .3rem; min-width: 0; }

.tt-infobar__label {
	font-size: .6875rem;
	font-weight: 700;
	letter-spacing: .1em;
	text-transform: uppercase;
	color: var( --tt-muted );
}

.tt-infobar__value {
	font-size: 1rem;
	font-weight: 600;
	color: var( --tt-ink );
	line-height: 1.35;
}

/* -------------------------------------------------------------- value props */

/* ------------------------------------------------------- blocks 05/06 value props
 *
 * Replaces the .tt-props / .tt-prop rules (was tt-core.css lines 202-212).
 *
 * Three layouts share one grid. The heading rule is the block's only ornament and it does
 * real work: it separates a condensed all-caps heading from body copy set in a different
 * face, which without a divider read as one run-on block.
 *
 * The heading scale is set here rather than inherited. The theme's h3 is a display face at
 * display size, which is right for a section title and far too loud for three parallel
 * sub-headings. clamp() keeps it proportional without a media query per breakpoint.
 */

.tt-props {
	display: grid;
	gap: var( --tt-gap );
}

.tt-cols-2 { grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); }
.tt-cols-3 { grid-template-columns: repeat( 3, minmax( 0, 1fr ) ); }
.tt-cols-4 { grid-template-columns: repeat( 4, minmax( 0, 1fr ) ); }

/* Photo bands need air between columns; inline marks do not. */
.tt-props--media { gap: calc( var( --tt-gap ) * 1.6 ) var( --tt-gap ); }

.tt-prop {
	display: flex;
	flex-direction: column;
	gap: 1rem;
	min-width: 0;
}

.tt-prop__body { min-width: 0; }

/* ---------------------------------------------------------------- media layout */

.tt-prop__media {
	position: relative;
	overflow: hidden;
	border-radius: var( --tt-radius );
	background: var( --tt-surface-2 );
	/* aspect-ratio holds the space before the image decodes, so the headings below stay
	   on a common baseline instead of shunting down one column at a time. */
	aspect-ratio: 4 / 3;
}

.tt-prop__img {
	display: block;
	width: 100%;
	height: 100%;
	/* cover, not contain: these are photographs and letterboxing them looks broken.
	   Focal point sits slightly above centre - action shots put the subject high. */
	object-fit: cover;
	object-position: 50% 40%;
}

/* ----------------------------------------------------------------- mark layout */

.tt-props--mark .tt-prop {
	flex-direction: row;
	gap: .9rem;
	/* Optical alignment. A mark beside a heading should sit on the heading's cap height,
	   not the top of its line box, so nudge it down by the leading's half-gap. */
	align-items: flex-start;
}

.tt-prop__mark {
	flex: 0 0 auto;
	width: 44px;
	height: 44px;
	object-fit: contain;
	margin-top: .1em;
}

/* ----------------------------------------------------------------------- type */

.tt-prop__heading {
	margin: 0 0 .55rem;
	font-size: clamp( 1.0625rem, .95rem + .45vw, 1.375rem );
	line-height: 1.15;
	/* Condensed display faces need a touch of tracking at this size or the counters close
	   up. Harmless on a neutral face. */
	letter-spacing: .01em;
	text-wrap: balance;
}

/* The rule. Spans the heading only, keys to the accent, and marks where the label ends
   and the argument begins. */
.tt-prop__heading::after {
	content: "";
	display: block;
	width: 2.25rem;
	height: 2px;
	margin-top: .55rem;
	/* currentColor, not --tt-accent. On the dark section in the screenshot the accent
	   resolves close to the background and the rule disappears; currentColor inherits the
	   heading colour, so it is contrasting by definition on any section treatment. */
	background: currentColor;
	opacity: .5;
}

/* Bare layout has no image, so the rule carries more weight. Give it more presence and
   put it above the heading, where it reads as a marker rather than an underline. */
.tt-props--bare .tt-prop__heading::after { display: none; }

.tt-props--bare .tt-prop {
	border-top: 2px solid currentColor;
	padding-top: .9rem;
}

.tt-prop__copy {
	color: var( --tt-muted );
	/* Measure. Three columns of unrestricted copy at desktop width run past the point
	   where the eye tracks a line reliably. */
	max-width: 34ch;
}

.tt-prop__copy p { margin: 0 0 .6em; }
.tt-prop__copy p:last-child { margin-bottom: 0; }

/* ----------------------------------------------------------------- responsive */

@media ( max-width: 1024px ) {
	/* Four photo bands never survive tablet width. */
	.tt-props--media.tt-cols-4 { grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); }
}

@media ( max-width: 600px ) {
	.tt-props--media,
	.tt-props--mark,
	.tt-props--bare { grid-template-columns: minmax( 0, 1fr ); }

	/* Single column: the photo band gets wider than it is useful at 4:3, so flatten it. */
	.tt-prop__media { aspect-ratio: 16 / 9; }

	/* Marks stay beside the heading on mobile - stacking them wastes the vertical space
	   that matters most here. This overrides the old `.tt-prop { flex-direction: column }`
	   rule at tt-core.css line 831, which should be deleted. */
	.tt-props--mark .tt-prop { flex-direction: row; }

	.tt-prop__copy { max-width: none; }
}

@media ( prefers-reduced-motion: no-preference ) {
	.tt-prop__img { transition: transform var( --tt-slow ) var( --tt-ease ); }
	.tt-prop:hover .tt-prop__img { transform: scale( 1.03 ); }
}

/* ------------------------------------------------------------------ venues */

.tt-venues { display: grid; gap: 2.25rem; }

/* Even halves. The map is the anchor and the details beside it are short, so an uneven split
   only makes the text column too wide to read comfortably. */
.tt-venue {
	display: grid;
	grid-template-columns: repeat( 2, minmax( 0, 1fr ) );
	gap: var( --tt-gap );
	/* Centred, not top-aligned. The details block is much shorter than the map, and pinning it
	   to the top leaves it floating against a tall empty column. */
	align-items: center;
}

/* No map, no split. Covers venues that are still to be announced. */
.tt-venue--nomap { grid-template-columns: minmax( 0, 1fr ); }

.tt-venue__info { min-width: 0; }
.tt-venue__name { margin: 0 0 .35rem; font-size: 1.125rem; }
.tt-venue__address { margin: 0 0 .9rem; color: var( --tt-muted ); }
.tt-venue__actions { display: flex; flex-wrap: wrap; gap: .5rem; }

.tt-venue__map {
	position: relative;
	/* 4:3 rather than 16:10. A map is read in two dimensions, and a letterbox crop shows a
	   corridor of road either side of the pin instead of the area around it. */
	aspect-ratio: 4 / 3;
	border: 1px solid var( --tt-line );
	border-radius: var( --tt-radius );
	overflow: hidden;
	background: var( --tt-surface-2 );
}

.tt-venue__map iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* ------------------------------------------------- travel: fee / air / hotels */

.tt-travel {
	display: grid;
	grid-template-columns: repeat( 3, minmax( 0, 1fr ) );
	gap: var( --tt-gap );
	align-items: start;
}

.tt-travel__item { min-width: 0; }
.tt-travel__item--wide { grid-column: 1 / -1; }

.tt-travel__label {
	margin: 0 0 .4rem;
	font-size: .6875rem;
	font-weight: 700;
	letter-spacing: .1em;
	text-transform: uppercase;
	color: var( --tt-muted );
}

.tt-travel__value { margin: 0; }
.tt-travel__value p:last-child { margin-bottom: 0; }

.tt-hotels {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat( 2, minmax( 0, 1fr ) );
	gap: .6rem;
}

.tt-hotel {
	display: flex;
	flex-direction: column;
	gap: .2rem;
	padding: .85rem 1rem;
	border: 1px solid var( --tt-line );
	border-radius: var( --tt-radius );
	background: var( --tt-surface );
}

.tt-hotel__name { font-weight: 600; }
.tt-hotel__loc  { font-size: .8125rem; color: var( --tt-muted ); }

/* ================================================================== schedule

   Two layouts. Both put the image on the left.

   SHOWCASE — one row per day, image left, copy right. Not an accordion any more: a
   three-day programme is the thing being sold, and hiding two thirds of it behind a
   click was the wrong default. Days are always open.

   TOURNAMENT — a supporting image beside the link or the coming-soon note.
   ========================================================================== */

.tt-days { display: grid; gap: 1.5rem; }

.tt-day {
	display: grid;
	grid-template-columns: minmax( 0, 0.85fr ) minmax( 0, 1.15fr );
	gap: 0;
	border: 1px solid var( --tt-line );
	border-radius: var( --tt-radius );
	background: var( --tt-surface );
	overflow: hidden;
}

/* No image on this day: one column, and the copy gets the full width. */
.tt-day--noimg { grid-template-columns: minmax( 0, 1fr ); }

.tt-day__media {
	position: relative;
	background: var( --tt-media );
	min-height: 260px;
}

.tt-day__img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Step number over the image, so the sequence reads before the words do. */
.tt-day__step {
	position: absolute;
	top: 14px;
	left: 16px;
	font-size: 2.25rem;
	font-weight: 800;
	line-height: 1;
	letter-spacing: -.03em;
	color: #fff;
	text-shadow: 0 2px 12px rgba( 0, 0, 0, .5 );
}

.tt-day__step--inline {
	position: static;
	display: block;
	color: var( --tt-line );
	text-shadow: none;
	margin-bottom: .5rem;
}

.tt-day__body { padding: 1.9rem 2rem; align-self: center; }

.tt-day__label {
	display: block;
	font-size: .6875rem;
	font-weight: 700;
	letter-spacing: .11em;
	text-transform: uppercase;
	color: var( --tt-muted );
	margin-bottom: .55rem;
}

.tt-day__theme { margin: 0 0 .8rem; font-size: 1.4375rem; line-height: 1.15; }
.tt-day__copy { color: var( --tt-muted ); font-size: .9375rem; }
.tt-day__copy p:last-child { margin-bottom: 0; }
.tt-day__tags { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: 1.1rem; }

/* Single-day showcase: nothing to sequence, so drop the number. */
.tt-days--single .tt-day__step { display: none; }

/* --- tournament --- */

.tt-sched {
	display: grid;
	grid-template-columns: minmax( 0, 1fr ) minmax( 0, 1fr );
	border: 1px solid var( --tt-line );
	border-radius: var( --tt-radius );
	background: var( --tt-surface );
	overflow: hidden;
}

.tt-sched--noimg { grid-template-columns: minmax( 0, 1fr ); background: var( --tt-surface-2 ); }

.tt-sched__media { background: var( --tt-media ); min-height: 230px; }

.tt-sched__img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.tt-sched__body {
	padding: 2rem 2.25rem;
	align-self: center;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 1.1rem;
}

.tt-sched--noimg .tt-sched__body { align-items: center; text-align: center; }

.tt-sched__note {
	margin: 0;
	color: var( --tt-muted );
	font-size: 1rem;
	max-width: 46ch;
}

@media ( prefers-reduced-motion: no-preference ) {
	.tt-day__img,
	.tt-sched__img { transition: transform var( --tt-slow ) var( --tt-ease ); }
	.tt-day:hover .tt-day__img { transform: scale( 1.03 ); }
}

/* ----------------------------------------------------------------- results */

.tt-results { display: grid; gap: 1.75rem; }
.tt-results__year { display: block; }
.tt-results__heading { margin: 0 0 .8rem; font-size: 1.125rem; }
.tt-results__grid { display: grid; grid-template-columns: repeat( 3, minmax( 0, 1fr ) ); gap: .75rem; }

.tt-result {
	display: flex;
	flex-direction: column;
	gap: .3rem;
	padding: .9rem 1rem;
	border: 1px solid var( --tt-line );
	border-radius: var( --tt-radius );
	background: var( --tt-surface );
}

.tt-result__division {
	font-size: .6875rem;
	font-weight: 700;
	letter-spacing: .08em;
	text-transform: uppercase;
	color: var( --tt-muted );
}

.tt-result__champion { font-weight: 600; }

/* ------------------------------------------------------------------- staff */

.tt-staff { display: grid; grid-template-columns: repeat( 4, minmax( 0, 1fr ) ); gap: var( --tt-gap ); }

.tt-person {
	border: 1px solid var( --tt-line );
	border-radius: var( --tt-radius );
	background: var( --tt-surface );
	overflow: hidden;
}

.tt-person__photo { display: block; width: 100%; height: auto; aspect-ratio: 4 / 5; object-fit: cover; }
.tt-person__photo--placeholder { background: var( --tt-surface-2 ); }
.tt-person__body { padding: .9rem 1rem 1.1rem; }
.tt-person__name { margin: 0 0 .2rem; font-size: 1rem; }
.tt-person__title { margin: 0 0 .35rem; font-size: .8125rem; font-weight: 600; color: var( --tt-muted ); }
.tt-person__cred { margin: 0; font-size: .8125rem; color: var( --tt-muted ); }

/* --------------------------------------------------------------- links hub */

.tt-links { display: grid; gap: var( --tt-gap ); grid-template-columns: repeat( 3, minmax( 0, 1fr ) ); }
.tt-links--1 { grid-template-columns: minmax( 0, 1fr ); }
.tt-links--2 { grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); }

.tt-links__col {
	padding: 1.25rem;
	border: 1px solid var( --tt-line );
	border-radius: var( --tt-radius );
	background: var( --tt-surface );
}

.tt-links__heading {
	margin: 0 0 .9rem;
	font-size: .6875rem;
	font-weight: 700;
	letter-spacing: .1em;
	text-transform: uppercase;
	color: var( --tt-muted );
}

.tt-links__list { list-style: none; margin: 0; padding: 0; display: grid; gap: .55rem; }
.tt-links__list li { margin: 0; }
.tt-links__list .tt-btn { display: block; width: 100%; }

/* ------------------------------------------------------------- register CTA */

.tt-register { display: flex; flex-wrap: wrap; gap: .75rem; justify-content: center; }
.tt-register--split .tt-btn { flex: 0 1 auto; }

/* ---------------------------------------------------------------- sponsors */

.tt-sponsors {
	display: grid;
	grid-template-columns: repeat( 6, minmax( 0, 1fr ) );
	gap: var( --tt-gap );
	align-items: center;
}

.tt-sponsor { display: flex; align-items: center; justify-content: center; }

.tt-sponsor__logo {
	max-width: 100%;
	height: auto;
	max-height: 60px;
	width: auto;
	object-fit: contain;
	filter: grayscale( 1 );
	opacity: .75;
	transition: filter .2s ease, opacity .2s ease;
}

.tt-sponsor:hover .tt-sponsor__logo { filter: none; opacity: 1; }

/* ------------------------------------------------------------------ quotes */

.tt-quotes { display: grid; gap: var( --tt-gap ); }

.tt-quote {
	margin: 0;
	padding: 1.4rem 1.5rem;
	border: 1px solid var( --tt-line );
	border-radius: var( --tt-radius );
	background: var( --tt-surface );
	box-shadow: var( --tt-shadow );
}

.tt-quote__body { color: var( --tt-ink ); }
.tt-quote__body p:last-child { margin-bottom: 0; }

.tt-quote__meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: .6rem;
	margin-top: 1rem;
}

.tt-quote__cite { font-size: .8125rem; font-weight: 600; font-style: normal; color: var( --tt-muted ); }

/* -------------------------------------------------------------------- FAQs */

.tt-faqs { display: grid; gap: .5rem; }
/* Chips and search share one tools row. Chips wrap and take the space they need; the search
   box takes what is left, down to a floor where it stops being usable and drops to its own
   line. */
.tt-faqs__tools {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: .5rem .75rem;
	margin-bottom: .9rem;
}

/* Visuals come from .tt-chip--filter above. This class is only a JS hook, declared so it is
   visible in the stylesheet rather than existing solely in the script. */
.tt-faqs__chip { }

.tt-faqs__filters {
	display: flex;
	flex-wrap: wrap;
	gap: .4rem;
}

.tt-faqs__n {
	font-variant-numeric: tabular-nums;
	opacity: .55;
	font-size: .875em;
	margin-left: .15em;
}

.tt-faqs__tools .tt-faqs__search { flex: 1 1 220px; min-width: 0; }

@media ( max-width: 600px ) {
	/* Search above the chips on a phone: it is the faster route when the chip row would
	   otherwise push it below the fold. */
	.tt-faqs__tools { flex-direction: column; align-items: stretch; }
	.tt-faqs__tools .tt-faqs__search { order: -1; }
}

.tt-faqs__search {
	width: 100%;
	max-width: 320px;
	padding: .65em .9em;
	border: 1px solid var( --tt-line );
	border-radius: var( --tt-radius );
	font: inherit;
	font-size: .9375rem;
}

.tt-faqs__empty { margin: 0 0 .5rem; color: var( --tt-muted ); }

.tt-faq {
	border: 1px solid var( --tt-line );
	border-radius: var( --tt-radius );
	background: var( --tt-surface );
	overflow: hidden;
}

.tt-faq__q {
	padding: 1rem 1.15rem;
	cursor: pointer;
	font-weight: 600;
	list-style: none;
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: 1rem;
}

.tt-faq__q::-webkit-details-marker { display: none; }
.tt-faq__q::after { content: "+"; color: var( --tt-muted ); font-weight: 400; font-size: 1.25rem; line-height: 1; flex: none; }
.tt-faq[open] .tt-faq__q::after { content: "\2212"; }

.tt-faq__a { padding: 0 1.15rem 1.2rem; color: var( --tt-muted ); }
.tt-faq__a p:last-child { margin-bottom: 0; }

/* ------------------------------------------------------------- series card */

.tt-series {
	padding: 1.4rem 1.5rem;
	border: 1px solid var( --tt-line );
	border-radius: var( --tt-radius );
	background: var( --tt-surface-2 );
}

.tt-series__name { margin: 0 0 .6rem; font-size: 1.0625rem; }
.tt-series__copy { color: var( --tt-muted ); font-size: .9375rem; }
.tt-series__copy p:last-child { margin-bottom: .9rem; }

/* ------------------------------------------------------------------- stats */

.tt-stats { display: grid; grid-template-columns: repeat( 4, minmax( 0, 1fr ) ); gap: var( --tt-gap ); }
.tt-stat { display: flex; flex-direction: column; align-items: center; gap: .3rem; text-align: center; }
.tt-stat__figure { font-size: clamp( 2rem, 4vw, 3rem ); font-weight: 700; line-height: 1; }
.tt-stat__label { font-size: .8125rem; letter-spacing: .04em; text-transform: uppercase; color: var( --tt-muted ); }

/* =========================================================== event index */

.tt-filters { display: grid; gap: .9rem; margin-bottom: 1.5rem; }
.tt-filters__chips { display: flex; flex-wrap: wrap; gap: .5rem; }
.tt-filters__row { display: flex; flex-wrap: wrap; gap: .6rem; align-items: center; }
.tt-filters__search { flex: 1 1 240px; min-width: 0; }
.tt-filters__select { flex: 0 1 auto; }

/* --- top bar: search · Filters button · sort · view ---------------------- */

.tt-fbar { display: flex; flex-wrap: wrap; gap: .6rem; align-items: center; }
.tt-fbar__search { flex: 1 1 260px; min-width: 0; }

.tt-fbtn {
	display: inline-flex;
	align-items: center;
	gap: .5em;
	padding: .6em 1.1em;
	border: 1px solid var( --tt-line );
	border-radius: var( --tt-radius );
	background: var( --tt-surface );
	color: var( --tt-ink );
	font: inherit;
	font-size: .875rem;
	cursor: pointer;
	white-space: nowrap;
}

.tt-fbtn[aria-expanded="true"] {
	background: var( --tt-accent );
	border-color: var( --tt-accent );
	color: var( --tt-accent-ink );
}

.tt-fbtn:focus-visible { outline: 2px solid var( --tt-accent ); outline-offset: 2px; }

/* Count badge: hidden at zero so it isn't visual noise on first load. */
.tt-fcount {
	display: none;
	min-width: 1.5em;
	height: 1.5em;
	padding: 0 .4em;
	border-radius: 99px;
	background: var( --tt-accent );
	color: var( --tt-accent-ink );
	font-size: 11px;
	font-weight: 700;
	align-items: center;
	justify-content: center;
	line-height: 1;
}

.tt-fcount.is-on { display: inline-flex; }
.tt-fbtn[aria-expanded="true"] .tt-fcount { background: var( --tt-accent-ink ); color: var( --tt-accent ); }

/* --- drawer: series · grad year · state ---------------------------------- */

.tt-drawer {
	padding: 20px;
	border: 1px solid var( --tt-line );
	border-radius: var( --tt-radius );
	background: var( --tt-surface-2 );
	/* Required for the height animation to clip rather than overflow mid-transition. */
	overflow: hidden;
}

.tt-drawer[hidden] { display: none; }

.tt-drawer__grid { display: grid; grid-template-columns: repeat( 3, minmax( 0, 1fr ) ); gap: 22px; }

.tt-dgroup__title {
	margin: 0 0 .6rem;
	font-size: .6875rem;
	font-weight: 700;
	letter-spacing: .1em;
	text-transform: uppercase;
	color: var( --tt-muted );
}

.tt-dgroup .tt-filters__select { display: block; }
.tt-dgroup select { width: 100%; }

.tt-fchk {
	display: flex;
	gap: .5em;
	align-items: center;
	margin-bottom: .35rem;
	font-size: .875rem;
	cursor: pointer;
}

.tt-drawer__foot {
	display: flex;
	gap: .6rem;
	align-items: center;
	justify-content: flex-end;
	margin-top: 18px;
	padding-top: 16px;
	border-top: 1px solid var( --tt-line );
}

.tt-clear {
	padding: 0;
	border: 0;
	background: none;
	font: inherit;
	font-size: .8125rem;
	color: var( --tt-muted );
	text-decoration: underline;
	cursor: pointer;
}

.tt-clear:hover { color: var( --tt-ink ); }

.tt-index__search,
.tt-filters__select select {
	width: 100%;
	padding: .6em .85em;
	border: 1px solid var( --tt-line );
	border-radius: var( --tt-radius );
	background: var( --tt-surface );
	font: inherit;
	font-size: .875rem;
	color: var( --tt-ink );
}

.tt-filters__views { display: flex; gap: .4rem; margin-left: auto; }

.tt-index__meta { margin-bottom: .9rem; }
.tt-index__count { font-size: .8125rem; letter-spacing: .04em; text-transform: uppercase; color: var( --tt-muted ); }

.tt-index__none {
	padding: 2.5rem 1.5rem;
	border: 1px dashed var( --tt-line );
	border-radius: var( --tt-radius );
	background: var( --tt-surface-2 );
	text-align: center;
}

.tt-index__reset { cursor: pointer; font-family: inherit; }
.tt-index__none h3 { margin: 0 0 .5rem; }
.tt-index__none p { margin: 0 0 1.1rem; color: var( --tt-muted ); }
.tt-index__empty { color: var( --tt-muted ); }

/* --- shared card ------------------------------------------------------- */

.tt-index__results { display: grid; gap: .75rem; }

.tt-card {
	border: 1px solid var( --tt-line );
	border-radius: var( --tt-radius );
	background: var( --tt-surface );
	overflow: hidden;
}

/* ---------------------------------------------------------- card media (1.5.1)
 *
 * Replaces the three-line .tt-card__media / .tt-card__logo / --placeholder block.
 *
 * Three layers inside .tt-card__media: the Featured Image, a scrim, then the logo. The scrim
 * direction is decided server-side from the logo's own luminance, because the logos here run
 * from knockout white (WLF, WWLF) to near-black (the 1020 wordmark) and no single treatment
 * serves both.
 */

.tt-card__media {
	display: block;
	position: relative;
	overflow: hidden;
	background: var( --tt-surface-2 );
	/* isolation, so the scrim's blend cannot reach the card's border or the body below. */
	isolation: isolate;
}

/* The photograph. Absolute, so the logo's own box drives the media height in grid view and
   nothing has to hardcode an aspect ratio in two places. */
.tt-card__backdrop {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	/* Sports photography puts the subject above centre. */
	object-position: 50% 38%;
}

.tt-card__scrim {
	position: absolute;
	inset: 0;
	pointer-events: none;
}

/* Light logo, dark scrim. Not flat: a diagonal keeps some of the photograph readable at the
   corners instead of turning it into a grey rectangle. */
.tt-card__media--scrim-dark .tt-card__scrim {
	background:
		linear-gradient( 160deg, rgba( 10, 12, 16, .34 ) 0%, rgba( 10, 12, 16, .68 ) 100% );
}

/* Dark logo, light scrim. Heavier than its dark counterpart because a dark mark needs more
   separation from a busy photograph than a white one does. */
.tt-card__media--scrim-light .tt-card__scrim {
	background:
		linear-gradient( 160deg, rgba( 255, 255, 255, .62 ) 0%, rgba( 255, 255, 255, .86 ) 100% );
}

/* --- optional per-event tint -------------------------------------------------
 *
 * `card_tint` on the event emits --tt-tint on .tt-card__media. When it is absent none of this
 * applies and the defaults below stand.
 *
 * The light and dark ends are derived with color-mix() rather than being stored as two fields.
 * One value cannot disagree with itself, and a director picking a brand colour should not have
 * to reason about where the ramp ends.
 *
 * Mix percentages are matched to the untinted versions so a tinted card and a default card have
 * the same weight in the same row: the gradient runs roughly 78% toward black at the top corner
 * and slightly lifted at the bottom, and the veil runs .34 to .68 alpha exactly as the dark
 * scrim does.
 */

.tt-card__media--tinted.tt-card__media--gradient {
	background:
		radial-gradient( 120% 90% at 50% 42%, rgba( 255, 255, 255, .10 ) 0%, transparent 60% ),
		linear-gradient( 160deg,
			color-mix( in srgb, var( --tt-tint ) 74%, #000 ) 0%,
			color-mix( in srgb, var( --tt-tint ) 88%, #fff ) 100% );
}

/* Over a photograph the tint replaces the veil colour and keeps the alpha ramp, so a light
   brand colour still darkens the image rather than washing it out to nothing. */
.tt-card__media--tinted .tt-card__scrim {
	background:
		linear-gradient( 160deg,
			color-mix( in srgb, var( --tt-tint ) 34%, transparent ) 0%,
			color-mix( in srgb, var( --tt-tint ) 68%, transparent ) 100% );
}

/* A tinted card owns its own treatment, so the measured light-scrim variant must not win over
   it. The two-class selectors above already outrank .tt-card__media--scrim-light on their own;
   this is here so the intent is stated rather than inferred from selector arithmetic. */
.tt-card__media--tinted.tt-card__media--scrim-light .tt-card__logo,
.tt-card__media--tinted.tt-card__media--scrim-dark .tt-card__logo {
	filter: drop-shadow( 0 2px 10px rgba( 0, 0, 0, .4 ) );
}

/* No color-mix support: fall back to the flat tint at a fixed alpha. Less refined, still on
   brand, and nothing disappears. */
@supports not ( background: color-mix( in srgb, red 50%, blue ) ) {
	.tt-card__media--tinted.tt-card__media--gradient { background: var( --tt-tint ); }
	.tt-card__media--tinted .tt-card__scrim { background: var( --tt-tint ); opacity: .55; }
}

/* No Featured Image. Black to grey, on the same diagonal as the scrims so a mixed row of
   cards still reads as one system.

   The subtle radial behind the logo position is what stops it looking like a dead grey box:
   it puts a soft pool of light where the mark sits. */
.tt-card__media.tt-card__media--gradient {
	background:
		radial-gradient( 120% 90% at 50% 42%, rgba( 255, 255, 255, .09 ) 0%, transparent 60% ),
		linear-gradient( 160deg, #101215 0%, #3a3f47 100% );
}

.tt-card__logo {
	display: block;
	position: relative;
	object-fit: contain;
	/* Above backdrop and scrim. */
	z-index: 1;
}

/* A logo on a photograph needs a shadow or it looks pasted on. Direction matches the scrim:
   a white mark casts dark, a dark mark casts light. */
.tt-card__media--scrim-dark .tt-card__logo {
	filter: drop-shadow( 0 2px 10px rgba( 0, 0, 0, .45 ) );
}

.tt-card__media--scrim-light .tt-card__logo {
	filter: drop-shadow( 0 2px 10px rgba( 255, 255, 255, .7 ) );
}

.tt-card__media--gradient .tt-card__logo {
	filter: drop-shadow( 0 2px 12px rgba( 0, 0, 0, .5 ) );
}

/* The placeholder is now only reached when an event has neither a logo nor a photograph. The
   gradient behind it is doing the work, so it just needs to hold the box open. */
.tt-card__logo--placeholder { background: transparent; }

/* --- list view --------------------------------------------------------------
 *
 * Same treatment, smaller box. The list row puts the media in a 96px cell, so the tile becomes
 * a rounded square: photograph cover-cropped, scrim over it, logo inset so the photo reads as
 * a frame rather than being completely covered by the mark.
 *
 * 96px rather than 72px. At 72 the mark was smaller than the event title beside it, which put
 * the weakest identifier in the row where the strongest should be. 96 is the point where a
 * detailed crest like Pacific Elite becomes legible rather than just a dark shape, and it still
 * fits the row height set by two lines of title plus the chips.
 */

.tt-index__results--list .tt-card__media {
	border-radius: calc( var( --tt-radius ) - 1px );
	/* The cell is 96px wide and the logo rule below sets the height, so the tile is square. */
	width: 96px;
}

.tt-index__results--list .tt-card__logo {
	padding: 6px;
	box-sizing: border-box;
}

/* A diagonal gradient across 72px is effectively flat, so the scrims are eased back here.
   At this size the tile only needs enough veil to separate the mark from the photograph. */
.tt-index__results--list .tt-card__media--scrim-dark .tt-card__scrim {
	background: linear-gradient( 160deg, rgba( 10, 12, 16, .42 ) 0%, rgba( 10, 12, 16, .62 ) 100% );
}

.tt-index__results--list .tt-card__media--scrim-light .tt-card__scrim {
	background: linear-gradient( 160deg, rgba( 255, 255, 255, .70 ) 0%, rgba( 255, 255, 255, .88 ) 100% );
}

/* Tinted tiles get the same lift at 96px: a diagonal across a small square is close to flat, so
   the veil needs a touch more weight to separate the mark from the photograph. */
.tt-index__results--list .tt-card__media--tinted .tt-card__scrim {
	background: linear-gradient( 160deg,
		color-mix( in srgb, var( --tt-tint ) 44%, transparent ) 0%,
		color-mix( in srgb, var( --tt-tint ) 74%, transparent ) 100% );
}

/* Shadows are tightened rather than removed. A 10px blur under a 60px mark is a smudge. */
.tt-index__results--list .tt-card__media--scrim-dark .tt-card__logo {
	filter: drop-shadow( 0 1px 4px rgba( 0, 0, 0, .5 ) );
}

.tt-index__results--list .tt-card__media--scrim-light .tt-card__logo {
	filter: drop-shadow( 0 1px 4px rgba( 255, 255, 255, .8 ) );
}

.tt-index__results--list .tt-card__media--gradient .tt-card__logo {
	filter: drop-shadow( 0 1px 5px rgba( 0, 0, 0, .55 ) );
}

/* Reading order in the body is: status → title → venue → chips → blurb.
   Chips sit below the venue so the event NAME is the first large thing in every row. */
.tt-card__chips { display: flex; flex-wrap: wrap; gap: .35rem; margin: .7rem 0 0; }

/* Status reads as an eyebrow above the title, so it needs a tight gap under it. */
.tt-card .tt-status { margin: 0 0 .5rem; }

/* The event name is the primary object on the card - it should be unambiguously the
   biggest thing in the row. clamp() keeps long names like "Pacific Elite Collegiate
   Experience — Girls" from dominating on narrow columns. */
.tt-card__title {
	margin: 0 0 .3rem;
	font-size: clamp( 1.25rem, 1.05rem + .7vw, 1.625rem );
	line-height: 1.15;
	letter-spacing: -.01em;
}

.tt-card__title a { color: inherit; text-decoration: none; }
.tt-card__title a:hover { text-decoration: underline; }

.tt-card__venue { margin: 0; font-size: .9375rem; color: var( --tt-muted ); }
.tt-card__blurb { margin: .55rem 0 0; font-size: .875rem; color: var( --tt-muted ); }

.tt-card__when { display: flex; flex-direction: column; gap: .25rem; }
.tt-card__dates { font-weight: 600; }
.tt-card__divs { font-size: .8125rem; color: var( --tt-muted ); }

.tt-card__actions { display: flex; gap: .5rem; }

/* --- list view --------------------------------------------------------- */

.tt-index__results--list .tt-card {
	display: grid;
	grid-template-columns: 96px minmax( 0, 1fr ) minmax( 0, 190px ) auto;
	gap: 1.1rem;
	align-items: center;
	padding: 1rem 1.15rem;
}

.tt-index__results--list .tt-card__logo { width: 96px; height: 96px; }
.tt-index__results--list .tt-card__blurb { display: none; }
.tt-index__results--list .tt-card__when { text-align: right; }
.tt-index__results--list .tt-card__actions { flex-direction: column; }
.tt-index__results--list .tt-card__actions .tt-btn { white-space: nowrap; }

/* --- grid view --------------------------------------------------------- */

.tt-index__results--grid {
	grid-template-columns: repeat( 3, minmax( 0, 1fr ) );
	gap: var( --tt-gap );
}

.tt-index__results--teaser { grid-template-columns: repeat( 4, minmax( 0, 1fr ) ); }

.tt-index__results--grid .tt-card { display: flex; flex-direction: column; }

/* No media background rule here on purpose.
 *
 * This used to paint surface-2, and the first attempt at fixing it set `background: none`. Both
 * are wrong for the same reason: a view-scoped selector is two classes, the gradient is one, so
 * whatever this rule says wins and the gradient never renders. The media background belongs to
 * .tt-card__media and its modifiers, and nothing view-scoped should touch it.
 *
 * List view is the proof: it has no such rule and the gradient has always worked there. */

.tt-index__results--grid .tt-card__logo {
	width: 100%;
	height: auto;
	aspect-ratio: 16 / 9;
	padding: 1.25rem;
	box-sizing: border-box;
}

.tt-index__results--grid .tt-card__logo--placeholder { aspect-ratio: 16 / 9; }
.tt-index__results--grid .tt-card__body { padding: 1.1rem 1.15rem .35rem; flex: 1 1 auto; }
.tt-index__results--grid .tt-card__when { padding: 0 1.15rem; }
.tt-index__results--grid .tt-card__actions { padding: .9rem 1.15rem 1.15rem; }
.tt-index__results--grid .tt-card__actions .tt-btn { flex: 1 1 0; }

/* --- hiding ------------------------------------------------------------ */

/*
 * These MUST come after the list/grid view rules above. `.tt-card[hidden]` and
 * `.tt-index__results--list .tt-card` are both specificity (0,2,0), so on a tie the
 * later rule wins — put these first and filtering silently stops hiding anything.
 * Extra class prefix here also lifts specificity so the order is not load-bearing.
 */
.tt-index .tt-card[hidden],
.tt-index__results .tt-card[hidden] { display: none; }

.tt-index .tt-index__results[hidden],
.tt-index [hidden] { display: none; }

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

@media ( max-width: 1024px ) {
	.tt-cols-4,
	.tt-staff,
	.tt-index__results--teaser { grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); }

	.tt-sponsors { grid-template-columns: repeat( 4, minmax( 0, 1fr ) ); }
	.tt-index__results--grid { grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); }
	.tt-links { grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); }

	.tt-index__results--list .tt-card {
		grid-template-columns: 76px minmax( 0, 1fr );
		grid-template-areas:
			"logo body"
			"when when"
			"actions actions";
		row-gap: .8rem;
	}

	.tt-index__results--list .tt-card__media  { grid-area: logo; }
	.tt-index__results--list .tt-card__body   { grid-area: body; }
	.tt-index__results--list .tt-card__when   { grid-area: when; text-align: left; }
	.tt-index__results--list .tt-card__actions{ grid-area: actions; flex-direction: row; }
	.tt-index__results--list .tt-card__logo   { width: 76px; height: 76px; padding: 6px; }
	.tt-index__results--list .tt-card__media  { width: 76px; }
	.tt-index__results--list .tt-card__actions .tt-btn { flex: 1 1 0; }
}

@media ( max-width: 782px ) {
	.tt-travel { grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); }
	.tt-hotels { grid-template-columns: minmax( 0, 1fr ); }
	.tt-infobar { grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); row-gap: 1rem; }
	.tt-venue { grid-template-columns: minmax( 0, 1fr ); }
	/* Stacked, the map would otherwise take most of a phone screen before the venue name. */
	.tt-venue__map { aspect-ratio: 16 / 10; }
	.tt-results__grid { grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); }
	.tt-stats { grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); row-gap: 1.6rem; }
	.tt-filters__views { margin-left: 0; }
}

@media ( max-width: 600px ) {
	.tt-cols-2,
	.tt-cols-3,
	.tt-cols-4,
	.tt-quotes,
	.tt-links,
	.tt-staff,
	.tt-results__grid,
	.tt-index__results--grid,
	.tt-index__results--teaser { grid-template-columns: minmax( 0, 1fr ); }

	.tt-sponsors { grid-template-columns: repeat( 3, minmax( 0, 1fr ) ); }
	.tt-infobar  { grid-template-columns: minmax( 0, 1fr ); }
	.tt-travel   { grid-template-columns: minmax( 0, 1fr ); }

	/* Filter chips scroll horizontally rather than stacking into a tall wall. */
	.tt-filters__chips {
		flex-wrap: nowrap;
		overflow-x: auto;
		padding-bottom: .35rem;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none;
	}

	.tt-filters__chips::-webkit-scrollbar { display: none; }
	.tt-filters__select { flex: 1 1 100%; }

	/* Drawer stacks, and the Filters button + sort share a row under the search box. */
	.tt-drawer__grid { grid-template-columns: minmax( 0, 1fr ); }
	.tt-fbar__search { flex: 1 1 100%; }
	.tt-fbar .tt-filters__select { flex: 1 1 auto; }
	.tt-filters__views { margin-left: auto; }
	.tt-drawer__foot { justify-content: space-between; }
}

@media ( max-width: 860px ) {
	.tt-drawer__grid { grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); }
}

/* ==========================================================================
   STRUCTURAL LOCK — keep this block LAST in the file.

   Correcting an earlier mistake. The rest of this stylesheet is deliberately
   low-specificity with no !important, on the theory that the theme and Beaver Builder
   should always be able to override it. That is right for colour, type and spacing. It is
   wrong for layout.

   The Design Shop theme (like most themes) sets global rules on button / input / select —
   typically display, width and margin. Those rules beat a single-class selector, which
   silently destroys the filter bar: buttons stack or vanish, and the count badge that
   should be hidden at zero shows up as "FILTERS 0".

   So: structure is the component's job, cosmetics are the theme's. These rules assert
   only layout primitives — display, width, margin, float, box-sizing — scoped inside
   .tt-index / .tt-card. Colour, font, border-radius and padding are all still fully
   themeable above.

   !important is used sparingly and only where a bare element selector in the theme would
   otherwise win. It is a deliberate trade, not laziness.
   ========================================================================== */

.tt-index,
.tt-index *,
.tt-card,
.tt-card * { box-sizing: border-box; }

/* Neutralise global form-element rules. */
.tt-index button,
.tt-index input,
.tt-index select,
.tt-index label,
.tt-index a.tt-btn {
	width: auto;
	max-width: none;
	margin: 0;
	float: none;
	vertical-align: middle;
	text-align: center;
}

.tt-index button,
.tt-index a.tt-btn {
	display: inline-flex !important;
	align-items: center;
	justify-content: center;
}

.tt-index input[type="search"],
.tt-index select {
	display: block !important;
	width: 100%;
}

.tt-index .tt-fbar__search,
.tt-index .tt-filters__search { display: block; }

/* Containers. */
.tt-index .tt-filters { display: grid !important; }
.tt-index .tt-fbar,
.tt-index .tt-filters__chips,
.tt-index .tt-filters__views,
.tt-index .tt-filters__row,
.tt-index .tt-drawer__foot,
.tt-index .tt-card__chips,
.tt-index .tt-card__actions { display: flex !important; }

.tt-index .tt-drawer__grid { display: grid !important; }
.tt-index .tt-drawer[hidden] { display: none !important; }

.tt-index .tt-fcount { display: none !important; }
.tt-index .tt-fcount.is-on { display: inline-flex !important; }

.tt-index .tt-status { display: inline-flex !important; }
.tt-index .tt-chip { display: inline-block; }
.tt-index button.tt-chip { display: inline-flex !important; }

/* Results + cards. */
.tt-index .tt-index__results { display: grid !important; }
.tt-index .tt-index__results--list .tt-card { display: grid !important; }
.tt-index .tt-index__results--grid .tt-card { display: flex !important; }
.tt-index .tt-card[hidden],
.tt-index .tt-index__results[hidden],
.tt-index .tt-index__none[hidden] { display: none !important; }

.tt-index .tt-card__when,
.tt-index .tt-card__body { display: block; }
.tt-index .tt-index__results--list .tt-card__when { display: flex !important; flex-direction: column; }

/* Images.
   `img { width: 100%; height: auto }` is in almost every theme and would blow a 96px logo
   up to the full column width. Sizes are asserted per view; object-fit keeps a wordmark
   from being cropped to a square. */
.tt-index .tt-card__media { display: block !important; flex: none; }

.tt-index .tt-card__logo {
	max-width: none;
	object-fit: contain;
}

/* The backdrop is absolutely positioned and must fill its box. A theme rule setting
   `max-width` or `height: auto` on img would otherwise letterbox it inside the card. */
.tt-index .tt-card__backdrop {
	position: absolute !important;
	inset: 0;
	width: 100% !important;
	height: 100% !important;
	max-width: none;
	object-fit: cover;
}

.tt-index .tt-index__results--list .tt-card__logo {
	width: 96px !important;
	height: 96px !important;
}

.tt-index .tt-index__results--grid .tt-card__logo {
	width: 100% !important;
	height: auto !important;
	aspect-ratio: 16 / 9;
	padding: 1.25rem;
}

/* The placeholder must stay transparent so the gradient behind it shows. It only needs to hold
   the box open now; the media element owns the background. */
.tt-index .tt-card__logo--placeholder { background: transparent; }

/* Status colours.
 *
 * The one cosmetic in this file that is locked rather than left low-specificity.
 *
 * These five are semantic signals, not decoration: green means you can still get in, red means
 * you cannot. Beaver Builder row and Themer text-colour settings emit rules like
 * `.fl-node-xxxx .fl-rich-text *` that beat a single class, so a hero row set to white text
 * turned the badge into white-on-pale-green and the state became unreadable. Locking the colour
 * is the exception the README calls out; everything else here still yields to BB.
 */
.tt-status--open        { color: #12683a !important; }
.tt-status--waitlist    { color: #8a5a00 !important; }
.tt-status--closed      { color: #96201d !important; }
.tt-status--coming-soon { color: var( --tt-muted ) !important; }
.tt-status--complete    { color: var( --tt-muted ) !important; }

/* The on-dark variant needs to win over the five above, hence two classes plus important. */
.tt-status--on-dark.tt-status--open,
.tt-status--on-dark.tt-status--waitlist,
.tt-status--on-dark.tt-status--closed,
.tt-status--on-dark.tt-status--coming-soon,
.tt-status--on-dark.tt-status--complete { color: #fff !important; }

/* Themes love adding margins to headings and paragraphs. Inside a card that breaks the
   vertical rhythm the grid is already handling. */
.tt-index .tt-card h3,
.tt-index .tt-card p,
.tt-index .tt-drawer h4 { margin-top: 0; }

.tt-index .tt-card__title { margin-bottom: .35rem; }
.tt-index .tt-card__venue { margin-bottom: .3rem; }
.tt-index .tt-card__blurb { margin-bottom: 0; }

/* wpautop can inject empty paragraphs and stray <br> around shortcode output. */
.tt-index p:empty,
.tt-index br + br { display: none !important; }

/* Lists inside the drawer / links hub shouldn't inherit theme list styling. */
.tt-index ul,
.tt-index ol { list-style: none; margin: 0; padding: 0; }

/* --------------------------------------------------------------------------
   Type hierarchy.

   A gray area: the theme should own typeface, weight and colour. But the
   RELATIVE hierarchy inside a card is the component's job - the event name has to
   out-rank the venue and the chips, or the row stops being scannable.

   Themes usually target headings as `.something h3`, which is (0,2,0) and beats a bare
   `.tt-card__title`. Three classes here so the size sticks without !important.
   Font family, weight and colour are all still inherited from the theme.
   -------------------------------------------------------------------------- */

.tt-index .tt-card .tt-card__title,
.tt-index__results .tt-card .tt-card__title {
	font-size: clamp( 1.25rem, 1.05rem + .7vw, 1.625rem );
	line-height: 1.15;
	margin: 0 0 .3rem;
}

.tt-index .tt-card .tt-card__venue { font-size: .9375rem; margin: 0; }
.tt-index .tt-card .tt-card__dates { font-size: 1rem; }
.tt-index .tt-card .tt-card__divs  { font-size: .8125rem; }
.tt-index .tt-card .tt-chip        { font-size: .6875rem; }
.tt-index .tt-card .tt-status      { font-size: .6875rem; }

/* ==========================================================================
   MOTION

   Three rules held throughout:

   1. Only `transform` and `opacity` are animated on anything that repeats or scales
      (cards, buttons, chips). Those run on the compositor and never trigger layout.
      The one exception is the drawer's height, which is a single deliberate interaction
      rather than something happening 14 times at once.

   2. Nothing here can hide content if motion is unavailable. Entrance animations live
      inside `prefers-reduced-motion: no-preference`, so the default resting state is
      always visible. Putting `opacity: 0` in the base state and relying on JS to remove
      it is how listings end up permanently blank when a script fails.

   3. Durations get shorter the more often an interaction happens. Hover is 120ms because
      you do it constantly; a card travelling across the list is 340ms because it needs to
      be followable.
   ========================================================================== */

/* --- always on: these are state feedback, not decoration ----------------- */

.tt-card,
.tt-btn,
.tt-chip,
.tt-fbtn,
.tt-card__logo,
.tt-status,
.tt-index__none { transition-timing-function: var( --tt-ease ); }

.tt-btn,
.tt-fbtn { transition: background-color var( --tt-fast ), color var( --tt-fast ), border-color var( --tt-fast ), transform var( --tt-fast ), opacity var( --tt-fast ); }

.tt-chip { transition: background-color var( --tt-fast ), color var( --tt-fast ), border-color var( --tt-fast ); }

@media ( prefers-reduced-motion: no-preference ) {

	/* --- cards ---------------------------------------------------------- */

	.tt-card {
		transition:
			transform var( --tt-base ) var( --tt-ease ),
			box-shadow var( --tt-base ) var( --tt-ease ),
			border-color var( --tt-base ) var( --tt-ease );
	}

	/* Lift is smaller in list view - a wide row rising far looks unstable. */
	.tt-index__results--list .tt-card:hover {
		transform: translateY( -2px );
		border-color: #c8ccd4;
		box-shadow: var( --tt-shadow-lift );
	}

	.tt-index__results--grid .tt-card:hover {
		transform: translateY( -4px );
		border-color: #c8ccd4;
		box-shadow: var( --tt-shadow-lift );
	}

	/* The logo gets a slow, barely-there scale. Enough to feel alive, not enough to
	   read as an effect. The media wrapper clips it. */
	.tt-card__media { overflow: hidden; }

	.tt-card__logo {
		transition: transform var( --tt-slow ) var( --tt-ease );
	}

	.tt-card:hover .tt-card__logo { transform: scale( 1.04 ); }

	/* Underline the title on card hover, not just on direct link hover - the whole row
	   reads as one target. */
	.tt-card__title a { transition: color var( --tt-fast ) var( --tt-ease ); }

	/* --- buttons -------------------------------------------------------- */

	.tt-btn:hover      { transform: translateY( -1px ); }
	.tt-btn:active     { transform: translateY( 0 ) scale( .985 ); transition-duration: 60ms; }
	.tt-fbtn:hover     { border-color: var( --tt-accent ); }
	.tt-fbtn:active    { transform: scale( .985 ); }
	button.tt-chip:active { transform: scale( .96 ); transition-duration: 60ms; }

	/* --- count badge ---------------------------------------------------- */

	/* Pops once when it appears so a filter taking effect is unmissable. */
	.tt-fcount.is-on { animation: tt-pop 260ms var( --tt-ease ); }

	/* --- results count -------------------------------------------------- */

	.tt-index__count { transition: opacity var( --tt-fast ) var( --tt-ease ); }

	/* --- empty state ---------------------------------------------------- */

	.tt-index__none { animation: tt-rise var( --tt-base ) var( --tt-ease ); }

	/* --- first paint ---------------------------------------------------- */

	/*
	 * The card entrance stagger is done in JS, not here.
	 *
	 * A CSS animation on every .tt-card would also fire on cards that start out hidden,
	 * and would collide with the FLIP animation that runs on the very first filter pass -
	 * two animations fighting over transform on the same element. JS runs the stagger once,
	 * over only the cards actually on screen, and knows to skip FLIP on that first pass.
	 *
	 * The upside of doing it here instead would be working without JS; but the filtering
	 * needs JS anyway, and a resting state of visible is the correct no-JS fallback.
	 */

	/* Filter chips fade in as a group rather than one by one - they are a control, and a
	   control that animates in piecemeal feels unready. */
	.tt-filters { animation: tt-fade var( --tt-base ) var( --tt-ease ) both; }
}

@keyframes tt-rise {
	from { opacity: 0; transform: translateY( 12px ); }
	to   { opacity: 1; transform: none; }
}

@keyframes tt-fade {
	from { opacity: 0; }
	to   { opacity: 1; }
}

@keyframes tt-pop {
	0%   { transform: scale( .6 ); opacity: 0; }
	60%  { transform: scale( 1.12 ); opacity: 1; }
	100% { transform: scale( 1 ); }
}

/* Belt and braces. Even if a rule above escapes its media query, this kills it. */
@media ( prefers-reduced-motion: reduce ) {
	.tt-index *,
	.tt-card,
	.tt-card * {
		animation: none !important;
		transition: none !important;
	}

	.tt-index .tt-status--open .tt-status__dot { animation: none !important; }
}

/* ------------------------------------------------------------------- print */

@media print {
	.tt-filters,
	.tt-card__actions,
	.tt-venue__map { display: none; }
}

/* ============================================================ experience tiles

   Photo at rest, muted video on hover, copy revealed on hover.

   The resting state is deliberately quiet — eyebrow and heading only. Showing all three
   tiles' copy at once turns the band into a wall of text and undoes the high image-to-text
   ratio that made the Trilogy reference worth copying.

   Everything animated is transform or opacity, except the copy's max-height, which is the
   one honest way to reveal unknown-length text.
   ========================================================================== */

.tt-xp { display: grid; gap: 14px; }
.tt-xp--1 { grid-template-columns: minmax( 0, 1fr ); }
.tt-xp--2 { grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); }
.tt-xp--3 { grid-template-columns: repeat( 3, minmax( 0, 1fr ) ); }

.tt-xp__tile {
	position: relative;
	display: block;
	border-radius: 8px;
	overflow: hidden;
	background: var( --tt-media );
	color: #fff;
	text-decoration: none;
	isolation: isolate;
}

/* Portrait. A tall tile reads as a poster; 16:9 reads as a thumbnail. */
.tt-xp__media {
	display: block;
	position: relative;
	aspect-ratio: 4 / 5;
}

.tt-xp__img,
.tt-xp__video {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.tt-xp__img--blank { background: var( --tt-media ); }

/* The video sits over the photo and fades in once it's actually playing, so a slow first
   load never shows a black frame. */
.tt-xp__video { opacity: 0; z-index: 1; }
.tt-xp__tile.is-playing .tt-xp__video { opacity: 1; }

/* Scrim so the copy stays legible over any footage. */
.tt-xp__tile::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 2;
	background: linear-gradient( 0deg, rgba( 8, 9, 11, .92 ) 0%, rgba( 8, 9, 11, .38 ) 38%, rgba( 8, 9, 11, .05 ) 70% );
	pointer-events: none;
}

.tt-xp__body {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 3;
	padding: 26px 24px 24px;
	display: block;
}

.tt-xp__eyebrow {
	display: block;
	font-size: .625rem;
	font-weight: 700;
	letter-spacing: .18em;
	text-transform: uppercase;
	color: rgba( 255, 255, 255, .72 );
	margin-bottom: 9px;
}

.tt-xp__h {
	display: block;
	font-size: clamp( 1.25rem, 1.1rem + .5vw, 1.5rem );
	font-weight: 800;
	text-transform: uppercase;
	letter-spacing: -.01em;
	line-height: 1.05;
}

/* Hidden at rest, revealed on hover. max-height rather than height so the copy can be any
   length; 7rem is roughly three lines, which is all this should ever hold. */
.tt-xp__copy {
	display: block;
	font-size: .9375rem;
	line-height: 1.5;
	color: rgba( 255, 255, 255, .84 );
	max-height: 0;
	opacity: 0;
	overflow: hidden;
}

.tt-xp__link {
	display: inline-block;
	margin-top: 14px;
	font-size: .6875rem;
	font-weight: 800;
	letter-spacing: .13em;
	text-transform: uppercase;
	border-bottom: 2px solid rgba( 255, 255, 255, .5 );
	padding-bottom: 3px;
	max-height: 0;
	opacity: 0;
	overflow: hidden;
}

@media ( prefers-reduced-motion: no-preference ) {

	.tt-xp__img { transition: transform 700ms var( --tt-ease ); }
	.tt-xp__video { transition: opacity var( --tt-base ) var( --tt-ease ); }

	.tt-xp__copy,
	.tt-xp__link {
		transition:
			max-height 320ms var( --tt-ease ),
			opacity 240ms var( --tt-ease ),
			margin-top 320ms var( --tt-ease );
	}

	.tt-xp__tile:hover .tt-xp__img,
	.tt-xp__tile:focus-visible .tt-xp__img { transform: scale( 1.05 ); }
}

.tt-xp__tile:hover .tt-xp__copy,
.tt-xp__tile:focus-visible .tt-xp__copy,
.tt-xp__tile:hover .tt-xp__link,
.tt-xp__tile:focus-visible .tt-xp__link { max-height: 7rem; opacity: 1; }

.tt-xp__tile:focus-visible { outline: 3px solid #fff; outline-offset: 3px; }

/* No hover: show the copy permanently. A tile that hides its own explanation on a phone is
   just a photo. */
@media ( hover: none ) {
	.tt-xp__copy,
	.tt-xp__link { max-height: 7rem; opacity: 1; }
}

/* Reduced motion still reveals on hover — it just doesn't animate getting there. */
@media ( prefers-reduced-motion: reduce ) {
	.tt-xp__copy,
	.tt-xp__link { transition: none; }
}

@media ( max-width: 900px ) {
	.tt-xp--3 { grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); }
}

@media ( max-width: 620px ) {
	.tt-xp--2,
	.tt-xp--3 { grid-template-columns: minmax( 0, 1fr ); }
	.tt-xp__media { aspect-ratio: 3 / 2; }
	.tt-xp__body { padding: 20px 18px 18px; }
}

/* ====================================================== bento gallery / video

   The span pattern repeats every six tiles, with grid-auto-flow: dense filling the holes.
   That's what makes it tile correctly at ANY image count — three photos and forty photos
   both look composed, and there's no PHP branching on the number.

   Pattern per 6: [2×2 large] [2×1 wide] [1×1] [1×1] [2×1 wide] [1×1]
   ========================================================================== */

.tt-bento {
	display: grid;
	grid-template-columns: repeat( 4, 1fr );
	grid-auto-rows: 11rem;
	grid-auto-flow: dense;
	gap: 10px;
}

.tt-bento__cell {
	position: relative;
	display: block;
	padding: 0;
	margin: 0;
	border: 0;
	border-radius: var( --tt-radius );
	overflow: hidden;
	background: var( --tt-media );
	cursor: zoom-in;
	appearance: none;
}

.tt-bento__img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* --- the rhythm --- */

.tt-bento--bento .tt-bento__cell:nth-child( 6n + 1 ) { grid-column: span 2; grid-row: span 2; }
.tt-bento--bento .tt-bento__cell:nth-child( 6n + 2 ) { grid-column: span 2; }
.tt-bento--bento .tt-bento__cell:nth-child( 6n + 5 ) { grid-column: span 2; }

/* Recap: the video takes the large tile, photos fill around it. */
.tt-bento--recap .tt-bento__cell--video { grid-column: span 2; grid-row: span 2; }
.tt-bento--recap .tt-bento__cell:nth-child( 4n + 4 ) { grid-column: span 2; }

/* Plain grid alternative. */
.tt-bento--grid { grid-auto-rows: 9rem; }

/* Zoom on hover — the image moves, the tile doesn't, so the grid never reflows. */
@media ( prefers-reduced-motion: no-preference ) {
	.tt-bento__img { transition: transform var( --tt-slow ) var( --tt-ease ); }
	.tt-bento__cell:hover .tt-bento__img { transform: scale( 1.05 ); }
}

.tt-bento__cell:focus-visible { outline: 3px solid var( --tt-accent ); outline-offset: 3px; }

/* --- video facade --- */

.tt-videowrap { border-radius: var( --tt-radius ); overflow: hidden; background: var( --tt-media ); }

.tt-video {
	position: relative;
	display: block;
	width: 100%;
	height: 100%;
	padding: 0;
	margin: 0;
	border: 0;
	background: var( --tt-media );
	cursor: pointer;
	appearance: none;
}

.tt-videowrap .tt-video { aspect-ratio: 16 / 9; }
.tt-video .tt-bento__img { width: 100%; height: 100%; object-fit: cover; opacity: .82; }
.tt-video__blank { display: block; width: 100%; aspect-ratio: 16 / 9; }

/* Play button. Drawn in CSS so there's no icon dependency. */
.tt-video__play {
	position: absolute;
	top: 50%;
	left: 50%;
	width: 74px;
	height: 74px;
	transform: translate( -50%, -50% );
	border-radius: 50%;
	background: rgba( 255, 255, 255, .94 );
	box-shadow: 0 6px 26px rgba( 0, 0, 0, .34 );
}

.tt-video__play::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 54%;
	transform: translate( -50%, -50% );
	border-style: solid;
	border-width: 11px 0 11px 18px;
	border-color: transparent transparent transparent #16181c;
}

@media ( prefers-reduced-motion: no-preference ) {
	.tt-video__play,
	.tt-video .tt-bento__img {
		transition: transform var( --tt-base ) var( --tt-ease ), opacity var( --tt-base ) var( --tt-ease );
	}
	.tt-video:hover .tt-video__play { transform: translate( -50%, -50% ) scale( 1.08 ); }
	.tt-video:hover .tt-bento__img { opacity: .68; transform: scale( 1.03 ); }
}

.tt-video:focus-visible { outline: 3px solid var( --tt-accent ); outline-offset: 3px; }

.tt-video__frame {
	display: block;
	width: 100%;
	aspect-ratio: 16 / 9;
	border: 0;
	border-radius: var( --tt-radius );
}

.tt-bento__cell--video .tt-video__frame { height: 100%; border-radius: 0; }

/* --- lightbox --- */

.tt-lb {
	max-width: 100vw;
	max-height: 100vh;
	width: 100%;
	height: 100%;
	padding: 0;
	border: 0;
	background: transparent;
	display: none;
}

.tt-lb[open] {
	display: grid;
	grid-template-columns: auto 1fr auto;
	align-items: center;
	justify-items: center;
	gap: 1rem;
	padding: clamp( 1rem, 4vw, 3rem );
	box-sizing: border-box;
}

.tt-lb::backdrop { background: rgba( 8, 9, 11, .93 ); }

/* The stage holds either an <img> or an <iframe>, so it sizes to whichever arrives rather
   than each media type carrying its own layout rules. */
.tt-lb__stage {
	grid-column: 2;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	max-width: min( 100%, 1600px );
	max-height: calc( 100vh - 6rem );
}

.tt-lb__img {
	max-width: 100%;
	max-height: calc( 100vh - 6rem );
	width: auto;
	height: auto;
	border-radius: var( --tt-radius );
	object-fit: contain;
}

/* Video fills the stage width at 16:9, capped so it never exceeds the viewport height. */
.tt-lb__video {
	width: 100%;
	aspect-ratio: 16 / 9;
	max-height: calc( 100vh - 6rem );
	border: 0;
	border-radius: var( --tt-radius );
	background: #000;
}

.tt-lb__close,
.tt-lb__nav {
	appearance: none;
	border: 0;
	background: rgba( 255, 255, 255, .12 );
	color: #fff;
	cursor: pointer;
	border-radius: 50%;
	width: 48px;
	height: 48px;
	font-size: 26px;
	line-height: 1;
	display: flex;
	align-items: center;
	justify-content: center;
	transition: background-color var( --tt-fast ) var( --tt-ease );
}

.tt-lb__close:hover,
.tt-lb__nav:hover { background: rgba( 255, 255, 255, .26 ); }

.tt-lb__close {
	position: absolute;
	top: clamp( .75rem, 3vw, 1.75rem );
	right: clamp( .75rem, 3vw, 1.75rem );
	font-size: 30px;
}

.tt-lb__nav[hidden] { display: none; }

.tt-lb__count {
	position: absolute;
	bottom: clamp( .75rem, 3vw, 1.75rem );
	left: 50%;
	transform: translateX( -50% );
	color: rgba( 255, 255, 255, .72 );
	font-size: 12.5px;
	letter-spacing: .14em;
}

/* --- responsive --- */

@media ( max-width: 1024px ) {
	.tt-bento { grid-auto-rows: 9rem; }
}

@media ( max-width: 700px ) {
	/* Two columns, and the large tile stops spanning rows — a 2×2 on a 2-col grid is just
	   a square that pushes everything else off the first screen. */
	.tt-bento { grid-template-columns: repeat( 2, 1fr ); grid-auto-rows: 8rem; gap: 8px; }
	.tt-bento--bento .tt-bento__cell:nth-child( 6n + 1 ) { grid-row: span 1; }
	.tt-bento--recap .tt-bento__cell--video { grid-row: span 1; }
	.tt-video__play { width: 56px; height: 56px; }
	.tt-video__play::after { border-width: 9px 0 9px 14px; }
	.tt-lb__nav { width: 40px; height: 40px; font-size: 22px; }
}

/* Fallbacks for the no-JS paths. Hidden from everyone else by <noscript>, but they still
   need to not look like raw browser defaults when they do appear. */
.tt-bento__fallback { list-style: none; margin: 1rem 0 0; padding: 0; display: grid; gap: .35rem; }
.tt-video__fallback { margin: .75rem 0 0; }

/* ============================================================ lodging (1.7.0)
 *
 * Replaces the .tt-travel three-up. Argument on the left, practical detail and the actions on
 * the right, because the two get read by different people: a coach scans the card, a director
 * reads the copy.
 */

.tt-lodge {
	display: grid;
	grid-template-columns: minmax( 0, 1.15fr ) minmax( 0, .85fr );
	gap: clamp( 1.5rem, 4vw, 3rem );
	align-items: start;
	padding: clamp( 1.25rem, 3vw, 2rem );
	border: 1px solid var( --tt-line );
	border-radius: var( --tt-radius );
	background: var( --tt-surface );
}

.tt-lodge__main { min-width: 0; }

.tt-lodge__brand { margin-bottom: 1rem; }

/* Contained, not stretched. A partner mark is theirs, and scaling it to fill a column is the
   fastest way to make a co-brand look careless. */
.tt-lodge__logo {
	width: auto;
	height: 34px;
	max-width: 190px;
	object-fit: contain;
	object-position: left center;
}

.tt-lodge__eyebrow {
	margin: 0 0 .3rem;
	font-size: .75rem;
	font-weight: 600;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var( --tt-muted );
}

.tt-lodge__h { margin: 0 0 .75rem; font-size: 1.25rem; line-height: 1.2; }

/* Stay to play decides whether a club can commit at all, so it reads as a flag rather than as
   a sentence inside the paragraph. Amber, matching the waitlist status: a condition to know
   about, not an error. */
.tt-lodge__flag {
	display: inline-block;
	margin: 0 0 .9rem;
	padding: .35em .8em;
	border-radius: 999px;
	background: #fdf3e0;
	color: #8a5a00;
	font-size: .75rem;
	font-weight: 600;
	letter-spacing: .04em;
}

.tt-lodge__blurb { color: var( --tt-muted ); max-width: 54ch; }
.tt-lodge__blurb p { margin: 0 0 .7em; }
.tt-lodge__blurb p:last-child { margin-bottom: 0; }

/* The per-event note is the only line written per event, so it is set apart from the standing
   copy rather than running on from it. */
.tt-lodge__note {
	margin-top: .9rem;
	padding-left: .9rem;
	border-left: 2px solid var( --tt-line );
	color: var( --tt-muted );
	font-size: .9375rem;
}

.tt-lodge__note p { margin: 0 0 .5em; }
.tt-lodge__note p:last-child { margin-bottom: 0; }

.tt-lodge__card {
	background: var( --tt-surface-2 );
	border-radius: var( --tt-radius );
	padding: 1.1rem 1.25rem;
}

.tt-lodge__rows { margin: 0; }

.tt-lodge__row {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	gap: 1rem;
	padding: .35rem 0;
	font-size: .875rem;
}

.tt-lodge__row dt { color: var( --tt-muted ); }
.tt-lodge__row dd { margin: 0; font-weight: 600; text-align: right; min-width: 0; }

/* An email address has no spaces to break on, so it overflows a narrow card unless told it
   may break anywhere. */
.tt-lodge__row dd a { overflow-wrap: anywhere; }

/* The pre-booking message. Sits between the detail rows and the button so it explains the
   button rather than trailing after it. */
.tt-lodge__pending {
	margin: .9rem 0 0;
	padding-top: .9rem;
	border-top: 1px solid var( --tt-line );
	font-size: .8125rem;
	line-height: 1.55;
	color: var( --tt-muted );
}

.tt-lodge__actions {
	display: flex;
	flex-direction: column;
	gap: .5rem;
	margin-top: 1.1rem;
}

.tt-lodge__btn { width: 100%; }

@media ( max-width: 782px ) {
	.tt-lodge { grid-template-columns: minmax( 0, 1fr ); }
}

/* ------------------------------------------------------------- buy photos */

/* Below the wall, not above it. Someone buys after finding the photo they want, so the order
   is browse, find, buy. */
.tt-gal__buy {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: .6rem;
	margin-top: 1.75rem;
	padding-top: 1.75rem;
	border-top: 1px solid var( --tt-line );
	text-align: center;
}

.tt-gal__buy-note {
	margin: 0;
	font-size: .8125rem;
	color: var( --tt-muted );
	max-width: 44ch;
}

/* ============================================================== photo wall
 *
 * Append to tt-core.css. Reads the same custom properties as everything else.
 *
 * The wall is a dense grid where a wide photograph takes two columns. That is the block's
 * only structural device and it carries real information: the tile is wide because the shot
 * was taken wide. It also fixes the flat rhythm you get from forcing every frame square.
 *
 * The viewer is deliberately spare. When a photograph goes full screen the photograph is
 * the design; chrome around it competes with it. Everything except the image sits at low
 * contrast until hovered or focused.
 */

.tt-gal { --tt-gal-col: 220px; }

/* -------------------------------------------------------------------- filters */

.tt-gal__filters {
	display: flex;
	flex-wrap: wrap;
	gap: .5rem;
	margin-bottom: 1.1rem;
}

.tt-gal__n {
	font-variant-numeric: tabular-nums;
	opacity: .55;
	font-size: .875em;
	margin-left: .15em;
}

/* ----------------------------------------------------------------------- wall */

.tt-gal__wall {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat( auto-fill, minmax( var( --tt-gal-col ), 1fr ) );
	/* dense lets a single-column tile backfill the hole a wide tile leaves at the end of a
	   row, so the wall has no gaps without anyone hand-ordering the gallery field. */
	grid-auto-flow: dense;
	gap: 10px;
}

.tt-gal__tile { min-width: 0; }

/* A wide tile is twice as wide and exactly as TALL as its neighbours, so it reads as a
   letterbox frame rather than a giant square. That keeps every row one tile-height high.
   Spanning two columns while keeping a 4:3 frame is what made the first version enormous: the
   tile was double height, so the whole row was.

   8/3 is two columns plus the gap over one row height. It does not have to be exact, since the
   frame is inside a grid cell whose width is already fixed; it only has to not be 4/3. */
.tt-gal__tile--wide { grid-column: span 2; }
.tt-gal__tile--wide .tt-gal__frame { aspect-ratio: 8 / 3; }

.tt-gal__frame {
	display: block;
	position: relative;
	overflow: hidden;
	border-radius: var( --tt-radius );
	background: var( --tt-surface-2 );
	aspect-ratio: 4 / 3;
	/* Kill the inline-element descender gap so the grid gaps are the real gaps. */
	line-height: 0;
	outline-offset: 3px;
}

.tt-gal__img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: 50% 42%;
}

/* Reveal. Only applied once JS confirms it is running, so a no-JS visitor never sees a
   wall of invisible tiles. */
.tt-gal--live .tt-gal__tile {
	opacity: 0;
	transform: translateY( 10px );
	transition: opacity var( --tt-base ) var( --tt-ease ), transform var( --tt-base ) var( --tt-ease );
}

.tt-gal--live .tt-gal__tile.is-in {
	opacity: 1;
	transform: none;
}

/* Hover. The frame lifts and the image pushes in slightly, which reads as the photo coming
   forward rather than the box growing. */
@media ( hover: hover ) and ( prefers-reduced-motion: no-preference ) {
	.tt-gal__frame { transition: box-shadow var( --tt-base ) var( --tt-ease ); }
	.tt-gal__img   { transition: transform var( --tt-slow ) var( --tt-ease ); }

	.tt-gal__frame:hover { box-shadow: var( --tt-shadow-lift ); }
	.tt-gal__frame:hover .tt-gal__img { transform: scale( 1.045 ); }
}

.tt-gal__more {
	display: flex;
	justify-content: center;
	margin-top: 1.25rem;
}

/* ---------------------------------------------------------------------- viewer */

/* Lock the page behind the viewer. scrollbar-gutter holds the gutter so the wall does not
   shift sideways as the overlay opens. */
.tt-gal-open { overflow: hidden; scrollbar-gutter: stable; }

.tt-gal__viewer {
	position: fixed;
	inset: 0;
	z-index: 9999;
	display: grid;
	place-items: center;
	padding: clamp( .75rem, 3vw, 3rem );
}

.tt-gal__viewer[hidden] { display: none; }

.tt-gal__scrim {
	position: absolute;
	inset: 0;
	background: rgba( 8, 10, 14, .93 );
	opacity: 0;
	transition: opacity var( --tt-base ) var( --tt-ease );
}

.tt-gal__viewer.is-open .tt-gal__scrim { opacity: 1; }
.tt-gal__viewer.is-closing .tt-gal__scrim { opacity: 0; }

.tt-gal__stage {
	position: relative;
	display: grid;
	place-items: center;
	max-width: min( 100%, 1600px );
	/* Room for the caption bar and tools without the image ever colliding with them. */
	max-height: calc( 100vh - 9rem );
}

.tt-gal__stage-img {
	display: block;
	max-width: 100%;
	max-height: calc( 100vh - 9rem );
	width: auto;
	height: auto;
	border-radius: 2px;
	/* The FLIP transform is written inline by the JS. transform-origin must be centre for
	   the translate/scale pair to resolve correctly. */
	transform-origin: 50% 50%;
	will-change: transform;
	box-shadow: 0 24px 70px rgba( 0, 0, 0, .5 );
}

/* --------------------------------------------------------------------- chrome */

.tt-gal__bar,
.tt-gal__tools,
.tt-gal__nav {
	position: absolute;
	opacity: 0;
	transition: opacity var( --tt-base ) var( --tt-ease );
}

/* Chrome arrives after the photo has landed, so the zoom is the only thing moving. */
.tt-gal__viewer.is-open .tt-gal__bar,
.tt-gal__viewer.is-open .tt-gal__tools,
.tt-gal__viewer.is-open .tt-gal__nav {
	opacity: 1;
	transition-delay: 220ms;
}

.tt-gal__viewer.is-closing .tt-gal__bar,
.tt-gal__viewer.is-closing .tt-gal__tools,
.tt-gal__viewer.is-closing .tt-gal__nav {
	opacity: 0;
	transition-delay: 0ms;
}

.tt-gal__bar {
	left: 0;
	right: 0;
	bottom: 1rem;
	display: flex;
	align-items: baseline;
	justify-content: center;
	gap: 1rem;
	padding: 0 1rem;
	color: #fff;
	text-align: center;
	pointer-events: none;
}

.tt-gal__caption {
	margin: 0;
	font-size: .9375rem;
	opacity: .82;
}

.tt-gal__caption[hidden] { display: none; }

.tt-gal__counter {
	margin: 0;
	font-size: .8125rem;
	font-variant-numeric: tabular-nums;
	letter-spacing: .06em;
	opacity: .5;
}

.tt-gal__tools {
	top: 1rem;
	right: 1rem;
	display: flex;
	gap: .35rem;
}

.tt-gal__tool {
	appearance: none;
	background: rgba( 255, 255, 255, .1 );
	border: 0;
	color: #fff;
	font: inherit;
	font-size: .8125rem;
	padding: .5rem .8rem;
	border-radius: 4px;
	cursor: pointer;
	text-decoration: none;
	transition: background var( --tt-fast ) var( --tt-ease );
}

.tt-gal__tool:hover,
.tt-gal__tool:focus-visible { background: rgba( 255, 255, 255, .24 ); }

.tt-gal__nav {
	top: 50%;
	transform: translateY( -50% );
	appearance: none;
	background: rgba( 255, 255, 255, .1 );
	border: 0;
	color: #fff;
	width: 46px;
	height: 46px;
	border-radius: 50%;
	display: grid;
	place-items: center;
	cursor: pointer;
}

.tt-gal__nav--prev { left: 1rem; }
.tt-gal__nav--next { right: 1rem; }

.tt-gal__nav:hover,
.tt-gal__nav:focus-visible { background: rgba( 255, 255, 255, .26 ); }

/* Focus must stay visible against a near-black scrim, so it cannot inherit the site's
   dark focus ring here. */
.tt-gal__viewer :focus-visible {
	outline: 2px solid #fff;
	outline-offset: 2px;
}

/* ----------------------------------------------------------------- responsive */

@media ( max-width: 782px ) {
	.tt-gal { --tt-gal-col: 150px; }
	.tt-gal__wall { gap: 6px; }

	/* Arrows are redundant next to swipe and they cover the photograph on a small screen. */
	.tt-gal__nav { display: none; }

	.tt-gal__tools { top: .5rem; right: .5rem; }
	.tt-gal__bar { bottom: .5rem; flex-direction: column; gap: .2rem; align-items: center; }
	.tt-gal__stage,
	.tt-gal__stage-img { max-height: calc( 100vh - 7rem ); }
}

@media ( max-width: 480px ) {
	/* Two columns, and wide tiles go full width. One column wastes the screen; three makes
	   faces too small to recognise, which is the entire point of the wall. */
	.tt-gal__wall { grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); }
	.tt-gal__tile--wide { grid-column: span 2; }
	/* Full width at two columns, so the letterbox would be very short. Back to 16:9. */
	.tt-gal__tile--wide .tt-gal__frame { aspect-ratio: 16 / 9; }
}

@media ( prefers-reduced-motion: reduce ) {
	.tt-gal--live .tt-gal__tile,
	.tt-gal__scrim,
	.tt-gal__bar,
	.tt-gal__tools,
	.tt-gal__nav {
		transition: none;
	}

	.tt-gal--live .tt-gal__tile {
		opacity: 1;
		transform: none;
	}

	.tt-gal__stage-img { will-change: auto; }
}

/* ============================================================== hero CTAs
 *
 * Append to tt-core.css.
 *
 * The button primitives read from --tt-accent, which on this build is near-black. That works
 * on the white sections and disappears entirely in a photographic hero: a black filled button
 * on a dark photo is a hole, and a ghost button is invisible outright.
 *
 * So the row declares which background it sits on, and the buttons follow. Nothing here
 * changes .tt-btn itself, so every other use of the primitive is untouched.
 */

.tt-cta { display: flex; flex-direction: column; gap: .75rem; }

.tt-cta__row {
	display: flex;
	flex-wrap: wrap;
	gap: .6rem;
	align-items: center;
}

/* --- on a dark hero --------------------------------------------------------- */

/* Primary inverts: white fill, dark text. On a photograph the brightest element in the frame
   is where the eye goes, and that should be the action. */
.tt-cta--on-dark .tt-btn {
	background: #fff;
	border-color: #fff;
	color: #12141a;
}

.tt-cta--on-dark .tt-btn:hover,
.tt-cta--on-dark .tt-btn:focus-visible {
	background: rgba( 255, 255, 255, .88 );
	border-color: rgba( 255, 255, 255, .88 );
	color: #12141a;
}

/* Secondary is a white outline. Kept at 70% so it reads as clearly subordinate to the filled
   button rather than a second equal choice. */
.tt-cta--on-dark .tt-btn--ghost {
	background: transparent;
	border-color: rgba( 255, 255, 255, .7 );
	color: #fff;
}

.tt-cta--on-dark .tt-btn--ghost:hover,
.tt-cta--on-dark .tt-btn--ghost:focus-visible {
	background: rgba( 255, 255, 255, .14 );
	border-color: #fff;
	color: #fff;
}

.tt-cta--on-dark .tt-cta__pending { color: rgba( 255, 255, 255, .72 ); }

/* Focus has to be visible against a photograph, so it cannot inherit a dark ring. */
.tt-cta--on-dark .tt-btn:focus-visible {
	outline: 2px solid #fff;
	outline-offset: 3px;
}

/* --- on a light section ----------------------------------------------------- */

/* Nothing to override. The primitives are already correct on white, so tone="light" exists to
   make the choice explicit at the call site rather than to restyle anything. */

.tt-cta--on-light .tt-cta__pending { color: var( --tt-muted ); }

/* --- pending notes ---------------------------------------------------------- */

/* A link that exists but has not opened yet. Set below the buttons, not among them, so it
   never reads as a disabled control someone should try clicking. */
.tt-cta__notes {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: .2rem 1.1rem;
}

.tt-cta__pending {
	font-size: .8125rem;
	letter-spacing: .02em;
}

/* --- responsive ------------------------------------------------------------- */

@media ( max-width: 600px ) {
	/* Full-width stacked buttons. Four uppercase labels wrapping mid-word across a phone is
	   worse than four clean rows, and these are the primary actions on the page. */
	.tt-cta__row { flex-direction: column; align-items: stretch; }
	.tt-cta__row .tt-btn { width: 100%; }
	.tt-cta__notes { flex-direction: column; gap: .2rem; }
}
