/*
Theme Name: Camoon
Theme URI: https://camoonagency.fi
Author: Camoon Agency
Author URI: https://camoonagency.fi
Description: A custom WordPress block theme for Camoon Agency — a rock and metal booking agency.
Requires at least: 6.7
Tested up to: 6.8
Requires PHP: 7.4
Version: 1.1.0
License: GNU General Public License v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: camoon
Tags: block-theme, full-site-editing, one-column, custom-colors, custom-logo, custom-menu, editor-style
*/

/*
 * Most styling lives in theme.json. This file carries what block settings cannot express:
 * the full-bleed image grids, the show table, and the light footer.
 *
 * THE SITE IS DARK. `theme.json` sets an `ink` background and `base` text globally, so
 * dark is the default state and needs no class. The single exception is the footer, which
 * inverts to white — every light-on-dark override in this file lives under `.camoon-footer`.
 * `.camoon-band--dark` survives in already-seeded page content and now simply restates the
 * default, which is why none of that content had to be rewritten.
 *
 * Photography is in COLOUR by default and desaturates on hover. An all-dark, all-grayscale
 * site is too much of one idea; the photographs are what keep it alive.
 */

/* ----------------------------------------------------------------- gutter -- */

/*
 * ONE WIDTH. The site is full-viewport with a gutter at each side; nothing is centred on
 * a narrower column except running prose, which keeps `contentSize` for readability.
 *
 * This variable is the single source of that gutter. theme.json's root padding is set to
 * `var(--camoon-gutter)`, so constrained pages and full-width sections are inset by the same
 * amount, and everything moves together if it is ever retuned. Custom properties resolve
 * at use time, so it does not matter that the global-styles stylesheet referencing this
 * may load before the declaration below.
 */
:root {
	--camoon-gutter: clamp(1.25rem, 3.5vw, 4rem);

	/*
	 * How far the copy inside a cover sits from the photograph's own edge. Larger than the
	 * gutter on purpose: once the image is inset rather than bleeding, text hard against
	 * its edge reads as a mistake.
	 */
	--camoon-hero-inset: clamp(1.5rem, 5vw, 6rem);

	/*
	 * Header logo height. A variable rather than a literal because the overlay menu's close
	 * button is positioned from it — the close icon has to land on exactly the same axis as
	 * the hamburger it replaced, and that axis is `spacing|40 + half the logo`. Change the
	 * logo size here and the close button follows.
	 */
	--camoon-header-logo-h: clamp(3.25rem, 2.5rem + 3vw, 4.25rem);
}

/* ------------------------------------------------------------------ reset -- */

/*
 * WordPress ships no box-sizing reset. Without one, any element that is both
 * `width: 100%` and padded is wider than its container — which is what made the two-up
 * form rows overlap.
 */
*,
*::before,
*::after {
	box-sizing: border-box;
}

/* ----------------------------------------------------------------- bands -- */

/*
 * Bands stack edge to edge. WordPress spaces the top-level template blocks with the
 * global block gap via `:where(.wp-site-blocks) > *`, which opens a visible strip above
 * the footer; that `:where()` has zero specificity, so this single rule wins.
 */
.wp-site-blocks > * {
	margin-block-start: 0;
}

/*
 * Push the footer to the bottom of short pages. The footer is the one white surface on a
 * dark site, so if the content does not fill the viewport the dark body shows BELOW it —
 * reading as a stray black band under the page rather than as the end of it. Empty states
 * are exactly the short pages where this happens.
 */
.wp-site-blocks {
	display: flex;
	flex-direction: column;
	min-height: 100vh;
}

.wp-site-blocks > main {
	flex: 1 0 auto;
}

.camoon-band {
	margin-block: 0;
}

/*
 * Side padding for anything inside a FLOW band that does not supply its own.
 *
 * Worth reading before deleting: core serves exactly two global-padding rules —
 * `.has-global-padding { padding-inline: … }` and
 * `.has-global-padding > .alignfull { margin-inline: -… }`. There is NO rule that pads the
 * children of an alignfull element; that behaviour belongs to *constrained* layouts only.
 * So a plain block dropped into one of these `layout: default` bands gets no side padding
 * whatsoever and runs to the viewport edge.
 *
 * The listing blocks never showed the problem because each carries its own
 * `padding-inline: var(--camoon-gutter)` — which is also why they are excluded here via
 * `:not(.alignfull)`, so nothing is padded twice.
 */
.camoon-band.is-layout-flow > *:not(.alignfull) {
	padding-inline: var(--camoon-gutter);
}

/*
 * Prose hangs from the LEFT gutter rather than being centred.
 *
 * Running text still keeps `contentSize` as a measure — 1180px of Barlow is readable and
 * 1900px is not — but a CENTRED measure starts at x=204 on a 1600px screen while every
 * section title, grid and the header start at the gutter, x=56. The page then reads as
 * two layouts fighting, which is exactly what this round set out to remove. Hanging the
 * measure off the same gutter gives the site one left edge from the header to the footer.
 *
 * `!important` is not laziness here and cannot be avoided by specificity: core's
 * constrained layout ships
 *   `.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull))
 *    { margin-left: auto !important; margin-right: auto !important }`
 * and an `!important` declaration is only ever beaten by another one. The alternative —
 * giving every section its own non-constrained layout — would push the problem into
 * client-editable page content, where it would come back the first time someone inserts
 * a group.
 *
 * `.aligncenter` is excluded so deliberately centring a single block still works.
 */
.wp-site-blocks .is-layout-constrained > *:not(.alignfull):not(.alignwide):not(.alignleft):not(.alignright):not(.aligncenter) {
	margin-left: 0 !important;
	margin-right: auto !important;
}

/*
 * …EXCEPT on the three long-form templates, which centre instead. Artist, event and news
 * pages are the ones you land on to *read*; everything you land on to *browse* stays
 * flush-left.
 *
 * Scoped to the PAGE, not to the body-copy class. An earlier version centred only
 * `.camoon-artist-content` and its two siblings, which left every other constrained block on
 * those pages — the cover's inner container, the Spotify player, the show list, the booking
 * form — still hanging from the left gutter. The symptom was easy to misread: inside a
 * left-hung 1180px box, centred text looks centred when the line is long and visibly
 * OFF-CENTRE when it is short, so the artist's name looked right while the genre line under
 * it looked broken. Same bug, seen through a short line.
 *
 * Full-width listings are untouched — they are `alignfull`, which the selector excludes, so
 * a page is never half-centred.
 *
 * `!important` and the extra class are both forced: the rule above is (0,7,0) and already
 * `!important`, so nothing quieter can override it.
 */
.wp-site-blocks .camoon-artist-page .is-layout-constrained > *:not(.alignfull):not(.alignwide):not(.alignleft):not(.alignright),
.wp-site-blocks .camoon-event-page .is-layout-constrained > *:not(.alignfull):not(.alignwide):not(.alignleft):not(.alignright),
.wp-site-blocks .camoon-news-page .is-layout-constrained > *:not(.alignfull):not(.alignwide):not(.alignleft):not(.alignright) {
	margin-left: auto !important;
	margin-right: auto !important;
}

/*
 * If a block's TEXT is centred, centre its BOX too.
 *
 * Without this, a centred h1 is centred inside a box the flush-left rule above has pinned
 * to the left gutter — so on a 1600px screen the title sits around x=646 instead of x=794
 * and reads as "not centred" even though `text-align: center` is doing exactly what it was
 * asked. Same failure as the artist page's genre line: centred text in a left-hung box.
 *
 * Deliberately keyed on `has-text-align-center` rather than listing the patterns that use
 * it, so anything the client centres in the editor later behaves correctly for free.
 *
 * The class is doubled to reach (0,8,0) — one step past the flush-left rule's (0,7,0) — so
 * this does not depend on winning a same-specificity tie by source order.
 */
