/*
Theme Name: Dicken
Theme URI: https://donbranco.fi
Author: Don Branco
Author URI: https://donbranco.fi
Description: Block theme for the Dicken site. Templates live in templates/ and parts/, design tokens in theme.json.
Requires at least: 6.7
Tested up to: 7.0
Requires PHP: 8.3
Version: 0.9.12
License: Proprietary
License URI: https://donbranco.fi
Text Domain: dicken
Tags: block-theme, full-site-editing, blog, one-column, custom-colors, custom-logo, custom-menu, editor-style, block-patterns, style-variations
*/

/*
 * Presentation belongs in theme.json, so that the site editor can see and
 * override it. This file is for the few things theme.json has no vocabulary
 * for; it is enqueued on the front end and, via add_editor_style(), in the
 * editor canvas.
 */

/* Raurus is tracked at 1px everywhere it is set — the client's call, applied
   across the board rather than per heading. It replaces a mix of three values
   (-0.02em, -0.01em and the board's 0.01em) that every heading block carried
   as its own inline letter-spacing, which is why this needs !important: an
   inline style outranks any selector, and the alternative was rewriting the
   typography of every heading in every pattern *and* every page already
   seeded from one. The value is theme.json's --wp--custom--tracking--display,
   and add_editor_style() hands this file to the editor, so the canvas shows
   the same tracking. theme.json's heading element keeps the tight value
   because it is also what the Inter headings inherit.

   The two quote blocks are listed by name because theme.json sets their face on
   the block, not on the paragraphs inside it that actually carry the words.

   Headings the design sets in Inter are left alone — a card title, the
   article's own subheads — which is what the :not() is for; those say so
   by class, by an inline font-family, or (the article's subheads) by where
   they sit. */
:is(h1, h2, h3, h4, h5):not(.has-sans-font-family, [style*="font-family--sans"], .dicken-article__content > h2:not(.alignwide)),
.has-display-font-family,
[style*="font-family--display"],
.wp-block-quote > p,
.wp-block-pullquote p {
	letter-spacing: var(--wp--custom--tracking--display) !important;
}

/* Every full-bleed band is 100vw wide (see .wp-block-post-content >
   .alignfull below), and 100vw counts a classic scrollbar that the page's own
   width does not — so wherever the browser draws one, which is every desktop
   browser on Windows, each page scrolled sideways by half its width: 8px at
   1440, measured. clip rather than hidden, because hidden makes the element a
   scroll container, and a scroll container between the sticky header and the
   viewport is what stops sticky working. On .wp-site-blocks rather than
   body: a body's overflow is handed up to the viewport, where clip becomes
   hidden and the 8px still counted towards the page's scroll width. */
.wp-site-blocks {
	overflow-x: clip;
}

/* A linked post title keeps the title's own colour. theme.json makes every
   link red, and core/post-title with isLink puts its text inside an <a>, so
   every linked card title on the site — the archive, a team's Uutiset, the
   article's related posts, the event cards — came out red while the
   homepage's unlinked ones were navy. The board draws them all navy. */
.wp-block-post-title a {
	color: inherit;
	text-decoration: none;
}

.wp-block-post-title a:hover,
.wp-block-post-title a:focus-visible {
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.15em;
}

/* theme.json has no focus pseudo-class, and the browser default is invisible
   against a dark background. */
:where(a, area, button, input, label[for], select, summary, textarea, [tabindex]):focus-visible {
	outline: 2px solid var(--wp--preset--color--red);
	outline-offset: 2px;
}

/* The board separates the utility bar's socials from its language pair with a
   1px rule the full height of the row's type. A border on the switcher rather
   than a spacer element: there is nothing to announce, and the 18px gap the
   group already has falls either side of it.

   `nav.` and not a bare class, because core/navigation copies the block's
   className onto its inner <ul class="wp-block-navigation__container"> as well
   as onto the <nav>. A bare `.dicken-header__languages` therefore matched both
   and drew the rule twice: once at the nav's left edge where the board wants
   it, and again 18px in — the nav's own padding — hard against the "FI", which
   is the stray hairline this fixes. Measured at 1440px: borders at x=1234 and
   x=1253, one divider intended. */
nav.dicken-header__languages {
	padding-left: 18px;
	border-left: 1px solid rgb(255 255 255 / 35%);
}

/* The language that is not the one you are reading is faded, and the one with
   nothing behind it yet (see inc/header.php) is faded further and takes no
   pointer — it is a label saying the site will be in Swedish, not a link
   offering to take you there now. */
.dicken-header__languages .lang-item:not(.current-lang) .wp-block-navigation-item__content {
	opacity: 0.6;
}

.dicken-header__language--dormant .wp-block-navigation-item__content {
	opacity: 0.45;
	cursor: default;
}

/* The design centres the crest between the primary navigation and the ticket
   button, with the two outer groups sharing the remaining space. Flex children
   do not grow by default in the block layout, and theme.json has no vocabulary
   for flex-grow on a specific child. */
.dicken-header__bar > .wp-block-group > :first-child,
.dicken-header__bar > .wp-block-group > :last-child {
	flex: 1 1 0;
}

/* Below 782px the primary navigation collapses to core/navigation's own
   mobile toggle (a 24px icon, not the desktop link row the flex-basis:0
   split above was measured against), and the equal share it and the
   "Lippukauppa" button were given assumed both sides had comparable
   content to fill that share with. The ticket button does not: at a
   325px-wide bar it was forced to an equal ~97px, well under what its
   own text needs, and the button's own word-break:break-word (core's
   default, wp-includes/blocks/buttons/style.css) broke the word "Lippu-
   kauppa" apart rather than overflowing — confirmed at 390px before this
   rule existed. flex:0 1 auto lets both ends size to their own content
   again; core/navigation's toggle and the button both fit comfortably
   either side of the crest at every width this theme supports, so nothing
   here needs the equal-share centring the desktop nav row did. */
@media (max-width: 781px) {
	.dicken-header__bar > .wp-block-group > :first-child,
	.dicken-header__bar > .wp-block-group > :last-child {
		flex: 0 1 auto;
	}
}

/* Moves core/navigation's own overlay breakpoint from 600px to this theme's
   782px.

   The rule above, and its comment, were written believing the toggle appears
   "below 782px". It does not: overlayMenu:"mobile" is core's own 600px
   (wp-includes/blocks/navigation/style.css), which left 600-781px with no
   toggle and the full desktop nav to fit — measured at 700px, the four links,
   the crest and the button needed more than the bar had, so the row wrapped,
   the crest slid to the right edge and "Lippukauppa" dropped onto a line of
   its own, tripling the header's height. Nothing caught it because both the
   render test and the responsive pass sampled 1440/1024/768/390, and 768 sits
   inside the band only because the utility row happens to survive there.

   Re-pointing the breakpoint rather than teaching the theme two of them: every
   other header rule here keys on 782px, the hero's overlay included, so a
   second breakpoint would mean the bar could be in its desktop layout while
   the hero was in its mobile one. Scoped to .dicken-header__nav so the utility
   row's own navigation — overlayMenu:"never", and no toggle to reveal — is
   untouched. */
@media (min-width: 600px) and (max-width: 781px) {
	.dicken-header__nav .wp-block-navigation__responsive-container:not(.is-menu-open) {
		display: none;
	}

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

	.dicken-header__nav .wp-block-navigation__responsive-container-close {
		display: flex;
	}
}

/* The design puts the crest on the left and the toggle on the right once the
   navigation has collapsed, which is the reverse of the source order — the
   navigation comes first in the markup because that is the order the desktop
   bar reads in. order, rather than reordering the markup, so the desktop bar
   (measured, and the one the design actually specifies) is left alone.

   The ticket button moves inside the overlay at the same width, as a fifth
   navigation link rather than this block: CSS cannot reparent a node into
   core's overlay container, and a button sitting outside it would be hidden
   behind the overlay's own backdrop while the menu is open. The two swap over
   at exactly one width, so precisely one "Lippukauppa" is reachable at any
   viewport — see .dicken-nav__cta below for the other half. */
@media (max-width: 781px) {
	.dicken-header__bar > .wp-block-group > .wp-block-site-logo {
		order: -1;
	}

	/* Scoped to the bar rather than left as a bare .dicken-header__cta: core
	   emits its own .wp-block-buttons display:flex for the block's layout
	   support, at the same specificity and later in the cascade, so the bare
	   selector lost and the button stayed visible next to the toggle. */
	/* The button stays. It used to be hidden here because the overlay carried
	   the only mobile "Lippukauppa" — but the board puts one in the bar on
	   every page, reachable without opening the menu, and the overlay's own
	   (inc/mobile-menu.php) is the second. Two routes to the same shop is what
	   the design asks for; one of them being three taps away was not. */
	.dicken-header__bar .dicken-header__cta .wp-block-button__link {
		padding: 10px 20px;
		font-size: var(--wp--preset--font-size--label);
	}
}

/* The overlay's own ticket link, and the bar's button, are the same call to
   action at two widths; this is the half that hides above the breakpoint.

   Selected through the list rather than as a bare .dicken-nav__cta: core's own
   .wp-block-navigation .wp-block-navigation-item{display:flex} outranks a
   single class, so the bare rule lost and "Lippukauppa" rendered twice on the
   desktop bar — once wrapped onto a second line of the navigation, once as the
   red button it already had. */
@media (min-width: 782px) {
	.dicken-header__nav .wp-block-navigation__container > .dicken-nav__cta {
		display: none;
	}
}

/* The overlay itself. core/navigation's overlayBackgroundColor gives it the
   navy ground (parts/header.html); everything below is the part theme.json has
   no vocabulary for — where the links sit in it, and how large.

   Centred both ways rather than core's default top-left stack: with five items
   on a navy full-screen ground, a left-aligned cluster under the close button
   reads as a fragment of a page rather than a menu. */
/* Centring vertically takes all three of core's own wrappers, not just the
   content: .wp-block-navigation__responsive-close carries height:100% but its
   .wp-block-navigation__responsive-dialog child is a plain block, so the
   content had nothing to centre itself within and sat under the close button
   at the top of an otherwise empty screen. */
.dicken-header__nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-close,
.dicken-header__nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-dialog {
	display: flex;
	flex-direction: column;
	flex-grow: 1;
}

.dicken-header__nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content {
	align-items: stretch;
	justify-content: flex-start;
	flex-grow: 1;
	width: 100%;
	/* padding-top: 0 because core sets 56px here for a menu whose content it
	   expects to centre. The dialog above already reserves the board's 76px top
	   bar, so core's would sit on top of that and push the first link down by
	   exactly the amount that made the menu look half-empty. */
	padding-top: 0;
	padding-inline: 20px;
}

/* The board stacks the four links down the left with a rule under each, rather
   than centring them in the screen. flex-grow on core's own list is what used to
   spread them over the whole height, so it is cancelled here — the list is now
   as tall as its links and everything below it follows in flow. */
.dicken-header__nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__container {
	align-items: stretch;
	justify-content: flex-start;
	flex-grow: 0;
	gap: 0;
	padding-top: 28px;
}

.dicken-header__nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item {
	width: 100%;
	padding-block: 20px;
	/* The board's own hairline: white at a tenth, so it reads as a division of
	   the navy rather than a line drawn on top of it. */
	border-bottom: 1px solid rgb(255 255 255 / 10%);
}

/* 26px against the bar's own 15px: a touch target on a full-screen menu has the
   room to be read at arm's length, and nothing else competes with it. */
.dicken-header__nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content {
	width: 100%;
	font-size: 26px;
	font-weight: 600;
	line-height: 32px;
}

/* The ticket link keeps the pill it has everywhere else — it is the one
   commercial action in the menu, and a plain link in a list of plain links
   would lose that. Padding and radius match the header button it stands in
   for; the extra top margin separates it from the four navigation links so it
   reads as an action rather than a fifth destination. */
/* The ticket link inside the list steps aside on mobile: the board puts the
   button below the teams row rather than as a fifth item among the pages, and
   inc/mobile-menu.php renders it there. Hidden rather than removed so the
   desktop bar, which is the same block, keeps it. */
.dicken-header__nav .wp-block-navigation__responsive-container.is-menu-open .dicken-nav__cta {
	display: none;
}

.dicken-header__nav .wp-block-navigation__responsive-container.is-menu-open .dicken-nav__cta .wp-block-navigation-item__content {
	padding: 15px 32px;
	border-radius: var(--wp--custom--radius--full);
	background-color: var(--wp--preset--color--red);
	color: var(--wp--preset--color--white);
}

/* The two heights the header is drawn at, and the one the hero pads itself by,
   so the hero and the header cannot drift apart.

   Measured from the render at 1440px, and together they match the design's
   174px frame exactly: 40px for the utility row (12px padding, a 16px line box)
   plus 134px for the navigation row (18px padding, the 98px crest). The utility
   row's line box depends on leading-snug on .dicken-header__utility — without
   it, the 13px label text inherits the body's 1.55 line-height instead of the
   1.2 that font size is drawn at, rounds up to 20px, and the header renders 4px
   tall.

   The utility height is load-bearing twice over: it is the negative offset the
   sticky rule below pins with, so a wrong value here leaves a sliver of the
   utility bar on screen or clips the navigation bar. Re-measure both if either
   row's padding, the logo's width attribute, or that line-height changes. */
:root {
	--dicken-header-utility-height: 40px;
	--dicken-header-height: 174px;
	/* What the two rows above condense to once pinned, measured from the render
	   the same way the two above it are — and wrong the moment .dicken-header-pinned's
	   own padding or crest width changes. The side rail and every heading's
	   scroll-margin offset from it. */
	--dicken-header-height-pinned: 88px;
}

/* The navigation bar's own navy ground, on every page and, below 782px, on
   the front page too — see the overlay rule just below for why the front
   page differs above that width.

   padding-block lives here rather than as a block-support style attribute on
   this element in parts/header.html, which is where it used to live and where
   it looked harmless: a block support renders as an inline style="padding-
   top:...;padding-bottom:..." on the element itself, and an inline style
   outranks any external-stylesheet declaration that lacks !important,
   regardless of selector specificity. The .dicken-header-pinned rule below
   was losing that fight silently — it kept matching, kept "winning" the
   cascade among stylesheet rules, and still changed nothing on screen, because
   there was never a contest with the inline style to begin with.
   !important would have won it back, but only by starting a fight that has to
   be refought at every future padding change; moving the value here instead
   means there is no inline style left to out-rank. Resting and pinned are two
   states of one measurement (see --dicken-header-height above), and a
   block-support value can only ever express one of them, so this stylesheet
   now owns both rather than splitting the pair across the editor and this
   file. The trade: this bar's padding is no longer adjustable from the site
   editor's Styles panel — the right call for chrome whose height is already a
   load-bearing measured constant, but a real loss, not a free one. */
.dicken-header__bar {
	background-color: var(--wp--preset--color--navy);
	padding-block: 18px;
}

/* The design shows the navigation bar transparent over the hero photo, on the
   front page only. body.home is the hook that is true there regardless of
   which "Front page displays" setting is active — a static page or the blog
   index — which a per-template class would not be; theme.json has no
   vocabulary for position, z-index or a body-class selector at all, so this
   cannot move there.
   The header overlays the hero here rather than sitting above it, but it still
   follows the scroll — the same sticky wrapper as every other page, pulled back
   over the hero by a negative margin-bottom of exactly its own height. That
   negative margin is what keeps it out of the flow's *spacing* while leaving it
   in the flow's *positioning*, which is the combination sticky needs: an
   absolutely positioned header cannot stick at all, which is why the homepage
   header used to scroll away entirely while every subpage's followed.

   The hero needs no change either way. It already reserves exactly
   var(--dicken-header-height) with its own padding-top (section-hero.php), and
   the negative margin here cancels the wrapper's own box so that padding still
   lands the hero's content in the same place.

   Scoped to 782px and up because the header stays in normal flow, navy ground
   and all, below it — the mobile overlay menu core/navigation opens there needs a
   solid header behind it, not the hero photo showing through. */
@media (min-width: 782px) {
	/* Keeps the sticky from the unqualified rule above, and takes back the space
	   it would occupy so the hero starts at the top of the viewport with the
	   header over it. */
	body.home .wp-site-blocks > header.wp-block-template-part {
		margin-bottom: calc(-1 * var(--dicken-header-height));
	}

	/* Every page, not only the front one: the bar rests on whatever is behind
	   it — the hero photograph on the front page, the page's own white
	   everywhere else — and takes its navy ground only once pinned. Below 782px
	   it keeps the solid navy from the unqualified rule above, because the
	   overlay menu core/navigation opens there needs a solid header behind it
	   rather than the page showing through. */
	.dicken-header__bar {
		background-color: transparent;
	}

	/* Once pinned the bar is over ordinary page content, so it needs its ground
	   back or the navigation becomes white-on-white. The pinned class is on
	   <html>, hence the descendant order. */
	.dicken-header-pinned .dicken-header__bar {
		background-color: var(--wp--preset--color--navy);
	}

	/* The ink half of the same swap. At rest on a subpage the bar sits on white,
	   where the white type it wears for its navy ground would be invisible —
	   but the front page's bar rests on a photograph and must keep that white,
	   so this cannot simply become the default. Hence the two negations: not
	   pinned, not the front page.

	   !important is unavoidable rather than lazy: the colours come from
	   parts/header.html's own textColor and elements.link attributes, which
	   compile to the has-white-color utility class and a --wp--style--color--link
	   custom property, and every preset colour class WordPress generates carries
	   its own !important (core's doing, not this theme's). A plain declaration
	   loses to it at any specificity.

	   The button link is excluded. The Lippukauppa pill carries its own white
	   type on the club red and is legible on either bar, so it is the one link
	   in here that must not follow the ground — swapping it to navy put dark
	   type on red until the header pinned. */
	html:not(.dicken-header-pinned) body:not(.home) .dicken-header__bar,
	html:not(.dicken-header-pinned) body:not(.home) .dicken-header__bar a:not(.wp-block-button__link) {
		color: var(--wp--preset--color--navy) !important;
	}

	/* The sand underline reads as a smudge on white; on the light bar the link
	   darkens to the club red instead, which is the accent the rest of the page
	   already uses for a live link. */
	html:not(.dicken-header-pinned) body:not(.home) .dicken-header__nav .wp-block-navigation-item__content::after {
		background-color: var(--wp--preset--color--red);
	}
}

/* theme.json's root blockGap (--wp--preset--spacing--30, 1rem) makes
   WordPress' own global styles add margin-block-start: 1rem to every
   top-level block in .wp-site-blocks except the first — there is no
   per-template exception for that in theme.json's vocabulary. Every other
   template's <main> overrides it with its own explicit margin-top
   (page.html, single.html, …); front-page.html deliberately carries none
   (see that template), because every section it renders supplies its own
   spacing and is full-bleed. Left unset, the 1rem would show up as a white
   seam between the header and the hero — at every viewport width, not only
   above 782px, since below it the header is still solid navy and directly
   above <main> in flow either way. */
body.home main {
	margin-block-start: 0;
}

/* The same 1rem, one level in. Core's `:root :where(.is-layout-constrained) >
   *` gives every section after the first a margin-block-start, and a page's
   sections are exactly that — top-level children of a constrained
   core/post-content. The design butts its bands together: a section carries
   its own padding, and a mist band's edge is meant to meet the white one
   above it with no seam. The 16px was showing as a white line across every
   tinted band and stretching the homepage 57px past the board's own height.

   A `<section>` element rather than a class, because that is what every one
   of the section patterns emits and nothing else in a page's content does. */
:where(.wp-block-post-content) > section.wp-block-group {
	margin-block-start: 0;
}

/* The last band on a subpage gives the navy footer air: 128px under it rather
   than the 72 every other band carries. Which band is last is a property of
   the page, not of any pattern — a team's sections are composed at seed time
   and a page's are the editor's — so it can only be said here, and every one
   of those patterns writes its padding as an inline style, which no selector
   outranks. Hence !important: the alternative is a render_block filter that
   rewrites a style attribute, which is a lot of machinery for one number.

   Not on the homepage: its own last band, the newsletter, is drawn tight to
   the footer on purpose. */
