/* theme.json can't express :focus-visible, open-state attribute selectors, or current-menu-item — these three rules cover what's left. */

/*
 * Anchor jumps land below the sticky header, not under it. --header-height is
 * set from the header's real measured height (assets/js/scroll-offset.js) --
 * its nav row wraps a different number of times at different widths, so no
 * single static number is correct everywhere; 220px is a fallback for the
 * brief moment before that script runs, sized to the tallest wrapped state
 * seen across breakpoints.
 */
html {
	scroll-padding-top: var(--header-height, 220px);
}

:focus-visible {
	outline: 2px solid var(--wp--preset--color--ink);
	outline-offset: 2px;

	.is-style-dark-section &,
	.site-footer & {
		outline-color: var(--wp--preset--color--light);
	}
}

/*
 * Dark footer (parts/footer.html). Links are light at rest, same as the rest
 * of the site's hover color (#aa1818, --hover) on hover -- the same rule
 * every other link on the site follows (theme.json's root link style).
 * Body links (directions, phone, email) follow styles/blocks/dark-section.json:
 * underlined at rest, underline dropped on hover. Footer nav links keep the
 * nav convention (no underline at rest, underline on hover); the general
 * nav-link rules further down are !important, so both states need
 * !important plus one more class to win.
 */
.site-footer a {
	color: var(--wp--preset--color--light);
	text-decoration: underline;
}

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

.site-footer .wp-block-navigation-item__content.wp-block-navigation-item__content {
	color: var(--wp--preset--color--light) !important;
}

.site-footer .wp-block-navigation-item__content.wp-block-navigation-item__content:hover {
	color: var(--wp--preset--color--hover) !important;
}

/*
 * Top edge of the footer, so it reads as its own block when a dark section
 * (is-style-dark-section, e.g. Home's showroom section) sits directly above it.
 */
.site-footer {
	border-top: 1px solid rgba(247, 245, 240, 0.15);
}

/*
 * Footer bottom row: Privacy policy / Cookie policy (a navigation block) plus
 * the "Cookie settings" button (parts/footer.html, a Buttons block since the
 * buttons-as-blocks change). Complianz's own script only reopens the consent
 * banner for a click on a literal `button.cmplz-manage-consent` element
 * (cmplz_add_event in complianz.js uses `e.target.closest(selector)`, and a
 * Gutenberg Button block always renders an `<a>`, never a `<button>`, so that
 * selector can never match it) -- assets/js/scroll-to-top.js's sibling
 * handler calls `window.cmplz_set_banner_status('show')` directly instead,
 * the same function Complianz's own handler calls. The wrapping
 * `.wp-block-buttons` is set to `display: contents` so the button sits
 * directly in `.footer-legal`'s flex row, exactly as the plain `<button>`
 * did before. It's styled here to match the nav links beside it: small,
 * bold, light, underline on hover only. The row's gap matches the nav's own
 * 1.5rem column gap, so the three items read as one evenly spaced row.
 */
.footer-legal {
	gap: 0.5rem 1.5rem;
}

.footer-legal .wp-block-buttons {
	display: contents;
}

.site-footer .footer-cookie-settings {
	margin: 0;
}

.site-footer .footer-cookie-settings .wp-block-button__link {
	padding: 0;
	border: 0;
	border-radius: 0;
	background: none;
	cursor: pointer;
	font-family: inherit;
	font-size: var(--wp--preset--font-size--small);
	font-weight: 700;
	line-height: inherit;
	color: var(--wp--preset--color--light);
	text-decoration: none;
}

.site-footer .footer-cookie-settings .wp-block-button__link:hover {
	color: var(--wp--preset--color--hover);
	text-decoration: underline;
}

/*
 * Footer phone/email icons, and the Instagram/Facebook icons below: deep red
 * (the hover token) in every state, independent of the link text color --
 * the same color as every other icon on the site (header phone icon,
 * scroll-to-top, cookie consent). Their SVGs use stroke="currentColor", so
 * setting color on the svg itself is enough.
 */
.site-footer a svg {
	color: var(--wp--preset--color--hover);
}

/* Footer Instagram/Facebook icons: side by side with a clear gap. */
.footer-social {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	margin-top: 0.75rem;
}

.footer-social svg {
	display: block;
}

/*
 * Footer divider: a faint bg-tinted rule instead of the light hairline token.
 * Background is cleared because theme.json's core/separator style sets both
 * a background and a border color -- with a translucent color the two layers
 * stack and the line renders at roughly double the intended opacity.
 */
.site-footer .wp-block-separator {
	color: rgba(247, 245, 240, 0.15);
	background-color: transparent;
	border-color: rgba(247, 245, 240, 0.15);
}

/*
 * Consecutive same-background sections: the second drops its top padding, so
 * the gap between them is one section of spacing, not two. Applies to
 * top-level blocks of any page's content (patterns render in place, so they
 * count too).
 *
 * A "section" here is a block with the section spacing token as its padding.
 * Matching on that inline style keeps the rule off things that aren't padded
 * sections -- the hero slider, full-bleed photos, the map band, separators --
 * so a section after a photo or a divider line keeps its top padding.
 * "Same background" is either both on the page background (no background
 * class, not the dark style) or both dark. !important is needed to beat the
 * padding set inline by the block markup.
 */
.wp-block-post-content > [style*="padding-bottom:var(--wp--preset--spacing--section)"]:not(.has-background):not(.is-style-dark-section)
	+ [style*="padding-top:var(--wp--preset--spacing--section)"]:not(.has-background):not(.is-style-dark-section),
.wp-block-post-content > .is-style-dark-section[style*="padding-bottom:var(--wp--preset--spacing--section)"]
	+ .is-style-dark-section[style*="padding-top:var(--wp--preset--spacing--section)"] {
	padding-top: 0 !important;
}

/*
 * Media & Text with the image on the right (media-text-right pattern and the
 * same block in page content): core pads the text column 8% on both sides,
 * which pushes its left edge ~50px in from the content edge every other
 * section's heading starts on. Dropping that left padding lines the text up
 * with the rest of the page; the right padding stays as the gap before the
 * image. That's only while text and image sit side by side; image-left
 * sections keep core's padding there, since their text starts after the image.
 */
@media (min-width: 601px) {
	.wp-block-media-text.has-media-on-the-right > .wp-block-media-text__content {
		padding-left: 0;
	}
}

/*
 * At 600px and below core stacks every media-text block (image on top, text
 * below) and still pads the text 8% on both sides, so the text sat ~26px in
 * from the content edge. Stacked, there's no image beside it to keep clear
 * of, so the text runs edge to edge like any other section -- image left or
 * right, light or dark (inside a dark section the content edge is the dark
 * group's own padding, which lines up the same way).
 */
@media (max-width: 600px) {
	.wp-block-media-text.is-stacked-on-mobile > .wp-block-media-text__content {
		padding-left: 0;
		padding-right: 0;
	}
}

/*
 * Media & Text images: 4:3, cropped to fill. This used to be an inline style
 * on each image, which the block editor doesn't write -- so those blocks
 * showed as invalid ("unexpected content") and the image couldn't be
 * replaced. As a theme rule every Media & Text block gets the same crop and
 * its markup is what the editor itself saves.
 */
.wp-block-media-text > .wp-block-media-text__media img {
	width: 100%;
	height: auto;
	aspect-ratio: 4 / 3;
	object-fit: cover;
}

/*
 * Links inside running text (functions.php adds .is-inline-link to links in
 * a <p>/<li> that has other text around them) keep their underline at rest;
 * the theme.json default is hover-red with no underline until hover.
 * a.is-inline-link outweighs the zero-specificity global link rule, but it
 * would also outweigh dark-section.json's own link rule (also zero
 * specificity), which drops the underline on hover -- so that's restored
 * explicitly. The footer isn't post content, so it never gets the class.
 */
a.is-inline-link {
	text-decoration: underline;
}

.is-style-dark-section a.is-inline-link:hover {
	text-decoration: none;
}

/*
 * Selected header nav item: bold + dark red, always (not just on hover).
 * Scoped to header specifically — the footer repeats some of the same
 * links (Sidor nav) and would otherwise also pick up "current" styling
 * there, which isn't wanted. Needs !important for the same specificity-tie
 * reason as the general nav-link rule below (identical property, so
 * whichever isn't !important loses regardless of source order).
 */
header .wp-block-navigation-item.current-menu-item .wp-block-navigation-item__content {
	color: var(--wp--preset--color--hover) !important;
	font-weight: 700;
}