.wp-site-blocks .is-layout-constrained > .has-text-align-center.has-text-align-center:not(.alignfull):not(.alignwide):not(.alignleft):not(.alignright) {
	margin-left: auto !important;
	margin-right: auto !important;
}

/* Restates the global default; kept because seeded content references it. */
.camoon-band--dark {
	background-color: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--base);
}

/*
 * Every listing block opens with this row: the section title at the left, an optional
 * "view all" link at the right, both on the gutter. It replaces the bare <h2> the blocks
 * used to emit, and with it the old `--inset` modifier — that existed only to pull a
 * heading back onto the 1180px measure above a full-bleed grid, and there is no longer a
 * second measure to pull it back to.
 *
 * `flex-end` rather than `baseline`: the title is several times the size of the link, and
 * sharing a baseline with it drags the link far from the row's bottom edge.
 */
.camoon-section__head {
	align-items: flex-end;
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--40);
	justify-content: space-between;
	margin-bottom: var(--wp--preset--spacing--40);
	padding-inline: var(--camoon-gutter);
}

.camoon-section__title {
	font-size: clamp(2.25rem, 1rem + 4.5vw, 4.5rem);
	margin: 0;
}

.camoon-section__more {
	color: var(--wp--preset--color--silver);
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--medium);
	letter-spacing: 0.12em;
	text-decoration: none;
	text-transform: uppercase;
	transition: color 0.25s ease;
	white-space: nowrap;
}

.camoon-section__more:hover {
	color: var(--wp--preset--color--base);
	text-decoration: underline;
}

/* The arrow slides on hover — the only movement a quiet text link gets. */
.camoon-section__more span {
	display: inline-block;
	transition: transform 0.25s ease;
}

.camoon-section__more:hover span {
	transform: translateX(0.25em);
}

/* ------------------------------------------------------------------ logo -- */

/*
 * The header logo. logo.png is drawn near-black (rgb 9–16) on a transparent ground, for
 * light backgrounds — dropped into the `ink` header as-is it is invisible. It is inverted
 * here rather than shipped as a second file, and for this mark inversion is exact rather
 * than approximate: the strokes land near-white, and the one white path in the artwork —
 * the counter inside the A of CAMOON — lands at rgb(7,7,7) against an rgb(11,11,11)
 * header, so it still reads as a hole rather than a white blob.
 *
 * `brightness(0) invert(1)` would NOT work: it flattens every fill to pure white, filling
 * that counter in and turning the A into a solid wedge.
 *
 * If a light-on-dark logo.png is ever supplied, drop the filter — nothing else changes.
 */
.camoon-logo {
	display: block;
	flex: none;
	line-height: 0;
}

.camoon-logo img {
	display: block;
	filter: invert(1);
	height: var(--camoon-header-logo-h);
	width: auto;
}

/* -------------------------------------------------------------- wordmark -- */

/*
 * Type, not artwork — the site title remains editable text.
 *
 * The HEADER no longer uses this: it renders logo.png (see .camoon-logo above). The
 * wordmark survives because the FOOTER still sets the site title as oversized type, which
 * is a deliberate contrast with the mark in the header rather than a leftover.
 * The footer follows the stored site title.
 *
 * `text-transform: uppercase` is what renders the stored site title "Camoon" as CAMOON.
 */
.camoon-wordmark {
	color: var(--wp--preset--color--base);
	font-family: var(--wp--preset--font-family--display);
	font-size: clamp(1.625rem, 1.25rem + 1.5vw, 2.5rem);
	font-weight: 700;
	letter-spacing: -0.02em;
	line-height: 1;
	text-transform: uppercase;
}

.camoon-wordmark a {
	color: inherit;
	text-decoration: none;
}

.camoon-wordmark a:hover {
	color: var(--wp--preset--color--silver);
}

/* Full-width type crosses the footer's dark/light boundary. */
.camoon-footer__mark {
	color: #fff;
	font-size: var(--camoon-footer-mark-size);
	line-height: 0.9;
	margin: 0;
	mix-blend-mode: difference;
	text-align: center;
	-webkit-user-select: none;
	user-select: none;
	white-space: nowrap;
}

/* ---------------------------------------------------------------- header -- */

/*
 * The header MUST set `color`, not just `background-color`.
 *
 * Core styles navigation links as
 *   `.wp-block-navigation .wp-block-navigation-item__content.wp-block-navigation-item__content { color: inherit }`
 * at specificity (0,3,0), which beats any reasonable `.camoon-header … a` rule. The links take
 * whatever the header inherits, so a header with no `color` gave invisible links. The rule
 * below doubles a class to reach (0,4,0) and outrank core outright.
 */
/*
 * No rule underneath. The header is sticky over dark bands, so a hairline was never doing
 * much separating — the solid background already marks where it ends.
 */
.camoon-header {
	background-color: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--base);
	padding-inline: var(--camoon-gutter);
	position: sticky;
	top: 0;
	z-index: 20;
}

.camoon-header .wp-block-navigation .wp-block-navigation-item__content.wp-block-navigation-item__content {
	color: currentColor;
	position: relative;
	transition: color 0.2s ease;
}

.camoon-header .wp-block-navigation .wp-block-navigation-item__content.wp-block-navigation-item__content:hover {
	color: var(--wp--preset--color--silver);
}

/*
 * Animated underline. Drawn as a pseudo-element rather than `text-decoration`, because
 * `text-decoration` cannot be transitioned — it can only snap on. Scaling from the left on
 * the way in and out gives the line a direction instead of a fade.
 */
.camoon-header .wp-block-navigation .wp-block-navigation-item__content::after {
	background-color: currentColor;
	bottom: -0.35em;
	content: "";
	height: 1px;
	inset-inline: 0;
	position: absolute;
	transform: scaleX(0);
	transform-origin: left center;
	transition: transform 0.25s ease;
}

.camoon-header .wp-block-navigation .wp-block-navigation-item__content:hover::after,
.camoon-header .wp-block-navigation .wp-block-navigation-item__content:focus-visible::after {
	transform: scaleX(1);
}

/*
 * Move the overlay-menu breakpoint from core's 600px up to 900px.
 *
 * `overlayMenu: "mobile"` hands the decision to core, which swaps to the hamburger below
 * 600px — far too late for this header. Five Finnish labels plus the logo need about
 * 780px, so between 600 and 779 the navigation wrapped onto a second row and doubled the
 * height of a STICKY header, costing that space on every scroll of every page.
 *
 * 900px rather than a tight 800: it is the breakpoint the rest of this file already uses,
 * and it leaves room for a sixth item or a longer translation without re-breaking. The
 * cost is a hamburger between 800 and 899 where the links would still just fit.
 *
 * Core sets these two rules in `@media (min-width: 600px)`, so both have to be undone or
 * the header shows the hamburger AND the inline list at once. The `.camoon-header` prefix
 * is what wins: core's selectors are (0,3,0) and (0,2,0), these are (0,4,0) and (0,3,0).
 * Nothing here is !important, because nothing in core's rules is either.
 */
@media (max-width: 899px) {
	.camoon-header .wp-block-navigation__responsive-container:not(.hidden-by-default):not(.is-menu-open) {
		display: none;
	}

	.camoon-header .wp-block-navigation__responsive-container-open:not(.always-shown) {
		display: flex;
	}
}