body:not(.home) :where(.wp-block-post-content) > section.wp-block-group:last-child {
	padding-bottom: var(--wp--preset--spacing--85) !important;
}

/* The same root blockGap once more, on the footer's template-part wrapper: a
   16px margin above it that showed as a white strip wherever the last band
   was tinted — mist on a team page, the article's related posts, Meistä's
   organisation band. The bands carry their own bottom padding, so nothing
   needed the extra 16px even where the page ends on white. */
.wp-site-blocks > footer.wp-block-template-part {
	margin-block-start: 0;
}

/* The header follows the reader down every page.

   The negative top is the whole mechanism: a sticky element's box starts 40px
   above the viewport, so the first 40px of scroll carries the utility bar off
   the top and the navigation bar comes to rest at top: 0 and stays there. No
   scroll listener, no measuring, no layout read per frame — the browser's own
   sticky implementation does all of it.

   Not scoped to :not(.home). The homepage's own rule above is position:
   absolute on `body.home .dicken-header` inside @media (min-width: 782px),
   which is both more specific and later, so it wins where it applies and this
   applies everywhere else — including the homepage below 782px, where the
   header is already solid navy and in flow, and where a phone benefits from a
   sticky navigation more than any other viewport.

   z-index above the homepage rule's 10, so a pinned header on a subpage passes
   over anything that section patterns stack.

   **The rule is on the template-part wrapper, not on .dicken-header itself, and
   that is the whole reason this works.** A sticky element can only travel inside
   its own containing block, and WordPress wraps a template part in a box that
   fits its content exactly — measured at 174px, the header's own height. Sticky
   on the inner element therefore had nowhere to go: it scrolled away with the
   page, reaching top: -654px at a scroll of 654px. The wrapper's containing
   block is .wp-site-blocks, which is the full document height, so the same
   declaration on the wrapper settles at exactly top: -40px as intended. Both
   numbers are measured, not inferred.

   No ancestor has overflow, transform, contain or will-change — that was checked
   and is the usual cause of a dead sticky. This was the other one, and it is
   invisible to every test in this suite because nothing here measures layout. */
.wp-site-blocks > header.wp-block-template-part {
	position: sticky;
	top: calc(-1 * var(--dicken-header-utility-height));
	z-index: 20;

	/* The box height is pinned to the uncondensed height so that condensing
	   cannot change it. This is what stops the header stuttering on a slow
	   scroll, and the loop it breaks is worth spelling out because the fix looks
	   arbitrary otherwise:

	   the header is in flow, so shrinking it shortens the document; the browser's
	   scroll anchoring compensates for content shrinking above the viewport by
	   reducing scrollY; near the top that clamps scrollY back to 0; at 0 the
	   utility bar is fully visible again, so the observer un-pins; the header
	   grows back and the whole thing repeats. Measured at eleven class flips
	   across a 120px slow scroll before this line existed.

	   The inner header still condenses freely inside this fixed box — 174px tall,
	   sticky at -40px, so a condensed 128px header still puts its bottom edge at
	   88px, which is the drawn design. */
	height: var(--dicken-header-height);

	/* The condensed header is shorter than the box above, and the leftover strip
	   would otherwise swallow clicks meant for the content scrolling under it. */
	pointer-events: none;
}

.wp-site-blocks > header.wp-block-template-part > * {
	pointer-events: auto;
}

/* The condensed state, once inc/header.php reports the utility bar has left.
   The crest comes down from 98px to 64px and the bar's padding from 18px to
   12px, which is 174px of header becoming 88px of it. Specificity (0,0,2,0)
   beats the resting rule's (0,0,1,0) cleanly now that both live here — see
   the comment on the resting rule above for what used to out-rank this one
   instead. */
.dicken-header-pinned .dicken-header__bar {
	padding-block: 12px;
}

.dicken-header-pinned .dicken-header__bar .wp-block-site-logo img {
	width: 64px;
}

/* Opt-in, the same way assets/animations.css guards every reveal: a reader who
   asked for less motion gets a header that changes size without animating,
   rather than one that animates and is then overridden. The properties are
   named rather than `all` so the navigation's own hover underlines, which
   transition on their own timing, are untouched.

   The slow token, and the navy ground fading in with the shrink. At `base`
   (220ms) a 98px crest dropping to 64 read as a jolt, and the ground, which
   had no transition, snapped on at the start of it — the design review asked
   for the nav to be softer (Annotate #13). One duration and one curve for all
   three, so the bar settles as one movement rather than three.

   An ease-in-out rather than the theme's --motion--ease. That token is an
   out-expo, right for something arriving, but it spends its change up front:
   measured, the bar was 94% navy and the crest within 2px of its pinned
   width 200ms into a 420ms transition, so the slower duration alone still
   read as a snap. This one moves through the middle of its time instead. */
@media screen and (prefers-reduced-motion: no-preference) {
	.dicken-header__bar {
		transition:
			padding-block var(--wp--custom--motion--slow) cubic-bezier(0.4, 0, 0.2, 1),
			background-color var(--wp--custom--motion--slow) cubic-bezier(0.4, 0, 0.2, 1);
	}

	.dicken-header__bar .wp-block-site-logo img {
		transition: width var(--wp--custom--motion--slow) cubic-bezier(0.4, 0, 0.2, 1);
	}
}

/* The design bleeds a brand shape off the footer's *right* edge, from its top.
   It is decoration, so it is a background rather than an <img> with no
   alternative text to write.

   The corner was wrong: this shipped anchored bottom-left, and the design's
   own node ("Footer shapes") is `right: -55px; top: -43px` on a 362x560 box —
   it hangs off the right edge and starts above the footer's top, where the
   navy band meets the section before it. Both offsets are that node's,
   verbatim. */
.dicken-footer {
	background-image: url("assets/images/footer-shape.svg");
	background-position: right -55px top -43px;
	background-repeat: no-repeat;
	background-size: 362px 560px;
}

/* The three link columns are one group anchored to the footer's right edge,
   72px apart, ending flush with the content column — not four columns spread
   evenly across it, which left about 130px of nothing after Palvelut. Core
   gives every column flex-basis: 0 and flex-grow: 1, so the fix is to stop
   the link columns growing and let the brand column take all the slack
   instead; where the three then sit is a consequence rather than three more
   measurements to keep. */
.dicken-footer__row > .wp-block-column {
	flex-grow: 0;
	flex-basis: auto;
}

.dicken-footer__row > .wp-block-column:first-child {
	flex-grow: 1;
}

/* Tietosuoja and Evästeet start on the Palvelut column's left edge rather
   than sitting flush right, where they ended 105px past the column's own
   text and read as belonging to nothing above them. The pair's box is made
   exactly one link column wide and left-packed, so it lands under Palvelut
   by construction: the columns are 208px each at 1200 — the 70% the brand
   column leaves, less three 72px gaps, split three ways — and the same
   expression here resolves against the same 1200px row, so the two cannot
   drift apart at another width. The rule the board never had above this row
   went at the same time. */
.dicken-footer__legal-links {
	width: calc((100% - 30% - 3 * 72px) / 3);
}

/* The phone's own utility row — socials on the left, FI / SV on the right.
   Absent above 782px, where the socials sit under the brand and the language
   pair is up in the header's team bar. Two copies of the same three social
   links exist in the document as a result; only one of them is ever displayed,
   and display: none takes the other out of the accessibility tree as well as
   off the screen, so a screen reader reads one set too. CSS cannot move a node
   from one flex container into another, and this is the honest alternative. */
.dicken-footer .dicken-footer__utils {
	display: none;
}

/* The bottom row is the page's quietest type: 14px at 55% white, and no
   underline — the two links there are legal furniture, not part of the
   reading. #FFFFFF8C is the board's own value; written as a channel-alpha
   rather than a palette entry because it is white with an opacity, not a
   colour the site uses anywhere else. */
.dicken-footer__legal,
.dicken-footer__legal a {
	color: rgb(255 255 255 / 55%);
	font-size: 14px;
	text-decoration: none;
}

.dicken-footer__legal a:hover,
.dicken-footer__legal a:focus-visible {
	color: var(--wp--preset--color--white);
}

/* page.html and page-no-title.html wrap <main> in its own padded, constrained
   group, on top of core/post-content's own padded, constrained layout — two
   has-global-padding layers deep. Core's own CSS for exactly that nesting
   zeroes an alignfull child's escape margin, on the assumption that the
   padding it would be escaping was already stripped a level up; here it
   was not, because it is <main>'s own, not post-content's. The visible
   result without this rule: a "full-bleed" section pattern capped at
   post-content's 1200px instead of the viewport, measured and confirmed
   at 1440px before this rule existed. This restates the escape with the
   viewport itself rather than the custom properties core's own rule reads,
   which is what makes it correct regardless of how deep the nesting is —
   every section pattern gets this for free by virtue of being alignfull
   directly inside post-content, not just the two the brief covers. */
.wp-block-post-content > .alignfull {
	width: 100vw;
	margin-left: calc(50% - 50vw);
	margin-right: calc(50% - 50vw);
}

/* The hero's photo, its top scrim, its whole-area tint and the brand shape
   bleeding across its lower half are all decoration with nothing for a screen
   reader to announce. As written here they are no block markup at all: the
   photo is the section's background, the scrim and tint its ::before, the
   shape its ::after. That is what the editor shows, and what the front end
   shows too until inc/hero.php's filter has added the moving versions — a
   photo layer, and the band as inline SVG — and `.dicken-hero--layered` with
   them, which stands the static photo and band down (below). overflow:hidden
   crops the shape at the section's own edges — the "bleeding across the lower
   hero" the brief describes — and is also what stops it creating horizontal
   scroll.

   The layers stack by z-index rather than source order, because ::before
   comes ahead of the injected photo in the tree and would otherwise paint
   under it: photo (auto), scrim and tint (1), shapes (2), the player cut out
   of the photo when there is one (3), slogan (4). isolation keeps those
   numbers local to the hero. */
.dicken-hero {
	position: relative;
	isolation: isolate;
	overflow: hidden;
	display: flex;
	/* To the bottom of the screen, whatever the screen: the client's call, over
	   the board's fixed 820px, which left a strip of the next section showing on
	   a 900px-tall laptop and cut the photo short on anything taller. svh rather
	   than vh so a phone's collapsing toolbar cannot push the edge below the
	   fold. The 640px floor is what the crest, the slogan and the shapes need
	   between them before they start to overlap on a short landscape screen. */
	min-height: max(640px, 100svh);
	background-image: url("assets/images/hero.jpg");
	background-repeat: no-repeat;
	background-position: 50%;
	background-size: cover;
}

.dicken-hero--layered {
	background-image: none;
}

/* The tint is 0% — the photograph at full strength. It was 30%, the client's
   own value at the time, because at 15% the photograph competed with the
   slogan; with the player standing in front of the shapes the design review
   (October 2026) asked for it off. It stays a declared colour rather than
   being deleted, so the intro still has something to lift from near-black to,
   and raising it again is this one number. The 240px scrim is a separate image
   layer at 60%, for the navigation rather than for the slogan, and stays.

   Both are on this one pseudo-element, rather than the scrim staying in the
   section's background beside the photo, because the moving photo is an
   element above that background and would cover it. Two black layers
   composite the same in either order, so drawing the scrim over the tint
   rather than under it changes nothing. */
.dicken-hero::before,
.dicken-hero__media--front .dicken-hero__photo::after {
	content: "";
	position: absolute;
	z-index: 1;
	inset: 0;
	background: linear-gradient(180deg, rgb(0 0 0 / 60%) 0%, rgb(0 0 0 / 0%) 100%) 50% 0 / 100% 240px no-repeat;
	background-color: rgb(0 0 0 / 0%);
}

/* The brand shapes across the lower hero, as the static ::after and as the
   front end's inline SVG — one box for both.

   Both measurements are the design's own, converted from its 1440px canvas
   into ratios of the viewport so they survive a wider one. The design
   (node "Brand shapes") sets the box full-bleed at the frame's width and
   draws the artwork at 1680px, centred: 1680/1440 is the 116.667% below.

   Written as a fixed `left: 0; width: 1440px` box, which is what a literal
   reading of the design gives, the shape stopped dead at 1440 and sat against
   the left edge of anything wider, with bare photo to the right of it. The
   box has to be the viewport, not the canvas the design was drawn on.

   Anchored to the hero's bottom, not its top: the hero is as tall as the
   screen now, so a fixed `top` left the band floating mid-photo on a tall one.
   -56px is the board's own overhang — top 618 plus the 258px box, against an
   820px frame — so at the drawn height it lands exactly where it did. The
   artwork's own height follows its width through the `auto`, and the 258px
   box crops it — more of it on a wide screen, which is the same full-bleed
   behaviour the horizontal bleed already has. */
.dicken-hero::after,
.dicken-hero__shapes {
	position: absolute;
	z-index: 2;
	inset-inline: 0;
	bottom: -56px;
	height: 258px;
}

.dicken-hero::after {
	content: "";
	background-image: url("assets/images/hero-shapes.svg");
	background-repeat: no-repeat;
	background-position: 50% 0%;
	background-size: 116.667% auto;
}

.dicken-hero--layered::after {
	content: none;
}

/* The photo layer, inset nowhere: the entrance's zoom is what covers its own
   pan, and the scroll parallax only ever moves it down by less than the page
   has scrolled, so its top edge never comes into the visible part. */
.dicken-hero__media,
.dicken-hero__photo {
	position: absolute;
	inset: 0;
}

/* The hero is a constrained-layout group, and core caps every direct child of
   one at the content width — measured, the photo and the band both came out
   1200px wide and centred, with bare navy either side. Two classes deep
   because core's own rule is one class and is printed after this stylesheet. */
.dicken-hero > .dicken-hero__media,
.dicken-hero > .dicken-hero__shapes {
	max-width: none;
}

/* The player cut out of the photo, standing in front of the shapes: the
   background layer again, the same photo masked to her outline by the
   transparent PNG (inc/hero.php, which also says why it is not the PNG that
   is painted), so the scrim and tint drawn inside it by the rule shared with
   ::before above cover her and nothing else. Without that she would be
   the one unshaded thing in the hero — brighter than the photo she was cut
   from, and outlined by the difference: at the top under the scrim, and
   everywhere during the intro, when the tint starts near-black.

   The overlay reaches half the hero below her: the scroll parallax moves it
   back up by what it moves the photo down (in the motion block below), so the
   scrim stays put against the hero exactly as ::before does, and its bottom
   edge must not come up into view as it goes. */
/* margin: 0 because the layout's blockGap gives every child after the first a
   16px margin-block-start, and this layer comes after the band: measured, it
   sat 16px lower and 16px shorter than the background, so `cover` also drew it
   smaller, and she came off her own outline. The background layer escaped it
   only by being the first child. */
.dicken-hero > .dicken-hero__media--front {
	z-index: 3;
	margin: 0;
}

.dicken-hero__media--front .dicken-hero__photo {
	mask-repeat: no-repeat;
	mask-position: 50%;
	mask-size: cover;
}

.dicken-hero__media--front .dicken-hero__photo::after {
	inset-block-end: -50%;
}

/* The cut-out as the editor shows it: the Image block itself, which on the
   front end inc/hero.php replaces with the layer above. Laid over the hero
   the same way. The scrim is left out, the editor's view being a guide rather
   than the page. max-width for the same constrained-layout cap as the layers
   above. */
.dicken-hero > .dicken-hero__front {
	position: absolute;
	z-index: 3;
	inset: 0;
	max-width: none;
	margin: 0;
}

.dicken-hero > .dicken-hero__front img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.dicken-hero__photo {
	background-repeat: no-repeat;
	background-position: 50%;
	background-size: cover;
	/* The player's face, roughly, so the zoom closes in on the action rather
	   than on the middle of the frame. Both photo layers share it, which is
	   what keeps the cut-out on her own outline while they zoom. Measured on
	   the layered photo (dicken_hero_tausta); a new photo wants it re-measured. */
	transform-origin: 50% 38%;
}

/* The SVG is the ::after's background-size and -position written as a box:
   116.667% wide, centred (half the 16.667% overhang off each side), top edge
   on the box's top, height from the viewBox. */
.dicken-hero__shapes svg {
	position: absolute;
	top: 0;
	left: -8.3335%;
	width: 116.667%;
	height: auto;
	overflow: visible;
	fill: var(--wp--preset--color--navy);
}

.dicken-hero__shapes-narrow {
	display: none;
}

/* Each shape moves about its own centre, not the SVG's origin. */
.dicken-hero__shape,
.dicken-hero__spin {
	transform-box: fill-box;
	transform-origin: 50% 50%;
}

/* The section's own flex-stretches this to its full box (820px tall, full
   width); block markup carries the padding that clears the header, but has
   no vocabulary for centring this box's single child within what that
   padding leaves over, so the centring is done here. z-index lifts it above
   the layers above, which would otherwise paint over it — an absolutely
   positioned layer always paints above static content in the same stacking
   context, regardless of source order. */
.dicken-hero__content {
	position: relative;
	z-index: 4;
	display: flex;
	flex: 1;
	flex-direction: column;
	align-items: center;
	justify-content: center;
}

/* The hero's motion, all of it, on the front end only — every selector here is
   on something inc/hero.php adds, so the editor, which never runs that filter,
   shows the hero still.

   Every animation supplies only its `from` and fills backwards, so the rules
   outside this block are the final frame: a reader who asks for reduced motion
   gets exactly the design, not some point part-way through it.

   In order of arrival: the photo settles from a 16% zoom, panning right to
   left as it does, while the tint lifts from near-black to clear; the slogan
   rises a word at a time through each word's own mask; the shapes rise from
   below the hero's edge in one wave, left to right. Then it all comes to rest,
   on the design exactly, with one exception: the star keeps turning.

   The first version kept everything alive after the intro — the photo
   drifting on a 30s loop, every shape bobbing out of phase with the others.
   The design review (Arttu, on staging) asked for it to stop: an intro that
   never ends reads as restless, and shapes drawn on one line should rest on
   one line, which out-of-phase bobs never let them do.

   The scroll parallax reads the two properties assets/hero.js sets: the photo
   falls behind the page at 0.4 of its speed, and the slogan sinks and fades
   over the first 55% of the hero. `translate`, not `transform`, so it composes
   with the keyframed transforms instead of replacing them. The shapes are
   left to scroll with the page: their artwork ends barely below the hero's
   edge on a narrow desktop window, so moving them up would show its bottom. */
@media screen and (prefers-reduced-motion: no-preference) {
	@keyframes dicken-hero-photo-in {
		from {
			transform: translateX(4%) scale(1.16);
		}

		to {
			transform: translateX(0) scale(1);
		}
	}

	@keyframes dicken-hero-tint-in {
		from {
			background-color: rgb(0 0 0 / 85%);
		}
	}

	@keyframes dicken-hero-rise {
		from {
			transform: translateY(112%);
		}
	}

	@keyframes dicken-hero-shape-rise {
		from {
			transform: translateY(120%);
		}
	}

	@keyframes dicken-hero-spin {
		to {
			transform: rotate(360deg);
		}
	}

	.dicken-hero__photo {
		animation: dicken-hero-photo-in 2.8s var(--wp--custom--motion--ease) both;
	}

	.dicken-hero--layered::before,
	.dicken-hero__media--front .dicken-hero__photo::after {
		animation: dicken-hero-tint-in 1.6s var(--wp--custom--motion--ease) 0.1s both;
	}

	/* The mask is the word's own box, padded up and back by the same amount so
	   the Å's ring sits inside it without the baseline moving. */
	.dicken-hero__word {
		display: inline-block;
		overflow: hidden;
		vertical-align: top;
		margin-block: -0.18em -0.06em;
		padding-block: 0.18em 0.06em;
	}

	.dicken-hero__word > span {
		display: inline-block;
		animation: dicken-hero-rise 1s var(--wp--custom--motion--ease) calc(0.35s + var(--dicken-hero-word) * 90ms) both;
	}

	.dicken-hero__shape {
		animation: dicken-hero-shape-rise 1.2s var(--wp--custom--motion--ease) calc(0.6s + var(--i) * 90ms) both;
	}

	/* One turn in two minutes: slow enough that it reads as the star having
	   moved since you last looked, not as spinning. */
	.dicken-hero__spin {
		animation: dicken-hero-spin 120s linear 1.8s infinite;
	}

	.dicken-hero__media {
		translate: 0 calc(var(--dicken-hero-scroll, 0) * 0.4px);
	}

	.dicken-hero__media--front .dicken-hero__photo::after {
		translate: 0 calc(var(--dicken-hero-scroll, 0) * -0.4px);
	}

	.dicken-hero--layered .dicken-hero__content {
		translate: 0 calc(var(--dicken-hero-scroll, 0) * 0.22px);
		opacity: calc(1 - var(--dicken-hero-progress, 0) / 0.55);
	}
}