/*
 * "Boka måttagning" / "Book a measurement" nav CTA (parts/header.html,
 * header-en.html). core/navigation's custom renderer doesn't reliably apply
 * per-link block-level color/typography style attributes (same renderer quirk
 * as the blockGap/orientation issues elsewhere in this theme), so this is a
 * plain class instead.
 *
 * Outline button: transparent, 1.5px brand-red border and text. Hover and
 * keyboard focus fill it red with white text; so does the current-page state
 * (the booking page itself). The arrow is a CSS mask filled with currentColor
 * (like the phone icon below), so it follows the text colour and, having no
 * text content, is invisible to screen readers (decorative, "aria-hidden" in
 * effect). The general nav-link override below is !important (needed to win
 * its own specificity tie against core), so these need !important too -- and,
 * since two !important rules still resolve by specificity, the hover/current
 * versions are each one class heavier than the rule they override.
 */
.wp-block-navigation-item.nav-link-cta .wp-block-navigation-item__content {
	display: inline-flex;
	align-items: center;
	gap: 0.4em;
	color: var(--wp--preset--color--hover) !important;
	font-weight: 700;
	background-color: transparent;
	border: 1.5px solid var(--wp--preset--color--hover);
	padding: 0.4rem 0.9rem;
	border-radius: 4px;
}

.wp-block-navigation-item.nav-link-cta .wp-block-navigation-item__content::after {
	content: "";
	flex: none;
	width: 1em;
	height: 1em;
	background-color: currentColor;
	-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14M13 6l6 6-6 6'/%3E%3C/svg%3E") center / contain no-repeat;
	mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14M13 6l6 6-6 6'/%3E%3C/svg%3E") center / contain no-repeat;
}

.wp-block-navigation-item.nav-link-cta .wp-block-navigation-item__content:hover,
.wp-block-navigation-item.nav-link-cta .wp-block-navigation-item__content:focus-visible {
	color: #fff !important;
	background-color: var(--wp--preset--color--hover);
	text-decoration: none !important;
}

.wp-block-navigation-item.nav-link-cta .wp-block-navigation-item__content:focus-visible {
	outline: 2px solid var(--wp--preset--color--ink);
	outline-offset: 2px;
}

/*
 * When the booking page itself is open, this item also gets current-menu-item
 * -- whose selector above (header .item.current-menu-item .content) is one
 * type-selector heavier than nav-link-cta's, so it would otherwise win the
 * colour tie (and turn the text bold red on the red fill). This combined
 * selector is heavier than either alone: the current page shows the button
 * filled red with white text.
 */
header .wp-block-navigation-item.nav-link-cta.current-menu-item .wp-block-navigation-item__content {
	color: #fff !important;
	background-color: var(--wp--preset--color--hover);
}

header .wp-block-navigation-item.nav-link-cta.current-menu-item .wp-block-navigation-item__content:hover,
header .wp-block-navigation-item.nav-link-cta.current-menu-item .wp-block-navigation-item__content:focus-visible {
	color: #fff !important;
}

/*
 * Header logo/nav row. The logo and nav text are already centered on the
 * same geometric box (confirmed via computed layout), but the logo's own
 * artwork is top-heavy — bold "ROLAND SYSTEM" wordmark over a thinner
 * subline — so its visual weight sits above its geometric center. Nudging
 * it up a few px lines it up with the nav text's optical center instead.
 * core/site-logo doesn't apply a custom className to its wrapper (dynamic
 * block render callback drops it), so this is scoped by ancestor instead.
 */
header .wp-block-site-logo {
	margin-top: -4px;
}

/*
 * Header phone link (parts/header.html). A plain nav item before the
 * "Boka måttagning" CTA, so it picks up the general nav-link color/hover
 * rules below and moves into the overlay menu on mobile along with the rest
 * of the nav. The phone icon can't live in the label (core/navigation-link
 * runs it through wp_kses_post, which strips <svg>), so it's a CSS mask
 * filled with currentColor -- it follows the link's ink/hover color.
 */
.nav-link-phone .wp-block-navigation-item__content::before {
	content: "";
	display: inline-block;
	width: 1em;
	height: 1em;
	margin-right: 0.35em;
	vertical-align: -0.125em;
	background-color: currentColor;
	-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M13.832 16.568a1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2A18 18 0 0 1 2 4a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-.8 1.6l-.468.351a1 1 0 0 0-.292 1.233 14 14 0 0 0 6.392 6.384'/%3E%3C/svg%3E") center / contain no-repeat;
	mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M13.832 16.568a1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2A18 18 0 0 1 2 4a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-.8 1.6l-.468.351a1 1 0 0 0-.292 1.233 14 14 0 0 0 6.392 6.384'/%3E%3C/svg%3E") center / contain no-repeat;
}

/*
 * Phone link in brand red (the hover token) at rest, text and icon (the icon
 * is currentColor). One class heavier than the general nav-link rule below,
 * which forces ink with !important; hover keeps that rule's red + underline.
 * Same selector matches inside the mobile overlay menu.
 */
.nav-link-phone .wp-block-navigation-item__content.wp-block-navigation-item__content {
	color: var(--wp--preset--color--hover) !important;
}

/*
 * Complianz's "manage consent" reopen tab. By default it sits mostly below
 * the viewport (bottom:-35px, only revealed on hover) as a plain unlabelled
 * text pill in the plugin's own banner colors — easy to miss entirely.
 * Complianz builds its own banner CSS as a JS string and injects it into a
 * <style> tag at runtime (see cmplz_append_css in its bundle), so it always
 * lands after this stylesheet in the DOM regardless of enqueue order —
 * matching selector specificity isn't enough here, these need !important.
 * Icon is the same stroke-SVG style used for the phone/email icons
 * elsewhere, baked in as a background-image since this button's content
 * isn't block markup we control.
 */
#cmplz-manage-consent .cmplz-manage-consent {
	bottom: 20px !important;
	left: 20px !important;
	right: auto !important;
	top: auto !important;
	height: 48px !important;
	width: 48px !important;
	min-width: 0 !important;
	display: flex !important;
	align-items: center !important;
	justify-content: center !important;
	padding: 0 !important;
	background-color: var(--wp--preset--color--bg) !important;
	border-radius: 999px !important;
	font-size: 0 !important;
	box-shadow: var(--wp--preset--shadow--natural) !important;
	animation: none !important;
}

#cmplz-manage-consent .cmplz-manage-consent::before {
	content: "";
	width: 1.5rem;
	height: 1.5rem;
	flex-shrink: 0;
	background-repeat: no-repeat;
	background-position: center;
	background-size: contain;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23aa1818' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 2a10 10 0 1 0 10 10 4 4 0 0 1-5-5 4 4 0 0 1-5-5'/%3E%3Cpath d='M8.5 8.5v.01'/%3E%3Cpath d='M16 15.5v.01'/%3E%3Cpath d='M12 12v.01'/%3E%3Cpath d='M11 17v.01'/%3E%3Cpath d='M7 14v.01'/%3E%3C/svg%3E");
}

#cmplz-manage-consent .cmplz-manage-consent:hover,
#cmplz-manage-consent .cmplz-manage-consent:focus {
	bottom: 20px !important;
	animation: none !important;
	background-color: var(--wp--preset--color--bg) !important;
}

/*
 * Hover/focus: same red fill + light icon as every other button. The icon is
 * a background-image, not currentColor, so it's swapped for a light-stroke
 * copy of the same SVG.
 */
#cmplz-manage-consent .cmplz-manage-consent:hover,
#cmplz-manage-consent .cmplz-manage-consent:focus-visible {
	background-color: var(--wp--preset--color--hover) !important;
}

#cmplz-manage-consent .cmplz-manage-consent:hover::before,
#cmplz-manage-consent .cmplz-manage-consent:focus-visible::before {
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23f7f5f0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 2a10 10 0 1 0 10 10 4 4 0 0 1-5-5 4 4 0 0 1-5-5'/%3E%3Cpath d='M8.5 8.5v.01'/%3E%3Cpath d='M16 15.5v.01'/%3E%3Cpath d='M12 12v.01'/%3E%3Cpath d='M11 17v.01'/%3E%3Cpath d='M7 14v.01'/%3E%3C/svg%3E");
}

/*
 * Consent dialog icons (close X and category chevrons). Same !important
 * requirement as above (Complianz's own CSS is injected at runtime, always
 * landing after this stylesheet). The close icon's path already uses
 * fill="currentColor", so setting color here is enough; the chevron paths
 * have no fill attribute at all (defaulting to SVG's own black), so those
 * need fill set directly.
 */