/*
 * The overlay menu itself.
 *
 * Colours are set on the BLOCK, not here — `overlayBackgroundColor`/`overlayTextColor` in
 * patterns/header.php. Core defaults an overlay whose nav has no colours to
 * `background: #fff; color: #000`, which opened a white sheet over an otherwise entirely
 * dark site. Overriding that in CSS means out-specifying a (0,5,0) core selector; setting
 * the attributes instead makes core emit the right classes and skip its own default, and
 * leaves the colours editable in wp-admin.
 *
 * Core lays the panel out top-aligned and inherits the bar's `justifyContent: right`, so
 * the items land in the top-right corner. Centring is two independent axes: `justify-content`
 * on the container (vertical — the close wrapper is auto-height, so centring it in the
 * full-height column centres the menu) and `align-items` on the content and list
 * (horizontal). Core's `padding-top: calc(2rem + 24px)` exists only to clear the close
 * button and would push the centred block down, so it goes.
 *
 * Every selector is prefixed with `.camoon-header` to clear core's (0,3,0) overlay rules.
 */
.camoon-header .wp-block-navigation__responsive-container.is-menu-open {
	justify-content: center;
}

.camoon-header .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content {
	align-items: center;
	justify-content: center;
	padding-top: 0;
}

.camoon-header .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__container {
	align-items: center;
	justify-content: center;
}

.camoon-header .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content {
	font-size: var(--wp--preset--font-size--x-large);
}

/*
 * Tap targets. Both buttons ship as a bare 24px SVG with no padding — half the 48px
 * minimum, and the smallest thing on the site to hit on a phone.
 *
 * Sizing both to 48px is also what aligns them. Each sits with its right edge on the
 * gutter — the hamburger as the last item in the header row, the close button via the
 * container's own gutter-width padding — so once the boxes match and both icons are
 * centred, the two icons share a vertical axis for free.
 *
 * The horizontal axis needs help: the close button is absolutely positioned against the
 * dialog, whose top is the overlay's padding edge, NOT the header's baseline. Switching it
 * to `fixed` re-anchors it to the viewport so it can be placed on the hamburger's exact
 * centre line — `spacing|40` of header padding plus half the logo.
 */
/*
 * ⚠️ Do NOT add `display` here. Whether the hamburger is shown is core's decision, taken in
 * `@media (min-width: 600px)` and amended by the 900px block above — and core's selector
 * `.wp-block-navigation__responsive-container-open:not(.always-shown)` is (0,2,0), exactly
 * the same weight as `.camoon-header .wp-block-navigation__responsive-container-open`.
 * The theme stylesheet loads after core's block styles, so a `display` declared here wins
 * the tie at EVERY width and the hamburger appears on desktop beside the links — which
 * also wraps the links onto a second row. Sizing only; visibility belongs above.
 */
.camoon-header .wp-block-navigation__responsive-container-open,
.camoon-header .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-close {
	align-items: center;
	justify-content: center;
	min-height: 48px;
	min-width: 48px;
}

.camoon-header .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-close {
	display: flex;
	position: fixed;
	right: var(--camoon-gutter);
	top: calc(var(--wp--preset--spacing--40) + (var(--camoon-header-logo-h) / 2));
	transform: translateY(-50%);
}

/*
 * Fade the overlay in WITHOUT transforming it.
 *
 * Core's `overlay-menu__fade-in-animation` animates `translateY(0.5em) → translateY(0)`
 * with `animation-fill-mode: forwards`, so the container keeps a transform for as long as
 * the menu is open. A transformed element becomes the containing block for its
 * `position: fixed` descendants — which is the close button above — and its containing
 * block would then be the container's PADDING box rather than the viewport, inseting the
 * button by a second gutter.
 *
 * Firefox measured identical with and without motion, so this is not a live bug there, but
 * it depends on how an engine treats a leftover `translateY(0)`, and only one engine was
 * available to test. Swapping in an opacity-only keyframe removes the question: with no
 * transform, `fixed` means the viewport everywhere.
 *
 * Only `animation-name` is overridden. Where core sets the shorthand its duration, easing
 * and fill-mode carry over; under `prefers-reduced-motion`, where core sets no animation at
 * all, the name alone inherits a 0s duration and stays inert.
 */
@keyframes camoon-overlay-menu-fade {
	from {
		opacity: 0;
	}

	to {
		opacity: 1;
	}
}

.camoon-header .wp-block-navigation__responsive-container.is-menu-open {
	animation-name: camoon-overlay-menu-fade;
}

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

/*
 * Core's `is-style-outline` sets its own border-width (2px) and padding
 * (0.667em/1.33em), overriding what theme.json declares. Filled and outline buttons
 * therefore came out different heights and widths. Restate both so a pair matches.
 *
 * The transition is here rather than in theme.json because theme.json has no field for
 * it — without it the outline button's hover snapped.
 */
.wp-block-button__link,
.wp-block-button.is-style-outline > .wp-block-button__link {
	border-style: solid;
	border-width: 1px;
	padding: 0.9rem 2rem;
	transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}

.wp-block-button.is-style-outline > .wp-block-button__link {
	background-color: transparent;
	border-color: var(--wp--preset--color--base);
	color: var(--wp--preset--color--base);
}

.wp-block-button.is-style-outline > .wp-block-button__link:hover {
	background-color: var(--wp--preset--color--base);
	color: var(--wp--preset--color--ink);
}

/*
 * Equal height is not enough when the two labels differ in length — the pair still looks
 * unbalanced. Give hero buttons a shared floor and centre their text.
 */
.camoon-hero .wp-block-button__link,
.camoon-cover__inner .wp-block-button__link {
	min-width: 14rem;
	text-align: center;
}

/* ------------------------------------------------------------------ hero -- */

/*
 * The hero and the artist/event headers are core/cover blocks, so image, overlay opacity
 * and height are all editable in wp-admin. These rules handle only what cover cannot:
 * holding the text on the content measure while the image runs full width.
 */
/*
 * Covers sit ON the gutter rather than bleeding past it, like every other section — and
 * they get there two different ways, because the three covers have different parents.
 *
 * The FRONT-PAGE hero is inside `.entry-content`, which has global padding, so core gives
 * its `alignfull` negative side margins to escape that padding. Cancelling them lands it
 * exactly on the gutter, because the root padding IS the gutter. Core's rule is
 * `.has-global-padding > .alignfull` at (0,2,0), so this selector is deliberately (0,3,0);
 * a bare `.camoon-cover` would lose the cascade. No `!important` needed — unlike core's
 * constrained-layout margins, these are ordinary declarations.
 *
 * The ARTIST and EVENT headers sit directly in `<main>`, which has no padding at all, so
 * there is no negative margin to cancel — they have to be inset by hand instead. Getting
 * this wrong is invisible on the front page and obvious on every artist page.
 *
 * Nothing else needs undoing: core's "pad the children of an alignfull element" rule skips
 * any class containing `__`, which is every child a cover has.
 */
.wp-site-blocks .has-global-padding > .camoon-cover {
	margin-inline: 0;
}

.wp-site-blocks > main > .camoon-cover {
	margin-inline: var(--camoon-gutter);
}

/* Left margin comes from the flush-left rule at the top of this file, not from here. */
.camoon-cover__inner {
	max-width: var(--wp--style--global--content-size);
	padding-inline: var(--camoon-hero-inset);
	width: 100%;
}

.camoon-cover__inner :where(h1, h2, p) {
	color: var(--wp--preset--color--base);
	text-wrap: balance;
}

/*
 * Brand watermark in the front-page hero — the CA monogram, large, white and faint.
 *
 * `brightness(0) invert(1)`, not the `invert(1)` the header logo uses. That distinction is
 * per-file, not stylistic: logo.png contains a white path (the counter inside the A) that
 * must survive, so it can only be inverted. icon.svg is a single near-black path with no
 * counter, so flattening it to pure white is both safe and independent of the artwork's
 * exact grey.
 *
 * STACKING. The mark is absolutely positioned and .camoon-cover__inner is static, and a
 * positioned element paints above a static sibling regardless of source order — so without
 * the second rule the monogram sits on top of the headline. Lifting the text to z-index 1
 * is what puts it back on top; the mark's own z-index: 0 keeps it above the cover's
 * background rather than disappearing behind it, which is what z-index: -1 would do.
 *
 * Decorative: alt="", aria-hidden, and pointer-events: none so it can never intercept a
 * click meant for the hero buttons.
 */