/* The design's Intro columns are fixed measurements, not proportions: the
   left column holds its 468px width rather than shrinking below it, and the
   right one grows but stops at 640px. A Columns block's width attribute only
   ever compiles to flex-basis (plus, from core's own stylesheet, flex-grow:0
   on whichever column carries one) — never flex-shrink or max-width, and
   theme.json has no vocabulary for either. */
.dicken-intro__column-left {
	flex-shrink: 0;
}

.dicken-intro__column-right {
	max-width: 640px;
}

/* Seven links across the Intro, Teams and News sections end in the same
   small triangle glyph. It is decoration with nothing for a screen reader
   to announce, so it is one reusable ::after pseudo-element rather than
   seven fetched SVGs, each of which would need its own aria-hidden wrapper
   — a pseudo-element's generated content is never exposed to the
   accessibility tree in the first place. Applied to whichever element the
   chevron follows (a core/read-more link, a core/button link, the Intro's
   own hand-written <a>); currentColor picks up that element's own text
   colour, so the one rule serves sand, red and navy links alike without
   repeating itself.

   The glyph is the brand's own filled triangle — shapes/M.svg turned −90°,
   which is an isoceles triangle in a square box, apex right — not a drawn
   chevron. clip-path over a currentColor ground reproduces it exactly and
   keeps the one-rule/any-colour property that a fetched SVG would lose.

   Both the triangle and its gap scale with the link's own text, which the
   design measures at three sizes: 20px→11/8, 17px→9/7, 15px→8/6. Those are
   0.55/0.53/0.53em and 0.40/0.41/0.40em, so a single em ratio lands within
   half a pixel of all three and needs no per-context rule.

   Centred on the capital height, which is what the eye reads a button label
   by. It used to sit on the baseline and 1px below it, putting its centre
   2.5px under the capitals' — measured, at every size — and the design review
   (Annotate #21) saw every arrow on the site hanging low. The capitals are
   0.733em tall in this face, so a 0.54em triangle centres on them with its
   base (0.733 - 0.54) / 2 = 0.1em above the baseline. vertical-align rather
   than `top` so it moves the box in the line, not just its paint. */
.dicken-chevron::after {
	content: "";
	display: inline-block;
	position: relative;
	vertical-align: 0.1em;
	width: 0.54em;
	height: 0.54em;
	margin-left: 0.4em;
	background: currentColor;
	clip-path: polygon(0 0, 100% 50%, 0 100%);
}

/* The team card's photo has to follow the card's own 10px corners at its top
   edge. core/post-featured-image's own border support radiuses the <img>
   itself, but the radius here belongs to the whole card, which also has a
   body below the photo with nothing to round — so the card clips its own
   content instead of the image rounding itself. min-height keeps all three
   cards the same height regardless of how long a team's excerpt is. */
.dicken-team-card {
	overflow: hidden;
	min-height: 480px;
}

/* …and min-height alone is not the same height: a grid row stretches its
   <li>, but the card inside it is a block that stops at its own content, so a
   team with a three-line excerpt (Juniorit) stood 44px taller than the other
   two. The <li> becomes a flex column and the card fills it, so all three
   cards end on one line whatever each excerpt runs to. */
.dicken-teams .wp-block-post-template > li {
	display: flex;
	flex-direction: column;
}

.dicken-teams .dicken-team-card {
	flex: 1;
}

/* …and equal cards still left their links on different lines: each link sat
   straight under its own excerpt, so Juniorit's four-line excerpt put its link
   44px below the other two (Annotate #20). The card is a column whose body
   takes the height the photo leaves, and the excerpt takes what the body's
   text leaves, so every link lands on the card's bottom padding. The excerpt
   grows rather than the link taking margin-top: auto, because the link's 6px
   top margin is an inline style from the block and only !important would
   outrank it. */
.dicken-teams .dicken-team-card,
.dicken-team-card__body {
	display: flex;
	flex-direction: column;
}

.dicken-team-card__body {
	flex: 1;
}

.dicken-team-card__body .wp-block-post-excerpt {
	flex: 1;
}

.dicken-team-card img {
	object-position: 50% 30%;
}

/* The News section's featured story is the one instance of this link that
   the design draws with a 7px gap rather than the usual 6px. */
.dicken-news__featured-link.dicken-chevron::after {
	margin-left: 7px;
}

/* The News section's featured row: min-height and clipping the way the team
   card needs them (see above), plus the 60%/grow split between the photo
   and its body — set via each child's own style.layout.selfStretch/flexSize
   attributes (a block attribute, so it needs no rule here) inside a plain
   flex row core/group already expresses. */
.dicken-news__featured {
	overflow: hidden;
	min-height: 440px;
}

/* The photo side of the featured row and of every card: relative so the
   category chip below can position against it, and a navy ground behind the
   <img> for the moment before it has loaded. The image itself is asked to
   fill this box (rather than sizing itself) because the box's own height is
   either the row's stretched height (featured) or a fixed 216px (cards),
   neither of which core/post-featured-image's own height attribute — a
   literal px value — can express. */
.dicken-news__featured-image,
.dicken-news__card-image {
	position: relative;
	overflow: hidden;
	background-color: var(--wp--preset--color--navy);
}

.dicken-news__card-image {
	height: 216px;
}

/* The featured row's photo side is set to a fixed 60% via its own
   style.layout.flexSize (a block attribute; see the pattern), but that
   attribute only ever compiles to flex-basis, the same gap the intro
   section's fixed-width column hit — flex-shrink still defaults to 1, so
   without this the body's own text content, wide enough to want more than
   the remaining 40%, shrinks the photo along with it instead of staying
   fixed. */
.dicken-news__featured-image {
	flex-shrink: 0;
}

/* core/post-featured-image wraps its <img> in a <figure> that is itself
   position:relative (wp-includes/blocks/post-featured-image/style.css, for
   its own dim-overlay feature) — the nearer of two positioned ancestors, so
   without this the <img>'s inset:0 below would fill the *figure*, not this
   box, and the figure — sized only by a child that is now out of flow —
   would collapse to zero height with nothing left to fill. Taking the
   figure out of flow the same way, against this box instead, is what lets
   the <img> reach it. */
.dicken-news__featured-image figure.wp-block-post-featured-image,
.dicken-news__card-image figure.wp-block-post-featured-image {
	position: absolute;
	inset: 0;
	margin: 0;
}

.dicken-news__featured-image img,
.dicken-news__card-image img {
	display: block;
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	margin: 0;
}

.dicken-news__card-image img {
	object-position: 50% 30%;
}

/* The category chip sits on the photo, not in the body, so it has to be
   taken out of flow. Sized and positioned for the featured row; the
   the cards use the same chip at the same size — 6px/12px, inset 16 from the
   photo's corner — which is why the `--card` modifier no longer changes
   anything and only marks which chip is which for anyone reading the DOM. Its
   own colour and typography come from the block's style attribute (see the
   pattern), since those need to beat the label styles theme.json gives
   core/post-terms globally — an inline style always outranks that rule,
   which a same-specificity class fighting it would not reliably do. The
   anchor inside is reset to the chip's own colour: core/post-terms links to
   the term archive, and without this it would render in the sitewide link
   colour (red, underlined) instead of matching the chip's white text. */
.wp-block-post-terms.dicken-news__chip {
	position: absolute;
	top: 16px;
	left: 16px;
	z-index: 1;
	margin: 0;
	background-color: var(--wp--preset--color--navy);
	border-radius: var(--wp--custom--radius--full);
	padding: 6px 12px;
	line-height: 1;
}

.wp-block-post-terms.dicken-news__chip a {
	color: inherit;
	text-decoration: none;
}

/* The three-card row's own white ground, radius and clipping — the card's
   image area sits flush with the card's top edge, so it has to be the card
   itself, not the image, that clips to the shared 10px corner. */
.dicken-news__card {
	overflow: hidden;
}

/* The match row's date chip is fixed at 72px via its own style.layout.flexSize
   (a block attribute; see the pattern) — but, the same gap the news featured
   image hit above, that child-layout attribute only ever compiles to
   flex-basis, never flex-shrink. Without this the chip would still yield its
   width to the meta line and fixture text growing beside it. The ticket
   button sits in the same row and needs the same guarantee for the same
   reason: neither is the flexible element the row's middle column is. */
.dicken-matches__chip,
.dicken-matches__cta {
	flex-shrink: 0;
}

/* The Start band's photo and the Newsletter card's photo are both a fixed
   42% column beside a growing panel, via each side's own child-layout
   style.layout.selfStretch/flexSize attribute — the same split and the same
   gap section-news.php's featured image already hit (see that rule above):
   the attribute only ever compiles to flex-basis, so without flex-shrink:0
   the panel's own text would still pull width away from the photo. Height
   and cover-fit are asserted here too, because a plain core/image has no
   "fill this box" attribute of its own the way core/post-featured-image's
   height/scale attributes do — its figure just needs a definite height to
   resolve img's own height:100% against, which it gets for free from the
   card row's own align-items:stretch (a stretched flex item's used height
   counts as definite for percentage resolution). navy behind both is the
   design's own measured fallback ground for the moment before either photo
   has loaded. */
.dicken-start__image,
.dicken-newsletter__image {
	position: relative;
	overflow: hidden;
	flex-shrink: 0;
	background-color: var(--wp--preset--color--navy);
}

.dicken-start__image figure.wp-block-image,
.dicken-newsletter__image figure.wp-block-image {
	margin: 0;
	height: 100%;
}

.dicken-start__image img,
.dicken-newsletter__image img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* The design's own crop for the Start band's photo favours the crest over
   the collar rather than the frame's true centre; the Newsletter photo has
   no such offset. */
.dicken-start__image img {
	object-position: 50% 35%;
}

/* The Juniorit hub's hero. Its two halves are a growing text column and a
   fixed 680px photograph, top-aligned — the board lines the heading's first
   line up with the top of the photo rather than centring two columns of
   different heights against each other.

   The photo rounds only its left pair of corners: its right edge is the frame
   edge, and rounding a corner that is off-screen shows as a nick rather than
   as a radius. object-fit needs a definite height to resolve against, which
   the fixed height gives it — a plain core/image has no "fill this box"
   attribute the way core/post-featured-image's own height/scale do, and this
   is the featured image, so scale:"cover" is doing half the work already. */
.dicken-junior-hero__row {
	align-items: flex-start;
}

.dicken-junior-hero__text {
	min-width: 0;
	max-width: 560px;
}

.dicken-junior-hero__text {
	flex: 0 1 560px;
}

/* 32px under the title. The group's own 28px blockGap never reached the lead:
   the margin reset that used to sit here zeroed it, and the lead sat 0px under
   an 88px heading — the "too tight" the client saw against the board. */
.dicken-junior-hero__lead {
	margin: 32px 0 0;
}

/* The photograph grows into whatever the text column leaves, so it reaches the
   frame's edge at any width. It was a fixed 680px, which is right at 1440 and
   stopped short of the edge on every wider screen — 464px short at 1920. 680
   is still its floor, so at the drawn width nothing moves. */
.dicken-junior-hero__image {
	flex: 1 0 680px;
	overflow: hidden;
	border-radius: var(--wp--custom--radius--md) 0 0 var(--wp--custom--radius--md);
	background: var(--wp--preset--color--navy);
}

.dicken-junior-hero__image .wp-block-post-featured-image {
	margin: 0;
}

.dicken-junior-hero__image img {
	display: block;
	width: 100%;
	height: 420px;
	object-fit: cover;
}

/* The Juniorit board's closing pair. Both cards stretch to the taller of the
   two (core gives a Columns row align-items: stretch, and the group inside has
   to be told to fill it), and the pill is pushed to the bottom of whichever
   card has less to say — so the two CTAs sit on one line rather than at two
   different heights, which is the difference between a pair of cards and two
   boxes that happen to be side by side. */
.dicken-junior-promo {
	display: flex;
	flex-direction: column;
	height: 100%;
	overflow: clip;
}

.dicken-junior-promo__photo {
	height: 260px;
}

.dicken-junior-promo__photo figure.wp-block-image {
	margin: 0;
	height: 100%;
}

.dicken-junior-promo__photo img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.dicken-junior-promo__body {
	display: flex;
	flex: 1;
	flex-direction: column;
}

.dicken-junior-promo__body > .wp-block-heading {
	margin: 0;
}

/* 24px between the title and the text. The body's own 18px blockGap is a
   margin, and it never arrived: a reset here used to zero this paragraph's
   margins along with the heading's, leaving the two touching. */
.dicken-junior-promo__lead {
	margin: 24px 0 0;
}

.dicken-junior-promo__cta {
	margin-top: auto;
	padding-top: 32px;
}

/* Four bands run off one edge of the frame and stop flush with the content
   column on the other: the Juniorit, Aloita and Tapahtuma heroes off the
   right, the Newsletter card off the left. It is the design's own way of
   saying a band is bigger than the page, and it is not a full-bleed section —
   one edge still lines up with everything above and below it.

   Two rules do it. The section drops the root padding on the bleeding side;
   its single child is then released from the constrained layout, which core
   centres with `margin-left`/`margin-right: auto` written !important, so
   there is no way to answer it but in kind. max-width: none is what lets the
   child grow past the 75rem content size into the space the dropped padding
   left. At 1440 that is a 1320px band starting at 0 or ending at 1440, which
   is exactly what the boards measure. */
.dicken-bleed-left {
	padding-left: 0;
}

.dicken-bleed-right {
	padding-right: 0;
}

/* …and the edge that does not bleed has to meet the content column, not the
   root padding. At 1440 those are the same 120px, which is the only width the
   boards were drawn at; past it the column centres and the root padding stays
   120, so on a 1920 screen the Juniorit hero's text started 240px left of
   every heading below it. The larger of the two is the column's own edge.

   100vw rather than 100%: a percentage padding resolves against the parent's
   width, and these sections are alignfull children of a padded <main>, so 100%
   is the main's 1680px content box at 1920 rather than the 1920 the band
   actually spans. 100vw is what .alignfull itself is sized by, above. */
.dicken-bleed-right {
	padding-left: max(var(--wp--style--root--padding-left), (100vw - var(--wp--style--global--content-size)) / 2);
}

.dicken-bleed-left {
	padding-right: max(var(--wp--style--root--padding-right), (100vw - var(--wp--style--global--content-size)) / 2);
}

.dicken-bleed-left > *,
.dicken-bleed-right > * {
	max-width: none;
	margin-left: 0 !important;
	margin-right: 0 !important;
}

/* The Start band's card and the Newsletter card both round to the theme's
   10px radius (set via each's own border.radius style attribute) and both
   need to clip their photo column to it, the same way the Team card above
   does — a block's border-radius rounds its own box, but it takes a plain
   overflow rule to stop a square-cornered child escaping past the corner. */
.dicken-start__card,
.dicken-newsletter__card {
	overflow: hidden;
}

/* theme.json has no vocabulary for a text block's own max-width — the Start
   and Newsletter panels both cap their body copy narrower than the panel
   itself, matching the design's own measured line length rather than the
   full column width the flex layout would otherwise give it. */
.dicken-start__body {
	max-width: 520px;
}

/* The panel's own child-layout attribute (style.layout.selfStretch:"fill")
   only ever compiles to flex-grow:1 — it has no vocabulary for flex-basis,
   so the panel's starting size before that growth is applied is still
   "auto": its own fit-content width, driven by the widest thing inside it.
   For the Start panel that is capped low enough by max-width above to
   never matter, but the Newsletter panel's form has no such cap on its
   field-and-button row, so its fit-content floor sat around 420px plus
   128px of padding — wider than the 58% share flex-grow was meant to give
   it at any viewport from 782px (where the Start/Newsletter cards stop
   stacking, below) up to about 945px, where 58% of the card's own growing
   width finally overtakes that floor. flex-basis:0 removes the floor by
   starting from nothing and letting flex-grow supply the whole 58%
   instead of merely adding to a fit-content one; min-width:0 overrides
   the flex default of min-width:auto (itself a min-content floor,
   otherwise still there even with flex-basis:0) so the panel can shrink
   the rest of the way at the very narrowest widths this still applies at.
   Confirmed by rendering at 900px before this rule existed. Each panel's
   own layout attribute also sets "verticalAlignment":"center", which for
   a vertical-orientation flex container compiles to justify-content, not
   align-items — align-items stays the base .is-layout-flex default of
   center (wp-includes/blocks/group/style.css), sizing every child to its
   own fit-content width rather than stretching it to the panel's now-
   correct width. stretch is harmless for the heading and the body copy,
   both already capped by their own max-width narrower than the stretched
   box would be either way, and is what lets the form itself, and the
   field-and-button row inside it, size against a real width at all. */
.dicken-start__panel,
.dicken-newsletter__panel,
.dicken-news__featured-body {
	flex-basis: 0;
	min-width: 0;
	align-items: stretch;
}

/* The stretched form (above) still has its own row to answer for: a flex
   item's default min-width is auto, not 0 — the same floor the panel
   itself just needed overriding on — so without this the row's button-
   and-input content would still refuse to shrink below its own
   fit-content width even once its stretched ancestor had room to spare. */
.dicken-newsletter__form,
.dicken-newsletter__row,
.dicken-newsletter__consent {
	min-width: 0;
}

.dicken-newsletter__body {
	max-width: 460px;
}

/* The Shop banner's photo fills it before anything else is drawn — the same
   layered-background technique the hero above uses, except this photo is
   content (the club's own jersey), not decoration, so it is a real <img>
   rather than a background-image. Positioned elements always paint above
   static content in the same stacking context regardless of source order (the
   same fact --dicken-hero__content's own z-index, above, answers for) — so the
   heading and button need z-index too, to stay above the photo.

   There is no scrim. A navy gradient (25% to 65%) used to sit over the photo
   as a ::after; the design review (Annotate #22) took it off, with the hover
   zoom, so the photograph shows as shot. */
.dicken-shop__banner {
	position: relative;
	overflow: hidden;
}

.dicken-shop__photo {
	position: absolute;
	inset: 0;
	margin: 0;
}

/* The board's own crop, which is a good deal tighter than plain cover: it
   draws the 1600x900 photograph at 1841px across a 1200px banner and hangs it
   268px above the top edge. Worked back, that is cover scaled by 1841/1200 =
   1.534 with the visible band centred — (268 + 768) / 2 lands at exactly half
   the scaled image's height — so a scale on a centred cover reproduces it, and
   unlike the design's two absolute pixel values it holds at any width. The
   difference is not subtle: at plain cover the crest reads small and enough
   pale background comes through to make the banner look washed out under its
   own navy scrim. The banner's overflow: hidden does the cropping. */
.dicken-shop__photo img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: 50% 50%;
	transform: scale(1.534);
}

.dicken-shop__banner > .wp-block-heading,
.dicken-shop__banner > .wp-block-buttons {
	position: relative;
	z-index: 1;
}

/* The Sponsors row's cells are a Query Loop's own repeated <li> — post-template
   carries style attributes on its own <ul>, never on the items it repeats, so
   the row's measured 64px cell height and its equal six-way growth (flex:1 1 0%,
   not merely flex-grow:1, so the six cells split the row exactly evenly
   regardless of how wide any one logo is) live here instead of in the pattern. */
.dicken-sponsors__row > li {
	display: flex;
	align-items: center;
	justify-content: center;
	height: 64px;
	flex: 1 1 0%;
}

