/*
Theme Name: A-AA Boston
Theme URI: https://austria-boston.org/
Author: Austro-American Association of Boston
Description: Block theme for the Austro-American Association of Boston, a non-profit cultural association founded 1944. English-language, event-forward, built to read as a living organization rather than an archive of one.
Version: 0.1.0
Requires at least: 6.5
Tested up to: 6.9
Requires PHP: 8.0
License: GNU General Public License v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: aaa-boston
Tags: block-theme, full-site-editing, non-profit, events, accessibility-ready
*/

/*
 * Colour, type and spacing live in theme.json. This file holds only what the
 * block system cannot express: the hero scrim, the event row, and the archive
 * year index.
 *
 * The two competing directions that used to be scoped here (.dir-photo and
 * .dir-graphic) are gone. Photo-led won; its values moved into theme.json and
 * the rules below are unscoped. The evaluation mockups remain in _preview/ on
 * staging for reference and should be deleted before this ships.
 */

/* ── hero ────────────────────────────────────────────────────────────────── */

.aaa-hero {
	position: relative;
	display: flex;
	align-items: flex-end;
	min-height: min(62vh, 30rem);
	background-color: var(--wp--preset--color--ink);
	background-image: var(--aaa-hero-image, none);
	background-size: cover;
	background-position: center 62%;
	color: #fff;
}

/*
 * Scrim, so white type stays legible over photographs of unknown exposure.
 *
 * Two layers, because one flat gradient cannot do both jobs. Measured against
 * the piano hero, whose keys reach pure white (relative luminance 0.998) right
 * where the headline sits:
 *
 *   72% flat  → mean 8.99:1 but worst-pixel 3.19:1  ✗ fails AA for the subhead
 *   86% flat  → worst-pixel 5.53:1 ✓ but flattens the whole image
 *
 * So the bottom band stays moderate and a second gradient weights the
 * bottom-left corner where the text block actually is. Combined alpha there is
 * 1-(1-0.72)(1-0.5) = 0.86, giving 5.53:1 against white — clears AA for normal
 * text with margin — while the right-hand side keeps its detail.
 *
 * The subhead is ~19px regular, which is NOT "large text" under WCAG, so 3:1
 * is not the bar to clear. 4.5:1 is. Re-measure if the image ever changes.
 */
.aaa-hero::after {
	content: "";
	position: absolute;
	inset: 0;
	background:
		linear-gradient(to top right, rgb(0 0 0 / 50%) 0%, rgb(0 0 0 / 22%) 38%, rgb(0 0 0 / 0%) 70%),
		linear-gradient(to top, rgb(0 0 0 / 72%) 0%, rgb(0 0 0 / 18%) 55%, rgb(0 0 0 / 5%) 100%);
}

.aaa-hero__inner {
	position: relative;
	z-index: 1;
	width: 100%;
	padding-block: var(--wp--preset--spacing--50);
}

.aaa-hero__inner :where(h1, p) {
	max-width: 34rem;
	text-wrap: balance;
}

/* The outline button sits on photography, so it needs its own light treatment. */
.aaa-hero .is-style-outline .wp-block-button__link {
	color: #fff;
	border-color: #fff;
	background: transparent;
}

/* ── base type scale ─────────────────────────────────────────────────────── */

/*
 * The whole scale, moved up 25%: body text lands at 20px instead of 16px.
 *
 * **Why the root and not the eighteen sizes below.** Every size in this theme
 * is already in rem, so moving the root moves the system in proportion and the
 * design keeps its relationships. Editing sizes one at a time is how a type
 * scale quietly stops being a scale.
 *
 * **Why a percentage and not 20px.** A percentage is relative to whatever the
 * reader has set as their browser's default text size. Someone who has already
 * raised it — exactly the reader this change is for — gets 25% more than
 * *their* setting, not 25% more than ours. `font-size: 20px` would overwrite
 * their preference with our guess and would be the wrong thing to do on a site
 * whose members are largely older.
 *
 * Two deliberate exceptions to pure scaling, both below:
 *   - the smallest labels are floored at 0.78rem, since 0.7rem scaled up is
 *     still only 14px and those labels were already the tightest thing here;
 *   - the headings are held *back* in theme.json (h1 2.5rem -> 2.1rem, h2 1.6
 *     -> 1.4, display 3.25 -> 2.7). At 20px body an unrestrained h1 reaches
 *     50px and the page starts shouting. Held back, it lands at 42px — larger
 *     than before in absolute terms, calmer in relative terms.
 */
html {
	font-size: 125%;
}