.camoon-hero__mark {
	filter: brightness(0) invert(1);
	height: auto;
	inset-inline-end: clamp(1.5rem, 4vw, 5rem);
	opacity: 0.12;
	pointer-events: none;
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	width: min(42vw, 40rem);
	z-index: 0;
}

.camoon-hero .camoon-cover__inner {
	position: relative;
	z-index: 1;
}

/*
 * Decorative images must not be selectable.
 *
 * Double-clicking anywhere in a cover starts a word selection. With no text under the
 * pointer the browser extends the range over the nearest nodes — which are these two
 * images — and a selected <img> is painted with the selection colour, so the monogram and
 * the photograph turn into flat grey rectangles over the hero.
 *
 * `pointer-events: none` does NOT prevent this. It stops the mark receiving the click; it
 * does not stop a selection from spanning it.
 *
 * Both images carry alt="", so nothing meaningful becomes unselectable — the hero's
 * headline, lead and buttons still select and copy exactly as before. Scoped to
 * .camoon-cover so the artist, event and news headers get the same treatment.
 */
.camoon-hero__mark,
.camoon-cover > .wp-block-cover__image-background {
	user-select: none;
}

/*
 * Hidden below 1100px — deliberately NOT the 900px the rest of the file breaks at.
 *
 * The watermark needs horizontal room the layout does not have below that: between roughly
 * 900 and 1100 the mark both crowds the lead paragraph and runs into the cover's right
 * edge, where `overflow: hidden` clips the A's leg. A decorative element earning its own
 * threshold is cheaper than shrinking it into illegibility at every width.
 */
@media (max-width: 1099px) {
	.camoon-hero__mark {
		display: none;
	}
}

.camoon-hero__meta {
	color: var(--wp--preset--color--silver);
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--medium);
	letter-spacing: 0.14em;
	text-transform: uppercase;
}

/* ------------------------------------------------------- full-bleed grids -- */

/*
 * The artist and event grids are the site's main device: edge to edge, no gutters, text
 * set over the photograph.
 *
 * Zero gap only reads as deliberate if the tiles are a true grid, so each tile is a fixed
 * SQUARE and the image is cropped to it. Square keeps a three-across grid from running
 * taller than the viewport, which portrait tiles did.
 */
/*
 * The gutter, applied to every FULL-WIDTH listing block. The grids no longer run to the
 * very edge of the viewport — the tiles still butt against each other with zero gap, but
 * the grid as a whole is inset like everything else, so the page has one width rather
 * than two.
 *
 * Conditional on `.alignfull` on purpose: the gutter exists to inset a listing that has
 * broken out of the page's padding. A listing left constrained — the artist page's show
 * list, for one — is already inside padded content, and adding the gutter again would
 * inset it twice.
 */
.camoon-artist-grid.alignfull,
.camoon-event-list.alignfull,
.camoon-show-list.alignfull,
.camoon-news-list.alignfull {
	padding-inline: var(--camoon-gutter);
}

.camoon-artist-grid,
.camoon-event-list {
	margin-block: 0;
}

/* The head supplies its own gutter, so it must not be inset twice. */
.camoon-artist-grid > .camoon-section__head,
.camoon-event-list > .camoon-section__head,
.camoon-show-list > .camoon-section__head,
.camoon-news-list > .camoon-section__head {
	padding-inline: 0;
}

.camoon-artists,
.camoon-events {
	display: grid;
	gap: 0;
	grid-template-columns: repeat(var(--camoon-columns, 3), minmax(0, 1fr));
	list-style: none;
	margin: 0;
	padding: 0;
}

.camoon-artist-grid--cols-1 .camoon-artists { --camoon-columns: 1; }
.camoon-artist-grid--cols-2 .camoon-artists { --camoon-columns: 2; }
.camoon-artist-grid--cols-3 .camoon-artists { --camoon-columns: 3; }
.camoon-artist-grid--cols-4 .camoon-artists { --camoon-columns: 4; }
.camoon-artist-grid--cols-5 .camoon-artists { --camoon-columns: 5; }
.camoon-artist-grid--cols-6 .camoon-artists { --camoon-columns: 6; }

.camoon-tile {
	aspect-ratio: 1 / 1;
	background-color: var(--wp--preset--color--carbon);
	display: block;
	overflow: hidden;
	position: relative;
	text-decoration: none;
}

.camoon-tile__media {
	inset: 0;
	position: absolute;
}

.camoon-tile__image {
	display: block;
	height: 100%;
	object-fit: cover;
	width: 100%;

	/*
	 * Colour by default, desaturating on hover — the inverse of the usual trick. On a
	 * fully dark site the photographs are the only colour there is, so removing it by
	 * default made everything relentless; taking it away on hover still marks the
	 * interaction without draining the page.
	 */
	filter: none;
	transition: filter 0.5s ease, transform 0.6s ease;
}

/*
 * The hover slideshow cross-fades between two stacked layers rather than swapping one
 * image's `src`, which cut hard. The script clones the rendered <img> into a second layer
 * and alternates their opacity; only cards that actually cycle ever get the class, so a
 * single-image tile is untouched markup.
 *
 * `opacity` is transitioned here rather than in the script so the duration lives with the
 * rest of the motion and honours the reduced-motion block at the end of this file.
 */
.camoon-tile--fading .camoon-tile__image {
	inset: 0;
	position: absolute;
	transition: filter 0.5s ease, opacity 0.9s ease, transform 0.6s ease;
}

.camoon-tile__image--back {
	opacity: 0;
}

.camoon-tile:hover .camoon-tile__image,
.camoon-tile:focus-visible .camoon-tile__image {
	filter: grayscale(1) contrast(1.08);
	transform: scale(1.04);
}

/* Fallback for entries with no featured image yet. */
.camoon-tile__placeholder {
	background-image: repeating-linear-gradient(
		45deg,
		transparent 0 12px,
		rgba(255, 255, 255, 0.05) 12px 24px
	);
	display: block;
	height: 100%;
	width: 100%;
}

/*
 * The scrim. Text sits on photographs of unknown brightness, so legibility cannot be left
 * to luck — and now that the images keep their colour it matters more, not less.
 */
.camoon-tile__body {
	color: var(--wp--preset--color--base);
	inset-inline: 0;
	padding: var(--wp--preset--spacing--50) var(--wp--preset--spacing--40) var(--wp--preset--spacing--40);
	position: absolute;
	transition: background 0.5s ease;
}

/* Artist cards: everything bottom-left. */
.camoon-tile__body:not(.camoon-tile__body--top):not(.camoon-tile__body--bottom),
.camoon-tile__body--bottom {
	background: linear-gradient(
		to top,
		rgba(0, 0, 0, 0.88) 0%,
		rgba(0, 0, 0, 0.55) 40%,
		rgba(0, 0, 0, 0) 100%
	);
	bottom: 0;
}

/*
 * Event cards: date and title at the TOP, the bill along the bottom. Same tile, same
 * grid, opposite anatomy — so an event never reads as an artist even at a glance.
 */
.camoon-tile__body--top {
	background: linear-gradient(
		to bottom,
		rgba(0, 0, 0, 0.88) 0%,
		rgba(0, 0, 0, 0.55) 45%,
		rgba(0, 0, 0, 0) 100%
	);
	padding: var(--wp--preset--spacing--40) var(--wp--preset--spacing--40) var(--wp--preset--spacing--50);
	top: 0;
}

.camoon-tile__body--bottom {
	padding-top: var(--wp--preset--spacing--60);
}

.camoon-tile:hover .camoon-tile__body:not(.camoon-tile__body--top) {
	background: linear-gradient(
		to top,
		rgba(0, 0, 0, 0.94) 0%,
		rgba(0, 0, 0, 0.65) 45%,
		rgba(0, 0, 0, 0) 100%
	);
}