#cmplz-cookiebanner-container .cmplz-close {
	color: var(--wp--preset--color--hover) !important;
}

#cmplz-cookiebanner-container .cmplz-category-toggle svg {
	fill: var(--wp--preset--color--hover) !important;
}

/*
 * Visually hides text that should still reach screen readers (the
 * scroll-to-top button's label, below) without an aria-label attribute --
 * which a Button block's save() has no slot for, so a literal one in the
 * markup would make the editor flag the block as invalid content.
 */
.visually-hidden {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/*
 * Scroll-to-top button (parts/footer.html, a Buttons block), paired with the
 * manage-consent icon in the opposite corner — same size/shape/shadow, and
 * the same deep-red icon color too (its arrow SVG uses stroke="currentColor").
 * The carousel arrows (.is-swipe-row-next, further down) share these exact
 * declarations and hover/focus states through the selector lists below, so
 * the two can't drift apart; only their position and chevron differ.
 * assets/js/scroll-to-top.js adds the click handler (a Button block's `<a>`
 * has no attribute slot for an inline onclick, and one would be mangled by
 * wptexturize on save regardless -- see the Map Band pattern's own comment).
 */
.scroll-to-top {
	position: fixed;
	bottom: 20px;
	right: 20px;
	z-index: 9998;
}

.scroll-to-top .wp-block-button__link,
.is-swipe-row-next {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 48px;
	height: 48px;
	padding: 0;
	border: none;
	border-radius: 999px;
	background-color: var(--wp--preset--color--bg);
	color: var(--wp--preset--color--hover);
	box-shadow: var(--wp--preset--shadow--natural);
	cursor: pointer;
}

.scroll-to-top .wp-block-button__link:hover,
.scroll-to-top .wp-block-button__link:focus-visible,
.is-swipe-row-next:hover,
.is-swipe-row-next:focus-visible {
	background-color: var(--wp--preset--color--hover);
	color: var(--wp--preset--color--light);
}

/*
 * Sticky header. position:sticky was on the <header> itself, but WordPress
 * wraps every template part in a plain .wp-block-template-part div with no
 * height of its own — since the header is that div's only child, the div is
 * exactly the header's height, leaving no room for the header to move within
 * it, so it never visibly stuck. Moving position:sticky to that wrapper
 * instead makes its containing block .wp-site-blocks (full page height),
 * which has the room. :first-child scopes this to the header's wrapper only —
 * the footer's part uses the same class but isn't wp-site-blocks' first child.
 * top/z-index match what the header's own block-level sticky support used to
 * generate, including the same admin-bar-height offset and the same
 * max-width:600px cutoff core uses to zero that offset out.
 */
.wp-site-blocks > .wp-block-template-part:first-child {
	position: sticky;
	top: var(--wp-admin--admin-bar--height, 0px);
	z-index: 10;
}

@media screen and (max-width: 600px) {
	.wp-site-blocks > .wp-block-template-part:first-child {
		top: 0;
	}
}

/*
 * Core's navigation block CSS carries its own doubled-class selector
 * (.wp-block-navigation-item__content.wp-block-navigation-item__content),
 * which has real (non-:where) specificity and forces color: inherit on
 * every nav link. That's the exact same selector text as this override, so
 * it's a specificity tie decided by DOM order alone — core's rule happened
 * to win, and only looked correct before because inherited body-text ink
 * coincidentally matched this rule's old ink value. !important removes the
 * order-dependency instead of relying on that coincidence again.
 * Header/footer nav items: ink + bold by default, dark red on hover.
 */
.wp-block-navigation-item__content.wp-block-navigation-item__content {
	color: var(--wp--preset--color--ink) !important;
	font-weight: 700;
	text-decoration: none;
}

.wp-block-navigation-item__content.wp-block-navigation-item__content:hover {
	color: var(--wp--preset--color--hover) !important;
	text-decoration: underline;
}

/*
 * core/navigation declares blockGap support, but its custom renderer
 * (WP_Navigation_Block_Renderer) doesn't apply block-style spacing the way
 * ordinary blocks do — the theme.json blockGap setting for core/navigation
 * never reaches the DOM. Matches Header.tsx's gap-x-6 gap-y-2 (fixed, not
 * fluid — the nav row doesn't scale with viewport width in source).
 */
.wp-block-navigation__container {
	row-gap: 0.5rem;
	column-gap: 1.5rem;
}

/*
 * Header nav: half the item spacing (12px, not 24px) so logo and nav share
 * one row from 1340px up. At 24px it wrapped below 1448px once "Våra
 * projekt" and "Inspiration" were in the nav.
 */
header .wp-block-navigation__container {
	column-gap: 0.75rem;
}

/*
 * Header bar (parts/header.html): logo, then two Navigation blocks --
 * .header-actions (phone, "Boka måttagning"; never collapses, so both stay
 * in the bar at every width) and .header-pages (the page links). Actions sit
 * against the pages nav with the same 12px as between nav items, and the
 * pair is pushed to the right.
 */
header .header-bar {
	column-gap: 0.75rem;
}

header .header-actions {
	margin-left: auto;
}

/*
 * Below 1340px the page links don't fit beside the logo, so they switch to
 * core's mobile menu (the ☰ button and overlay) instead of wrapping. Core
 * only does that below 600px; between 600 and 1339px these two rules do the
 * same: show the open button, hide the inline list. The overlay itself
 * (.is-menu-open) is core's, unchanged.
 */
@media (min-width: 600px) and (max-width: 1339.98px) {
	header .header-pages .wp-block-navigation__responsive-container-open:not(.always-shown) {
		display: flex;
	}

	header .header-pages .wp-block-navigation__responsive-container:not(.hidden-by-default):not(.is-menu-open) {
		display: none;
	}
}

/*
 * Phones: logo and ☰ on the first line, phone and "Boka måttagning" on a
 * second line below -- all four don't fit side by side at 375px without
 * shrinking the logo or labels.
 */
@media (max-width: 599.98px) {
	/*
	 * Language switcher sits just before the ☰ on this same first line --
	 * margin-left: auto on it (rather than header-pages) pushes it flush
	 * against the hamburger the same way header-actions does on desktop,
	 * instead of space-between spreading all three row-1 items apart.
	 */
	header .header-lang {
		order: 1;
		margin-left: auto;
	}

	header .header-pages {
		order: 2;
	}

	header .header-actions {
		order: 3;
		flex-basis: 100%;
		margin-left: 0;
	}
}

/*
 * Header language switcher (polylang/navigation-language-switcher, inside
 * .header-lang, parts/header.html), dropdown + flags + names. functions.php
 * strips the name text back out of the closed-state trigger (flag + caret
 * only there); the open list's items keep it. Sizing the flag to the nav
 * text's line-height keeps it visually aligned with the rest of the bar.
 */
.header-lang img {
	height: 1em;
	width: auto;
	vertical-align: middle;
	margin-right: 0.4em;
}

/*
 * Language switcher toggle: the current flag and the caret are one button
 * (functions.php), with a tap area of at least 44x44 CSS px made of padding
 * and min-size -- the flag (16x11) and caret (about 8px) are drawn at the same
 * size as before. The button is 44px tall but its vertical margin takes back
 * the extra 8px, so the header row keeps the height the 36px logo gives it
 * and nothing moves. Its right edge stays where the caret's was, so the gap
 * to the hamburger is unchanged.
 */
.header-lang .roland-lang-toggle {
	box-sizing: border-box;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	min-width: 44px;
	min-height: 44px;
	margin-block: -6px;
	padding: 0 0.5rem;
	border: 0;
	background: transparent;
	color: inherit;
	cursor: pointer;
}

.header-lang .roland-lang-toggle__flag {
	display: inline-flex;
	align-items: center;
}

.header-lang .roland-lang-toggle img {
	margin-right: 0;
}

.header-lang .roland-lang-toggle svg {
	flex: none;
	width: 8.4px;
	height: 8.4px;
	margin: 0;
}

/*
 * Open list: right-aligned under the toggle (it is the last thing in the
 * header, so a left-aligned 12.5rem list ran off the right edge and made the
 * page scroll sideways) and starting below the 44px toggle so it never
 * covers the toggle's lower edge; a second tap on the toggle must close it.
 */
nav.header-lang .has-child .wp-block-navigation__submenu-container {
	left: auto;
	right: 0;
	top: calc(100% + 6px);
}

/*
 * Polylang always includes the current language in the dropdown's data (it
 * needs it to build the closed-state trigger), so the open list would
 * otherwise repeat it. Hiding just the nested copy inside the submenu
 * panel -- not the trigger itself, which lives outside
 * .wp-block-navigation__submenu-container -- leaves only the other two
 * flags in the open state.
 */
.header-lang .wp-block-navigation__submenu-container .current-lang {
	display: none;
}

/*
 * Footer "Sidor" nav (parts/footer.html). Same renderer gap: the
 * orientation:"vertical" block attribute is dropped, so it renders with the
 * same horizontal flex layout as the header nav and wraps into pairs at this
 * column's width. Source stacks it as a single column (ul className="space-y-2").
 */
.footer-sidor-nav.wp-block-navigation,
.footer-sidor-nav .wp-block-navigation__container {
	flex-direction: column;
	align-items: flex-start;
}

/* Same text size as the Contact and Opening hours columns (body size). */
.site-footer .footer-sidor-nav.wp-block-navigation {
	font-size: var(--wp--preset--font-size--body);
}

/*
 * A Pages link that doesn't fit its column wraps onto a second line (and, as
 * a last resort, breaks inside a word) instead of spilling into the next
 * column -- e.g. when a browser translates the labels into longer English.
 */
.site-footer .footer-sidor-nav .wp-block-navigation-item {
	min-width: 0;
}

.site-footer .footer-sidor-nav .wp-block-navigation-item__content {
	white-space: normal;
	overflow-wrap: break-word;
}

/*
 * Footer columns (parts/footer.html has one Columns block: logo and
 * description, Pages, Contact, Opening hours). Side by side (from 782px,
 * core's stacking breakpoint), Pages takes 20% of a column's width from the
 * logo column: flex-grow 0.8 / 1.2 / 1 / 1. Contact and Opening hours keep
 * exactly the width of an equal quarter, as before; the logo column's text
 * wraps a little earlier and the logo scales down with it.
 */
@media (min-width: 782px) {
	.site-footer .wp-block-columns > .wp-block-column:nth-child(1) {
		flex-grow: 0.8;
	}

	.site-footer .wp-block-columns > .wp-block-column:nth-child(2) {
		flex-grow: 1.2;
	}
}

/*
 * Wide screens: the Pages list in two sub-columns of four under the one
 * "Pages" heading (Skjutdörrsgarderober … Inspiration left, Våra projekt …
 * Om oss right). It stays one list in page order, laid out column by column,
 * so narrower screens simply keep the single list. At the 18px body size the
 * two need ~315px on one line; the widened Pages column has that from
 * 1254px (323px at 1280px), and 1264px leaves a little slack. Sub-columns
 * can shrink to their share, so longer labels wrap rather than overflow.
 * Same 8px row spacing as the single list.
 */
@media (min-width: 79rem) {
	.site-footer .footer-sidor-nav .wp-block-navigation__container {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, max-content));
		grid-template-rows: repeat(4, auto);
		grid-auto-flow: column;
		column-gap: 1.5rem;
		row-gap: 0.5rem;
	}
}