/* Each logo's own height is a design choice (23-46px), not a rule derivable
   from its own aspect ratio, so one shared img rule cannot reproduce all
   six — nth-child keys each logo to its position in the loop instead. This
   holds only because content() (inc/seed.php) seeds the six sponsors in
   this exact order and the loop's own orderBy is menu_order; reordering a
   sponsor in the editor would need this list updated to match. Width is
   left to auto, so each logo's own aspect ratio sets it — only the measured
   height is asserted, and none of the six need cropping to fit it. */
.dicken-sponsors__row > li:nth-child(1) img {
	height: 28px;
}

.dicken-sponsors__row > li:nth-child(2) img {
	height: 25px;
}

.dicken-sponsors__row > li:nth-child(3) img {
	height: 23px;
}

.dicken-sponsors__row > li:nth-child(4) img {
	height: 26px;
}

.dicken-sponsors__row > li:nth-child(5) img {
	height: 28px;
}

.dicken-sponsors__row > li:nth-child(6) img {
	height: 46px;
}

.dicken-sponsors__row img {
	width: auto;
	max-width: 100%;
}

/* The Newsletter's sign-up form is the one core/html in the theme (see the
   pattern's own docblock for why); every value below is the same design
   token any block's own style attribute would reference, just applied by
   hand since this markup carries no block attributes to carry them
   instead. */
.dicken-newsletter__form {
	display: flex;
	flex-direction: column;
	gap: 10px;
}

.dicken-newsletter__row {
	display: flex;
	align-items: center;
	gap: 12px;
	margin-top: 6px;
	width: 100%;
	max-width: 480px;
}

/* The design shows only the field's placeholder, not a second visible label
   above it — but a placeholder is never a substitute for a real accessible
   name, so the label exists and is visually hidden instead of omitted. */
.dicken-newsletter__field-label {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
}

.dicken-newsletter__field {
	flex-grow: 1;
	flex-basis: 0%;
	min-width: 0;
	border: 1px solid var(--wp--preset--color--line);
	border-radius: var(--wp--custom--radius--full);
	padding: 17px 24px;
	background-color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--sans);
	font-size: 16px;
	color: var(--wp--preset--color--navy);
}

.dicken-newsletter__field::placeholder {
	color: var(--wp--preset--color--muted);
}

.dicken-newsletter__submit {
	flex-shrink: 0;
	border: none;
	border-radius: var(--wp--custom--radius--full);
	padding: 18px 36px;
	background-color: var(--wp--preset--color--red);
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--sans);
	font-size: 16px;
	font-weight: 700;
	cursor: pointer;
}

.dicken-newsletter__submit:hover {
	background-color: var(--wp--preset--color--red-600);
}

.dicken-newsletter__consent {
	display: flex;
	align-items: center;
	gap: 10px;
	max-width: 460px;
}

/* appearance:none is what lets the border, radius and background below
   actually paint — the browser default checkbox otherwise ignores most box
   styling. The checked state gets its own small rotated-border checkmark
   rather than the native tick, which appearance:none also removes. */
.dicken-newsletter__checkbox {
	appearance: none;
	flex-shrink: 0;
	position: relative;
	width: 20px;
	height: 20px;
	margin: 0;
	border: 1.5px solid var(--wp--preset--color--line);
	border-radius: var(--wp--custom--radius--sm);
	background-color: var(--wp--preset--color--white);
	cursor: pointer;
}

.dicken-newsletter__checkbox:checked {
	background-color: var(--wp--preset--color--red);
	border-color: var(--wp--preset--color--red);
}

.dicken-newsletter__checkbox:checked::after {
	content: "";
	position: absolute;
	top: 3px;
	left: 6px;
	width: 5px;
	height: 9px;
	border: solid var(--wp--preset--color--white);
	border-width: 0 2px 2px 0;
	transform: rotate(45deg);
}

.dicken-newsletter__consent label {
	font-family: var(--wp--preset--font-family--sans);
	font-size: var(--wp--preset--font-size--label);
	color: var(--wp--preset--color--muted);
	line-height: 1.55;
}

/* The design is desktop-only at 1440px, so everything below is derived
   behaviour, not a measured target. core/columns stacks its own children
   below 782px for free (wp-includes/blocks/columns/style.css), and this
   theme's header already treats 782px as the line between its overlay
   (desktop) and normal-flow (mobile) presentation — see the header rules
   above. These four rows carry none of that for free: each is a
   core/group flex layout using child-layout style.layout.selfStretch/
   flexSize attributes (the Start/Newsletter/News-featured 42-60% splits,
   the Matches chip/info/cta row), and that attribute only ever compiles to
   flex-basis on a row Core never stacks — confirmed by rendering at 390px
   before this rule existed: the News featured body, the Start and
   Newsletter panels and the Matches ticket button all overflowed the
   viewport, because each side's own fixed flex-basis leaves the other no
   room to shrink into once the row narrows past its own content floor.
   782px is this rule's own choice, not a measured one, picked to match
   the rest of the theme's one mobile threshold rather than invent a
   second. */
@media (max-width: 781px) {
	.dicken-start__card,
	.dicken-newsletter__card,
	.dicken-news__featured {
		flex-direction: column;
	}

	.dicken-start__image,
	.dicken-newsletter__image,
	.dicken-news__featured-image {
		flex-basis: auto;
		width: 100%;
		height: 240px;
	}

	/* width:100% is this rule's own addition — align-items:stretch
	   (above, unconditional) already stretches each panel to fill the
	   card's cross axis, but that axis is the card's HEIGHT until the
	   flex-direction:column rule above turns it into width. The
	   padding-*:!important is the one exception to this file's usual
	   avoidance of it, for the same reason core/columns' own mobile
	   stacking rule (wp-includes/blocks/columns/style.css) needs it: the
	   64px/56px/48px figures are the pattern's own inline style attribute
	   (block markup cannot express a media query, so it never varies by
	   viewport), and an inline style beats any class selector's specificity
	   regardless of source order — confirmed by measuring the Newsletter
	   field at 390px with only the plain (non-!important) rule in place:
	   the panel's padding was still 64px, the row still had only 197px to
	   work with, and the email field rendered at 75px wide, wide enough
	   for about three characters of its own placeholder. */
	.dicken-start__panel,
	.dicken-newsletter__panel,
	.dicken-news__featured-body {
		width: 100%;
		padding-right: 32px !important;
		padding-left: 32px !important;
	}

	/* The chip (72px) and the ticket button both refuse to shrink (see
	   their own flex-shrink:0 rule above) so the info column between them
	   is the only side that can give — and past this width it has nothing
	   left to give. Wrapping the row and giving the button its own full
	   line is the same "stack it" answer as the two-panel cards above,
	   just expressed as a wrap instead of a column, since the chip and
	   the info column are meant to stay side by side even here. */
	.dicken-matches__row {
		flex-wrap: wrap;
	}

	.dicken-matches__cta {
		flex-basis: 100%;
		justify-content: center;
	}

	/* The row's own flexWrap:wrap (the pattern's layout attribute) can only
	   wrap once a cell actually runs out of room to shrink into, and cells
	   here never do: flex:1 1 0% lets each shrink toward zero, and each
	   logo's own img rule leaves width to auto, so there is no floor
	   forcing a wrap — six cells just kept splitting one row into
	   ever-thinner slices instead, each logo scaled down past legibility
	   and, for the widest wordmarks, past its own slot's edge. Fixing each
	   cell at 50% (two per row, three rows) gives every logo — 44 to 126px
	   wide at its own design height, measured at 390px — comfortable room
	   regardless of aspect ratio, which a taller floor alone could not
	   guarantee for all six at once. */
	.dicken-sponsors__row > li {
		/* Half the row's own 16px blockGap (style attribute, section-
		   sponsors.php), subtracted from each cell so two of them plus the
		   gap between still sum to exactly 100% — flex-basis:50% alone
		   left no room for that gap, pushing every pair past the row's own
		   width and wrapping to one cell per line (six rows, not three)
		   instead of the two-per-row this rule means to produce. */
		flex: 0 0 calc(50% - 8px);
	}
}

/* ---------------------------------------------------------------------------
   Motion

   The rule this section follows: motion goes on things you can actually
   click. None of the cards on this page is a link — section-teams.php,
   section-news.php and section-matches.php all render their images and titles
   with isLink:false, and the only anchor inside a card is its own "Lue lisää"
   / "Siirry joukkueeseen" line. So a card lifting under the cursor would be
   promising a click target that is not there. Cards instead move the one thing
   that *is* clickable (their link's chevron) and let their photograph breathe,
   which points at the link rather than impersonating one. Lifts are reserved
   for buttons and sponsor logos, which are genuinely anchors.

   Durations and the curve come from settings.custom.motion in theme.json.
   Nothing here animates a layout property: transform, opacity, colour and
   border only, so none of it triggers reflow.
   --------------------------------------------------------------------------- */

/* The signature move. .dicken-chevron is the design's own recurring
   read-more, on every team card, every news card and the Intro — the arrow
   leans in the direction the link goes. :focus-visible carries it too, so it
   is feedback for the keyboard rather than decoration for the mouse. */
.dicken-chevron::after {
	transition: transform var(--wp--custom--motion--base) var(--wp--custom--motion--ease);
}

.dicken-chevron:hover::after,
.dicken-chevron:focus-visible::after,
.dicken-team-card:hover .dicken-chevron::after,
.dicken-news__card:hover .dicken-chevron::after,
.dicken-news__featured:hover .dicken-chevron::after {
	transform: translateX(3px);
}

/* The photograph inside a card. Slow and small — 1.04 over 420ms reads as the
   image settling rather than zooming, and the card already clips its own
   content (see .dicken-team-card and .dicken-news__featured above), so the
   scale has an edge to grow into. transform-origin centres it so the crop
   does not drift toward one corner. */
.dicken-team-card img,
.dicken-news__card-image img,
.dicken-news__featured-image img {
	transition: transform var(--wp--custom--motion--slow) var(--wp--custom--motion--ease);
	transform-origin: 50% 50%;
}

.dicken-team-card:hover img,
.dicken-news__card:hover img,
.dicken-news__featured:hover img {
	transform: scale(1.04);
}

/* Buttons are anchors, so they may lift. 1px, not the 4px a card would take:
   the pill is small and a larger lift on a 46px-tall element reads as the
   element detaching. :active returns it to rest, which is the press.

   The colour change itself is already in theme.json (elements.button:hover,
   red to red-600); all this adds is the time it takes, since an instant swap
   at this size reads as a flicker rather than a response. */
.wp-element-button,
.wp-block-button__link,
.dicken-newsletter__submit {
	transition:
		background-color var(--wp--custom--motion--fast) var(--wp--custom--motion--ease),
		border-color var(--wp--custom--motion--fast) var(--wp--custom--motion--ease),
		color var(--wp--custom--motion--fast) var(--wp--custom--motion--ease),
		transform var(--wp--custom--motion--fast) var(--wp--custom--motion--ease);
}

.wp-element-button:hover,
.wp-block-button__link:hover,
.dicken-newsletter__submit:hover {
	transform: translateY(-1px);
}

.wp-element-button:active,
.wp-block-button__link:active,
.dicken-newsletter__submit:active {
	transform: translateY(0);
}

/* The two outline pills — "Kaikki uutiset" and "Kaikki yhteistyökumppanit" —
   are navy-on-transparent with a navy hairline. They fill rather than lift:
   the border is already the shape, so completing it is the more natural
   answer than moving it. Specificity has to beat the inline style attribute
   those two buttons carry from their block markup, hence !important — the
   colours are set inline by the pattern (section-news.php,
   section-sponsors.php) on the anchor itself, and an inline style outranks
   every selector that is not !important. The className lands on the wrapping
   .wp-block-button div, not the anchor, so the anchor is reached through it. */
.dicken-news__pill .wp-block-button__link:hover,
.dicken-sponsors__pill .wp-block-button__link:hover {
	background-color: var(--wp--preset--color--navy) !important;
	color: var(--wp--preset--color--white) !important;
}

/* Header and footer navigation. An underline wipes in from the left rather
   than a colour change: the links sit white on navy (and, on the front page,
   white over the hero photograph), where a colour shift has little room to
   read. scaleX on a pseudo-element, so nothing reflows.

   The footer's is sand, the crest's own accent. The header's was too, until
   the design review (Annotate #19) asked for white, the colour of the link
   itself. The light bar on a subpage overrides it to red (above). */
.dicken-header__nav .wp-block-navigation-item__content,
/* Medium, the way the board draws them. A footer link list at Regular reads as
   body copy that happens to be blue-on-navy; the half-step of weight is what
   makes it read as a list of destinations. */
.dicken-footer .wp-block-navigation-item__content {
	font-weight: 500;
	position: relative;
}

.dicken-header__nav .wp-block-navigation-item__content::after,
.dicken-footer .wp-block-navigation-item__content::after {
	content: "";
	position: absolute;
	inset-inline: 0;
	bottom: -4px;
	height: 1.5px;
	background-color: var(--wp--preset--color--sand);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform var(--wp--custom--motion--base) var(--wp--custom--motion--ease);
}

.dicken-header__nav .wp-block-navigation-item__content::after {
	background-color: var(--wp--preset--color--white);
}

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

/* The ticket pill inside the overlay is a button wearing a navigation-item's
   markup; it gets the button's own treatment above, not the underline. */
.dicken-header__nav .dicken-nav__cta .wp-block-navigation-item__content::after {
	content: none;
}

/* The utility row's team links and the language switcher: too small for an
   underline to sit cleanly under, so they take the colour instead. */
.dicken-header__utility .wp-block-navigation-item__content {
	transition: color var(--wp--custom--motion--fast) var(--wp--custom--motion--ease);
}

.dicken-header__utility .wp-block-navigation-item__content:hover {
	color: var(--wp--preset--color--sand);
}

/* Social icons, header and footer. Scale from their own centre; the icons are
   monochrome white, so size is the only channel with room to say anything. */
.wp-block-social-link {
	transition: transform var(--wp--custom--motion--base) var(--wp--custom--motion--ease);
}

.wp-block-social-link:hover {
	transform: scale(1.12);
}

/* Sponsor logos are real anchors (isLink:true, section-sponsors.php), so they
   may lift. Kept to 2px and paired with a small scale: these are other
   companies' marks, and distorting them further would be taking a liberty
   with someone else's brand. */
.dicken-sponsors__row a {
	display: inline-block;
	transition: transform var(--wp--custom--motion--base) var(--wp--custom--motion--ease);
}

.dicken-sponsors__row a:hover {
	transform: translateY(-2px) scale(1.03);
}

/* The newsletter field. The design gives it a line border; focus deepens it to
   navy rather than adding a glow, which would be the only shadow on the page. */
.dicken-newsletter__field {
	transition: border-color var(--wp--custom--motion--fast) var(--wp--custom--motion--ease);
}

.dicken-newsletter__field:focus {
	border-color: var(--wp--preset--color--navy);
}

/* Everything above is feedback, not choreography, so switching it off costs a
   user nothing but the animation itself — every hover state still changes
   colour, still fills, still underlines. Written as durations rather than
   `animation: none` so no state is left mid-transition. */
@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		transition-duration: 0.01ms !important;
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		scroll-behavior: auto !important;
	}
}

/* ---------------------------------------------------------------------------
   The Ajankohtaista archive
   --------------------------------------------------------------------------- */

/* The Tapahtumat view's own lead. Capped at the board's measure rather than
   running the full 1200px column: a 20px line that long stops being a lead and
   becomes a paragraph. */
.dicken-archive__lead {
	max-width: 720px;
	margin-block: 0;
}

/* The head, the filters and the results are three full-bleed sections rather
   than one, so each keeps its own vertical rhythm from the board: 80/40 for the
   head, 24/40 for the filters, and the results' own 48px column gap. */
.dicken-archive__tabs {
	display: flex;
	align-items: flex-end;
	gap: 32px;
	margin-top: 12px;
}

/* The active tab is marked by a red rule under it, and by aria-current in the
   markup — the colour alone would be the only signal for a reader who cannot
   see it. The inactive tab keeps muted text so the pair reads as one control
   rather than as a link beside a heading. */
.dicken-archive__tab {
	padding-bottom: 10px;
	border-bottom: 2px solid transparent;
	color: var(--wp--preset--color--muted);
	font-size: var(--wp--preset--font-size--medium);
	font-weight: 500;
	text-decoration: none;
}

.dicken-archive__tab--active {
	border-bottom-color: var(--wp--preset--color--red);
	color: var(--wp--preset--color--navy);
	font-weight: 700;
}

/* The search field and the sort control share a row, pushed apart, the way the
   board draws them: the field left at a fixed 360px, the sort hard right. */
.dicken-archive__form {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
}

/* Both controls sit on mist with an 8px radius. 8px is the board's own value and
   is deliberately not a token: adding one for two controls would imply a scale
   that nothing else uses, and substituting radius-md (10px) would visibly
   disagree with the board. */
.dicken-archive__search,
.dicken-archive__sort {
	display: flex;
	align-items: center;
	gap: 10px;
	border-radius: 8px;
	background-color: var(--wp--preset--color--mist);
}

.dicken-archive__search {
	flex-direction: row-reverse;
	width: 360px;
	max-width: 100%;
	padding: 13px 16px;
}

.dicken-archive__sort {
	padding: 13px 18px;
}

/* row-reverse above puts the magnifier first visually while leaving the input
   first in the DOM, so the submit button stays after the field it submits for a
   keyboard reader. */
.dicken-archive__search-input {
	flex: 1;
	min-width: 0;
	border: 0;
	background: none;
	color: var(--wp--preset--color--navy);
	font-size: 16px;
}

/* The board's placeholder is #8794A5 on #F2F4F7, about 2.9:1 — below AA for
   text. muted is 5.3:1 on the same ground and is the closest palette value, so
   the deviation is deliberate and should not be "corrected" back. */
.dicken-archive__search-input::placeholder {
	color: var(--wp--preset--color--muted);
	opacity: 1;
}

.dicken-archive__search-input:focus-visible {
	outline: 2px solid var(--wp--preset--color--navy);
	outline-offset: 4px;
}

/* The magnifier is the form's submit control, not decoration — see the
   pattern's docblock. Sized to its 16px glyph so the field's own padding is
   what separates it from the text. */
.dicken-archive__submit {
	display: flex;
	flex-shrink: 0;
	padding: 0;
	border: 0;
	background: none;
	color: var(--wp--preset--color--muted);
	cursor: pointer;
}

.dicken-archive__sort-select {
	border: 0;
	background: none;
	color: var(--wp--preset--color--navy);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 500;
}

.dicken-archive__pills {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
}

.dicken-archive__pill {
	padding: 8px 18px;
	border-radius: var(--wp--custom--radius--full);
	background-color: var(--wp--preset--color--mist);
	color: var(--wp--preset--color--navy);
	font-size: 14px;
	font-weight: 500;
	text-decoration: none;
}

.dicken-archive__pill--active {
	background-color: var(--wp--preset--color--navy);
	color: var(--wp--preset--color--white);
	font-weight: 600;
}

@media screen and (prefers-reduced-motion: no-preference) {
	.dicken-archive__pill,
	.dicken-archive__tab {
		transition:
			background-color var(--wp--custom--motion--fast) var(--wp--custom--motion--ease),
			color var(--wp--custom--motion--fast) var(--wp--custom--motion--ease),
			border-color var(--wp--custom--motion--fast) var(--wp--custom--motion--ease);
	}
}

.dicken-archive__pill:hover,
.dicken-archive__pill:focus-visible {
	background-color: var(--wp--preset--color--line);
}

.dicken-archive__pill--active:hover,
.dicken-archive__pill--active:focus-visible {
	background-color: var(--wp--preset--color--navy-700);
}

/* The count is announced, not shown: the visible signal that filtering happened
   is the list changing, and a duplicate "6 results" line is not in the board.
   Not display:none — a hidden live region is not announced by every screen
   reader. This is core's own .screen-reader-text geometry. */
.dicken-archive__count {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	border: 0;
	clip-path: inset(50%);
	white-space: nowrap;
}