.camoon-tile:hover .camoon-tile__body--top {
	background: linear-gradient(
		to bottom,
		rgba(0, 0, 0, 0.94) 0%,
		rgba(0, 0, 0, 0.65) 50%,
		rgba(0, 0, 0, 0) 100%
	);
}

.camoon-tile__name {
	display: block;
	font-family: var(--wp--preset--font-family--display);
	font-size: clamp(1.375rem, 1rem + 1.4vw, 2.125rem);
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1;
	text-transform: uppercase;
}

.camoon-tile__meta {
	color: var(--wp--preset--color--silver);
	display: block;
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--small);
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

/* On artist cards the meta follows the name; on event cards it leads. */
.camoon-tile__body:not(.camoon-tile__body--top) .camoon-tile__meta {
	margin-top: 0.45em;
}

.camoon-tile__body--top .camoon-tile__meta {
	margin-bottom: 0.5em;
}

/*
 * The bill along the bottom of an event card. Set in the display face at poster size
 * rather than as a caption — on an event, who is playing is most of the information.
 */
.camoon-tile__lineup {
	color: var(--wp--preset--color--silver);
	display: block;
	font-family: var(--wp--preset--font-family--display);
	font-size: clamp(0.9375rem, 0.8rem + 0.4vw, 1.125rem);
	letter-spacing: 0.06em;
	line-height: 1.35;
	text-transform: uppercase;
}

/*
 * Marquee. A long bill will not fit one line of a square tile, and wrapping it to three
 * lines swallows the photograph — so an overflowing lineup scrolls instead.
 *
 * CSS cannot ask whether text overflows, so the classes below are added by tiles.js only
 * after it has measured. Until then (and forever, under reduced motion, or with JS off)
 * the lineup is ordinary wrapping text — nothing is hidden by default.
 *
 * The seamless loop works by duplicating the names into a second, aria-hidden copy and
 * translating the pair by exactly -50%: at the end of the animation copy 2 sits precisely
 * where copy 1 began, so the restart is invisible. `--camoon-marquee-duration` is set per
 * element from the measured width, keeping every card scrolling at the same speed.
 */
.camoon-tile__lineup--measuring,
.camoon-tile__lineup--scrolling {
	overflow: hidden;
}

.camoon-tile__lineup--measuring .camoon-tile__lineup-track,
.camoon-tile__lineup--scrolling .camoon-tile__lineup-track {
	display: inline-block;
	white-space: nowrap;
}

/*
 * The gap between the two copies is padding on each track, not a separator character —
 * the halves have to stay exactly equal for -50% to land copy 2 where copy 1 started.
 */
.camoon-tile__lineup--scrolling .camoon-tile__lineup-track {
	/* Flex items shrink by default; a shrunk half would break the -50% arithmetic. */
	flex: 0 0 auto;
	padding-right: 2.5em;
}

.camoon-tile__lineup-marquee {
	animation: camoon-marquee var(--camoon-marquee-duration, 12s) linear infinite;
	display: flex;
	width: max-content;
	will-change: transform;
}

@keyframes camoon-marquee {
	from {
		transform: translateX(0);
	}

	to {
		transform: translateX(-50%);
	}
}

@media (max-width: 899px) {
	.camoon-artists {
		grid-template-columns: repeat(min(2, var(--camoon-columns, 3)), minmax(0, 1fr));
	}

	.camoon-events {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 559px) {
	.camoon-artists,
	.camoon-events {
		grid-template-columns: 1fr;
	}

	/* A square tile is very tall when it is the full width of a phone. */
	.camoon-tile {
		aspect-ratio: 3 / 2;
	}
}

/* ------------------------------------------------------------------ shows -- */

/* Artist list and text cards share the photo grid's links and typography. */
.camoon-artist-grid--list .camoon-artists {
	grid-template-columns: 1fr;
}

.camoon-artist-grid--no-images .camoon-artists {
	gap: 1px;
}

.camoon-artist-grid--list .camoon-tile,
.camoon-artist-grid--no-images .camoon-tile {
	aspect-ratio: auto;
	display: flex;
	align-items: center;
	min-height: 6rem;
	height: 100%;
}

.camoon-artist-grid--list .camoon-tile {
	border-bottom: 1px solid var(--wp--preset--color--silver);
	padding: var(--wp--preset--spacing--30);
	gap: var(--wp--preset--spacing--30);
}

.camoon-artist-grid--list .camoon-tile__media {
	position: relative;
	inset: auto;
	flex: 0 0 5rem;
	width: 5rem;
	height: 5rem;
	overflow: hidden;
}

.camoon-artist-grid--list .camoon-tile__body:not(.camoon-tile__body--top):not(.camoon-tile__body--bottom),
.camoon-artist-grid--no-images .camoon-tile__body:not(.camoon-tile__body--top):not(.camoon-tile__body--bottom) {
	position: static;
	background: none;
	min-width: 0;
	padding: var(--wp--preset--spacing--30);
	overflow-wrap: anywhere;
}

.camoon-artist-grid--list .camoon-tile:hover .camoon-tile__body,
.camoon-artist-grid--no-images .camoon-tile:hover .camoon-tile__body {
	background: none;
	text-decoration: underline;
	text-underline-offset: 0.15em;
}

.camoon-artist-grid--list .camoon-tile__image {
	filter: none;
	transform: none;
}

/*
 * A gig calendar is read, not browsed, so it stays a text list — no thumbnails.
 *
 * The ticket column is a FIXED width, not `auto`. `grid-template-columns` sits on each
 * row, so every row is its own grid: with an `auto` track, rows with a ticket link sized
 * that column to the link and rows without collapsed it to zero, and the `1fr` tracks
 * absorbed the difference — so venues landed at a different x on every row. A fixed track
 * makes every row identical regardless of content.
 */
.camoon-shows {
	list-style: none;
	margin: 0;
	padding: 0;
}

/*
 * `center`, not `baseline`. The row mixes four type sizes — a medium date, an x-large
 * artist, a medium venue and the ticket links — and sharing a baseline across them left
 * the small cells sitting oddly high against the big one.
 */
.camoon-show {
	align-items: center;
	border-top: 1px solid rgba(255, 255, 255, 0.18);
	display: grid;
	gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--40);
	grid-template-columns: 13rem minmax(0, 1fr) minmax(0, 1fr) 12rem;
	padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--20);
	transition: background-color 0.2s ease;

	/*
	 * The row is padded and then pulled back out by the same amount, so the hover tint
	 * extends past the text while the text itself stays aligned with the section head
	 * above it. Padding alone would indent the whole list; the negative margin alone would
	 * have nothing to fill.
	 *
	 * Deliberately spacing--20 (0.75rem) rather than the gutter: `--camoon-gutter` bottoms out
	 * at 1.25rem, so pulling by the gutter would put rows flush against the viewport edge
	 * on a phone.
	 */
	margin-inline: calc(var(--wp--preset--spacing--20) * -1);
}

.camoon-show:hover {
	background-color: rgba(255, 255, 255, 0.05);
}

/* On an artist's own page the artist column is suppressed, so the row has one cell fewer. */
.camoon-shows--no-artist .camoon-show {
	grid-template-columns: 13rem minmax(0, 1fr) 12rem;
}

.camoon-shows > .camoon-show:last-child {
	border-bottom: 1px solid rgba(255, 255, 255, 0.18);
}

.camoon-show__date {
	color: var(--wp--preset--color--silver);
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--medium);
	font-weight: 500;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	white-space: nowrap;
}

.camoon-show__artist {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--x-large);
	font-weight: 700;
	line-height: 1.1;
	text-transform: uppercase;
}

.camoon-show__artist a {
	text-decoration: none;
}