/*
 * Headings, held back — enforced here rather than left to theme.json alone.
 *
 * theme.json carries the same values (x-large 1.4rem, xx-large 2.1rem, display
 * 2.7rem) and its *merged data* resolves to them correctly, but the generated
 * global stylesheet kept emitting the previous numbers. It is not the theme
 * file (md5 verified on the server), not the user global-styles record (no
 * fontSizes override on any of the four), not a transient (absent), and not
 * anything in the options table (no row contains the old value). Whatever is
 * holding it, the cascade is somewhere this file can simply outrank.
 *
 * `:root` prefix is deliberate: theme.json emits `:root :where(.has-…)`, and
 * :where() contributes zero specificity, so `:root .has-…` (0,2,0) beats it
 * (0,1,0) regardless of source order. Same reasoning for the elements.
 *
 * If the generated stylesheet ever catches up, these become redundant rather
 * than wrong — they assert the identical values.
 */
:root h1,
:root .has-xx-large-font-size {
	font-size: 2.1rem;
}

:root h2,
:root .has-x-large-font-size {
	font-size: 1.4rem;
}

:root .has-display-font-size {
	font-size: 2.7rem;
}

/* ── event rows ──────────────────────────────────────────────────────────── */

.aaa-date {
	display: flex;
	flex: 0 0 auto;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	width: 4.5rem;
	padding-block: 0.5rem;
	line-height: 1.1;
	text-align: center;
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: 2px;
}

.aaa-date__month {
	font-size: 0.78rem;
	font-weight: 700;
	letter-spacing: 0.08em;
	color: var(--wp--preset--color--accent);
}

.aaa-date__day {
	font-size: 1.75rem;
	font-weight: 700;
	font-variant-numeric: tabular-nums;
}

.aaa-date__year {
	font-size: 0.78rem;
	color: var(--wp--preset--color--muted);
	font-variant-numeric: tabular-nums;
}

.aaa-event {
	display: flex;
	gap: 1.25rem;
	align-items: flex-start;
	padding-block: 1rem;
	border-block-end: 1px solid var(--wp--preset--color--rule);
}

.aaa-events > .aaa-event:last-child {
	border-block-end: 0;
}

.aaa-event__body {
	min-width: 0; /* so long titles wrap instead of stretching the flex row */
	flex: 1 1 auto;
}

/*
 * The listing thumbnail.
 *
 * `contain`, not `cover`: the images are a mix of landscape photographs and
 * portrait flyer scans, and cropping either to a common shape loses the part
 * that made it worth showing. A bounded box with letterboxing is honest about
 * the variety instead of pretending it away.
 *
 * Only a handful of events have a usable featured image, so this must look
 * deliberate when absent — hence no placeholder and no reserved space.
 */
.aaa-event__thumb {
	display: block;
	flex: 0 0 auto;
	width: 5.5rem;
}

.aaa-event__thumb-img {
	display: block;
	width: 100%;
	height: auto;
	max-height: 7rem;
	object-fit: contain;
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: 2px;
	background: var(--wp--preset--color--wash);
}

.aaa-event__title {
	margin: 0 0 0.2rem;
	font-size: 1.1rem;
	line-height: 1.3;
}

.aaa-event__title a {
	text-decoration: none;
	color: inherit;
}

.aaa-event__title a:hover,
.aaa-event__title a:focus-visible {
	text-decoration: underline;
}

.aaa-event__meta {
	margin: 0;
	font-size: 0.875rem;
	color: var(--wp--preset--color--muted);
}

.aaa-event__summary {
	margin: 0.35rem 0 0;
	font-size: 0.9rem;
	line-height: 1.5;
	max-width: 44rem;
}

/*
 * The empty state is a first-class case, not a fallback. This Association
 * programs in bursts — September, December, January — and goes months with
 * nothing on the books. A list that renders to nothing in between makes an
 * eighty-year-old organization look defunct.
 */
.aaa-empty {
	padding-block: 1.25rem;
	color: var(--wp--preset--color--muted);
}

/* ── archive year index ──────────────────────────────────────────────────── */

.aaa-years {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem 0.9rem;
	margin-block: 1rem 1.5rem;
	font-variant-numeric: tabular-nums;
}

.aaa-years a {
	text-decoration: none;
	padding: 0.15rem 0.1rem;
	border-block-end: 2px solid transparent;
	color: inherit;
}

.aaa-years a:hover,
.aaa-years a:focus-visible {
	border-block-end-color: var(--wp--preset--color--rule);
}