/*
 * Vanliga frågor / Boka måttagning accordion. The question counter ("01",
 * "02", ...) is pure CSS (counter-increment below), not stored text: a
 * number typed into the page content would need hand-renumbering every time
 * a question is added, edited or removed, and Gutenberg's own editing
 * canvas made that worse than it sounds -- core/details' summary always
 * collapses to a single rich-text editing node in the editor (confirmed via
 * its DevTools-rendered DOM), regardless of how many real elements the
 * saved markup has inside <summary>. A counter badge that depended on
 * <summary> having two real child elements (one per grid column) rendered
 * correctly on the front end, but in the editor every question's heading
 * got crushed into a few pixels of width, because the editor's single
 * child only ever fills the grid's first (narrow) column. Keeping the
 * counter entirely in CSS -- not a real element inside <summary> at all --
 * sidesteps that mismatch completely: both contexts just see <summary>
 * containing the question text, nothing else, and the counter is drawn
 * without needing a second grid-column citizen to exist. It also means the
 * number updates live, instantly and correctly, when a question is
 * duplicated, deleted or reordered in the editor -- no save-and-reload
 * needed to see the renumbering, since it was never a number to update.
 *
 * The answer row keeps using --faq-counter-col (below) so its left border
 * still lines up under the question column, same as before.
 */
.wp-block-group:has(> .faq-item) {
	counter-reset: faq-item;
}

.faq-item {
	--faq-counter-col: 3.75rem;
	counter-increment: faq-item;
}

.faq-item summary {
	position: relative;
	list-style: none;
	cursor: pointer;
	padding-top: 1.75rem;
	padding-bottom: 1.75rem;
	padding-left: calc(var(--faq-counter-col) + var(--wp--preset--spacing--gutter));
}

.faq-item summary::-webkit-details-marker {
	display: none;
}

.faq-item summary::marker {
	content: "";
}

.faq-item summary::before {
	content: counter(faq-item, decimal-leading-zero);
	position: absolute;
	left: 0;
	top: 1.75rem;
	width: var(--faq-counter-col);
	white-space: nowrap;
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--eyebrow);
	color: var(--wp--preset--color--secondary);
}

.faq-item[open] summary::before {
	color: var(--wp--preset--color--hover);
}

/*
 * .faq-question is a real heading (h2 on Vanliga frågor, h3 on Boka
 * måttagning) instead of a span, for document outline / SEO. margin and
 * line-height are reset because theme.json's global h2/h3 element styles and
 * the browser's default heading margin would otherwise apply to this tag and
 * change its appearance. letter-spacing is set explicitly to the same
 * -0.015em every other heading uses, so it matches whether it's an h2 or h3. Sized to heading-3, not
 * heading-2, so it stays clearly smaller than the section h2 above the list
 * (e.g. Boka måttagning's "Vanliga frågor innan du ringer"), and so the
 * question size matches between the two pages even though one uses h2 and
 * the other h3.
 */
.faq-question {
	min-width: 0;
	margin: 0;
	font-size: var(--wp--preset--font-size--heading-3);
	font-weight: 600;
	line-height: inherit;
	letter-spacing: -0.015em;
}

/*
 * The answer row is a Group block (.faq-answer-row) inside the Details
 * block, so the block editor can save it. Its first grid column is a
 * ::before spacer (a pseudo-element takes part in the grid like a first
 * child), which carries the open-state border -- no extra markup needed.
 * The spacer column is the gutter narrower than the summary's counter
 * column, with a fixed 1rem gap taking up the difference: the border (at
 * the spacer's right edge) then lands 1rem before the question/answer
 * column starts, giving the border breathing room from the answer text
 * while keeping the text itself aligned with the question above it.
 */
.faq-answer-row {
	display: grid;
	grid-template-columns: calc(var(--faq-counter-col) + var(--wp--preset--spacing--gutter) - 1rem) 1fr;
	gap: 1rem;
	padding-bottom: 2.5rem;
}

.faq-answer-row::before {
	content: "";
}

.faq-item[open] .faq-answer-row::before {
	border-right: 2px solid var(--wp--preset--color--hover);
}

.faq-answer {
	/*
	 * An answer with more than one paragraph (e.g. the ROT question): without
	 * this, CSS grid auto-placement fills .faq-answer-row's two columns
	 * left-to-right row by row, so the first paragraph lands in column 2 but
	 * the second lands back in column 1 (the spacer column) -- each
	 * paragraph alternating columns and getting squeezed into the narrow
	 * spacer's width. Pinning every answer paragraph to column 2 keeps them
	 * stacked in one column regardless of how many there are.
	 */
	grid-column: 2;
	font-size: var(--wp--preset--font-size--body);
}

@media (min-width: 48rem) {
	.faq-item summary {
		padding-top: 2.5rem;
		padding-bottom: 2.5rem;
	}

	.faq-item summary::before {
		top: 2.5rem;
		font-size: var(--wp--preset--font-size--small);
	}

	.faq-answer {
		font-size: var(--wp--preset--font-size--heading-3);
	}
}