.camoon-show__artist a:hover {
	text-decoration: underline;
}

/* Barlow ships a real 600 (assets/fonts/), so this is a true weight, not a synthesised bold. */
.camoon-show__place {
	color: var(--wp--preset--color--silver);
	font-size: var(--wp--preset--font-size--large);
	font-weight: 600;
}

/*
 * Right-aligned, because the row's border runs the full width of the grid. With the links
 * at the left of their fixed track the border carried on well past LIPUT and the row read
 * as unfinished; ending the link flush with the border closes it off.
 */
.camoon-show__links {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--30);
	justify-content: flex-end;
	white-space: nowrap;
}

.camoon-show__tickets,
.camoon-show__event {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--medium);
	font-weight: 500;
	letter-spacing: 0.1em;
	text-transform: uppercase;
}

.camoon-show__tickets {
	border-bottom: 2px solid currentColor;
	text-decoration: none;
}

@media (max-width: 899px) {
	/*
	 * The no-artist variant is listed explicitly: media queries add no specificity, so
	 * `.camoon-shows--no-artist .camoon-show` (0,2,0) would otherwise keep its desktop columns.
	 */
	.camoon-show,
	.camoon-shows--no-artist .camoon-show {
		gap: var(--wp--preset--spacing--20);
		grid-template-columns: 1fr;
	}

	/* Single column: the links sit under the venue, so they lead rather than trail. */
	.camoon-show__links {
		justify-content: flex-start;
		margin-top: var(--wp--preset--spacing--20);
	}
}

/* ------------------------------------------------------------------- news -- */

/*
 * News is text-led rather than another photo grid. Artists and events are browsed by
 * looking; news is read, and a third wall of tiles would flatten the difference.
 */
/*
 * Two columns where there is room, one below 900px — the same step the artist and event
 * grids use, so the whole site changes shape at the same widths.
 *
 * Unlike the tile grids this one keeps a COLUMN GAP. Tiles butted together read as a
 * deliberate mosaic; two columns of text butted together just read as one confusing block.
 */
.camoon-news {
	column-gap: var(--wp--preset--spacing--50);
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	list-style: none;
	margin: 0;
	padding: 0;
}

/*
 * A HORIZONTAL rule between items, and only horizontal — the column gap already separates
 * the two columns, and a vertical rule as well would turn a reading list into a table.
 *
 * Lighter than the site's other hairlines (0.10 rather than 0.18): the padding is still
 * doing most of the separating, and the rule is only there to confirm it.
 */
.camoon-news-item {
	border-top: 1px solid rgba(255, 255, 255, 0.1);
	display: grid;
	gap: var(--wp--preset--spacing--40);
	grid-template-columns: 10rem minmax(0, 1fr);
	padding: var(--wp--preset--spacing--50) 0;
}

/*
 * …but not above the FIRST ROW. The rule is there to separate one article from the next,
 * so a line above the first one separates it from nothing and just boxes the list in.
 *
 * Which items make up the first row depends on the column count, so this takes two rules:
 * item 1 always, and item 2 as well once there are two columns.
 */
.camoon-news-item:first-child {
	border-top: 0;
}

@media (min-width: 900px) {
	.camoon-news-item:nth-child(2) {
		border-top: 0;
	}
}

.camoon-news-item--no-image {
	grid-template-columns: minmax(0, 1fr);
}

.camoon-news-item__media {
	aspect-ratio: 4 / 3;
	background-color: var(--wp--preset--color--carbon);
	display: block;
	overflow: hidden;
}

.camoon-news-item__image {
	display: block;
	height: 100%;
	object-fit: cover;
	width: 100%;
}

.camoon-news-item__date {
	color: var(--wp--preset--color--silver);
	display: block;
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--small);
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

.camoon-news-item__title {
	font-size: var(--wp--preset--font-size--x-large);
	margin: 0.3em 0 0.4em;
}

.camoon-news-item__title a {
	text-decoration: none;
}

.camoon-news-item__title a:hover {
	text-decoration: underline;
}

.camoon-news-item__excerpt {
	color: var(--wp--preset--color--silver);
	font-size: var(--wp--preset--font-size--large);
	margin: 0;
}

.camoon-news-hero__date {
	color: var(--wp--preset--color--silver);
	font-family: var(--wp--preset--font-family--display);
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

/*
 * The article's featured image. `alignfull` spans the page, so it is inset to the gutter
 * here like everything else rather than bleeding to the viewport edge.
 *
 * The height cap is the important half. At 16/9 a full-width image is over 2000px tall on
 * a 4K display — the headline scrolls away and the article starts below the fold. `vh` and
 * a `rem` ceiling together mean it stays proportionate on a laptop and stops growing on a
 * very large screen; `object-fit: cover` keeps the crop centred instead of squashing it.
 */
.camoon-news-image {
	margin-inline: 0;
	padding-inline: var(--camoon-gutter);
}

.camoon-news-image img {
	max-height: min(60vh, 34rem);
	object-fit: cover;
	width: 100%;
}

/* Its own breathing room: the article sat flush against the image and the band below it. */
/*
 * The three long-form bodies share ONE rule so they cannot drift apart. They did: news got
 * this vertical padding, artist got its own copy of it, and event was left flush against
 * the image above and the band below, which is exactly the mismatch that got reported.
 */
.camoon-artist-content,
.camoon-event-content,
.camoon-news-content {
	padding-block: var(--wp--preset--spacing--50);
}

@media (max-width: 899px) {
	.camoon-news {
		grid-template-columns: 1fr;
	}
}

@media (max-width: 599px) {
	.camoon-news-item {
		grid-template-columns: 1fr;
	}

	.camoon-news-item__media {
		aspect-ratio: 16 / 9;
	}
}

/* ---------------------------------------------------------------- spotify -- */

.camoon-spotify__frame {
	border: 0;
	display: block;
	width: 100%;
}

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

/*
 * Listings that vanish when empty read as a broken page — to visitors, and more often to
 * the client previewing a section they have not filled in yet. A brand-new site is ALL
 * empty states, so they are part of the design rather than an afterthought.
 */
.camoon-empty {
	border: 1px dashed rgba(255, 255, 255, 0.25);
	color: var(--wp--preset--color--silver);
	font-size: var(--wp--preset--font-size--medium);
	margin: var(--wp--preset--spacing--40) 0;
	padding: var(--wp--preset--spacing--50) var(--wp--preset--spacing--40);
	text-align: center;
}

/* ------------------------------------------------------- artist / event -- */

.camoon-artist-hero__meta {
	color: var(--wp--preset--color--silver);
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--medium);
	letter-spacing: 0.14em;
	text-transform: uppercase;
}

/*
 * The outbound link row. It used to sit inside the hero, over the press photo, where six
 * links competed with the artist's name; it now lives below the image and above the bio,
 * which is where someone actually looks for it.
 */
.camoon-artist-hero__links {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--30);
	list-style: none;
	margin: var(--wp--preset--spacing--30) 0 0;
	padding: 0;
}

.camoon-artist-hero__links a {
	align-items: center;
	display: inline-flex;
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--small);
	gap: 0.5em;
	letter-spacing: 0.1em;
	text-decoration: none;
	text-transform: uppercase;
	transition: color 0.2s ease;
}

.camoon-artist-hero__links a:hover {
	color: var(--wp--preset--color--silver);
	text-decoration: underline;
}

/*
 * Icons are stroked, not filled, so each one carries the same visual weight whatever its
 * shape. They inherit `currentColor`, so they follow the link through its hover state
 * without a second rule.
 */
.camoon-link-icon {
	flex: 0 0 auto;
	height: 1.25em;
	width: 1.25em;
}

/*
 * A long bill needs columns, not a wrapped row. A club night has three or four acts and a
 * wrapping row reads fine; a festival can have thirty, and thirty names wrapped into a
 * run-on paragraph is unreadable. The `--long` class is added by the block once the count
 * passes eight, because CSS cannot count its own children usefully here.
 */