.aaa-years a.is-current {
	border-block-end-color: var(--wp--preset--color--accent);
	font-weight: 700;
}

.aaa-filter {
	font-size: 0.9rem;
	color: var(--wp--preset--color--muted);
}

@media (prefers-reduced-motion: no-preference) {
	.wp-element-button {
		transition: transform 120ms ease;
	}

	.wp-element-button:hover {
		transform: translateY(-1px);
	}
}

/* ── page mark ───────────────────────────────────────────────────────────── */

/*
 * Title row: the glyph sits beside the heading rather than above it, so it
 * reads as part of the title and not as an orphaned graphic. It shrinks on
 * narrow screens but never wraps below — a lone icon on its own line looks
 * like a loading error.
 */
.aaa-pagehead {
	gap: 1rem;
	align-items: flex-start;
	margin-block-end: var(--wp--preset--spacing--40);
	padding-block-end: var(--wp--preset--spacing--30);
	border-block-end: 1px solid var(--wp--preset--color--rule);
}

.aaa-pagehead > :where(h1, .wp-block-post-title, .wp-block-query-title) {
	margin: 0;
}

.aaa-mark {
	flex: 0 0 auto;
	display: grid;
	place-items: center;
	width: clamp(2.5rem, 6vw, 3.25rem);
	aspect-ratio: 1;
	border-radius: 50%;
	color: var(--wp--preset--color--accent);
	background: color-mix(in srgb, var(--wp--preset--color--accent) 8%, transparent);
}

.aaa-mark svg {
	width: 58%;
	height: 58%;
	display: block;
}

/* Fallback for browsers without color-mix(). */
@supports not (background: color-mix(in srgb, red 8%, transparent)) {
	.aaa-mark {
		background: var(--wp--preset--color--wash);
	}
}

.aaa-event__meta--single {
	margin-block-start: 0.4rem;
	font-size: 1rem;
}

.aaa-past {
	display: inline-block;
	padding: 0.1rem 0.5rem;
	margin-inline-end: 0.35rem;
	border-radius: 2px;
	background: var(--wp--preset--color--wash);
	border: 1px solid var(--wp--preset--color--rule);
	font-size: 0.8rem;
	text-transform: uppercase;
	letter-spacing: 0.06em;
}

/* ── section headings ────────────────────────────────────────────────────── */

/*
 * A heading with an optional link on the right, sitting on a rule. Gives the
 * homepage a repeating structure instead of a run of unrelated blocks — which
 * was the substance of "all pages are plain".
 */
.aaa-sechead {
	align-items: baseline;
	gap: 1rem;
	margin-block-end: var(--wp--preset--spacing--30);
	padding-block-end: 0.6rem;
	border-block-end: 2px solid var(--wp--preset--color--ink);
}

.aaa-sechead > * {
	margin: 0;
}

.aaa-sechead a {
	text-decoration: none;
	white-space: nowrap;
}

.aaa-sechead a:hover,
.aaa-sechead a:focus-visible {
	text-decoration: underline;
}

/* ── news cards ──────────────────────────────────────────────────────────── */

.aaa-newsgrid .aaa-card {
	height: 100%;
}

/*
 * Not every post has a featured image — of the seven news items, several do
 * not. An empty figure would leave ragged cards, so it collapses instead of
 * reserving space.
 */
.aaa-card .wp-block-post-featured-image {
	margin-block-end: var(--wp--preset--spacing--30);
}

.aaa-card .wp-block-post-featured-image:empty {
	display: none;
}

.aaa-card .wp-block-post-featured-image img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: 2px;
}

.aaa-card .wp-block-post-title {
	line-height: 1.3;
}

.aaa-card .wp-block-post-title a {
	text-decoration: none;
	color: inherit;
}

.aaa-card .wp-block-post-title a:hover,
.aaa-card .wp-block-post-title a:focus-visible {
	text-decoration: underline;
}

.aaa-card .wp-block-post-excerpt {
	color: var(--wp--preset--color--muted);
}

/* Keep the grid from collapsing to one cramped column too early. */
@media (max-width: 40rem) {
	.aaa-newsgrid .wp-block-post-template {
		grid-template-columns: 1fr !important;
	}
}

/* ── brand mark ──────────────────────────────────────────────────────────── */

/*
 * The Austrian flag beside the site title, matching the favicon — which is the
 * same mark, and was already the Association's. Inline SVG so it is crisp at
 * any size and costs no request.
 *
 * The hairline border matters: the flag's middle band is white, so on a white
 * page the mark would otherwise read as two disconnected red bars.
 */