/* While a fetch is in flight the list dims rather than being replaced by a
   spinner: the old results stay readable, and nothing reflows twice. */
.dicken-archive__results[aria-busy="true"] {
	opacity: 0.55;
}

@media screen and (prefers-reduced-motion: no-preference) {
	.dicken-archive__results {
		transition: opacity var(--wp--custom--motion--fast) var(--wp--custom--motion--ease);
	}
}

/* Näytä lisää is core's pagination-next, so it arrives as a bare link. The board
   draws it as the same outlined pill the homepage's "Kaikki uutiset" uses, so it
   is given that treatment here rather than in the pattern — a core pagination
   block takes no border or padding attributes to carry it. */
.dicken-archive__more {
	margin-top: 8px;
}

.dicken-archive__more .wp-block-query-pagination-next {
	padding: 15px 32px;
	border: 1.5px solid var(--wp--preset--color--navy);
	border-radius: var(--wp--custom--radius--full);
	color: var(--wp--preset--color--navy);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 700;
	text-decoration: none;
}

.dicken-archive__more .wp-block-query-pagination-next:hover,
.dicken-archive__more .wp-block-query-pagination-next:focus-visible {
	background-color: var(--wp--preset--color--navy);
	color: var(--wp--preset--color--white);
}

@media screen and (prefers-reduced-motion: no-preference) {
	.dicken-archive__more .wp-block-query-pagination-next {
		transition:
			background-color var(--wp--custom--motion--base) var(--wp--custom--motion--ease),
			color var(--wp--custom--motion--base) var(--wp--custom--motion--ease);
	}
}

/* Neither the featured row nor the card grid needs a rule here at 781px. The
   featured row's stacking is the pre-existing .dicken-news__featured /
   -featured-image rule above (~line 949) — it already carries this exact
   breakpoint, already targets these exact classes (shared with the homepage's
   News section, so a second rule here would fight it rather than help it),
   and was tuned against a real 390px render (see its own comment). The card
   grid's collapse is not CSS at all: hidden-archive-news.php's post-template
   sets minimumColumnWidth alongside columnCount, which makes core emit a
   responsive auto-fill grid that narrows on its own (see that file's
   docblock). What is left, and is genuinely archive-only, is the filter
   form. */
@media (max-width: 781px) {
	.dicken-archive__form {
		flex-wrap: wrap;
	}

	.dicken-archive__search {
		width: 100%;
	}
}

/* The event card: the same 10px corner and clipping as the news card, but its
   body sits on mist rather than white. That is the board, and it is why this is
   its own class rather than a reuse — the news card's white body works against
   the mist section it sits in on the homepage, and this view's ground is white. */
.dicken-event-card {
	overflow: hidden;
}

/* Photo and body meet with no seam. The card's own blockGap — core's 16px,
   as a margin on the body in the stacked card and a flex gap in the wide one —
   showed as a white strip between the photograph and the mist panel, which is
   what made the cards look like two boxes rather than one. */
.dicken-event-card.wp-block-group {
	gap: 0;
}

.dicken-event-card.wp-block-group > * {
	margin-block: 0;
}

/* …and one height for the row: the grid stretches each <li>, the card fills
   it, and the mist body takes whatever is left under the photo, so a shorter
   excerpt no longer leaves a card ending 24px above its neighbours. */
.dicken-archive__grid > li {
	display: flex;
	flex-direction: column;
}

.dicken-archive__grid .dicken-event-card {
	display: flex;
	flex: 1;
	flex-direction: column;
}

.dicken-archive__grid .dicken-event-card__body {
	flex: 1;
}

/* Same reasoning as .dicken-news__card-image: relative and clipping so the
   image can be asked to fill a box whose height is either the row's stretched
   height or a fixed 216px, neither of which core/post-featured-image's own
   height attribute can express. */
.dicken-event-card__image {
	position: relative;
	overflow: hidden;
	height: 216px;
	background-color: var(--wp--preset--color--navy);
}

.dicken-event-card--wide {
	min-height: 220px;
}

/* The wide card's photo is a fixed 48% via its own style.layout.flexSize, which
   only ever compiles to flex-basis — the same gap the news featured image hit.
   Without flex-shrink: 0 the body's text would squeeze the photo. */
.dicken-event-card--wide .dicken-event-card__image {
	flex-shrink: 0;
	height: auto;
}

.dicken-event-card__image figure.wp-block-post-featured-image {
	position: absolute;
	inset: 0;
	margin: 0;
}

.dicken-event-card__image img {
	display: block;
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	margin: 0;
	object-fit: cover;
}

@media (max-width: 781px) {
	.dicken-event-card--wide {
		flex-wrap: wrap;
	}

	.dicken-event-card--wide .dicken-event-card__image {
		flex-basis: 100% !important;
		height: 240px;
	}
}

/* The ingressi. Set larger and slightly heavier than the body, which is the whole
   of what the board does to it — no colour change, no rule, no indent. Offered as
   a block style (inc/article.php) so an author picks it, rather than as a rule on
   whichever paragraph happens to be first. */
.is-style-lead {
	font-size: 22px;
	font-weight: 500;
	line-height: var(--wp--custom--leading--normal);
}

/* ---------------------------------------------------------------------------
   The article page
   --------------------------------------------------------------------------- */

.dicken-article__back {
	display: inline-block;
	color: var(--wp--preset--color--muted);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	text-decoration: none;
}

.dicken-article__back:hover,
.dicken-article__back:focus-visible {
	color: var(--wp--preset--color--navy);
}

/* The category chip in the article head is the news chip's pill without the
   absolute positioning — there is no photo here for it to sit on. */
.wp-block-post-terms.dicken-article__chip {
	margin: 0;
	border-radius: var(--wp--custom--radius--full);
	background-color: var(--wp--preset--color--navy);
	padding: 6px 12px;
	line-height: 1;
}

.wp-block-post-terms.dicken-article__chip a {
	color: inherit;
	text-decoration: none;
}

.dicken-article__share {
	display: flex;
	align-items: center;
	gap: 12px;
}

.dicken-article__share-label {
	color: var(--wp--preset--color--muted);
	font-size: var(--wp--preset--font-size--label);
	font-weight: 600;
}

.dicken-article__share-link {
	display: flex;
	color: var(--wp--preset--color--navy);
}

/* core's social icons are drawn at 24 with no fill of their own; 20 keeps the
   row the height of the byline beside it. */
.dicken-article__share-link svg {
	width: 20px;
	height: 20px;
	fill: currentColor;
}

/* The author's photo slot, a circle the size of the two lines beside it —
   the same placeholder the event contact card draws, for the same reason: the
   byline names a team, and there is no photo to put here yet. */
.dicken-article__avatar {
	flex-shrink: 0;
	width: 44px;
	height: 44px;
	border-radius: var(--wp--custom--radius--full);
	background: var(--wp--preset--color--line);
}

.dicken-article__share-link:hover,
.dicken-article__share-link:focus-visible {
	color: var(--wp--preset--color--red);
}

/* An empty caption paragraph would still occupy a line box. The binding returns
   null for an uncaptioned photo, which leaves the paragraph empty rather than
   absent, so :empty is what removes the gap. */
.dicken-article__caption:empty {
	display: none;
}

/* The body's rhythm. The board draws 18px at 178%; the size is snapped to the
   `medium` token (17px) to keep the type scale token-driven — a deliberate 1px
   concession, recorded in the plan's deviations. The line-height stays a ratio so
   it follows whatever the token holds. */
.dicken-article__content {
	font-size: var(--wp--preset--font-size--medium);
	line-height: 1.78;
}

/* An article's reading content is Inter, all of it. The display face is for
   the boards' own display headings and for the pullquote below, which is an
   accent inside the reading rather than part of it — theme.json gives every
   heading Raurus, so a subheading in the middle of a paragraph of Inter needs
   this to say otherwise. */
.dicken-article__content > h2 {
	margin-top: var(--wp--preset--spacing--50);
	font-family: var(--wp--preset--font-family--sans);
	font-size: var(--wp--preset--font-size--x-large);
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1.3;
}

/* The board's pullquote: a 3px red rule, 28px of space, and the attribution
   under it. Scoped inside the content so core/quote elsewhere on the site keeps
   theme.json's own treatment. */
.dicken-article__content > .wp-block-quote {
	margin-block: var(--wp--preset--spacing--40);
	border-left: 3px solid var(--wp--preset--color--red);
	padding-left: 28px;
	font-size: var(--wp--preset--font-size--large);
	font-style: normal;
}

.dicken-article__content > .wp-block-quote cite {
	display: block;
	/* Inter, while the quote itself stays Raurus: the name and title are a
	   label under the accent, not part of it. theme.json sets core/quote's
	   family on the block, and the cite inherited it. */
	font-family: var(--wp--preset--font-family--sans);
	margin-top: 12px;
	color: var(--wp--preset--color--red);
	font-size: var(--wp--preset--font-size--small);
	font-style: normal;
	font-weight: 600;
}

/* A wide heading introduces a band inside the article — "Kuvia ottelusta"
   over its gallery — rather than a step in the reading, so it takes the
   display face the site's other band headings use, not the Inter of the
   subheads above. */
.dicken-article__content > h2.alignwide {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--xx-large);
	font-weight: 500;
	line-height: var(--wp--custom--leading--tight);
}

/* A gallery an author marks as wide reaches 1040px, past the 820px measure. That
   is post-content's own wideSize (see single.html), so nothing is needed here
   beyond the heading above it sharing the same lane. */
.dicken-article__content > .wp-block-heading.alignwide,
.dicken-article__content > .wp-block-gallery.alignwide {
	max-width: 1040px;
}

/*
 * The team page.
 *
 * The hero is a cover block, so its own min-height and overlay do most of the
 * work; what is left here is the type's position over the photo and the
 * breadcrumb above it.
 */

/* theme.json's root blockGap (--wp--preset--spacing--30, 1rem) makes
   WordPress' own global styles add margin-block-start: 1rem to every
   top-level block in .wp-site-blocks except the first — the same rule
   body.home main (above) already overrides for the front page, for the
   identical reason: there is no per-template exception for it in
   theme.json's own vocabulary. Every other template's <main> either
   supplies its own explicit margin-top (page.html, single.html) or opens
   on white beneath a white header, where the 1rem is invisible either way.
   The team hero is the first full-bleed photograph to sit directly under
   the header, so this is the first template where the seam shows: measured
   at /joukkueet/miehet/, header wrapper bottom 174, hero top 190 — a 16px
   white gap between the header and the photo.

   Scoped to this template's own <main> rather than lowering blockGap
   globally, which would move every page's vertical rhythm to chase one
   template's seam. */
.dicken-team {
	margin-block-start: 0;
}

/* The header's own space, painted navy while it is pinned. The sticky box
   keeps the full 174px that space measures (see the sticky rule) while the
   bar inside it condenses to 88px, so for the first 86px of scroll the 46px
   strip under the condensed bar showed whatever was behind the box — on
   this template, the page's white over the top of the hero photograph
   (measured from 20px of scroll to 86px). With the space navy, that strip
   reads as the bar's own ground, and the hero scrolling up eats into it.

   A painted space rather than a header that waits for the hero to shrink:
   the space scrolls with the page, in the same frame as the hero, so no
   scroll speed in either direction can open the strip. A script driving the
   bar measured 10-32px of white scrolling up, a frame behind the page; a
   timed shrink, 27-45px behind it.

   This template only: it is the one whose content sits flush under the
   header (above). Every other page opens 16px or more lower and on white,
   under a white header, where the strip is white on white. Fades in with
   the bar's ground (the transition with the header's own, below), and below
   782px there is nothing to paint behind — the header stays in the flow
   there, solid navy, with the content after it. */
@media (min-width: 782px) {
	.dicken-team {
		position: relative;
	}

	.dicken-team::before {
		content: "";
		position: absolute;
		inset-inline: 0;
		bottom: 100%;
		height: var(--dicken-header-height);
		background-color: var(--wp--preset--color--navy);
		opacity: 0;
		pointer-events: none;
	}

	.dicken-header-pinned .dicken-team::before {
		opacity: 1;
	}
}

@media screen and (min-width: 782px) and (prefers-reduced-motion: no-preference) {
	.dicken-team::before {
		transition: opacity var(--wp--custom--motion--slow) cubic-bezier(0.4, 0, 0.2, 1);
	}
}

/* The hero's title sits over the photo via core/cover's own contentPosition
   attribute (bottom center; see the pattern) rather than a hand-rolled flex
   column: a flex column on this element turns the h1 and the breadcrumb into
   flex items, and once either of the constrained layout's own margin-inline
   auto values has to compete with a flex cross-axis alignment, the browser
   drops the item to its own shrink-to-fit width instead of the 1200px the
   layout attribute asks for — measured at 220px wide, sitting flush against
   the cover's own left padding, instead of 1200px centred in it. Content
   position's "center" half keeps the inner container at its default
   width: 100% (core's own cover/style.css only shrinks it to fit-content
   for the "left"/"right" halves, not "center"), which is what leaves the
   constrained layout's max-width and auto margins free to do the 1200px
   centring themselves, exactly as they already do on every other
   alignfull section in this theme. Bottom-aligning within the cover, and
   the 10px gap above the title on a junior team's breadcrumb, are both the
   cover block's own style.spacing (contentPosition and blockGap; see the
   pattern) rather than repeated here — no CSS is left to write for either
   once the block's own attributes carry them. */

/* The soft lift under the white title the design specifies. Written here
   rather than as a block style attribute because core/post-title has no
   text-shadow support of its own (no "shadow" feature in its block.json,
   unlike core/cover's own box-shadow). The value is the design's own,
   verbatim — rgba(0, 0, 0, 0) is fully transparent, so this is a no-op
   against the seeded photo today, but it is what the design specifies and
   costs nothing to carry: a future, brighter crop is exactly the case this
   would start to matter for. */
.dicken-team-hero .wp-block-post-title {
	text-shadow: 0 2px 3px rgb(0 0 0 / 0%);
}

.dicken-team-hero__breadcrumb {
	margin: 0;
	font-weight: 600;
	letter-spacing: 0.04em;
}

.dicken-team-hero__breadcrumb::before {
	content: "← ";
}

/* The link is the breadcrumb's own sand, not the site's red: render_breadcrumb()
   writes a real <a> into the paragraph, and theme.json's link colour and
   underline reached it, so the arrow was sand and the word beside it was red
   and underlined over the photograph. The board draws the two as one mark. */
.dicken-team-hero__breadcrumb a {
	color: inherit;
	text-decoration: none;
}