.camoon-event-meta__lineup--long {
	display: grid;
	gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--40);
	grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
	text-align: left;
}

.camoon-event-meta__actions {
	margin-top: var(--wp--preset--spacing--40);
}

/* --------------------------------------------------- artist / event page -- */

/* Hero content stays centered; artist body copy is left-aligned in its column. */
.camoon-artist-page .camoon-cover__inner,
.camoon-artist-page .camoon-artist-hero__wrap,
.camoon-artist-page .camoon-artist-content,
.camoon-artist-page .camoon-spotify,
.camoon-event-page .camoon-cover__inner,
.camoon-event-page .camoon-event-meta {
	text-align: center;
}

.camoon-artist-page .camoon-artist-hero__links,
.camoon-event-page .camoon-artist-hero__links {
	justify-content: center;
}

/*
 * A long bill keeps its columns left-aligned even in a centred hero — thirty ragged-centred
 * names in narrow columns is harder to scan than thirty flush ones. The grid as a whole is
 * still centred; only the text inside each column is not.
 */
.camoon-event-page .camoon-event-meta__lineup--long {
	justify-content: center;
	text-align: left;
}

/* The link row sits between the cover and the bio, so it owns the space around itself. */
.camoon-artist-page > .camoon-artist-hero__wrap {
	margin-block: var(--wp--preset--spacing--50) 0;
	padding-inline: var(--camoon-gutter);
}


/* Centre the section heads, which are otherwise a title/link row pushed to both edges. */
.camoon-artist-page .camoon-section__head {
	justify-content: center;
	text-align: center;
}

/* …but put the rows back to normal reading alignment. */
.camoon-artist-page .camoon-shows {
	text-align: left;
}

/*
 * Galleries. Artists and events carry many images, and they arrive as an ordinary
 * core/gallery block in the post body rather than a custom field — so the styling has to
 * make a stock gallery look like part of the design. Tight gap, to echo the grids.
 *
 * These are also the images the artist cards cycle through on hover, so they stay in
 * colour to match.
 */
.camoon-artist-content .wp-block-gallery,
.camoon-event-content .wp-block-gallery,
.camoon-news-content .wp-block-gallery {
	gap: 2px;
	margin-block: var(--wp--preset--spacing--50);
}

.camoon-artist-content .wp-block-gallery img,
.camoon-event-content .wp-block-gallery img,
.camoon-news-content .wp-block-gallery img {
	transition: filter 0.4s ease;
}

.camoon-artist-content .wp-block-gallery img:hover,
.camoon-event-content .wp-block-gallery img:hover,
.camoon-news-content .wp-block-gallery img:hover {
	filter: grayscale(1) contrast(1.08);
}

.camoon-artist-content .wp-block-gallery figcaption,
.camoon-event-content .wp-block-gallery figcaption,
.camoon-news-content .wp-block-gallery figcaption {
	color: var(--wp--preset--color--silver);
	font-size: var(--wp--preset--font-size--small);
}

/* ------------------------------------------------------------------ form -- */

/*
 * Contact Form 7 emits its own markup, so inputs are styled by element rather than by a
 * class we control.
 */
.camoon-form .wpcf7-form p {
	margin: 0;
}

.camoon-form input[type="text"],
.camoon-form input[type="email"],
.camoon-form input[type="tel"],
.camoon-form input[type="date"],
.camoon-form textarea {
	background-color: transparent;
	border: 1px solid var(--wp--preset--color--steel);
	border-radius: 0;
	color: inherit;
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--medium);
	padding: 0.85rem 1rem;
	transition: border-color 0.25s ease;
	width: 100%;
}

.camoon-form input::placeholder,
.camoon-form textarea::placeholder {
	color: var(--wp--preset--color--steel);
	opacity: 1;
}

/*
 * The date field, which browsers refuse to treat like the other inputs.
 *
 * Two separate problems. First, `color-scheme` tells the browser to render the field's
 * native furniture — the calendar icon and the picker itself — for a dark UI; without it
 * they come out as light-mode chrome on a black form.
 *
 * Second, a date input ignores `placeholder` entirely and prints its own format hint
 * ("pp.kk.vvvv") in the *text* colour. So while every other field showed a grey
 * placeholder, this one showed white text, which is the difference that was visible.
 * Matching it to the placeholder colour makes the empty row read as one row.
 *
 * The trade-off: a date the visitor has actually chosen also stays grey until the field is
 * focused or hovered. CSS has no selector for "date input with a value" — `:placeholder-shown`
 * does not apply to date inputs — so this is as close as it gets without scripting a form
 * that is deliberately unscripted.
 */
.camoon-form input[type="date"] {
	color: var(--wp--preset--color--steel);
	color-scheme: dark;
}

.camoon-form input[type="date"]:focus,
.camoon-form input[type="date"]:hover {
	color: var(--wp--preset--color--base);
}

.camoon-form input:focus,
.camoon-form textarea:focus {
	border-color: var(--wp--preset--color--base);
}

.camoon-form .wpcf7-submit {
	background-color: var(--wp--preset--color--base);
	border: 1px solid var(--wp--preset--color--base);
	border-radius: 0;
	color: var(--wp--preset--color--ink);
	cursor: pointer;
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	letter-spacing: 0.12em;
	padding: 0.9rem 2.25rem;
	text-transform: uppercase;
	transition: background-color 0.25s ease, color 0.25s ease;
	width: auto;
}

.camoon-form .wpcf7-submit:hover {
	background-color: transparent;
	color: var(--wp--preset--color--base);
}

/* ---------------------------------------------------------------- footer -- */

/*
 * The one light surface on the site. After a page of black bands and photography the
 * inversion reads as a full stop — which is why every rule here has to undo the dark
 * defaults rather than inherit them.
 *
 * No rule above the copyright: spacing separates it, and a hairline there was the last
 * thing making this look like a stock WordPress footer.
 */
.camoon-footer {
	/* Oswald's six-letter CAMOON advance, including its -0.02em tracking. */
	--camoon-footer-mark-size: calc((100vw - 16px) / 3.43);
	background: linear-gradient(
		to bottom,
		var(--wp--preset--color--ink) 0,
		var(--wp--preset--color--ink) calc(var(--camoon-footer-mark-size) * 0.5),
		var(--wp--preset--color--base) calc(var(--camoon-footer-mark-size) * 0.5)
	);
	color: var(--wp--preset--color--ink);
	isolation: isolate;
	/* Oversized type must not extend the page's scroll area below the footer. */
	overflow: clip;
	/* Also overrides the top padding in previously saved footer patterns. */
	padding-block-start: 0 !important;
	padding-inline: var(--camoon-gutter);
}

.camoon-footer :where(h1, h2, h3, h4, h5, h6) {
	color: var(--wp--preset--color--ink);
}

.camoon-footer a {
	color: var(--wp--preset--color--ink);
	text-decoration: none;
}

.camoon-footer a:hover {
	color: var(--wp--preset--color--steel);
	text-decoration: underline;
}

/*
 * Keep the wordmark in a full-width row.
 */
.camoon-footer__row {
	display: grid;
	gap: var(--wp--preset--spacing--40);
	grid-template-columns: minmax(0, 1fr);
	/* Let clicks pass through the decorative wordmark and its row. */
	pointer-events: none;
}

.camoon-footer.camoon-band > .camoon-footer__row {
	padding-inline: 0;
}

.camoon-footer__row > .camoon-footer__mark {
	margin-inline: calc(-1 * var(--camoon-gutter));
}

.camoon-footer__legal {
	color: var(--wp--preset--color--steel);
	font-size: var(--wp--preset--font-size--small);
	margin-top: var(--wp--preset--spacing--60);
}