.aaa-brand {
	gap: 0.6rem;
	align-items: center;
}

.aaa-brand .wp-block-site-title {
	margin: 0;
}

.aaa-flag {
	display: block;
	flex: 0 0 auto;
	width: 1.9rem;
	line-height: 0;
}

.aaa-flag svg {
	display: block;
	width: 100%;
	height: auto;
}

@media (max-width: 30rem) {
	.aaa-flag {
		width: 1.6rem;
	}
}

/* ── event provenance ────────────────────────────────────────────────────── */

/*
 * Only third-party events are marked. The Association's own are 203 of 259 —
 * badging the majority would bury the exception, which is the one thing a
 * reader actually needs to spot.
 */
.aaa-badge {
	display: inline-block;
	margin-inline-start: 0.5rem;
	padding: 0.1rem 0.45rem;
	border-radius: 2px;
	font-size: 0.78rem;
	font-weight: 600;
	letter-spacing: 0.03em;
	text-transform: uppercase;
	vertical-align: 0.15em;
	white-space: nowrap;
	border: 1px solid var(--wp--preset--color--rule);
	background: var(--wp--preset--color--wash);
	color: var(--wp--preset--color--muted);
}

/* Muted, not alarming — these are events the Association recommends. */
.aaa-event--external .aaa-date {
	border-style: dashed;
}

.aaa-event--external .aaa-date__month {
	color: var(--wp--preset--color--muted);
}

.aaa-notice {
	margin-block-start: 1rem;
	padding: 0.75rem 1rem;
	border-inline-start: 3px solid var(--wp--preset--color--rule);
	background: var(--wp--preset--color--wash);
	font-size: 0.9rem;
	color: var(--wp--preset--color--muted);
}

@media (max-width: 30rem) {
	.aaa-badge {
		display: block;
		margin: 0.35rem 0 0;
		width: fit-content;
	}
}

/* ── venue block on an event page ────────────────────────────────────────── */

.aaa-venue {
	display: flex;
	gap: 1rem;
	margin-block-start: 1.25rem;
	padding-block: 0.9rem;
	border-block: 1px solid var(--wp--preset--color--rule);
}

.aaa-venue__label {
	margin: 0; /* it is a <p> only to survive wpautop — see shortcodes.php */
	flex: 0 0 4.5rem;
	font-size: 0.78rem;
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--wp--preset--color--muted);
	padding-block-start: 0.2rem;
}

.aaa-venue__body {
	min-width: 0;
}

.aaa-venue address {
	font-style: normal;
	line-height: 1.6;
}

/* A side trip, not the main action — sized below the address it belongs to. */
.aaa-venue__map {
	margin: 0.35rem 0 0;
	font-size: 0.85rem;
}

.aaa-event__link {
	margin-block-start: 1rem;
	font-size: 0.95rem;
}

/* ── flyers ──────────────────────────────────────────────────────────────── */

/*
 * A flyer is a download, so it is styled as an object to pick up rather than as
 * prose. The size is part of the affordance, not decoration: on a phone the
 * difference between a page and a 4 MB PDF decides whether to tap now or later.
 */
.aaa-event__flyer {
	margin: 0.5rem 0 0;
}

.aaa-flyer {
	display: inline-flex;
	align-items: baseline;
	gap: 0.4rem;
	max-width: 100%;
	padding: 0.25rem 0.6rem;
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: 2px;
	background: var(--wp--preset--color--wash);
	font-size: 0.85rem;
	line-height: 1.4;
	text-decoration: none;
	color: inherit;
}

.aaa-flyer:hover,
.aaa-flyer:focus-visible {
	border-color: var(--wp--preset--color--accent);
}

.aaa-flyer__label {
	text-decoration: underline;
	text-underline-offset: 0.15em;
}

.aaa-flyer__size {
	font-size: 0.78rem;
	color: var(--wp--preset--color--muted);
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

.aaa-flyer__icon {
	font-size: 0.9em;
}

/* On the event's own page the flyer is a primary action, not an aside. */
.aaa-event__flyer--single {
	margin-block-start: 1.25rem;
}

.aaa-flyer--single {
	padding: 0.45rem 0.9rem;
	font-size: 0.95rem;
}

@media (max-width: 30rem) {
	.aaa-venue {
		flex-direction: column;
		gap: 0.35rem;
	}

	/* The thumbnail is the first thing to go when space is tight — the date
	   chip and the title carry the row on their own. */
	.aaa-event__thumb {
		display: none;
	}

	.aaa-flyer {
		width: 100%;
	}
}