.dicken-team-hero__breadcrumb a:hover,
.dicken-team-hero__breadcrumb a:focus-visible {
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.dicken-team-news {
	background: var(--wp--preset--color--white);
}

.dicken-team-nav__list {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.dicken-team-nav__chip {
	display: inline-block;
	padding: 10px 18px;
	border-radius: var(--wp--custom--radius--full);
	background: var(--wp--preset--color--white);
	color: var(--wp--preset--color--navy);
	font-size: var(--wp--preset--font-size--label);
	font-weight: 600;
	text-decoration: none;
}

/* The board fills the current tab navy and leaves the rest white. Which tab
   that is follows the reader down the page — assets/team.js sets is-current
   from an IntersectionObserver over the same sections the chips were derived
   from, and marks the first one before it has observed anything, so the bar is
   never drawn with no tab lit. Hover lands on the same treatment: the chip
   shows you what picking it would look like. */
.dicken-team-nav__chip.is-current,
.dicken-team-nav__chip:hover,
.dicken-team-nav__chip:focus-visible {
	background: var(--wp--preset--color--navy);
	color: var(--wp--preset--color--white);
}

/* The board caps the introduction at 560px and lets the column be as wide as
   the row leaves it — a 20px lead running the full 740px would be a longer
   line than anything else on the site. theme.json has no vocabulary for a
   column's own measure, so it is said here, the way the Start band's text
   block already is. */
.dicken-team-intro__lead > * {
	max-width: 560px;
}

/* 420px is the card, not the card's contents. A column's width attribute
   compiles to flex-basis, which resolves against the content box, so the 40px
   of padding either side was landing outside it and the box measured 500. */
.dicken-facts {
	box-sizing: border-box;
}

/* The one info box the site has: the team page's facts, the Tapahtuma board's
   Tiedot card and the Yhteystiedot card are the same component with different
   rows in it. The rhythm is a rule *above* each row after the first and 22px
   of air either side of it, rather than a rule below each row but the last —
   the same drawing, but this way the card's own 36px padding is what sits
   above the first row and below the last, with nothing added to it. */
.dicken-fact {
	padding-block: 22px;
	border-top: 1px solid var(--wp--preset--color--line);
}

.dicken-fact:first-child {
	padding-top: 0;
	border-top: 0;
}

.dicken-fact:last-child {
	padding-bottom: 0;
}

/* 96px is a measurement, not a guess: it is the widest of the six row labels
   with room to spare, and fixing it is the whole point — the values line up
   with each other in one column instead of each ragging off the right edge of
   a row as long as its own label is short.

   The colour stays `muted`. The board's own label grey is #8794A5, which is
   2.9:1 on mist and fails AA at any size these labels are drawn at; the same
   substitution is made for the archive search placeholder, for the same
   reason, and is noted there too. */
.dicken-fact__label {
	flex: 0 0 96px;
	margin: 0;
	text-transform: uppercase;
	letter-spacing: 0.12em;
	font-weight: 700;
}

.dicken-fact__value {
	margin: 0;
}

/*
 * The number sits over the photo's lower-left corner, as the board draws it —
 * so the photo group is the positioning context and the number is taken out of
 * flow rather than laid out beneath the image. width/height are written here
 * rather than left to the flex column's own stretch, matching how every other
 * fixed-size photo box in this theme (.dicken-news__card-image and siblings)
 * states its own box size in CSS rather than leaving it implicit.
 */
.dicken-player-card__photo {
	position: relative;
	overflow: clip;
	width: 100%;
	height: 260px;
}

.dicken-player-card__number {
	position: absolute;
	left: 16px;
	bottom: 12px;
	z-index: 1;
	margin: 0;
}

/*
 * The board has no with-photo state to copy — none of its own cards carry a
 * photo either (see the pattern's own docblock) — so legibility once a team
 * does add one is this fix's own call: a navy number, right on a photo, can
 * disappear into it exactly the way it does not on the mist placeholder the
 * board actually specifies. :has() scopes both the scrim and the colour
 * switch to the moment an <img> actually exists, so the photo-less
 * placeholder above is untouched.
 * The gradient is navy's own RGB triplet (#001C44) rather than a preset
 * reference because theme.json defines no gradient or partial-opacity
 * colour token for either the palette or a fade to transparent.
 */
.dicken-player-card__photo:has(img)::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	background: linear-gradient(to top, rgb(0 28 68 / 70%), transparent 60%);
	pointer-events: none;
}

/*
 * !important because textColor:"navy" (the pattern) compiles to the
 * has-navy-color utility class, and every preset colour class WordPress
 * generates carries its own !important (core's own doing, not this
 * theme's) — a plain declaration here would lose to it regardless of
 * selector specificity.
 */
.dicken-player-card__photo:has(img) .dicken-player-card__number {
	z-index: 2;
	color: var(--wp--preset--color--white) !important;
}

.dicken-staff-card__photo img {
	border-radius: var(--wp--custom--radius--full);
}

/* The photo slot the board draws on every staff card, whether or not the
   person has a photo yet. core/post-featured-image renders nothing at all
   without one, so the card lost its circle and its text jumped to the left
   edge; this puts the same 56px circle in its place, the way the event
   contact card draws its own. :has() rather than a class because only the
   rendered card knows whether the image came out. */
.dicken-staff-card:not(:has(.dicken-staff-card__photo))::before {
	content: "";
	flex-shrink: 0;
	width: 56px;
	height: 56px;
	border-radius: var(--wp--custom--radius--full);
	background: var(--wp--preset--color--line);
}

/* One height for every card in the row, whichever of them has a phone number
   as well as an email: the grid stretches each <li>, and the card is told to
   fill it. */
.dicken-team-staff .wp-block-post-template > li {
	display: flex;
}

.dicken-team-staff .dicken-staff-card {
	flex: 1;
}

.dicken-practice-row,
.dicken-match-row {
	padding: 16px 0;
	border-bottom: 1px solid var(--wp--preset--color--line);
}

.dicken-practice-row p,
.dicken-match-head p,
.dicken-match-row p {
	margin: 0;
}

/* The board labels the four lanes above the first fixture. Small caps on the
   same rule the rows are separated by, so it reads as the top of a table
   rather than as a fifth row. */
.dicken-match-head {
	padding-bottom: 10px;
	border-bottom: 1px solid var(--wp--preset--color--line);
	text-transform: uppercase;
	letter-spacing: 0.1em;
	font-weight: 700;
}

/*
 * Fixed-width lanes, not gap. The opponent names vary in length row to row, and
 * a row laid out on gap alone puts every column in a different place on every
 * row — the date under the venue, the venue under the result.
 */
.dicken-practice-row__day {
	width: 120px;
	flex-shrink: 0;
	font-weight: 700;
}

.dicken-practice-row__time {
	width: 120px;
	flex-shrink: 0;
}

.dicken-practice-row__venue {
	flex: 1;
}

.dicken-match-row__date {
	width: 88px;
	flex-shrink: 0;
	font-weight: 700;
}

.dicken-match-row__fixture {
	flex: 1;
	font-weight: 600;
}

/* 200px and left-aligned, not 120 and ragged right: "Lauttasaaren
   liikuntapuisto" does not fit 120px and was wrapping to a second line on
   every row, which is also what left the Paikka lane with nothing to be a
   lane of. */
.dicken-match-row__venue {
	width: 200px;
	flex-shrink: 0;
}

.dicken-match-row__result {
	width: 72px;
	flex-shrink: 0;
	text-align: right;
	font-weight: 700;
}

/*
 * assets/team.js hides a filtered-out row by setting its `hidden` property, and
 * the UA stylesheet's [hidden]{display:none} is not enough to do it here: the
 * row is a flex group, so core's global stylesheet declares
 * .is-layout-flex{display:flex} — an author-origin rule, which outranks any UA
 * one whatever its selector. This is the author-origin answer, at specificity
 * 0,2,0 against core's 0,1,0, so it wins on the cascade rather than on
 * !important. Without it "Kotipelit" marks its chip active and hides nothing.
 *
 * The second selector is for the phone, whose stacking rule is
 * `.dicken-match-row.is-layout-flex {display: block}` — 0,2,0 as well, and later
 * in this file, so it won the tie and every hidden row showed again. 0,3,0
 * outranks it wherever it sits.
 */
.dicken-match-row[hidden],
.dicken-match-row.is-layout-flex[hidden] {
	display: none;
}

.dicken-match-filter {
	padding: 8px 18px;
	border: 0;
	border-radius: var(--wp--custom--radius--full);
	background: var(--wp--preset--color--mist);
	color: var(--wp--preset--color--navy);
	font-family: inherit;
	font-size: var(--wp--preset--font-size--label);
	font-weight: 600;
	cursor: pointer;
}

.dicken-match-filter.is-active {
	background: var(--wp--preset--color--navy);
	color: var(--wp--preset--color--white);
}

/*
 * Torneopal's rows (inc/torneopal.php) are printed by PHP, not rendered from a
 * group block, so they do not get the per-instance container class core
 * generates for the pattern's rows. These are the two values that class would
 * carry. Two classes in the selector to outrank core's `.is-layout-flex
 * {flex-wrap: wrap}`, which they do carry.
 */
.dicken-match-row.dicken-match-row--torneopal {
	flex-wrap: nowrap;
	justify-content: space-between;
}

/* The fixture list's "Näytä kaikki ottelut". The site's secondary pill — navy
   hairline on transparent, filling navy on hover — the same as the news and
   sponsors bands' buttons, since the red one is reserved for tickets. */
.dicken-match-more {
	display: flex;
	justify-content: center;
	margin-top: var(--wp--preset--spacing--40);
}

.dicken-match-more__button {
	padding: 13px 32px;
	border: 1px solid var(--wp--preset--color--navy);
	border-radius: var(--wp--custom--radius--full);
	background: transparent;
	color: var(--wp--preset--color--navy);
	font-family: var(--wp--preset--font-family--sans);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 700;
	cursor: pointer;
	transition: background-color 0.2s ease, color 0.2s ease;
}

.dicken-match-more__button:hover,
.dicken-match-more__button:focus-visible {
	background: var(--wp--preset--color--navy);
	color: var(--wp--preset--color--white);
}

.dicken-match-more__button[hidden] {
	display: none;
}

.dicken-match-row__series {
	display: block;
	margin-top: 2px;
	color: var(--wp--preset--color--muted);
	font-size: var(--wp--preset--font-size--micro);
	font-weight: 400;
}

/*
 * The standings panel is a third of the band, so the table is set tight: the
 * figures in tabular numerals so the columns line up digit under digit, and
 * the team name the only column allowed to take up the slack.
 */
.dicken-standings__table {
	width: 100%;
	margin-top: 10px;
	border-collapse: collapse;
	color: var(--wp--preset--color--navy);
	font-size: var(--wp--preset--font-size--label);
	font-variant-numeric: tabular-nums;
}

.dicken-standings__table th,
.dicken-standings__table td {
	padding: 8px 4px;
	border-bottom: 1px solid var(--wp--preset--color--line);
	text-align: center;
	white-space: nowrap;
}

.dicken-standings__table thead th {
	padding-top: 0;
	color: var(--wp--preset--color--muted);
	font-size: var(--wp--preset--font-size--micro);
	font-weight: 700;
	letter-spacing: 0.1em;
	text-transform: uppercase;
}

.dicken-standings__table abbr {
	text-decoration: none;
}

.dicken-standings__table .dicken-standings__pos {
	width: 1.5em;
	padding-left: 0;
	text-align: left;
}

.dicken-standings__table .dicken-standings__team {
	width: 100%;
	text-align: left;
	font-weight: 500;
}

/* The flex is on a span inside the cell: on the cell itself it would stop
   being a table cell and fall out of the column. */
.dicken-standings__club {
	display: inline-flex;
	align-items: center;
	gap: 8px;
}

.dicken-standings__club img {
	flex-shrink: 0;
	width: 20px;
	height: 20px;
	object-fit: contain;
}

.dicken-standings__table .dicken-standings__points {
	padding-right: 0;
	font-weight: 700;
}

/* Torneopal's own cut-off lines, between playoff places and the rest. */
.dicken-standings__table tr.is-divider > * {
	border-bottom: 2px solid var(--wp--preset--color--navy);
}

.dicken-standings__table tr.is-club > * {
	background: var(--wp--preset--color--white);
	font-weight: 700;
}

.dicken-standings__source {
	margin-top: 10px;
}

.dicken-calendar-box__buttons .wp-block-button,
.dicken-calendar-box__buttons .wp-block-button__link {
	width: 100%;
}

/*
 * overflow so the photo's top corners follow the card's radius, and a zeroed
 * featured-image margin to close the seam between photo and panel — the same
 * seam the homepage's split cards had.
 */
.dicken-junior-card {
	overflow: hidden;
}

.dicken-junior-card .wp-block-post-featured-image {
	margin-bottom: 0;
}

.dicken-junior-card__body p {
	margin: 0;
}

/*
 * The Tapahtuma board.
 *
 * The back link matches the article's own, and the aside's card and contact
 * card reuse the mist-panel shape the team page already established — what is
 * here is only what those do not cover.
 */
.dicken-event__back {
	display: inline-block;
	color: var(--wp--preset--color--muted);
	font-size: var(--wp--preset--font-size--label);
	font-weight: 600;
	letter-spacing: 0.04em;
	text-decoration: none;
}

.dicken-event__back:hover,
.dicken-event__back:focus-visible {
	color: var(--wp--preset--color--navy);
}

/* Inter, like every other card title on the site; theme.json hands a heading
   Raurus, and a 17px Raurus at 700 read as a different face from the facts
   under it. No rule of its own under it: the first fact's border-top already
   draws one there, and the two together were the doubled line the card had. */
.dicken-event-facts__title {
	margin: 0 0 6px;
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1.3;
}

/*
 * The event's Tiedot rows stack label over value, where the team page's facts
 * box sets the same class side by side — so the flex direction and the value's
 * alignment are both overridden here rather than in a second row component.
 */
/* Stacked rather than side by side — that is this card's own board — but on
   the same rule-above rhythm .dicken-fact sets, and with the label back to
   auto width because there is no second column for it to line one up with. */
.dicken-event-fact {
	display: block;
}

.dicken-event-fact .dicken-fact__label {
	flex: none;
}

/* Sits under the signup pill, not against it: the buttons group's own 8px gap
   reads as cramped once the pill's radius is in play. */
.dicken-event__deadline {
	margin: 0;
	padding-top: 10px;
}

.dicken-event-contact-card__avatar {
	flex-shrink: 0;
	width: 56px;
	height: 56px;
	border-radius: var(--wp--custom--radius--full);
	background: var(--wp--preset--color--line);
}

.dicken-event-contact-card__role {
	text-transform: uppercase;
	letter-spacing: 0.12em;
	font-weight: 700;
}

.dicken-event-contact-card__name,
.dicken-event-contact-card__reach {
	margin: 0;
}

/* The board's own bullets are red, and core's list markers inherit text colour. */
.dicken-event__content ul {
	padding-left: 1.1em;
}

.dicken-event__content ul li::marker {
	color: var(--wp--preset--color--red);
}

.dicken-event-gallery__grid.wp-block-gallery {
	gap: var(--wp--preset--spacing--20);
}

/*
 * A long page with a side rail — the Vanhemmalle board.
 *
 * The rail is generated from the page's own h2s (inc/page-nav.php); what is
 * here is the box they sit in and the current-section marker assets/page-nav.js
 * toggles.
 */
/* Two things at once. max-width alone would centre these: the constrained
   layout gives every child margin-left/right: auto, so a child narrower than
   its column sits in the middle rather than against the measure's left edge —
   hence the explicit margin-inline. And both selectors carry their section's
   class as well as their own, because core's own rule
   (.is-layout-constrained > :where(...)) ties with a single class on
   specificity — and it carries !important on both margins:

     .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull))
       { max-width: ...; margin-left: auto !important; margin-right: auto !important }

   so no selector, at any specificity, wins without !important of its own. This
   is the same shape as the header's colour swap: core sets !important, so
   overriding it needs !important, and the alternative is not overriding it. */
.dicken-page-hero .dicken-page-hero__lead {
	max-width: 780px;
}

/* The board's own measure — prose stops at 720px while headings, grids and
   venue lists run the full column. */
.dicken-page__content .dicken-page__prose {
	max-width: 720px;
}

.dicken-page__eyebrow {
	margin-bottom: 0;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	font-weight: 600;
}

/* Each value and venue sits under its own rule, which is what separates the
   pairs into a grid rather than a list. */
.dicken-page__pair {
	padding-top: 22px;
	border-top: 1px solid var(--wp--preset--color--line);
}

/* Sticky rather than fixed, so the rail scrolls with its own column and stops
   against the pinned header rather than the viewport top. The offset is the
   pinned header's own measured height plus a little air. */
/* The rail's column has to be as tall as the content beside it for sticky to
   have anywhere to travel. It is a top-aligned column — core's
   `.is-vertically-aligned-top { align-self: flex-start }` — so it was exactly
   as tall as the rail itself, 302px, and the rail scrolled away with the
   page. Stretched, it runs the full height of the section and the rail stays
   under the header to the end of it. */
.wp-block-columns > .wp-block-column.dicken-page-nav {
	align-self: stretch;
}

.dicken-page-nav__box {
	position: sticky;
	top: calc(var(--dicken-header-height-pinned) + 24px);
}

.dicken-page-nav__list {
	margin: 0;
	padding: 0;
	list-style: none;
}

.dicken-page-nav__link {
	display: block;
	padding: 10px 14px;
	border-left: 2px solid transparent;
	color: var(--wp--preset--color--muted);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 500;
	text-decoration: none;
	transition: color var(--wp--custom--motion--base) var(--wp--custom--motion--ease);
}

.dicken-page-nav__link:hover,
.dicken-page-nav__link:focus-visible {
	color: var(--wp--preset--color--navy);
}

/* The board marks the current section with a navy rule, a mist ground and
   weight — three signals rather than colour alone, because the rail's resting
   state is already a muted grey and a single step darker would not read. */
.dicken-page-nav__link.is-current {
	border-left-color: var(--wp--preset--color--navy);
	background: var(--wp--preset--color--mist);
	color: var(--wp--preset--color--navy);
	font-weight: 700;
}

/* Every rail link jumps to a heading that would otherwise land under the pinned
   header. scroll-margin-top is the whole fix, and it belongs on the target
   rather than in the script. */
.dicken-page__content :is(h2, h3) {
	scroll-margin-top: calc(var(--dicken-header-height-pinned) + 24px);
}

/* 56px between sections, the gap the board sets on the content column itself —
   expressed here as a top margin on each heading after the first, because the
   column is a core/post-content whose blockGap is a global. */
.dicken-page__content > h2:not(:first-child) {
	margin-top: 56px;
}

/* core/details is the board's FAQ row: a rule between each, and the marker
   swapped for the board's own +/- at the right-hand end. */
.dicken-page__content .wp-block-details {
	padding: 18px 0;
	border-bottom: 1px solid var(--wp--preset--color--line);
}

.dicken-page__content .wp-block-details summary {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	cursor: pointer;
	color: var(--wp--preset--color--navy);
	font-weight: 600;
	list-style: none;
}

.dicken-page__content .wp-block-details summary::-webkit-details-marker {
	display: none;
}

.dicken-page__content .wp-block-details summary::after {
	content: "+";
	flex-shrink: 0;
	color: var(--wp--preset--color--red);
	font-size: var(--wp--preset--font-size--large);
	font-weight: 400;
	line-height: 1;
}

.dicken-page__content .wp-block-details[open] summary::after {
	content: "\2013";
}

@media (max-width: 781px) {
	/* The rail becomes a list above the content rather than a column beside it,
	   and stops sticking — a sticky box in a stacked layout would trail the
	   reader down a page it is no longer beside. */
	.dicken-page-nav__box {
		position: static;
		top: auto;
	}
}

/*
 * The Meistä board: a page of full-bleed bands under a head with the Seura
 * sub-navigation.
 */
.dicken-page-subnav__list {
	display: flex;
	flex-wrap: wrap;
	gap: 32px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.dicken-page-subnav__link {
	display: inline-block;
	padding-bottom: 6px;
	border-bottom: 2px solid transparent;
	color: var(--wp--preset--color--muted);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	text-decoration: none;
}

.dicken-page-subnav__link:hover,
.dicken-page-subnav__link:focus-visible {
	color: var(--wp--preset--color--navy);
}

/* The board underlines the current page in the club red — the same accent the
   header's own hover rule uses on a light bar. */
.dicken-page-subnav__link.is-current {
	border-bottom-color: var(--wp--preset--color--red);
	color: var(--wp--preset--color--navy);
}

/* The Meistä hero photograph rounds to the card radius the rest of the site
   uses. The image block asks for it, but its saved markup — the seed writes the
   <img> itself — never carried the inline style core would have put there, so
   the radius only ever existed in the block's comment. */
.dicken-about-intro .wp-block-image img {
	border-radius: var(--wp--custom--radius--md);
}

/* A stat card's number and its label are one block each, so the card's own gap
   does the spacing; these only strip the margins core gives a paragraph. */
.dicken-stat-card p {
	margin: 0;
}

/* The split card is one box 440px tall with the photograph stretched down its
   left. The photograph carries no aspect ratio: one would size the image and
   then the column, so a 1/1 crop in a 42% column stood ~500px tall and pushed
   past the panel beside it. Letting the card state its own height and the image
   fill it is what keeps the two halves level, which is how the board draws it. */
.dicken-about-path {
	min-height: 440px;
	overflow: clip;
}

.dicken-about-path > .wp-block-column {
	align-self: stretch;
}

/* The photograph is taken out of flow so it cannot be what sizes the card:
   `height: 100%` alone still let a portrait image's intrinsic height through,
   and the 1053x1500 juniors photo stood the card 718px tall against a panel
   of text needing ~420 — on Aloita käsipallo and on Meistä, which share this
   card. Out of flow, the text panel sets the height, the 440px floor holds, and
   the photo covers whatever that comes to. */
.dicken-about-path > .wp-block-column:has(> .wp-block-image) {
	position: relative;
	min-height: 280px;
}

.dicken-about-path .wp-block-image {
	position: absolute;
	inset: 0;
	margin: 0;
}

.dicken-about-path .wp-block-image img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Each value sits under its own rule, as on the Vanhemmalle board — but this
   board's grid is a two-column flex wrap with a wider row gap, so the pair
   spacing is stated here rather than reused from .dicken-page__pair. */
/* The board's own 26px above each rule, and a 500px measure on the body so a
   short value does not run the full half-column. */
.dicken-about-value {
	padding-top: 26px;
	border-top: 1px solid var(--wp--preset--color--line);
}

.dicken-about-value__body {
	max-width: 500px;
}

.dicken-about-value p {
	margin: 0;
}

/* The organisation rows are core/details on a mist band, capped at the board's
   own 820px and centred under a centred heading. */
.dicken-about-org__rows {
	max-width: 820px;
	margin-inline: auto !important;
}

.dicken-about-org__rows .wp-block-details {
	padding: 18px 22px;
	border-radius: var(--wp--custom--radius--md);
	background: var(--wp--preset--color--white);
}

.dicken-about-org__rows .wp-block-details summary {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	cursor: pointer;
	color: var(--wp--preset--color--navy);
	font-weight: 600;
	list-style: none;
}

.dicken-about-org__rows .wp-block-details summary::-webkit-details-marker {
	display: none;
}

.dicken-about-org__rows .wp-block-details summary::after {
	content: "\25BC";
	flex-shrink: 0;
	color: var(--wp--preset--color--red);
	font-size: 10px;
	line-height: 1;
	transition: transform var(--wp--custom--motion--base) var(--wp--custom--motion--ease);
}

.dicken-about-org__rows .wp-block-details[open] summary::after {
	transform: rotate(180deg);
}

/*
 * The Historia and Yhteistyökumppanit boards, which share the Meistä board's
 * head and bands.
 */
/* margin-inline for the reason the Vanhemmalle lead needs it: core's
   constrained-layout rule centres any child narrower than its column, with
   !important on both margins. */
.dicken-seura__prose {
	max-width: 720px;
}

.dicken-seura__eyebrow {
	margin-bottom: 0;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	font-weight: 600;
}

/* The film the board draws over the introduction. A placeholder box, not an
   embed: nothing in the content model holds a video, and an empty embed block
   reads as broken where a mist box with a play button reads as not-yet-added. */
.dicken-history__film {
	display: flex;
	align-items: center;
	justify-content: center;
	height: 480px;
	border-radius: var(--wp--custom--radius--md);
	background: #E7EBF1;
}

.dicken-history__play {
	display: block;
	width: 64px;
	height: 64px;
	border-radius: var(--wp--custom--radius--full);
	background: var(--wp--preset--color--white);
	box-shadow: 0 2px 12px rgb(0 28 68 / 12%);
	position: relative;
}

/* A triangle from borders rather than a glyph or an SVG: it needs no font to be
   loaded and no file to be fetched, and it is the one shape borders draw well. */
.dicken-history__play::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-40%, -50%);
	border-style: solid;
	border-width: 9px 0 9px 15px;
	border-color: transparent transparent transparent var(--wp--preset--color--navy);
}

/*
 * The timeline. The rule down the middle is the body column's own left border,
 * and the dot is a pseudo-element sitting on it — so the line is exactly as tall
 * as the entries and needs no separate element to keep in step with them.
 */
.dicken-timeline__entry {
	align-items: flex-start;
}

.dicken-timeline__year {
	flex-shrink: 0;
	width: 184px;
	padding-right: 32px;
	margin: 0;
}