/* --------------------------------------------------------- accessibility -- */

a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
	outline: 2px solid var(--wp--preset--color--silver);
	outline-offset: 3px;
}

.camoon-footer a:focus-visible,
.camoon-footer button:focus-visible {
	outline-color: var(--wp--preset--color--ink);
}

/* The tile is the link, so its focus ring must sit inside the tile to stay visible. */
.camoon-tile:focus-visible {
	outline-offset: -4px;
}

@media (prefers-reduced-motion: reduce) {
	.camoon-tile__image,
	.camoon-tile--fading .camoon-tile__image,
	.camoon-tile__body,
	.wp-block-button__link,
	.camoon-section__more,
	.camoon-section__more span,
	.camoon-show,
	.camoon-form input,
	.camoon-form textarea,
	.camoon-artist-content .wp-block-gallery img,
	.camoon-event-content .wp-block-gallery img,
	.camoon-news-content .wp-block-gallery img {
		transition: none;
	}

	.camoon-tile:hover .camoon-tile__image,
	.camoon-section__more:hover span {
		transform: none;
	}

	/*
	 * The marquee classes are never added under reduced motion — tiles.js returns before
	 * it measures — so the lineup simply wraps. This is a belt-and-braces stop in case
	 * the preference changes after the page has been set up.
	 */
	.camoon-tile__lineup-marquee {
		animation: none;
	}
}

/* Artist details and contact card share a bounded two-column layout below the hero. */
.camoon-artist-page .camoon-artist-layout {
	display: grid;
	grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
	align-items: start;
	gap: var(--wp--preset--spacing--50);
	max-width: var(--wp--style--global--wide-size);
	margin: var(--wp--preset--spacing--50) auto;
	padding-inline: var(--camoon-gutter);
}

.camoon-artist-layout > * {
	min-width: 0;
	margin-block-start: 0;
}

.camoon-artist-details .camoon-band {
	padding-inline: 0;
}

.camoon-artist-details .camoon-artist-content {
	text-align: left;
}

.camoon-artist-contact {
	overflow-wrap: anywhere;
}

.camoon-artist-contact h2 {
	margin-top: 0;
}

.camoon-artist-contact p {
	margin-block: var(--wp--preset--spacing--20);
}

.camoon-artist-contact__name {
	font-weight: 600;
}

.camoon-artist-contact__person {
	display: flex;
	align-items: flex-start;
	gap: var(--wp--preset--spacing--30);
}

.camoon-artist-contact__details {
	flex: 1;
	min-width: 0;
}

.camoon-artist-contact__details > :first-child {
	margin-top: 0;
}

.camoon-artist-contact__photo {
	flex: 0 0 auto;
	width: clamp(5rem, 8vw, 7rem);
	height: auto;
	aspect-ratio: 1;
	object-fit: cover;
}

.camoon-artist-contact .wp-block-button {
	margin-top: var(--wp--preset--spacing--40);
}

#form {
	scroll-margin-top: 2rem;
}


.camoon-form__fields {
	display: grid;
	gap: var(--wp--preset--spacing--30);
}
.camoon-form .camoon-form__row {
	display: grid;
	gap: var(--wp--preset--spacing--30);
	grid-template-columns: repeat(2, minmax(0, 1fr));
}
.camoon-form .camoon-form__field {
	display: grid;
	gap: .5rem;
	min-width: 0;
	margin: 0;
}
.camoon-form .wpcf7-form-control-wrap {
	display: block;
	min-width: 0;
}

.camoon-form input, .camoon-form textarea, .camoon-form select {
	box-sizing: border-box;
	min-width: 0;
}

.camoon-form select {
	width: 100%;
	padding: .85rem 1rem;
	background: var(--wp--preset--color--ink);
	color: inherit;
	border: 1px solid var(--wp--preset--color--steel);
	border-radius: 0;
	font: inherit;
	font-size: var(--wp--preset--font-size--medium);
	color-scheme: dark;
}
.camoon-form select:focus {
	border-color: var(--wp--preset--color--base);
}

.camoon-form .wpcf7-not-valid-tip {
	margin-top: .5rem;
}

.camoon-form .wpcf7-response-output {
	margin: var(--wp--preset--spacing--30) 0 0;
}

.camoon-form__fields > input[type="hidden"] {
	display: none;
}


@media (prefers-reduced-motion: no-preference) {
	html {
		scroll-behavior: smooth;
	}

}
@media (max-width: 781px) {
	.camoon-artist-page .camoon-artist-layout {
		grid-template-columns: minmax(0, 1fr);
	}

}
@media (max-width: 599px) {
	.camoon-form .camoon-form__row {
		grid-template-columns: minmax(0, 1fr);
	}

}

/* The shared form stays centered even on pages whose body content aligns left. */
.wp-site-blocks .camoon-form.is-layout-constrained > *:not(.alignfull):not(.alignwide):not(.alignleft):not(.alignright) {
	margin-left: auto !important;
	margin-right: auto !important;
}

.camoon-header__actions {
	gap: var(--wp--preset--spacing--40);
}

.camoon-header__booking {
	flex-shrink: 0;
}

.camoon-header__booking .wp-block-button__link {
	padding: .75rem 1rem;
	white-space: nowrap;
}

@media (max-width: 899px) {
	.camoon-header__actions {
		gap: 1rem;
	}

	.camoon-header__booking {
		order: -1;
	}
}

@media (max-width: 399px) {
	.camoon-header > .wp-block-group {
		gap: .75rem;
	}

	.camoon-header__actions {
		gap: .75rem;
	}

	.camoon-header__booking .wp-block-button__link {
		font-size: .75rem;
		padding: .75rem;
	}
}

/* Organizer material bank. */
.camoon-promoter-hero { padding: var(--wp--preset--spacing--60) var(--camoon-gutter, 1.5rem); text-align: center; }
.camoon-promoter-hero h1 { margin: 0; font-size: var(--wp--preset--font-size--display); }
.camoon-promoter-content { max-width: 1180px; margin: auto; padding: var(--wp--preset--spacing--50) var(--camoon-gutter, 1.5rem) var(--wp--preset--spacing--60); }
.camoon-promoter-login { max-width: 580px; margin: auto; }
.camoon-promoter-login form { display: grid; gap: 1rem; margin: 2rem 0; }
.camoon-promoter-login input { box-sizing: border-box; width: 100%; min-width: 0; padding: .8rem; border: 1px solid #777; border-radius: 0; font: inherit; }
.camoon-promoter-login button { justify-self: start; cursor: pointer; }
.camoon-promoter-toolbar { display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap; margin-bottom: 2rem; }
.camoon-promoter-logout { border: 0; padding: .5rem 0; background: transparent; color: inherit; font: inherit; text-decoration: underline; cursor: pointer; }
.camoon-promoter-artists { list-style: none; padding: 0; margin: 0; }
.camoon-promoter-artists li { border-bottom: 1px solid #c7ccd2; }
.camoon-promoter-artists a { display: flex; justify-content: space-between; gap: 1rem; padding: 1.25rem 0; font-family: var(--wp--preset--font-family--heading, inherit); font-size: 1.5rem; }
.camoon-promoter-section { margin: 3rem 0; }
.camoon-promoter-files { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); gap: 1.5rem; }
.camoon-promoter-files figure { margin: 0; min-width: 0; }
.camoon-promoter-files img { display: block; width: 100%; max-height: 420px; object-fit: contain; background: #f3f3f3; }
.camoon-promoter-files figcaption { padding: .75rem 0; overflow-wrap: anywhere; }
.camoon-promoter-text { white-space: pre-wrap; overflow-wrap: anywhere; }
.camoon-artist-promoter-link { margin: 1.25rem 0 0; }
.camoon-promoter-page :focus-visible { outline: 3px solid currentColor; outline-offset: 4px; }