/*
 * Formidable Forms ships its own stylesheet (formidableforms.css) with
 * generic default field styling that carries none of the theme's tokens.
 * Scoped to the booking form specifically (:is(#form_bokamttagning, #form_bokamttagning-en)) so it
 * doesn't affect any other Formidable form on the site. Values match
 * boka-mattagning.tsx's fieldClasses / labelClasses exactly.
 *
 * The 40rem cap goes on .booking-form's children, not on .booking-form
 * itself. .booking-form's own box gets no override, so WP's
 * is-layout-constrained rules position it exactly like every sibling
 * section -- centered within the content size at viewports wider than
 * that, same as the H1/FAQ/email sections. Capping the group itself
 * (and forcing its margin to pin it to the padding edge, which was tried
 * first) broke that: at viewports wider than the content size, siblings
 * center inward while the pinned group stayed at the outer edge, visibly
 * misaligning it. The children have no auto-centering of their own, so
 * they simply hug the left edge of whatever box .booking-form lands in,
 * keeping the form aligned with the rest of the page at any width.
 *
 * The separator is left uncapped so it still spans the full section width
 * like every other section's hairline. The form container needs
 * !important: Formidable's own .frm_forms.frm_style_formidable-style.
 * with_frm_style rule sets max-width:var(--form-width) (100%) with three
 * classes' worth of specificity, beating a plain class selector here.
 */
.booking-form > h2,
.booking-form > p {
	max-width: 40rem;
}

.booking-form > .frm_forms {
	max-width: 40rem !important;
}

/*
 * Booking page, form section (50 / 416): the form on the left and "Prefer to
 * write?" on the right. A hairline vertical rule (the colour and 1px weight of
 * the separators between sections) divides the two, with one and a half
 * gutters of space on each side of it. On phones the columns stack and the same hairline runs
 * horizontally between them, as the separators did before.
 */
.booking-form > .wp-block-columns {
	gap: 0;
}

@media (min-width: 782px) {
	.booking-form > .wp-block-columns > .wp-block-column:first-child {
		padding-right: calc(var(--wp--preset--spacing--gutter) * 1.5);
	}

	.booking-form > .wp-block-columns > .wp-block-column:last-child {
		padding-left: calc(var(--wp--preset--spacing--gutter) * 1.5);
		border-left: 1px solid var(--wp--preset--color--hairline);
	}
}

@media (max-width: 781px) {
	.booking-form > .wp-block-columns > .wp-block-column:last-child {
		margin-top: var(--wp--preset--spacing--section);
		padding-top: var(--wp--preset--spacing--section);
		border-top: 1px solid var(--wp--preset--color--hairline);
	}
}

/*
 * Vertical space between form fields: half the gutter (24px at desktop, the
 * same half-gutter step the header row uses), floored at 1rem so fields don't
 * crowd on phones where half the gutter would be ~13px. The full gutter
 * (48px at desktop) made the form read as a list of separate blocks.
 */
:is(#form_bokamttagning, #form_bokamttagning-en) {
	--form-row-gap: max(1rem, calc(var(--wp--preset--spacing--gutter) / 2));
}

:is(#form_bokamttagning, #form_bokamttagning-en) .frm_form_field {
	margin-bottom: var(--form-row-gap);
}

/*
 * Two rows of two on tablet/desktop (the container also holds hidden inputs,
 * hence nth-of-type): Namn and Telefon on row 1, E-post and Ort on row 2, in
 * the form's field order, so keyboard order matches what you see. Everything
 * else (textarea, consent, submit) spans both columns. Single column on
 * mobile -- no grid at all there.
 */
@media (min-width: 48rem) {
	:is(#form_bokamttagning, #form_bokamttagning-en) .frm_fields_container {
		display: grid;
		grid-template-columns: 1fr 1fr;
		gap: var(--form-row-gap) var(--wp--preset--spacing--gutter);
	}

	:is(#form_bokamttagning, #form_bokamttagning-en) .frm_fields_container > .frm_form_field {
		grid-column: 1 / -1;
		margin-bottom: 0;
	}

	:is(#form_bokamttagning, #form_bokamttagning-en) .frm_fields_container > .frm_form_field:nth-of-type(1) {
		grid-column: 1;
		grid-row: 1;
	}

	:is(#form_bokamttagning, #form_bokamttagning-en) .frm_fields_container > .frm_form_field:nth-of-type(2) {
		grid-column: 2;
		grid-row: 1;
	}

	:is(#form_bokamttagning, #form_bokamttagning-en) .frm_fields_container > .frm_form_field:nth-of-type(3) {
		grid-column: 1;
		grid-row: 2;
	}

	:is(#form_bokamttagning, #form_bokamttagning-en) .frm_fields_container > .frm_form_field:nth-of-type(4) {
		grid-column: 2;
		grid-row: 2;
	}
}

/*
 * Consent checkbox label. Not flex: the label's content is loose text, the
 * "integritetspolicy" link and a full stop, and as a flex container each of
 * those became its own column, so the link and full stop sat apart from the
 * sentence. As a block with the checkbox pinned in the left padding, the
 * whole thing wraps as one sentence. The checkbox (enlarged below, since the
 * native size is well under a comfortable tap target) is centred on the
 * first line of text: 1lh is that line's height.
 */
:is(#form_bokamttagning, #form_bokamttagning-en) .frm_checkbox label {
	display: block;
	position: relative;
	box-sizing: border-box; /* Formidable sets width:100%; keep the padding inside it. */
	padding: 0.5rem 0 0.5rem 2.25rem;
	cursor: pointer;
}

/*
 * !important needed to beat Formidable's own
 * .with_frm_style ... input[type="checkbox"] rule, which sets width/height
 * to 16px with !important.
 */
/*
 * The privacy-policy link sits in running text too, but inside a <label>,
 * which the is-inline-link filter (p/li only) doesn't see -- so it's
 * underlined here. Red on ink text alone is too low-contrast to mark a link.
 */
:is(#form_bokamttagning, #form_bokamttagning-en) .frm_checkbox label a {
	text-decoration: underline;
}

/*
 * Optional marketing opt-in (.roland-optin, last field before the submit
 * button). Its checkbox text is the whole label, so the group name Formidable
 * prints above it ("Nyhetsbrev" / "Newsletter") is hidden visually but kept
 * for screen readers (it names the group), and the label is at least 44px
 * tall so one-line text still gives a full-size tap target.
 */
:is(#form_bokamttagning, #form_bokamttagning-en) .roland-optin .frm_primary_label {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

:is(#form_bokamttagning, #form_bokamttagning-en) .roland-optin .frm_checkbox label {
	min-height: 44px;
}

:is(#form_bokamttagning, #form_bokamttagning-en) .frm_checkbox input[type="checkbox"] {
	position: absolute;
	left: 0;
	top: 0.5rem;
	top: calc(0.5rem + (1lh - 1.5rem) / 2);
	width: 1.5rem !important;
	min-width: 1.5rem !important;
	height: 1.5rem !important;
	margin: 0 !important;
	accent-color: var(--wp--preset--color--ink);
}

:is(#form_bokamttagning, #form_bokamttagning-en) .frm_primary_label {
	display: block;
	margin-bottom: 0.5rem;
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 600;
	color: var(--wp--preset--color--ink);
}

:is(#form_bokamttagning, #form_bokamttagning-en) .frm_description {
	margin-top: 0.5rem;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--secondary);
}