.dicken-timeline__body {
	flex: 1;
	position: relative;
	padding-left: 40px;
	padding-bottom: 52px;
	border-left: 2px solid var(--wp--preset--color--line);
}

.dicken-timeline__entry:last-child .dicken-timeline__body {
	padding-bottom: 0;
	/* The rule stops at the last entry rather than running past it into the
	   band's own padding. */
	border-left-color: transparent;
}

/* 18px including its ring, centred on the 2px rule. An absolute box's `left`
   is measured from the padding edge — the *inside* of the border — so the
   rule's centre is 1px left of that edge, and a 12px dot centred on it starts
   at -7px. It was -10, which measured from the border's outside edge instead
   and set every dot 3px left of the line. The 3px mist ring is what stops the
   rule reading straight through the dot; box-shadow rather than a border, so
   the ring grows outward and the dot itself stays 12px. */
.dicken-timeline__body::before {
	content: "";
	position: absolute;
	top: 12px;
	left: -7px;
	width: 12px;
	height: 12px;
	border-radius: var(--wp--custom--radius--full);
	background: var(--wp--preset--color--red);
	box-shadow: 0 0 0 3px var(--wp--preset--color--mist);
}

.dicken-timeline__body h3,
.dicken-timeline__body p {
	margin: 0;
}

.dicken-timeline__body p {
	max-width: 680px;
}

/* The gallery runs the full width of the page on this board, not the content
   column's, so the grid's own gap is the board's 8px rather than the theme's.

   Every tile is the same 236px box. core/gallery lays its figures out as a flex
   row and sizes each one from its own image, so a landscape photo in the top
   row came out over twice the height of the row under it and the grid read as
   two different galleries — the board draws eight identical tiles. The height
   is stated and the images cover it; the width stays the flex basis core's own
   columns-4 computes, so the count still follows the block's setting. */
.dicken-history__gallery.wp-block-gallery {
	gap: 8px;
}

.dicken-history__gallery.wp-block-gallery .wp-block-image {
	height: 236px;
}

.dicken-history__gallery.wp-block-gallery .wp-block-image img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/*
 * Partner logos. Each is a featured image in a Query Loop, so the cell sets the
 * height and the logo is contained inside it — a logo set to cover would crop,
 * and these are wordmarks.
 */
.dicken-partners__main .wp-block-post-featured-image,
.dicken-partners__all .wp-block-post-featured-image {
	display: flex;
	align-items: center;
	justify-content: center;
	margin: 0;
}

/* A fixed box with contain, not a max-height: these logos are supplied at
   whatever size their owner sends, so capping the height leaves a wordmark that
   arrived small rendering small next to one that arrived large. Giving every
   cell the same box and containing the artwork inside it is what makes the row
   read as a row. */
.dicken-partners__main img,
.dicken-partners__all img {
	width: 100%;
	height: 44px;
	object-fit: contain;
}

/* The board rules off the main partners from the full list below them. */
.dicken-partners__main {
	padding-bottom: var(--wp--preset--spacing--50);
	border-bottom: 1px solid var(--wp--preset--color--line);
}

.dicken-partners__all img {
	height: 32px;
}

/* A benefit card: a thumbnail band over a white body. The thumbnail is a
   placeholder for the same reason the film is — the benefits are editorial
   content nothing in the model holds yet. */
.dicken-benefit {
	overflow: clip;
}

.dicken-benefit__thumb {
	height: 150px;
	background: var(--wp--preset--color--line);
}

.dicken-benefit__body p,
.dicken-benefit__body h3 {
	margin: 0;
}

/* The pitch card is the Meistä board's split card with a navy panel instead of
   a mist one, so it takes the same height and photo rules. */
.dicken-partner-pitch {
	min-height: 440px;
	overflow: clip;
}

.dicken-partner-pitch > .wp-block-column {
	align-self: stretch;
}

.dicken-partner-pitch .wp-block-image,
.dicken-partner-pitch .wp-block-image img {
	height: 100%;
}

.dicken-partner-pitch .wp-block-image img {
	width: 100%;
	object-fit: cover;
}

/*
 * Any block given a reading measure narrower than the content column.
 *
 * Two rules are fighting over these. Core centres every child of a constrained
 * layout — `margin-left: auto !important` — so a 720px paragraph sat in the
 * middle of the column instead of under the heading above it. Setting
 * `margin-left: 0` fixed that inside a column and broke it inside a full-bleed
 * band: the band is wider than the 1200px column, so its heading is centred at
 * 1200 while a zero-margin paragraph went all the way out to the band's own
 * padding edge, sticking out to the left of everything else on the page.
 *
 * So the margin is not 0 and not auto — it is exactly the column's own offset.
 * When the parent is wider than the content column, that offset is half the
 * difference, which is precisely where the column's left edge is; when the
 * parent is narrower (inside a column, a grid cell, a timeline entry) the max()
 * floors it at 0 and the block simply starts where its parent does.
 *
 * !important because core's own declarations carry it. Grouped rather than
 * repeated so the next capped block joins the list instead of rediscovering all
 * of this.
 */
.dicken-page-hero__lead,
.dicken-archive__lead,
.dicken-page__prose,
.dicken-seura__prose,
.dicken-about-value__body,
.dicken-timeline__body p {
	margin-left: max(0px, calc((100% - var(--wp--style--global--content-size)) / 2)) !important;
	margin-right: auto !important;
}

/*
 * The Yhteystiedot board: the office card, the message form, and the managers'
 * table.
 */
.dicken-page-head__lead {
	max-width: 820px;
	margin-left: max(0px, calc((100% - var(--wp--style--global--content-size)) / 2)) !important;
	margin-right: auto !important;
}

/* The office rows are the event board's stacked label-over-value shape. Its
   rules live on .dicken-event-fact, so this reuses them by name rather than
   restating them — see .dicken-event-fact above. */
/* Stacked, like the Tapahtuma card and for the same reason. */
.dicken-contact-fact {
	display: block;
}

.dicken-contact-fact .dicken-fact__label {
	flex: none;
}

/* 280px against the board's 200: the board drew an empty slot, and a live map
   at 200 spends a quarter of its height on OpenStreetMap's attribution bar,
   which the licence does not let us hide. */
.dicken-contact-map {
	height: 280px;
	overflow: hidden;
	border-radius: var(--wp--custom--radius--md);
	background: var(--wp--preset--color--mist);
}

/* The embedded map fills the board's 200px slot; the box's own clipping is
   what rounds its corners, since an iframe's content ignores a radius set on
   the iframe itself in some engines. */
.dicken-contact-map iframe {
	display: block;
	width: 100%;
	height: 100%;
	border: 0;
}

/*
 * The form. Its fields are plain inputs rather than styled block controls,
 * because core has no form blocks this theme could restyle — so the whole
 * control surface is stated here.
 */
.dicken-contact-form__field {
	display: flex;
	flex-direction: column;
	gap: 6px;
	margin: 0 0 18px;
}

.dicken-contact-form__field label {
	color: var(--wp--preset--color--navy);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
}

/* box-sizing because width: 100% on a content-box control adds the padding and
   border on top of it: the 613px form made a 647px input, overflowing the card
   by exactly the 32px of padding plus 2px of border. Core happens to set
   border-box on select and button but not on input and textarea, which is why
   two of the four controls looked right and two did not. */
/* **One rule for every form on the site: a field is recognised by the contrast
   of its fill, never by an outline.** Which fill that is follows the card the
   field sits on rather than the field itself — mist in the Aloita board's
   white card, white in the Yhteystiedot board's mist one — so the card sets
   --dicken-field and the field reads it, instead of two near-identical blocks
   of control CSS. 8px is the board's own radius here, one step under the 10px
   the cards round to; there is no token for it because nothing else uses it.

   appearance: none removes the platform control's own border and ground, which
   would otherwise paint over all of this on a select. The chevron it also
   removes is drawn back below. */
.dicken-contact-form__wrap {
	--dicken-field: var(--wp--preset--color--white);
}

.dicken-contact-form__field :is(input, select, textarea) {
	box-sizing: border-box;
	appearance: none;
	width: 100%;
	padding: 13px 16px;
	border: 0;
	border-radius: 8px;
	background: var(--dicken-field, var(--wp--preset--color--mist));
	color: var(--wp--preset--color--navy);
	font-family: var(--wp--preset--font-family--sans);
	font-size: var(--wp--preset--font-size--small);
}

/* The board's own chevron, as a data: URI rather than a fetched file — it is
   one 12x8 path and a request for it would cost more than the bytes. The right
   padding clears it. currentColor cannot be used inside a data: URI, so the
   muted grey is written into the SVG; it is the one place in the theme where a
   palette value is duplicated, and it is unavoidable. */
.dicken-contact-form__field select {
	padding-right: 42px;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235A6675' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right 16px center;
	background-size: 12px 8px;
}

.dicken-contact-form__field textarea {
	resize: vertical;
	min-height: 120px;
}

.dicken-contact-form__field :is(input, select, textarea):focus-visible {
	outline: 2px solid var(--wp--preset--color--navy);
	outline-offset: 1px;
}

.dicken-contact-form__field ::placeholder {
	color: var(--wp--preset--color--muted);
	opacity: 1;
}

/* The honeypot. Off-screen rather than display:none or visibility:hidden — the
   crude bots this catches skip anything a browser would not render at all, and
   fill anything it would. aria-hidden and tabindex on the field itself keep it
   away from screen readers and the keyboard. */
.dicken-contact-form__trap {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* The submit is the theme's own button, restated because it is a <button> rather
   than core's wp-element-button anchor and inherits none of its styling. */
.dicken-contact-form__submit {
	width: 100%;
	padding: 15px 32px;
	border: 0;
	border-radius: var(--wp--custom--radius--full);
	background: var(--wp--preset--color--red);
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--sans);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 700;
	cursor: pointer;
}

.dicken-contact-form__submit:hover,
.dicken-contact-form__submit:focus-visible {
	background: var(--wp--preset--color--red-600);
}

.dicken-contact-form__notice {
	margin: 0 0 18px;
	padding: 12px 16px;
	border-radius: var(--wp--custom--radius--sm);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
}

.dicken-contact-form__notice.is-ok {
	background: var(--wp--preset--color--white);
	color: var(--wp--preset--color--navy);
}

.dicken-contact-form__notice.is-error {
	background: var(--wp--preset--color--white);
	color: var(--wp--preset--color--red-600);
}

/*
 * The managers' table. Core's table block draws borders on every cell; the board
 * rules the rows only, with an uppercase header.
 */
.dicken-contact-table table {
	border-collapse: collapse;
	width: 100%;
}

.dicken-contact-table :is(th, td) {
	padding: 16px 0;
	border: 0;
	border-bottom: 1px solid var(--wp--preset--color--line);
	text-align: left;
}

.dicken-contact-table th {
	color: var(--wp--preset--color--muted);
	font-size: var(--wp--preset--font-size--label);
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

.dicken-contact-table td {
	color: var(--wp--preset--color--navy);
	font-size: var(--wp--preset--font-size--small);
}

.dicken-contact-table td:first-child {
	font-weight: 700;
}

.dicken-contact-table a {
	color: var(--wp--preset--color--navy);
	text-decoration: none;
}

.dicken-contact-table a:hover,
.dicken-contact-table a:focus-visible {
	color: var(--wp--preset--color--red);
	text-decoration: underline;
}

/*
 * The Aloita käsipallo board. Most of it is components this stylesheet already
 * has — .dicken-stat-card for the navy reasons, .dicken-about-path for the split
 * card — so what is here is the hero, the FAQ rows and the enrolment form.
 */
.dicken-start-faq .wp-block-details {
	padding: 18px 0;
	border-bottom: 1px solid var(--wp--preset--color--line);
}

.dicken-start-faq .wp-block-details summary {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	cursor: pointer;
	color: var(--wp--preset--color--navy);
	font-weight: 600;
	list-style: none;
}

.dicken-start-faq .wp-block-details summary::-webkit-details-marker {
	display: none;
}

.dicken-start-faq .wp-block-details summary::after {
	content: "+";
	flex-shrink: 0;
	color: var(--wp--preset--color--red);
	font-size: var(--wp--preset--font-size--large);
	font-weight: 400;
	line-height: 1;
}

.dicken-start-faq .wp-block-details[open] summary::after {
	content: "\2013";
}

/* The Aloita hero, and the Tapahtuma hero below it, are the Juniorit hero's
   arrangement on a different board: a growing text column and the same fixed
   680px photograph running off the right edge, rounded on its left pair of
   corners only. The bleed itself is `dicken-bleed-right` on the band. */
/* The measure is 560; the auto end-margin is what stops the cap turning into
   slack. Where the row is wider than 560 + gap + 680 — the Tapahtuma head,
   whose gap is 40 against the Aloita hero's 80 — the capped column would
   otherwise leave the difference sitting after the photograph, and the bleed
   would stop 40px short of the frame edge. */
.dicken-start-hero__text {
	max-width: 560px;
}

/* Matched through the row, not on the class alone: core's own
   `:root :where(.is-layout-flex) > * { margin: 0 }` ties this on specificity
   and is printed after this file, so a single-class rule sets no margin at
   all. */
.wp-block-columns > .dicken-start-hero__text {
	margin-inline-end: auto;
}

.dicken-start-hero__image,
.dicken-event__hero-image {
	overflow: hidden;
	border-radius: var(--wp--custom--radius--md) 0 0 var(--wp--custom--radius--md);
}

.dicken-start-hero__image figure.wp-block-image,
.dicken-event__hero-image figure.wp-block-image {
	margin: 0;
}

.dicken-start-hero__image img,
.dicken-event__hero-image img {
	display: block;
	width: 100%;
	border-radius: 0;
}

/* The board caps the FAQ at 920px while the bands around it run the full
   column, so this is the one band with its own measure — and it is centred in
   that column rather than anchored to its left edge, which is the difference
   between a block of questions and a band that looks short. !important on both
   margins because that is how core writes the constrained layout's own
   centring. */
.dicken-start-faq,
.dicken-start-faq-band > .wp-block-heading {
	max-width: 920px;
	margin-left: auto !important;
	margin-right: auto !important;
}

/*
 * The enrolment form. Two fields to a row where they pair up — a name beside a
 * birth year, a guardian beside their email — because a column of eight
 * full-width inputs reads as longer than it is and this is the form standing
 * between somebody and joining.
 */
.dicken-signup-form__row {
	display: flex;
	gap: 20px;
}

.dicken-signup-form__row > .dicken-contact-form__field {
	flex: 1;
	min-width: 0;
}

.dicken-signup-form__consent {
	display: flex;
	align-items: flex-start;
	gap: 10px;
	margin: 0 0 20px;
	color: var(--wp--preset--color--muted);
	font-size: var(--wp--preset--font-size--small);
}

.dicken-signup-form__consent input {
	flex-shrink: 0;
	width: 18px;
	height: 18px;
	margin-top: 2px;
	accent-color: var(--wp--preset--color--red);
}

@media (max-width: 781px) {
	/* Paired fields stack rather than squeezing to half a phone's width. */
	.dicken-signup-form__row {
		display: block;
	}
}

/*
 * The mobile menu's own contents — everything inc/mobile-menu.php injects under
 * the four page links. Scoped to the open overlay so none of it can reach the
 * desktop header, which renders the same navigation block.
 */
/* Hidden by default, shown only once the overlay is open. core keeps the
   responsive container in the flow at desktop width — it is a modal only on
   mobile — so markup injected into it renders in the desktop bar unless its own
   visibility says otherwise. Scoping the styling to .is-menu-open was not
   enough: the children carried their own rules and drew themselves anyway. */
.dicken-menu__extras {
	display: none;
}

.dicken-header__nav .is-menu-open .dicken-menu__extras {
	display: flex;
	flex-direction: column;
	gap: 24px;
	padding-top: 28px;
}

.dicken-menu__eyebrow {
	margin: 0 0 10px;
	color: var(--wp--preset--color--sand);
	font-size: 12px;
	font-weight: 700;
	letter-spacing: 0.12em;
	line-height: 16px;
	text-transform: uppercase;
}

.dicken-menu__team-list {
	display: flex;
	flex-wrap: wrap;
	gap: 20px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.dicken-menu__team-list a {
	/* White at four fifths: present but a step below the four page links above,
	   which is the hierarchy the board draws between them. */
	color: rgb(255 255 255 / 80%);
	font-size: 17px;
	font-weight: 500;
	line-height: 22px;
	text-decoration: none;
}

.dicken-menu__team-list a:hover,
.dicken-menu__team-list a:focus-visible {
	color: var(--wp--preset--color--white);
}

.dicken-menu__cta {
	display: block;
	padding: 16px 32px;
	border-radius: var(--wp--custom--radius--full);
	background: var(--wp--preset--color--red);
	color: var(--wp--preset--color--white);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 700;
	text-align: center;
	text-decoration: none;
}

.dicken-menu__cta:hover,
.dicken-menu__cta:focus-visible {
	background: var(--wp--preset--color--red-600);
	color: var(--wp--preset--color--white);
}

.dicken-menu__utils {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 20px;
}

.dicken-menu__langs {
	display: flex;
	gap: 14px;
	margin: 0;
	color: rgb(255 255 255 / 45%);
	font-size: var(--wp--preset--font-size--label);
	font-weight: 600;
	letter-spacing: 0.08em;
}

.dicken-menu__langs .is-current {
	color: var(--wp--preset--color--white);
}

/*
 * The crest in the menu's top-left, and the shape behind everything.
 *
 * Both are pseudo-elements on core's own dialog rather than markup, because the
 * dialog is the one box that exists only while the menu is open — so neither can
 * leak into the desktop header, and neither adds a node for a screen reader to
 * announce. The shape is the footer's own, reused: it is the same family of
 * marks the board draws here, and a second SVG would be a second thing to keep
 * in step with the brand.
 */
.dicken-header__nav .is-menu-open .wp-block-navigation__responsive-dialog {
	position: relative;
	overflow: hidden;
	padding-top: 76px;
}

.dicken-header__nav .is-menu-open .wp-block-navigation__responsive-dialog::before {
	content: "";
	position: absolute;
	top: 12px;
	left: 20px;
	width: 52px;
	height: 52px;
	background-image: url("assets/images/crest.svg");
	background-size: contain;
	background-repeat: no-repeat;
}

/* The shape sits on the dialog rather than the container, and above the navy
   rather than behind it. z-index: -1 was the whole bug: the navy is the
   container's background, not the dialog's, so a negative index painted the
   shape behind that fill and it vanished. It is a positioned pseudo-element at
   z-index 0 now, which paints above the container's background — and the
   dialog's own children are lifted to 1 so the links stay above the shape.
   overflow: hidden on the dialog is what lets it hang off the left edge without
   the container growing a scrollbar to reach it.

   The artwork is the board's own, exported from the design file rather than
   borrowed from the footer: they are the same family of marks but not the same
   shape, and the real one fills with navy-700 so it needs no opacity to sit
   back into the ground. */
.dicken-header__nav .is-menu-open .wp-block-navigation__responsive-dialog::after {
	content: "";
	position: absolute;
	left: -70px;
	bottom: -40px;
	z-index: 0;
	width: 470px;
	height: 336px;
	background-image: url("assets/images/menu-shape.svg");
	background-size: contain;
	background-repeat: no-repeat;
	/* No opacity: the artwork fills with navy-700, the palette's own lighter
	   navy, so it already reads as a shade of the ground rather than a mark on
	   it. Fading it as well would only make it muddier than drawn. */
	pointer-events: none;
}

/* The content is lifted above the shape, and only the content: the same rule
   applied to every child of the dialog also caught core's close button, whose
   absolute positioning is what puts it in the top-right corner. Turning that
   relative dropped the X out of the corner and into the flow, where it took 60px
   of height above the first link — one rule, three symptoms. */
.dicken-header__nav .is-menu-open .wp-block-navigation__responsive-container-content {
	position: relative;
	z-index: 1;
}

/* The close button sits in the same 76px bar as the crest, and above the shape.
   position is restated because core sets it and the rule above must not be the
   thing that decides it. */
.dicken-header__nav .is-menu-open .wp-block-navigation__responsive-container-close {
	position: absolute;
	top: 26px;
	right: 20px;
	z-index: 2;
}

/* The overlay drops the site's own root padding. That padding is right for a
   page's content and wrong for a full-screen menu: it inset the dialog by 32px
   at this width, which stopped the shape reaching either edge and pushed the
   links to 52px from the left where the board puts them at 20px. The 20px is
   the content's own, so the dialog stays full width and only the text is
   inset. */
.dicken-header__nav .wp-block-navigation__responsive-container.is-menu-open {
	padding-inline: 0;
}

/*
 * The mobile home board's own measurements.
 *
 * Grouped here rather than folded into each component's own rules, because
 * these are one decision — the design is drawn at 390px and everything in it
 * sits in a 350px column — and reading them together is what makes the 20px
 * obvious as the shared figure rather than five coincidences.
 */
@media (max-width: 781px) {
	/* 20px a side, not the 32.5px the root's clamp gives at this width. The
	   design puts every band's content in a 350px column inside a 390px frame,
	   and one override here moves every section that uses global padding
	   rather than each of them separately. */
	body {
		--wp--style--root--padding-right: 20px;
		--wp--style--root--padding-left: 20px;
	}

	/* The section rhythm collapses with the viewport. These presets are the
	   vertical padding of nearly every band on the site, so redefining them
	   here is what tightens the whole page at once — the board's intro band is
	   48px top and bottom where the desktop one is 128px, and every band below
	   it follows the same proportion. */
	:root {
		--wp--preset--spacing--70: 2.5rem;
		--wp--preset--spacing--75: 3rem;
		--wp--preset--spacing--80: 3rem;
		--wp--preset--spacing--85: 3rem;
	}

	/* The screen's height less the navy team strip above it, which is in flow
	   on a phone rather than laid over the photo — so the hero ends where the
	   screen does, the same as on the desktop. This used to be a fixed 600px, on
	   the argument that a hero filling the phone hides that the page goes on;
	   the client preferred the full screen. 560px is the floor below which the
	   slogan and the shapes collide.

	   The top scrim is 160px here against the desktop's 240 — it exists to
	   carry the navigation's white type over the photograph, and the mobile bar
	   is barely half the height of the desktop one. */
	.dicken-hero {
		min-height: max(560px, calc(100svh - var(--dicken-header-utility-height)));
	}

	/* The cut-out's overlay with it, or her head is shaded by the 240px scrim
	   while the photo round it has this one — measured, a visible band. */
	.dicken-hero::before,
	.dicken-hero__media--front .dicken-hero__photo::after {
		background-size: 100% 160px;
	}

	/* The team bar keeps its three links and nothing else, which is what the
	   board draws: a navy strip of Naiset / Miehet / Juniorit and no more. The
	   socials and the language pair have two homes on a phone already — the
	   overlay menu and the footer's own utility row — and a third copy of both
	   crowds a 350px column for nothing. */
	/* Two classes deep, and that is load-bearing: core's own
	   `.is-layout-flex{display:flex}` is on this element too and its stylesheet
	   is printed after this one, so a single-class rule ties on specificity and
	   loses on order — the row stayed visible with `display: none` sitting
	   right there in the cascade. */
	.dicken-header__utility .dicken-header__utility-end {
		display: none;
	}

	/* The board floats the navigation over the hero photograph on the phone,
	   the same as on the desktop — but from under the team bar rather than from
	   the very top of the frame, so the navy strip stays and only the 76px
	   navigation row overlays the photo. The negative margin is the bar's own
	   height, which is the header minus that strip.

	   Scoped to the front page, like its desktop counterpart: everywhere else
	   the bar sits on the page's own white and keeps its ground. The overlay
	   menu core/navigation opens is a fixed, full-screen dialog with its own
	   navy, so it does not need a solid bar behind it — which was the reason
	   this rule used to stop at 782px. */
	body.home .wp-site-blocks > header.wp-block-template-part {
		margin-bottom: calc(var(--dicken-header-utility-height) - var(--dicken-header-height));
	}

	body.home .dicken-header__bar {
		background-color: transparent;
	}

	html.dicken-header-pinned body.home .dicken-header__bar {
		background-color: var(--wp--preset--color--navy);
	}

	/* Three bars of equal length, 24x2 with 5px between them. core draws two
	   16px-wide rects in an SVG, which is a different mark. The SVG goes and
	   the button draws the glyph itself: its own background is the middle bar,
	   the two pseudo-elements are the outer pair, and 2 + 5 + 2 + 5 + 2 is the
	   16px box they sit in. */
	.dicken-header__nav .wp-block-navigation__responsive-container-open svg {
		display: none;
	}

	.dicken-header__nav .wp-block-navigation__responsive-container-open {
		position: relative;
		width: 24px;
		height: 16px;
		padding: 0;
		background: linear-gradient(currentColor 0 0) 0 50% / 24px 2px no-repeat;
	}

	.dicken-header__nav .wp-block-navigation__responsive-container-open::before,
	.dicken-header__nav .wp-block-navigation__responsive-container-open::after {
		content: "";
		position: absolute;
		left: 0;
		width: 24px;
		height: 2px;
		background: currentColor;
	}

	.dicken-header__nav .wp-block-navigation__responsive-container-open::before {
		top: 0;
	}

	.dicken-header__nav .wp-block-navigation__responsive-container-open::after {
		bottom: 0;
	}

	/* Two lines, not one. The board breaks the slogan after "liten", and the
	   only thing that puts the break there is the measure: 190px at 54px is
	   wide enough for "Från liten" and too narrow for "Från liten till" —
	   180px breaks it in the wrong place, after "Från". */
	.dicken-hero__content .wp-block-heading {
		max-width: 190px;
		/* !important because the size comes from theme.json's `hero` preset,
		   and every preset class WordPress generates carries its own
		   !important. There is no specificity that beats it. */
		font-size: 54px !important;
		line-height: 1.04;
	}

	/* The shapes anchor to the hero's bottom rather than a fixed offset from
	   its top, so they stay welded to the lower edge whatever the hero's height
	   turns out to be — and they are drawn larger than the viewport (110%,
	   starting 5% off the left) so the artwork bleeds past both edges instead
	   of sitting in the frame as a picture of itself. The overflow on .dicken-hero
	   crops it. */
	/* The board's own mobile composition, measured: a 470x336 box at top 340,
	   left -40, with the artwork contained inside it and anchored to the box's
	   top edge. Held by its bottom rather than that top, now that the hero is
	   the screen's height: -76px is 340 + 336 against the board's 600px frame,
	   so the band keeps the same overhang whatever the phone. Centred with `left: 50%` and a half-width translate rather than
	   written as `left: -40px`, because at the 390px frame the board is drawn
	   at those are the same number — (390 - 470) / 2 is exactly -40 — and the
	   centred form keeps the composition centred on a wider phone instead of
	   sliding it off to one side.

	   It bleeds past both edges and past the hero's bottom; .dicken-hero's own
	   overflow is what crops all three.

	   The artwork is the design's mobile one, not the desktop band shrunk:
	   its own 532x380 viewBox is the same 1.4 ratio as the board's 470x336, so
	   `contain` inside that box draws it at exactly the drawn size. It fills
	   with the hero's navy, so it reads as shapes cut out of the photograph
	   rather than a graphic laid over it. */
	.dicken-hero::after,
	.dicken-hero__shapes {
		top: auto;
		bottom: -76px;
		left: 50%;
		right: auto;
		transform: translateX(-50%);
		width: 470px;
		height: 336px;
	}

	.dicken-hero::after {
		background-image: url("assets/images/hero-shapes-mobile.svg");
		background-size: contain;
		background-position: 50% 0%;
	}

	/* The phone's own artwork, at the box's size: its viewBox is the box's
	   1.4 ratio, so full width is the `contain` above. */
	.dicken-hero__shapes-wide {
		display: none;
	}

	.dicken-hero__shapes .dicken-hero__shapes-narrow {
		display: block;
		left: 0;
		width: 100%;
	}

	/* No bleeds on the phone. A band that runs off one edge and stops flush
	   with the other needs a content column wide enough for the difference to
	   read as deliberate; in a 350px column it reads as a mistake. */
	.dicken-bleed-left {
		padding-left: var(--wp--style--root--padding-left);
	}

	.dicken-bleed-right {
		padding-right: var(--wp--style--root--padding-right);
	}

	/* The Juniorit hero stacks: the text, then the photograph under it at the
	   column's width. It had no phone rule at all, so its nowrap row squeezed
	   the heading and the pill into a 48px column beside a 680px photo. With
	   the bleed gone (above) the photo rounds all four corners. */
	.dicken-junior-hero__row.is-layout-flex {
		flex-direction: column;
		align-items: stretch;
		gap: var(--wp--preset--spacing--50);
	}

	.dicken-junior-hero__text,
	.dicken-junior-hero__image {
		flex: none;
		max-width: none;
	}

	.dicken-junior-hero__image {
		border-radius: var(--wp--custom--radius--md);
	}

	.dicken-junior-hero__image img {
		height: 240px;
	}

	/* …and the photo goes back to a share of the card, since the card is no
	   longer 1320px wide for the board's 624 to be a share of. */
	.dicken-newsletter__image {
		flex-basis: 42% !important;
	}

	/* Every corner, not just the top two. Stacked, the card's photo is its top
	   edge and its body its bottom, so a radius on the group alone leaves the
	   image's own square corners showing through — overflow is what clips them
	   back to the card's shape. */
	.dicken-news__featured,
	.dicken-news__card {
		border-radius: var(--wp--custom--radius--md);
		overflow: hidden;
	}

	/* The field and its button stack and fill the width. Side by side in a
	   350px column the field had room for about a word, and the design draws
	   them as two full-width rows. */
	.dicken-newsletter__row {
		flex-direction: column;
		align-items: stretch;
		gap: 10px;
		max-width: none;
	}

	/* box-sizing as well as width: the field is a content-box control with 24px
	   of padding and a border, so width: 100% made it 50px wider than the row
	   it sits in. Side by side that never showed — flex had it beaten down to
	   whatever was left — and it only surfaced once the row stacked. The same
	   trap the contact form's controls hit. */
	.dicken-newsletter__row .dicken-newsletter__field,
	.dicken-newsletter__row .dicken-newsletter__submit {
		box-sizing: border-box;
		width: 100%;
	}
}

/*
 * The mobile team board — Dicken – Joukkue – Miehet – Mobile.
 *
 * The header is the part that differs from the home page rather than merely
 * shrinking: on a subpage the design draws a white bar with the crest, the
 * ticket button and the toggle, where the home page's bar sits transparent over
 * the hero photograph. Everything else here is the desktop layout collapsing to
 * one column's worth of room.
 */
@media (max-width: 781px) {
	/* 76px, not 134: a 52px crest in 12px of padding, which is the board's own
	   arithmetic. The desktop's 98px crest is most of the difference. */
	.dicken-header__bar {
		padding-block: 12px;
	}

	/* The header's box is pinned to this height (see the pinned rules above,
	   where a fixed box is what stops the scroll-anchoring oscillation). With a
	   76px bar instead of 134 the old 174 left 58px of empty white under the
	   crest, so the constant has to follow the bar down: 40 of utility plus 76
	   of bar. Everything measured from it — the sticky offset, the front page's
	   hero padding — follows in one move. */
	:root {
		--dicken-header-height: 116px;
	}

	/* Crest, then the shop, then the toggle: the board groups the last two on
	   the right with the toggle outermost, where a thumb reaches it. Without
	   this the toggle sits between the crest and the button, because that is
	   the order the blocks are authored in for the desktop bar. */
	/* Both selected as direct children of the bar's own group, not as
	   descendants. core puts the navigation block's className on its inner
	   <ul> as well as on the <nav>, so a descendant rule reordered the open
	   menu's link list too — which put the teams, the ticket button and the
	   socials above the four pages instead of below them. */
	.dicken-header__bar > .wp-block-group > .dicken-header__cta {
		order: 1;
		/* auto margin rather than a gap: the bar justifies space-between for its
		   desktop three, which spread the button into the middle once it was no
		   longer hidden. This collapses the space onto one side so the crest
		   keeps the left and the shop and the toggle travel together. */
		margin-left: auto;
	}

	.dicken-header__bar > .wp-block-group > .dicken-header__nav {
		order: 2;
	}

	.dicken-header__bar .wp-block-site-logo img {
		width: 52px;
	}

	/* White at rest on a subpage, navy once pinned — the same swap the desktop
	   bar makes, and for the same reason: at rest it sits on the page's own
	   white, pinned it sits over content. The front page keeps its navy here,
	   because its bar is over a photograph rather than over white. */
	/* Background only, deliberately: no colour swap to go with it.
	   
	   The desktop bar swaps its ink to navy here as well, because it holds
	   visible navigation links. The mobile bar holds none — a crest, a red
	   button with its own white type, and the toggle — so there is nothing to
	   recolour. And the overlay's markup is a descendant of this same bar, so a
	   colour on it inherits straight into the open menu and paints every link
	   navy on a navy screen. That is exactly what it did: the menu rendered with
	   its links present, sized and "visible", and invisible. */
	html:not(.dicken-header-pinned) body:not(.home) .dicken-header__bar {
		background-color: var(--wp--preset--color--white);
	}

	/* The toggle is the one thing in the bar that has to follow the swap, and it
	   gets its own rule rather than inheriting for the reason above. */
	html:not(.dicken-header-pinned) body:not(.home) .dicken-header__nav .wp-block-navigation__responsive-container-open {
		color: var(--wp--preset--color--navy);
	}

	/* 340px, not 560: the hero is a title over a photograph, and on a phone the
	   photograph earns less than two thirds of the first screen. */
	/* !important because the cover block writes its 560px as an inline style —
	   a block attribute has no vocabulary for a media query, so it is the same
	   value at every width and no selector outranks it. */
	.dicken-team-hero {
		min-height: 340px !important;
	}

	.dicken-team-hero .wp-block-post-title {
		font-size: 48px;
	}

	/* One row that scrolls, rather than three rows that wrap. A tab bar wrapping
	   onto its own third line stops reading as a bar at all — and the sections
	   it lists grow with the page, so wrapping gets worse rather than better.
	   The negative margins let it scroll edge to edge while its first chip still
	   lines up with the text above it. */
	.dicken-team-nav__list {
		flex-wrap: nowrap;
		overflow-x: auto;
		margin-inline: -20px;
		padding-inline: 20px;
		scrollbar-width: none;
	}

	.dicken-team-nav__list::-webkit-scrollbar {
		display: none;
	}

	.dicken-team-nav__item {
		flex-shrink: 0;
	}

	/*
	 * The phone's footer, which the board draws as its own component rather
	 * than as the desktop one narrowed. Same markup, four differences:
	 * the brand reads across instead of down, each link group is a wrapping
	 * row instead of a column, the groups are separated by hairlines, and the
	 * socials travel to their own row at the bottom beside the language pair.
	 *
	 * The desktop footer stacked to 860px on a phone against the board's ~557.
	 */
	/* The columns stack, and each link group is separated from the next by the
	   board's own hairline rather than by the 40px the desktop row puts
	   between its columns. */
	.dicken-footer__row.wp-block-columns {
		gap: 0;
	}

	.dicken-footer__row > .wp-block-column {
		padding-block: 22px;
		border-top: 1px solid rgb(255 255 255 / 10%);
	}

	/* Matched as a child of the row, not on its own class: the rule above that
	   gives every column its 22px and its hairline is a child selector, so a
	   single-class rule here would lose to it and the brand would keep both. */
	.dicken-footer__row > .dicken-footer__brand {
		display: flex;
		align-items: center;
		gap: 16px;
		padding-top: 0;
		border-top: 0;
	}

	.dicken-footer__brand .wp-block-site-logo img {
		width: 60px;
	}

	/* The socials leave the brand block for the utility row at the foot. Two
	   classes deep for the same reason the header's utility row is: core's
	   `.is-layout-flex{display:flex}` is on this list too, and its stylesheet
	   is printed after this one. */
	.dicken-footer__brand .dicken-footer__social {
		display: none;
	}

	.dicken-footer .dicken-footer__utils {
		display: flex;
		padding-block: 22px;
		border-top: 1px solid rgb(255 255 255 / 10%);
	}

	/* The group heads are the design's 12px small caps in sand, a step quieter
	   than the 15px white they are on the desktop — on a phone they label a
	   single wrapped line rather than heading a column. */
	.dicken-footer__row .wp-block-heading {
		margin-bottom: 10px;
		/* !important on both: the size and the colour each come from a preset
		   class the part carries, and WordPress writes every generated preset
		   class with its own !important. */
		color: var(--wp--preset--color--sand) !important;
		font-size: var(--wp--preset--font-size--micro) !important;
	}

	/* Naiset Miehet Juniorit on one line, not three. The links are short and a
	   phone's footer is the last thing on a very long page. */
	.dicken-footer__row .wp-block-navigation__container {
		flex-direction: row;
		flex-wrap: wrap;
		gap: 8px 20px;
	}

	/* Four hairlines, and only four: under the brand, between each of the three
	   link groups, and above the utility row. The copyright line follows the
	   utility row directly, so the padding the desktop gives it (an inline
	   style, hence !important) is taken off here. */
	.dicken-footer__legal {
		padding-top: 0 !important;
	}

	/* The desktop's column alignment for the legal pair (below) means nothing
	   once the columns have stacked. */
	.dicken-footer__legal-links {
		width: auto;
	}

	/* The board's own footer artwork, and a different one: the tonal drumso
	   band at #0A2A5C, laid along the bottom edge and bleeding off both sides
	   and the foot. It is meant to be barely visible — one step off the navy —
	   where the desktop's shape hangs off the top right corner at full
	   contrast. */
	.dicken-footer {
		background-image: url("assets/images/footer-shape-mobile.svg");
		background-position: 50% 100%;
		background-size: 702px auto;
	}

	.dicken-team-nav__chip {
		font-size: 14px;
	}

	/* Two to a row. Five columns in a 350px column gives each player 60px, which
	   is narrower than their own squad number. */
	.dicken-team-roster .wp-block-post-template {
		grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
	}

	/* The photo takes the card's own proportion rather than the desktop's fixed
	   260px, which on a 167px card is half again as tall as it is wide. The
	   board draws it at roughly 166 by 180. */
	.dicken-player-card__photo {
		height: auto;
		aspect-ratio: 166 / 180;
	}

	/* The fixture row stacks. Its desktop layout is four fixed lanes across a
	   1200px column; at 350px the opponent's name had 22px to live in and set
	   itself one character per line, 256px tall. Stacked, each part gets the
	   full width and the row is the board's own 106px. */
	/* .is-layout-flex in the selector, not for style but for weight: core emits
	   `body .is-layout-flex{display:flex}` for the block's own layout support,
	   which outranks a single class. Naming the layout class as well ties on
	   specificity and wins on order. Without it the row kept its four lanes and
	   only the padding changed. */
	/* The rows stack on the phone, so there are no lanes left for the column
	   heads to name. .is-layout-flex in the selector for the reason given on
	   the row below: a lone class loses to core's `body .is-layout-flex`, and
	   the heads were showing on the phone as one letter per line. */
	.dicken-match-head.is-layout-flex {
		display: none;
	}

	.dicken-match-row.is-layout-flex {
		display: block;
		padding-block: 16px;
		border-top: 1px solid var(--wp--preset--color--line);
		border-bottom: 0;
	}

	.dicken-match-row > p {
		width: auto;
		margin: 0 0 6px;
		text-align: left;
	}

	.dicken-match-row > p:last-child {
		margin-bottom: 0;
	}

	/* The date and the result read as the row's two facts, so they keep their
	   weight; the fixture is the row's headline. */
	.dicken-match-row__fixture {
		font-size: var(--wp--preset--font-size--medium);
	}

	.dicken-match-filters {
		flex-wrap: nowrap;
		overflow-x: auto;
		scrollbar-width: none;
	}

	.dicken-match-filters::-webkit-scrollbar {
		display: none;
	}

	.dicken-match-filter {
		flex-shrink: 0;
	}
}