:is(#form_bokamttagning, #form_bokamttagning-en) input[type="text"],
:is(#form_bokamttagning, #form_bokamttagning-en) input[type="tel"],
:is(#form_bokamttagning, #form_bokamttagning-en) input[type="email"],
:is(#form_bokamttagning, #form_bokamttagning-en) select,
:is(#form_bokamttagning, #form_bokamttagning-en) textarea {
	display: block;
	width: 100%;
	box-sizing: border-box;
	padding: 0.75rem 1rem;
	border: 1px solid var(--wp--preset--color--hairline);
	border-radius: 4px;
	background-color: #fff;
	color: var(--wp--preset--color--ink);
	font-family: var(--wp--preset--font-family--sans);
	font-size: var(--wp--preset--font-size--body);
}

/*
 * Focus: the site's dark outline (same as the global :focus-visible rule)
 * instead of Formidable's blue border and glow. !important because Formidable's
 * own .with_frm_style focus rule sets border-color and box-shadow with it.
 */
:is(#form_bokamttagning, #form_bokamttagning-en) input[type="text"]:focus,
:is(#form_bokamttagning, #form_bokamttagning-en) input[type="tel"]:focus,
:is(#form_bokamttagning, #form_bokamttagning-en) input[type="email"]:focus,
:is(#form_bokamttagning, #form_bokamttagning-en) textarea:focus {
	border-color: var(--wp--preset--color--hairline) !important;
	box-shadow: none !important;
	outline: 2px solid var(--wp--preset--color--ink);
	outline-offset: 2px;
}

:is(#form_bokamttagning, #form_bokamttagning-en) .frm_button_submit {
	cursor: pointer;
	border: none;
	border-radius: 4px;
	background-color: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--bg);
	padding: 0.75rem 1.5rem;
	font-family: var(--wp--preset--font-family--sans);
	font-size: var(--wp--preset--font-size--body);
}

:is(#form_bokamttagning, #form_bokamttagning-en) .frm_button_submit:hover,
:is(#form_bokamttagning, #form_bokamttagning-en) .frm_button_submit:focus-visible {
	background-color: var(--wp--preset--color--hover);
	color: var(--wp--preset--color--light);
}

/*
 * Map band (the "Map Band" synced pattern, wp_block). Content width, not full
 * bleed, with the same section padding as other sections. A raw iframe has no
 * block attributes for height, so the fixed 280px/360px breakpoint from
 * Footer.tsx's h-[280px] md:h-[360px] is set here. Complianz intercepts the
 * iframe and injects its own consent placeholder client-side (white box,
 * semi-transparent black button) — restyled with the theme's existing button
 * tokens (ink/bg/hover, 4px radius) so it doesn't look like a default
 * plugin widget.
 */
.map-band-address {
	margin-bottom: var(--wp--preset--spacing--gutter);
}

.map-band-wrap {
	position: relative;
}

.map-band-embed {
	display: block;
	width: 100%;
	height: 280px;
	border: 0;
}

/*
 * Greyscale and a little flatter so the map sits quietly in the page's
 * palette; full colour on hover (and keyboard focus) when someone is actually
 * looking at it. Until marketing consent is given, Complianz shows its own
 * placeholder instead of the live map -- a map image set as the background of
 * .cmplz-blocked-content-container, which wraps the iframe -- so that gets the
 * same treatment. Its consent notice sits inside and greys with it, but
 * hovering the notice also hovers the map, which lifts the filter, so the
 * notice's red hover still shows.
 */
.map-band-embed,
.map-band .cmplz-blocked-content-container {
	filter: grayscale(1) contrast(0.9);
	transition: filter 0.3s ease;
}

.map-band-wrap:hover .map-band-embed,
.map-band-wrap:focus-within .map-band-embed,
.map-band-wrap:hover .cmplz-blocked-content-container,
.map-band-wrap:focus-within .cmplz-blocked-content-container {
	filter: none;
}

@media (prefers-reduced-motion: reduce) {
	.map-band-embed,
	.map-band .cmplz-blocked-content-container {
		transition: none;
	}
}

@media (min-width: 48rem) {
	.map-band-embed {
		height: 360px;
	}
}

/*
 * Click-to-activate overlay (a Buttons block inside the Map Band pattern):
 * sits on top of the iframe until clicked, so a page-scroll wheel event over
 * the map area scrolls the page instead of being captured by Google's own
 * zoom-on-scroll handler. A whole-map click target, not a normal CTA, so the
 * button's own wrapper (.map-band-activate, the block's "Additional CSS
 * class") is positioned absolutely and its link stretched to fill it, rather
 * than styling the link as a normal inline button.
 *
 * !important on the hidden state: core's own block-library CSS sets
 * `.wp-block-buttons > .wp-block-button { display: inline-block }`, two
 * classes (0,2,0) against this rule's one (0,1,0) -- with neither
 * `.map-band-wrap.is-map-live` match nor a source-order tie to rely on, core
 * wins and the overlay showed through Complianz's own blocked-content notice
 * before a real map had loaded. Confirmed via Chrome DevTools' matched-styles
 * panel, which is the only way this was actually found -- the two rules
 * read as correct and non-conflicting from the stylesheet alone.
 */
.map-band-activate {
	/* Hidden until the live map has loaded; see .is-map-live below. */
	display: none !important;
	position: absolute;
	inset: 0;
}

.map-band-wrap.is-map-live .map-band-activate {
	display: block !important;
}

.map-band-activate .wp-block-button__link {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	height: 100%;
	border: 0;
	border-radius: 0;
	background: rgba(26, 26, 26, 0.15);
	color: var(--wp--preset--color--bg);
	font-family: var(--wp--preset--font-family--sans);
	font-size: var(--wp--preset--font-size--body);
	font-weight: 600;
	text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
	cursor: pointer;
}

.map-band-activate .wp-block-button__link:hover {
	background: rgba(26, 26, 26, 0.25);
}

.map-band .cmplz-blocked-content-container {
	background-color: var(--wp--preset--color--bg);
	border-radius: 0;
	box-shadow: none;
}

/*
 * Keep the blocked-map placeholder the same height as the map that replaces
 * it. Complianz sizes that box from its placeholder image (the Google Maps
 * picture, 1280x920) and writes the height into an inline style once the box
 * scrolls into view (.cmplz-placeholder-N { height: ...px }), which made the
 * band about twice as tall before consent (967px at 1440px wide instead of
 * 360px) and made the page jump when consent was given. Two classes outweigh
 * Complianz's one, so the box stays 280px (phones) / 360px (from 48rem), the
 * same as .map-band-embed above. The placeholder picture is cropped to fit
 * (background-size: cover, set by Complianz).
 */
.map-band .cmplz-blocked-content-container {
	height: 280px;
}

@media (min-width: 48rem) {
	.map-band .cmplz-blocked-content-container {
		height: 360px;
	}
}

.map-band .cmplz-blocked-content-notice {
	font-family: var(--wp--preset--font-family--sans);
	font-size: var(--wp--preset--font-size--body);
	max-width: 320px;
	padding: 0.75rem 1.5rem;
	background-color: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--bg);
	border-radius: 4px;
	line-height: 1.4;
}

.map-band .cmplz-blocked-content-notice:hover {
	background-color: var(--wp--preset--color--hover);
}

/*
 * Complianz's placeholder for a blocked YouTube embed. Complianz sizes that
 * box from the placeholder image (YouTube's 4:3 thumbnail) and writes the
 * height into an inline <style> (.cmplz-placeholder-N { height: ...px }), so
 * before consent it is taller than the 16:9 video that replaces it and the
 * page jumps when consent is given. Two classes outweigh Complianz's one,
 * so this keeps the box 16:9 before and after. The 4:3 thumbnail is cropped
 * to fit (Complianz sets background-size: cover); centred, the crop falls on
 * the video frame and cuts off the black bars baked into the thumbnail.
 */
.wp-block-embed.is-provider-youtube .wp-block-embed__wrapper.cmplz-blocked-content-container {
	aspect-ratio: 16 / 9;
	height: auto;
	background-position: center;
}

/*
 * Material swatch grid (Material page, Skjutdörrsgarderober and Inredning page
 * content, door-materials-teaser pattern). Core's
 * group block has no attribute for "N columns on desktop, fewer on mobile" —
 * its grid layout type only offers a single auto-fill minimum-width (continuous,
 * not a discrete per-breakpoint count) or a fixed non-responsive column count.
 * Swatches need an exact "5-6 desktop / 3 mobile" count, so this fills that gap.
 */
.roland-swatch-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: var(--wp--preset--spacing--gutter);
}

@media (min-width: 48rem) {
	.roland-swatch-grid {
		grid-template-columns: repeat(6, 1fr);
	}
}

/*
 * Subheadings between swatch groups (Material page: Decor panels, Mirror,
 * Glass). At the default 1em top margin (24px) a subheading sat as close to
 * the swatch row above it as to its own swatches, so the groups ran
 * together. 2em doubles that gap. Targets only h3s that sit directly in a
 * group alongside a swatch grid, so no page content needs a class and other
 * headings (e.g. "Door materials" on Skjutdörrsgarderober, an h2) are
 * unaffected.
 */
.wp-block-group:has(> .roland-swatch-grid) > h3.wp-block-heading {
	margin-top: 2em;
}

/*
 * Inspiration gallery swipe row (inspiration-page pattern). Mobile-first: a
 * horizontal scroll-snap row by default (each card ~72% wide, so the next one
 * is visibly cut off), switching to the same 3-then-2 layout the desktop grid
 * always had once it's rendered as one flat row of 5 images (a 6-column grid
 * with the first three spanning 2 columns and the last two spanning 3 — same
 * visual result as three equal columns then two equal columns, just achieved
 * in one grid instead of two, since a single mobile scroll container needs
 * all 5 images as siblings rather than split across two separate rows).
 * Scrollbar hidden across engines; overflow-x stays auto so touch/trackpad
 * scrolling keeps working. No JS, no transitions.
 */
.is-swipe-row {
	display: flex;
	overflow-x: auto;
	gap: var(--wp--preset--spacing--gutter);
	scroll-snap-type: x mandatory;
	scrollbar-width: none;
	-ms-overflow-style: none;
}

.is-swipe-row::-webkit-scrollbar {
	display: none;
}

.is-swipe-row > * {
	flex: 0 0 72%;
	scroll-snap-align: start;
}

@media (min-width: 48rem) {
	.is-swipe-row {
		display: grid;
		grid-template-columns: repeat(12, 1fr);
		overflow-x: visible;
	}

	/* Three to a row by default (3, 6, 9 photos). The rules below handle the
	   counts that don't divide by three, so the last row is never one orphan:
	   2 = two halves, 4 = four across, 5 = three then two, 7 = four then
	   three. :first-child:nth-last-child(N) matches a row with exactly N
	   children (a quantity query), so the editor can add or remove a photo
	   and the layout follows. */
	.is-swipe-row > * {
		grid-column: span 4;
	}

	.is-swipe-row > :first-child:nth-last-child(2),
	.is-swipe-row > :first-child:nth-last-child(2) ~ * {
		grid-column: span 6;
	}

	.is-swipe-row > :first-child:nth-last-child(4),
	.is-swipe-row > :first-child:nth-last-child(4) ~ * {
		grid-column: span 3;
	}

	.is-swipe-row > :first-child:nth-last-child(5) ~ :nth-child(n+4) {
		grid-column: span 6;
	}

	.is-swipe-row > :first-child:nth-last-child(7),
	.is-swipe-row > :first-child:nth-last-child(7) ~ :nth-child(-n+4) {
		grid-column: span 3;
	}
}

/*
 * Mobile-only scroll hint for the swipe row above: a small circular chevron
 * button pinned to the row's right edge. It lives on .is-swipe-row-wrap (a
 * plain, non-scrolling parent) rather than inside .is-swipe-row itself, so it
 * stays fixed in place while the row scrolls under it instead of scrolling
 * away. Its positioning box is sized/placed as a 4:3 box matching one card's
 * image (not the card, which also includes the caption) so it's vertically
 * centered on the images specifically. That positioning box stays
 * pointer-events:none so it doesn't block swipes across the rest of its
 * (mostly empty) area — only the small circular button inside re-enables
 * pointer-events, and its onclick advances the row by one card's width
 * (matching the JS-in-markup pattern already used for footer.html's
 * scroll-to-top button, since this theme has no other enqueued script).
 */
.is-swipe-row-wrap {
	position: relative;
}

.is-swipe-row-hint {
	position: absolute;
	top: 0;
	right: 0;
	width: 72%;
	aspect-ratio: 4 / 3;
	display: flex;
	align-items: center;
	justify-content: flex-end;
	padding-right: 0.5rem;
	pointer-events: none;
}

.is-swipe-row-next {
	/* Look: shared with .scroll-to-top above (48px circle, so well over the
	   44px tap minimum). Here: re-enable taps inside the pass-through hint box
	   and swap the page's "→" text for the same chevron the scroll-to-top
	   button draws (Lucide chevron-right, 2px round stroke), as a mask so it
	   takes the button's text colour on hover/focus too. The glyph in the
	   markup stays (no page edits) but is hidden with font-size 0. */
	pointer-events: auto;
	font-size: 0;
	line-height: 0;
}

.is-swipe-row-next::before {
	content: "";
	width: 1.5rem;
	height: 1.5rem;
	background-color: currentColor;
	-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m9 18 6-6-6-6'/%3E%3C/svg%3E") center / contain no-repeat;
	mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m9 18 6-6-6-6'/%3E%3C/svg%3E") center / contain no-repeat;
}

@media (min-width: 48rem) {
	.is-swipe-row-hint {
		display: none;
	}
}

/*
 * Project tiles (Home and Skjutdörrsgarderober, "Våra projekt" / "Our work"):
 * six cards, a 3x2 grid on desktop and one swipe row on phones. Both come
 * from .is-swipe-row above (six children = three to a row), so .tricky-tiles
 * needs no layout rules of its own; it stays on the row as a hook for the
 * 4:5 tile photos below.
 */

/* The scroll hint centres itself on a 4:3 photo; the tiles' photos are 4:5. */
.is-swipe-row-wrap:has(.tricky-tiles) .is-swipe-row-hint {
	aspect-ratio: 4 / 5;
}

/* Home and Skjutdörrsgarderober split the six tiles into two rows of three,
   each under its own line of text; clear space between the two. */
.tile-subsection + .tile-subsection {
	margin-top: var(--wp--preset--spacing--section);
}

/*
 * Image cards (Home tricky tiles, Skjutdörrsgarderober "Inspiration"). Each
 * card is a Group block (.tricky-tile) holding an Image block linked to its
 * Inspiration anchor and an H3 (.tricky-tile__label) with the same link, so
 * the photo can be replaced in the block editor. Both links stay text-colored
 * with no underline; hovering or focusing either one turns the label red,
 * so the card still reads as one target. No hover animation on the image
 * (red only for hover/focus states).
 */
.tricky-tile .wp-block-image {
	margin: 0;
}

/* Core makes the image link inline-block, which leaves a descender gap
   under the photo; as a block the label sits exactly 0.75rem below it. */
.tricky-tile .wp-block-image a {
	display: block;
}

.tricky-tile img {
	display: block;
	width: 100%;
}

.tricky-tile a {
	color: inherit;
	text-decoration: none;
}

.tricky-tile__label {
	margin: 0.75rem 0 0;
	font-size: var(--wp--preset--font-size--body);
	font-weight: 600;
}

.tricky-tile:hover .tricky-tile__label a,
.tricky-tile:focus-within .tricky-tile__label a {
	color: var(--wp--preset--color--hover);
}

/*
 * Vertical crop position for cover-cropped Image blocks, as a class (Advanced
 * > Additional CSS class) because the Image block has no focal-point setting
 * and an inline object-position makes the editor flag the block as invalid.
 * The number is the vertical position in percent (50% 25% = a little above
 * centre).
 */
.wp-block-image.crop-y-15 img {
	object-position: 50% 15%;
}

.wp-block-image.crop-y-25 img {
	object-position: 50% 25%;
}

/*
 * Light button hover/focus (styles/blocks/light-button.json, used by the
 * homepage hero's Cover block button). The variation JSON already sets
 * these, but WordPress prints the variation's resting colours after its
 * :hover/:focus-visible colours, both at :where() zero specificity, so the
 * resting colours always win. This restates the hover with real specificity.
 */
.wp-block-button.is-style-light-button .wp-block-button__link:hover,
.wp-block-button.is-style-light-button .wp-block-button__link:focus-visible {
	background-color: var(--wp--preset--color--hover);
	color: var(--wp--preset--color--light);
}

/*
 * Privacy notice under the booking forms' submit button (added to the forms'
 * submit_html in Formidable). Small, secondary text; the link is underlined
 * like other links in running text.
 */
:is(#form_bokamttagning, #form_bokamttagning-en) .frm-privacy-notice {
	margin: 1rem 0 0;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--secondary);
}

:is(#form_bokamttagning, #form_bokamttagning-en) .frm-privacy-notice a {
	color: inherit;
	text-decoration: underline;
}

/*
 * Home hero call button ("Frågor? Ring en människa." / "Questions? Call a
 * human."; class hero-call-button on pages 411 and 44): filled brand red with
 * white text, a step larger than the standard button. White on #aa1818 is
 * 7.4:1 (WCAG AA needs 4.5:1); the hover red #8a1212 is 9.7:1. Hover and
 * keyboard focus both darken it; the focus outline is white because the
 * button sits on a dark photo (the global ink outline would vanish there).
 */
.wp-block-button.hero-call-button .wp-block-button__link {
	background-color: var(--wp--preset--color--hover); /* #aa1818 */
	color: #fff;
	padding: 1rem 2rem;
	font-size: 1.25rem;
	font-weight: 600;
}

/* Phones: less side padding so the Swedish label stays on one line at 390px. */
@media (max-width: 30rem) {
	.wp-block-button.hero-call-button .wp-block-button__link {
		padding-right: 1.25rem;
		padding-left: 1.25rem;
	}
}

.wp-block-button.hero-call-button .wp-block-button__link:hover,
.wp-block-button.hero-call-button .wp-block-button__link:focus-visible {
	background-color: #8a1212;
	color: #fff;
}

.wp-block-button.hero-call-button .wp-block-button__link:focus-visible {
	outline-color: #fff;
}

/*
 * Inspiration galleries (.inspiration-grid, a Group of Image blocks): the
 * Inspiration page and Home's Inspiration section. Laid out like Bomann's own
 * feed: 1 column on phones, 2 on tablets, 3 from 64rem, every image a square
 * centre crop (CSS only; the files keep their full frame) and never shown
 * wider than 640px. The gap is the same both ways.
 */
.inspiration-grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 1.5rem;
}

.inspiration-grid > * {
	margin-block: 0;
}

@media (min-width: 601px) {
	.inspiration-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 64rem) {
	.inspiration-grid {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

.inspiration-grid .wp-block-image {
	max-width: 640px;
}

.inspiration-grid .wp-block-image img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 1;
	object-fit: cover;
	object-position: center;
}

/*
 * "AI visualisation" label: the Image block style of that name (Styles panel
 * in the editor). functions.php adds the label as real text on the site; the
 * editor shows the same label with ::before, since it doesn't run that filter.
 */
.wp-block-image.is-style-ai-visualisation {
	position: relative;
}

.wp-block-image.is-style-ai-visualisation .ai-visualisation-label,
.editor-styles-wrapper .wp-block-image.is-style-ai-visualisation::before {
	position: absolute;
	top: 0.5rem;
	left: 0.5rem;
	z-index: 1;
	padding: 0.125rem 0.5rem;
	background: var(--wp--preset--color--light);
	color: var(--wp--preset--color--ink);
	font-size: var(--wp--preset--font-size--small);
	line-height: 1.5;
}

.editor-styles-wrapper .wp-block-image.is-style-ai-visualisation::before {
	content: "AI visualisation";
}

/*
 * Våra projekt's room-category jump links (.project-filters paragraph):
 * pill buttons instead of plain inline text links, so it reads as a set of
 * filters rather than a run-on sentence. gap handles the spacing the old
 * " · " separators used to -- the markup carries none any more.
 */
.project-filters {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
}

.project-filters a {
	display: inline-flex;
	align-items: center;
	padding: 0.4rem 1rem;
	/* Dark red outline by default -- a neutral ink border didn't read as
	   clickable; red (the same token used for the filled/selected and hover
	   states below) signals it up front. */
	border: 1px solid var(--wp--preset--color--hover);
	/* Same radius as the header's "Boka måttagning" nav CTA (below) and the
	   hero's own button (styles/blocks/light-button.json), not a full pill. */
	border-radius: 4px;
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	color: var(--wp--preset--color--ink);
	text-decoration: none;
}

/*
 * Hover matches the filled/selected look below (dark red fill, light text)
 * rather than a lighter hint -- hovering any pill previews what clicking it
 * looks like, not a separate third state.
 */
.project-filters a:hover,
.project-filters a:focus-visible {
	background-color: var(--wp--preset--color--hover);
	color: var(--wp--preset--color--light);
}

/*
 * Filled state for whichever room the URL's #fragment currently points at.
 * :target only reflects the address bar, not scroll position, which is
 * exactly right here -- these are click-to-jump filters, not a
 * continuously-updating scroll-spy, so no JS is needed. :has() lets a
 * descendant's :target state style an unrelated element elsewhere in the
 * same scope (the pattern this theme already uses for the swatch-grid and
 * FAQ-item counters, in the same stylesheet).
 */
.wp-block-post-content:has(#bedroom:target) .project-filters a[href="#bedroom"],
.wp-block-post-content:has(#sloped-ceiling:target) .project-filters a[href="#sloped-ceiling"],
.wp-block-post-content:has(#under-stairs:target) .project-filters a[href="#under-stairs"],
.wp-block-post-content:has(#stairwell:target) .project-filters a[href="#stairwell"],
.wp-block-post-content:has(#room-divider:target) .project-filters a[href="#room-divider"],
.wp-block-post-content:has(#hall:target) .project-filters a[href="#hall"],
.wp-block-post-content:has(#walk-in:target) .project-filters a[href="#walk-in"],
.wp-block-post-content:has(#showroom:target) .project-filters a[href="#showroom"] {
	background-color: var(--wp--preset--color--hover);
	border-color: var(--wp--preset--color--hover);
	color: var(--wp--preset--color--light);
}

/*
 * Booking page, top section (50 / 416): the eyebrow, H1, line and call button
 * on the left, a team photo with a caption on the right, vertically centred
 * against each other. The photo has a fixed 4:3 shape (it never depends on the
 * text beside it). On phones the columns stack: text and button first, then the
 * photo. 4px corners, the radius of the site's buttons and pills.
 */
.page-photo-columns .page-photo {
	margin: 0;
}

.page-photo-columns .page-photo img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 4 / 3;
	object-fit: cover;
	object-position: 50% 30%;
	border-radius: 4px;
}

/*
 * Home hero slider (.hero-slider; assets/js/hero-slider.js). Replaces the
 * single Cover block: the slides are Image blocks (.hero-slide) stacked behind
 * the heading, subhead and call button (.hero-slider__content), which stay put.
 * The same radial "hero-overlay" gradient the Cover used sits over the photos
 * so the white text stays readable on any of them. Scoped to .wp-site-blocks
 * (the front end), so in the block editor the slides show as a normal stack of
 * images and stay easy to edit. Before the script runs the first slide shows.
 */
.wp-site-blocks .hero-slider {
	position: relative;
	display: flex;
	align-items: flex-end;
	min-height: 70vh;
	overflow: hidden;
}

.wp-site-blocks .hero-slider > * {
	margin-block: 0;
}

.wp-site-blocks .hero-slider::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	background: var(--wp--preset--gradient--hero-overlay);
	pointer-events: none;
}

.wp-site-blocks .hero-slider__slides {
	position: absolute;
	inset: 0;
	max-width: none;
}

.wp-site-blocks .hero-slider .hero-slide {
	position: absolute;
	inset: 0;
	max-width: none;
	margin: 0;
	opacity: 0;
	transition: opacity 0.9s ease;
}

.wp-site-blocks .hero-slider .hero-slide:first-child,
.wp-site-blocks .hero-slider .hero-slide.is-active {
	opacity: 1;
}

.wp-site-blocks .hero-slider.is-enhanced .hero-slide:first-child:not(.is-active) {
	opacity: 0;
}

.wp-site-blocks .hero-slider .hero-slide img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.wp-site-blocks .hero-slider__content {
	position: relative;
	z-index: 2;
	width: 100%;
	padding-top: 2rem;
	padding-bottom: 2rem;
}

/* Keeps the heading and subhead readable over the lighter parts of a photo
   (the sky in the building shot), where the gradient has already faded out. */
.wp-site-blocks .hero-slider__content :is(h1, p) {
	text-shadow: 0 1px 4px rgba(0, 0, 0, 0.55);
}

.hero-slider__controls {
	position: absolute;
	right: var(--wp--preset--spacing--gutter);
	bottom: 1.25rem;
	z-index: 3;
	display: flex;
	align-items: center;
	gap: 0.125rem;
	padding: 0.125rem 0.375rem;
	border-radius: 999px;
	background: rgba(26, 26, 26, 0.55);
}

/* 28px hit areas (WCAG 2.2 target size) around the small visible dot/icon. */
.hero-slider__dot,
.hero-slider__toggle {
	position: relative;
	width: 1.75rem;
	height: 1.75rem;
	padding: 0;
	border: 0;
	background: transparent;
	color: #fff;
	cursor: pointer;
}

.hero-slider__dot::before {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	width: 0.625rem;
	height: 0.625rem;
	margin: -0.3125rem 0 0 -0.3125rem;
	border: 1.5px solid #fff;
	border-radius: 50%;
	background: transparent;
}

.hero-slider__dot.is-active::before {
	background: #fff;
}

/* Pause / play icon, drawn in CSS so it needs no image. */
.hero-slider__toggle::before,
.hero-slider__toggle::after {
	content: "";
	position: absolute;
	top: 50%;
	height: 0.75rem;
	margin-top: -0.375rem;
	background: #fff;
}

.hero-slider__toggle::before {
	left: calc(50% - 0.3125rem);
	width: 0.1875rem;
}

.hero-slider__toggle::after {
	left: calc(50% + 0.125rem);
	width: 0.1875rem;
}

.hero-slider__toggle.is-paused::before {
	left: calc(50% - 0.25rem);
	width: 0.625rem;
	clip-path: polygon(0 0, 100% 50%, 0 100%);
}

.hero-slider__toggle.is-paused::after {
	display: none;
}

.hero-slider__dot:focus-visible,
.hero-slider__toggle:focus-visible {
	outline: 2px solid #fff;
	outline-offset: 0;
	border-radius: 50%;
}

@media (prefers-reduced-motion: reduce) {
	.wp-site-blocks .hero-slider .hero-slide {
		transition: none;
	}
}
