/**
 * Acoustic Calculator
 *
 * Palette, gradient and type scale are inherited from the wdm-stigarm theme:
 *   --font-300…700  Keiner
 *   #212121 text · #6B6D63 muted · #C2CBD4 border
 *   gradient 270deg #099734 → #12B846 → #1BDA58 → #12BF86 → #09A3B5
 */

/* Tokens live on their own selector: the select menus are rendered into a
   layer on <body>, outside .acoucalc, and need the same palette and motion
   scale. Everything below the token block is calculator layout and stays
   on .acoucalc alone. */
.acoucalc,
.acoucalc-select-layer {
	--ac-ink: #212121;
	--ac-ink-soft: #6B6D63;
	--ac-line: #E4E8EC;
	--ac-line-strong: #C2CBD4;
	--ac-surface: #fff;
	--ac-canvas: #F6F8F9;
	--ac-green: #1BDA58;
	--ac-teal: #09A3B5;
	--ac-mint: #12BF86;
	--ac-danger: #B22020;
	/* Brand teal at text weight. --ac-teal itself is only 2.8:1 on white, so
	   anything that carries a label or a hairline uses this shade instead —
	   same hue (186°) and saturation, dropped in value to 4.8:1. */
	--ac-teal-ink: #0B7F8D;
	/* Placeholder text. The old #868D95 was 3.4:1 on white and 3.2:1 on the
	   canvas — under AA either way, and WAVE flagged every material select for
	   it. Same hue (212°) and saturation, dropped in value to 4.9:1 on white
	   and 4.6:1 on the canvas, so it clears AA on both surfaces the calculator
	   paints and still reads as a prompt rather than an answer. */
	--ac-ink-faint: #6B727A;
	/* Room figures. The neutrals are teal-leaning, not blue-grey: the old
	   #E3E9ED/#D2D9DF sat at hue 205° and read cold against a 186° brand. */
	--ac-fig-edge: #6E8082;
	--ac-fig-top-lit: #FFFFFF;
	--ac-fig-top-shade: #EDF4F4;
	--ac-fig-left: #E0EAEA;
	--ac-fig-right: #CBD9DA;
	--ac-fig-ghost: #97A9AB;
	--ac-fig-witness: #9CCBD3;
	--ac-gradient: linear-gradient(270deg, #099734 0%, #12B846 18.03%, #1BDA58 36.05%, #12BF86 54.08%, #09A3B5 72.1%);
	--ac-radius: 14px;
	--ac-radius-sm: 8px;
	/* Width reserved for the "+ Treatment" column. Every surface row is its
	   own grid, so an `auto` track collapses on the rows that carry no button
	   — the floor, and the header — and the tracks left of it stretch to fill
	   the space, throwing those rows out of line with the rest. A definite
	   track keeps all four columns identical whether the button is there or
	   not. The button stretches into it, so this is also its width — measured
	   in Chrome, "+ Treatment" fits in 110px, so 150 left 40px of dead space
	   inside the pill and 124 leaves it a comfortable but not baggy 14. The
	   width it gives up goes to the material select, which can use it. */
	--ac-treat-col: 124px;
	/* Motion. One curve for anything that settles into place — a long tail that
	   decelerates hard, the feel Apple's interfaces have — and one that
	   overshoots slightly for things that arrive rather than move. Durations are
	   a three-step scale so nothing in here drifts out of step with the rest.
	   Everything driven from JS reads the same numbers, so retuning motion means
	   editing these five lines and nothing else. */
	--ac-ease: cubic-bezier(0.32, 0.72, 0, 1);
	--ac-ease-spring: cubic-bezier(0.34, 1.4, 0.5, 1);
	--ac-dur-fast: 0.18s;
	--ac-dur: 0.34s;
	--ac-dur-slow: 0.52s;
}

.acoucalc {
	max-width: 1120px;
	margin: 0 auto;
	/* The host page may have any background — this theme uses a saturated
	   gradient — so the calculator carries its own surface and never relies
	   on what sits behind it for contrast. */
	padding: clamp(20px, 3vw, 44px);
	background: var(--ac-canvas);
	border-radius: 20px;
	color: var(--ac-ink);
	font-family: var(--font-400, "Keiner 400", system-ui, sans-serif);
	font-size: 16px;
	line-height: 1.45;
	letter-spacing: -0.01em;
	text-align: left;
}

/*
 * The `hidden` attribute has to win.
 *
 * The browser's own rule for it is `[hidden] { display: none }` at the user
 * agent level, which any author `display` in this file outranks. So every
 * element here that is given a display — a grid, a flex row, a block — quietly
 * stops honouring `hidden`, and the JS that sets it appears to do nothing.
 * This was being patched one selector at a time as each case was noticed:
 * three more were not, and the second-height field, the report panel and the
 * metrics strip were all being "hidden" while staying on screen. It also
 * breaks the motion helpers outright — slide() collapses a box to nothing and
 * then hands it back at full height.
 *
 * One rule instead, and a test that keeps it honest: the audit in MOTION.md
 * sets `hidden` on every element the code hides and asserts each one computes
 * to display:none.
 */
.acoucalc [hidden] {
	display: none;
}

.acoucalc *,
.acoucalc *::before,
.acoucalc *::after,
.acoucalc-select-layer,
.acoucalc-select-layer *,
.acoucalc-select-layer *::before,
.acoucalc-select-layer *::after {
	box-sizing: border-box;
}

.acoucalc .screen-reader-text {
	position: absolute !important;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(1px, 1px, 1px, 1px);
	clip-path: inset(50%);
	white-space: nowrap;
}

/* ── intro ───────────────────────────────────────────────── */

.acoucalc__intro {
	margin-bottom: 40px;
}

/* Matches the theme's own small text: Keiner 600, uppercase like its headings,
   tight tracking, breadcrumb ink. The previous 0.14em gradient treatment was
   alien to the typeface and to the rest of the site. */
.acoucalc__eyebrow {
	margin: 0 0 14px;
	font-family: var(--font-600, "Keiner 600", sans-serif);
	font-size: 14px;
	line-height: 1.2;
	letter-spacing: -0.01em;
	text-transform: uppercase;
	color: var(--ac-ink-soft);
}

.acoucalc__title {
	margin: 0 0 16px;
	font-family: var(--font-600, "Keiner 600", sans-serif);
	font-size: clamp(28px, 3.2vw, 40px);
	line-height: 1.1;
	letter-spacing: -0.01em;
	text-transform: uppercase;
}

.acoucalc__subtitle {
	max-width: 62ch;
	margin: 0;
	font-size: 17px;
	color: var(--ac-ink-soft);
}

/* ── step shell ──────────────────────────────────────────── */

.acoucalc-step {
	position: relative;
	margin-bottom: 20px;
	background: var(--ac-surface);
	border: 1px solid var(--ac-line);
	border-radius: var(--ac-radius);
	box-shadow: 0 1px 2px rgba(33, 33, 33, 0.03), 0 12px 32px -20px rgba(33, 33, 33, 0.18);
	overflow: hidden;
}

.acoucalc-step__head {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 14px;
	padding: 22px 28px;
	border-bottom: 1px solid var(--ac-line);
	background: linear-gradient(180deg, #FBFCFC 0%, #fff 100%);
}

.acoucalc-step__num {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 30px;
	height: 30px;
	border-radius: 50%;
	background: var(--ac-gradient);
	color: #fff;
	font-family: var(--font-600, "Keiner 600", sans-serif);
	font-size: 14px;
	line-height: 1;
}

.acoucalc-step__title {
	margin: 0;
	font-family: var(--font-600, "Keiner 600", sans-serif);
	font-size: 20px;
	letter-spacing: -0.015em;
}

.acoucalc-step__note {
	flex: 1 1 260px;
	margin: 0;
	font-size: 13px;
	line-height: 1.4;
	color: var(--ac-ink-soft);
}

.acoucalc-step__controls {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
	margin-left: auto;
}

.acoucalc-step__body {
	padding: 28px;
}

/* ── fields ──────────────────────────────────────────────── */

.acoucalc-field {
	display: block;
	margin-bottom: 18px;
}

.acoucalc-field--wide {
	max-width: 520px;
}

.acoucalc-field > label,
.acoucalc-custom label > span {
	display: block;
	margin-bottom: 7px;
	font-family: var(--font-500, "Keiner 500", sans-serif);
	font-size: 12px;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--ac-ink-soft);
}

.acoucalc input[type="text"],
.acoucalc input[type="email"],
.acoucalc select {
	width: 100%;
	height: 48px;
	padding: 0 14px;
	background: #fff;
	border: 1px solid var(--ac-line-strong);
	border-radius: var(--ac-radius-sm);
	color: var(--ac-ink);
	font-family: inherit;
	font-size: 15px;
	line-height: 46px;
	-webkit-appearance: none;
	appearance: none;
	transition: border-color 0.18s ease, box-shadow 0.18s ease;
}

.acoucalc input::placeholder {
	color: var(--ac-ink-faint);
}

.acoucalc input:focus,
.acoucalc select:focus {
	outline: none;
	border-color: var(--ac-mint);
	box-shadow: 0 0 0 3px rgba(18, 191, 134, 0.16);
}

.acoucalc-input {
	position: relative;
}

.acoucalc-input input {
	padding-right: 42px;
}

.acoucalc-unit {
	position: absolute;
	top: 50%;
	right: 14px;
	transform: translateY(-50%);
	pointer-events: none;
	font-size: 13px;
	color: var(--ac-ink-soft);
}

.acoucalc-select {
	position: relative;
}

.acoucalc-select::after {
	content: "";
	position: absolute;
	top: 50%;
	right: 16px;
	width: 8px;
	height: 8px;
	margin-top: -6px;
	border-right: 1.5px solid var(--ac-ink);
	border-bottom: 1.5px solid var(--ac-ink);
	transform: rotate(45deg);
	pointer-events: none;
}

.acoucalc-select select {
	padding-right: 38px;
	line-height: normal;
	cursor: pointer;
}

/* ── the dropdown ────────────────────────────────────────────
 *
 * Everything above styles the native <select>, which is what a reader without
 * JavaScript gets. With JavaScript the select is kept as the value store and
 * hidden, and the rules below dress the button and listbox drawn in its place
 * — a native popup is painted by the OS and cannot carry the calculator's
 * type, spacing or motion.
 *
 * The menu itself is not here: it is rendered into `.acoucalc-select-layer`
 * on <body>, because the cards these controls sit in are overflow:hidden and
 * would clip a menu positioned inside them. Its rules are further down, on
 * that layer.
 */

.acoucalc-select.is-enhanced::after {
	display: none;
}

/* Off-screen, not display:none — it stays a real form control holding the
   value, and a hidden field is one the browser will not restore on a back
   navigation. Clipped the way .screen-reader-text is, and with the same
   !important, because the size rules further down are written against
   `.acoucalc-select select` and would otherwise win on order. */
.acoucalc .acoucalc-select__native {
	position: absolute !important;
	width: 1px !important;
	height: 1px !important;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	clip-path: inset(50%);
	border: 0;
	white-space: nowrap;
	pointer-events: none;
}

.acoucalc-select__trigger {
	display: flex;
	align-items: center;
	gap: 10px;
	width: 100%;
	height: 48px;
	padding: 0 14px;
	background: #fff;
	border: 1px solid var(--ac-line-strong);
	border-radius: var(--ac-radius-sm);
	color: var(--ac-ink);
	font-family: inherit;
	font-size: 15px;
	line-height: 1.2;
	text-align: left;
	cursor: pointer;
	transition: border-color var(--ac-dur-fast) ease, box-shadow var(--ac-dur-fast) ease,
		background-color var(--ac-dur-fast) ease;
}

.acoucalc-select__trigger:hover {
	border-color: #9AA6B2;
}

.acoucalc-select__value {
	flex: 1;
	min-width: 0;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
}

/* Nothing chosen yet: same grey the inputs give their placeholder, so an
   untouched row reads as one empty line rather than two different ones. */
.acoucalc-select__trigger.is-empty .acoucalc-select__value {
	color: var(--ac-ink-faint);
}

.acoucalc-select__chevron {
	flex: none;
	width: 10px;
	height: 6px;
	color: var(--ac-ink-soft);
	transition: transform var(--ac-dur) var(--ac-ease), color var(--ac-dur-fast) ease;
}

.acoucalc-select__trigger:focus {
	outline: none;
}

.acoucalc-select__trigger:focus-visible,
.acoucalc-select__trigger[aria-expanded="true"] {
	border-color: var(--ac-mint);
	box-shadow: 0 0 0 3px rgba(18, 191, 134, 0.16);
}

.acoucalc-select__trigger[aria-expanded="true"] .acoucalc-select__chevron {
	transform: rotate(180deg);
	color: var(--ac-mint);
}

/* Size variants, matching the native rules they replace. */
.acoucalc-select--inline .acoucalc-select__trigger {
	height: 40px;
	border-radius: 20px;
	padding: 0 18px;
	font-size: 14px;
}

.acoucalc-surface .acoucalc-select__trigger,
.acoucalc-treatment .acoucalc-select__trigger {
	height: 44px;
	font-size: 14px;
}

/* ── the menu layer ──────────────────────────────────────── */

/* This one keeps its own: the layer is appended to the body, outside
   .acoucalc, so the blanket rule at the top of the file cannot reach it. */
.acoucalc-select-layer[hidden] {
	display: none;
}

.acoucalc-select-layer {
	position: fixed;
	inset: 0;
	z-index: 99990;
	pointer-events: none;
	font-family: var(--font-400, "Keiner 400", system-ui, sans-serif);
	color: var(--ac-ink);
	letter-spacing: -0.01em;
}

/* Only the sheet needs one — on a pointer device an outside click is caught
   on the document instead, so the page keeps its normal hover and scroll. */
.acoucalc-select__backdrop {
	position: absolute;
	inset: 0;
	background: rgba(20, 26, 28, 0.38);
	/* The sheet floats over the page rather than locking its scroll: a lock
	   shifts the layout underneath, and this stops the drag without it. */
	touch-action: none;
	opacity: 0;
	transition: opacity var(--ac-dur) var(--ac-ease);
}

.acoucalc-select-layer.is-sheet.is-open .acoucalc-select__backdrop {
	pointer-events: auto;
	opacity: 1;
}

.acoucalc-select__menu {
	position: absolute;
	top: 0;
	left: 0;
	display: flex;
	flex-direction: column;
	max-height: 320px;
	padding: 6px;
	background: var(--ac-surface);
	border: 1px solid var(--ac-line);
	border-radius: var(--ac-radius);
	/* Two shadows: a wide soft cast that lifts the card off the page, and a
	   tight one that keeps its edge readable against a white panel. */
	box-shadow: 0 20px 44px -14px rgba(21, 31, 33, 0.28), 0 2px 8px rgba(21, 31, 33, 0.06);
	pointer-events: auto;
	opacity: 0;
	transform: translateY(-8px) scale(0.97);
	transform-origin: top center;
	transition: opacity var(--ac-dur-fast) var(--ac-ease), transform var(--ac-dur) var(--ac-ease);
}

/* Opening upwards: grow from the bottom edge, so the motion still reads as
   the menu coming out of the button. */
.acoucalc-select__menu.is-up {
	transform: translateY(8px) scale(0.97);
	transform-origin: bottom center;
}

.acoucalc-select__menu.is-open {
	opacity: 1;
	transform: none;
}

.acoucalc-select__menu:focus {
	outline: none;
}

.acoucalc-select__scroll {
	/* The offsetParent the script measures rows against when scrolling the
	   highlight into view. */
	position: relative;
	/* A flex item will not shrink below its content without this, and the
	   menu's max-height would then be the list's height. */
	min-height: 0;
	overflow-y: auto;
	overscroll-behavior: contain;
	-webkit-overflow-scrolling: touch;
	scrollbar-width: thin;
	scrollbar-color: var(--ac-line-strong) transparent;
}

.acoucalc-select__scroll::-webkit-scrollbar {
	width: 6px;
}

.acoucalc-select__scroll::-webkit-scrollbar-thumb {
	background: var(--ac-line-strong);
	border-radius: 3px;
}

.acoucalc-select__option {
	display: flex;
	align-items: center;
	gap: 10px;
	min-height: 40px;
	padding: 8px 10px 8px 12px;
	border-radius: var(--ac-radius-sm);
	font-size: 14.5px;
	line-height: 1.3;
	cursor: pointer;
	transition: background-color var(--ac-dur-fast) ease, color var(--ac-dur-fast) ease;
}

.acoucalc-select__option + .acoucalc-select__option {
	margin-top: 1px;
}

.acoucalc-select__label {
	flex: 1;
	min-width: 0;
}

/* One highlight, driven from the script, so pointer and keyboard land on the
   same row — a :hover rule of its own would light a second row whenever the
   pointer happens to rest over the list while the arrows are being used. */
.acoucalc-select__option.is-active {
	background: var(--ac-canvas);
}

.acoucalc-select__option[aria-selected="true"] {
	background: rgba(18, 191, 134, 0.1);
	font-family: var(--font-500, "Keiner 500", sans-serif);
}

.acoucalc-select__option[aria-selected="true"].is-active {
	background: rgba(18, 191, 134, 0.18);
}

.acoucalc-select__option.is-blank {
	color: var(--ac-ink-soft);
}

.acoucalc-select__option.is-blank[aria-selected="true"] {
	background: transparent;
	font-family: inherit;
}

.acoucalc-select__option.is-blank[aria-selected="true"].is-active {
	background: var(--ac-canvas);
}

.acoucalc-select__option.is-blank .acoucalc-select__tick {
	display: none;
}

.acoucalc-select__option[aria-disabled="true"] {
	color: var(--ac-ink-soft);
	opacity: 0.55;
	cursor: default;
}

.acoucalc-select__tick {
	flex: none;
	width: 13px;
	height: 10px;
	color: var(--ac-mint);
	opacity: 0;
	transform: scale(0.6);
	transition: opacity var(--ac-dur-fast) var(--ac-ease), transform var(--ac-dur) var(--ac-ease-spring);
}

.acoucalc-select__option[aria-selected="true"] .acoucalc-select__tick {
	opacity: 1;
	transform: none;
}

.acoucalc-select__grouplabel {
	padding: 12px 12px 6px;
	font-family: var(--font-500, "Keiner 500", sans-serif);
	font-size: 11px;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--ac-ink-soft);
}

.acoucalc-select__group + .acoucalc-select__group,
.acoucalc-select__option + .acoucalc-select__group {
	margin-top: 4px;
	border-top: 1px solid var(--ac-line);
}

/* The sheet's header. Present in the markup at every width so the listbox
   keeps its accessible name; only shown once the menu becomes a sheet. */
.acoucalc-select__head {
	display: none;
}

/* ── the menu as a sheet ─────────────────────────────────── */

/*
 * On a phone a menu anchored to a 44px button has almost no room to open
 * into, and the finger covers what little there is. It becomes a sheet on the
 * bottom edge instead — the same list, at a size a thumb can hit.
 *
 * 600px rather than the 782px the layout reflows at: this is a question of
 * touch and of how much height there is above the fold, not of how many
 * columns fit, and a 700px window is still a pointer sitting at a desk.
 */
.acoucalc-select-layer.is-sheet .acoucalc-select__menu {
	top: auto !important;
	right: 8px;
	bottom: 0;
	left: 8px !important;
	width: auto !important;
	max-height: min(66vh, 460px) !important;
	padding: 0 8px calc(8px + env(safe-area-inset-bottom, 0px));
	border-radius: 22px 22px 0 0;
	border-bottom: 0;
	transform: translateY(101%);
	transform-origin: bottom center;
	transition: transform var(--ac-dur-slow) var(--ac-ease), opacity var(--ac-dur-fast) linear;
}

.acoucalc-select-layer.is-sheet .acoucalc-select__menu.is-open {
	transform: none;
}

/* The handle. `touch-action: none` is what lets the script see the whole
   gesture: without it the browser claims a vertical drag for the page before
   the second pointermove arrives, and the sheet moves a few pixels and stops.
   The padding is deliberate — 8/10 around a 4px bar and its caption is a 46px
   strip, which is the target, not the bar. */
.acoucalc-select-layer.is-sheet .acoucalc-select__head {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 10px;
	padding: 8px 4px 10px;
	touch-action: none;
	cursor: grab;
	user-select: none;
	-webkit-user-select: none;
}

.acoucalc-select-layer.is-sheet .acoucalc-select__head:active {
	cursor: grabbing;
}

.acoucalc-select__grip {
	width: 38px;
	height: 4px;
	border-radius: 2px;
	background: var(--ac-line-strong);
	transition: background-color var(--ac-dur-fast) ease;
}

/* Under the finger the sheet is following the pointer frame by frame, so the
   transition that normally smooths its arrival has to be out of the way — it
   would otherwise chase every move a fifth of a second behind it. The grip
   darkens because a handle that does not acknowledge being held reads as one
   that was not grabbed. */
.acoucalc-select-layer.is-sheet .acoucalc-select__menu.is-dragging {
	transition: none;
}

.acoucalc-select__menu.is-dragging .acoucalc-select__grip {
	background: var(--ac-ink-soft);
}

.acoucalc-select__title {
	font-family: var(--font-500, "Keiner 500", sans-serif);
	font-size: 12px;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--ac-ink-soft);
}

.acoucalc-select-layer.is-sheet .acoucalc-select__option {
	min-height: 48px;
	font-size: 15px;
}

@media (prefers-reduced-motion: reduce) {
	.acoucalc-select__menu,
	.acoucalc-select-layer.is-sheet .acoucalc-select__menu,
	.acoucalc-select__backdrop,
	.acoucalc-select__tick,
	.acoucalc-select__chevron {
		transition-duration: 0.01ms;
	}

	.acoucalc-select__menu,
	.acoucalc-select-layer.is-sheet .acoucalc-select__menu {
		transform: none;
	}
}

/* ── chips & toggles ─────────────────────────────────────── */

.acoucalc-shape {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin-bottom: 24px;
}

.acoucalc-chip {
	padding: 0 18px;
	height: 40px;
	background: #fff;
	border: 1px solid var(--ac-line-strong);
	border-radius: 20px;
	color: var(--ac-ink);
	font-family: inherit;
	font-size: 14px;
	cursor: pointer;
	transition: all 0.18s ease;
}

.acoucalc-chip:hover {
	border-color: var(--ac-ink);
}

.acoucalc-chip.is-active {
	background: var(--ac-ink);
	border-color: var(--ac-ink);
	color: #fff;
}

/*
 * Equal segments, always. The buttons were sized to their own labels, so the
 * m/ft pair came out 53px and 49px and the pill that parks over the selected
 * one changed width as it moved — on a control this small the two halves
 * reading as different sizes is the whole of what makes it look wrong.
 * `grid-auto-columns: 1fr` in a shrink-to-fit grid gives every track the
 * widest track's max-content width, which is the equalisation an inline-flex
 * row cannot do: `flex: 1` there still resolves against a container sized to
 * the sum of the items. The pill is absolutely positioned and so out of flow,
 * which is why it can stay the grid's first child without claiming a column.
 */
.acoucalc-toggle {
	position: relative;
	display: inline-grid;
	grid-auto-flow: column;
	grid-auto-columns: 1fr;
	padding: 3px;
	background: var(--ac-canvas);
	border: 1px solid var(--ac-line);
	border-radius: 22px;
}

.acoucalc-toggle button {
	padding: 0 16px;
	height: 34px;
	background: transparent;
	border: 0;
	border-radius: 18px;
	color: var(--ac-ink-soft);
	font-family: inherit;
	font-size: 13px;
	cursor: pointer;
	transition: all 0.18s ease;
}

.acoucalc-toggle button.is-active {
	background: #fff;
	color: var(--ac-ink);
	box-shadow: 0 1px 3px rgba(33, 33, 33, 0.12);
}

.acoucalc-select--inline select {
	height: 40px;
	border-radius: 20px;
	font-size: 14px;
}

.acoucalc-select--inline::after {
	right: 18px;
}

/* ── geometry grid ───────────────────────────────────────── */

/* ── room diagram + dimensions ───────────────────────────── */

.acoucalc-room {
	display: grid;
	grid-template-columns: minmax(210px, 0.8fr) minmax(0, 1.2fr);
	gap: 32px;
	align-items: start;
	margin-bottom: 28px;
}

/* All figures stay stacked in the same box so they can cross-fade. The box
   holds its own height from the shared viewBox ratio, so nothing reflows when
   the shape changes. */
.acoucalc-room__figure {
	position: relative;
	width: 100%;
	max-width: 320px;
	margin: 0;
	aspect-ratio: 266 / 202;
}

.acoucalc-room__figure svg {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	opacity: 0;
	visibility: hidden;
	transform: translateY(8px) scale(0.985);
	transition:
		opacity 0.32s cubic-bezier(0.22, 0.61, 0.36, 1),
		transform 0.32s cubic-bezier(0.22, 0.61, 0.36, 1),
		visibility 0s linear 0.32s;
}

.acoucalc-room__figure svg.is-active {
	opacity: 1;
	visibility: visible;
	transform: none;
	transition:
		opacity 0.32s cubic-bezier(0.22, 0.61, 0.36, 1),
		transform 0.32s cubic-bezier(0.22, 0.61, 0.36, 1),
		visibility 0s;
}

@media (prefers-reduced-motion: reduce) {
	.acoucalc-room__figure svg,
	.acoucalc-room__figure svg.is-active {
		transition: none;
	}
}

/* Paint-server holder: carries no geometry, so it must not join the cross-fade
   stack or sit over the live figure as a transparent sheet. */
.acoucalc-room__figure svg.acoucalc-fig__defs {
	position: absolute;
	width: 0;
	height: 0;
	pointer-events: none;
}

.acoucalc-fig__stop-lit {
	stop-color: var(--ac-fig-top-lit);
}

.acoucalc-fig__stop-shade {
	stop-color: var(--ac-fig-top-shade);
}

/* The footprint, blurred and dropped a few units — the solid reads as sitting
   on a surface rather than floating. It is the same parallelogram in all three
   shapes, which is why it can be identical markup: only the roof ever moves.
   Tinted with the brand teal rather than neutral black so the shade stays in
   the palette. Without blur support it degrades to a thin tinted sliver along
   the near edges, which is still the right idea. */
.acoucalc-fig__shadow {
	fill: var(--ac-teal-ink);
	opacity: 0.15;
	filter: blur(5px);
	transform: translateY(6px);
}

.acoucalc-fig__solid path {
	stroke: var(--ac-fig-edge);
	stroke-width: 1.1;
	stroke-linejoin: round;
}

/* Three faces, three tones: the roof catches the most light, the two walls
   step down from it. Isometric means only these three are ever visible.
   The roof takes a gradient rather than a flat tone — a single value over a
   plane that large is what made the solid read as a sticker. */
.acoucalc-fig__roof {
	fill: url(#acoucalc-fig-top);
}

.acoucalc-fig__left {
	fill: var(--ac-fig-left);
}

.acoucalc-fig__right {
	fill: var(--ac-fig-right);
}

.acoucalc-fig__solid--ghost path {
	fill: none;
	stroke-dasharray: 5 4;
	stroke: var(--ac-fig-ghost);
}

.acoucalc-fig__dim path {
	fill: none;
	stroke: var(--ac-teal-ink);
	stroke-width: 1.1;
	stroke-linecap: round;
}

/* Both need to out-specify `.acoucalc-fig__dim path` (0,1,1) above, or the
   arrowheads inherit fill:none and render hollow. */
.acoucalc-fig__dim path.acoucalc-fig__witness {
	stroke: var(--ac-fig-witness);
	stroke-width: 0.8;
}

.acoucalc-fig__dim path.acoucalc-fig__arrow {
	fill: var(--ac-teal-ink);
	stroke: none;
}

.acoucalc-fig__dim--inner {
	stroke-dasharray: 4 4;
}

/* A halo so a label can cross its own leader line — the pitched H₂ sits on
   one. Kept to roughly two line-widths: enough to break a 1.1 hairline, tight
   enough that it reads as an outline and not a knockout box on the face it
   happens to be over. */
.acoucalc-fig__dim text {
	fill: var(--ac-teal-ink);
	font-family: var(--font-600, "Keiner 600", sans-serif);
	font-size: 15px;
	letter-spacing: -0.01em;
	paint-order: stroke fill;
	stroke: var(--ac-surface);
	stroke-width: 2.2px;
	stroke-linejoin: round;
}

.acoucalc-fig__volume {
	font-size: 34px;
}

/* The L / B / H after a field label is the same symbol as the one on the
   figure, so it has to be the same ink — they are read as a pair. */
.acoucalc-field__letter {
	margin-left: 2px;
	color: var(--ac-teal-ink);
	text-transform: none;
}

.acoucalc-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
	gap: 16px;
}

.acoucalc-grid .acoucalc-field {
	margin-bottom: 0;
}

.acoucalc-derived {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
	gap: 1px;
	margin: 0;
	padding: 0;
	background: var(--ac-line);
	border: 1px solid var(--ac-line);
	border-radius: var(--ac-radius-sm);
	overflow: hidden;
}

.acoucalc-derived__item {
	padding: 16px 18px;
	background: #FBFCFC;
}

.acoucalc-derived dt {
	margin: 0 0 4px;
	font-size: 12px;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--ac-ink-soft);
}

.acoucalc-derived dd {
	margin: 0;
	font-family: var(--font-600, "Keiner 600", sans-serif);
	font-size: 22px;
	letter-spacing: -0.02em;
	font-variant-numeric: tabular-nums;
}

/* The figure counts to its new value rather than cutting to it, so it needs a
   box of its own to lift in — an inline span cannot be transformed. */
.acoucalc-derived dd [data-out] {
	display: inline-block;
}

.acoucalc-derived dd i {
	font-style: normal;
	font-size: 13px;
	font-family: var(--font-400, "Keiner 400", sans-serif);
	color: var(--ac-ink-soft);
}

/* ── surfaces ────────────────────────────────────────────── */

.acoucalc-surfaces {
	border: 1px solid var(--ac-line);
	border-radius: var(--ac-radius-sm);
	overflow: hidden;
}

.acoucalc-surfaces__head,
.acoucalc-surface__row {
	display: grid;
	grid-template-columns: minmax(150px, 1.1fr) 130px minmax(200px, 1.6fr) var(--ac-treat-col);
	gap: 14px;
	align-items: center;
}

.acoucalc-surfaces__head {
	padding: 12px 20px;
	background: var(--ac-canvas);
	border-bottom: 1px solid var(--ac-line);
	font-size: 11px;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--ac-ink-soft);
}

/* Rows are grouped by section — a room can have more than one wall — so the
   hairline between two sections is drawn between the groups. Inside a group
   the rows are the same surface split up, and a lighter line says so. */
.acoucalc-surface-group + .acoucalc-surface-group {
	border-top: 1px solid var(--ac-line);
}

.acoucalc-surface + .acoucalc-surface {
	border-top: 1px dashed var(--ac-line);
}

/* The row's name and, once the section carries more than one, the control
   that takes this one away. */
.acoucalc-surface__title {
	display: flex;
	align-items: center;
	gap: 8px;
}

.acoucalc-surface__title strong {
	min-width: 0;
}

/* Add another wall. Dashed and quiet: it sits under every section, so it has
   to stay out of the way of the row above it until it is wanted.

   The gap over it is carried here rather than by the row above, because that
   row can end in a filled panel — an open treatment, a grid of custom
   coefficients — whose own padding reads as part of the panel and not as space
   around the button. So there is room under every row, and more under a row
   that is showing one. */
.acoucalc-surfaces__add {
	padding: 12px 20px 16px;
}

.acoucalc-surface.is-treated + .acoucalc-surfaces__add,
.acoucalc-surface.is-custom + .acoucalc-surfaces__add {
	padding-top: 20px;
}

.acoucalc-split {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	height: 30px;
	padding: 0 12px;
	background: transparent;
	border: 1px dashed var(--ac-line-strong);
	border-radius: 15px;
	color: var(--ac-ink-soft);
	font-family: inherit;
	font-size: 12px;
	cursor: pointer;
	transition: all 0.18s ease;
}

.acoucalc-split:hover:not(:disabled) {
	border-color: var(--ac-mint);
	color: #0B7A57;
}

.acoucalc-split:disabled {
	opacity: 0.45;
	cursor: default;
}

.acoucalc-split__icon {
	font-size: 14px;
	line-height: 1;
}

.acoucalc-surface__row {
	padding: 16px 20px;
}

.acoucalc-surface__name strong {
	display: block;
	font-family: var(--font-600, "Keiner 600", sans-serif);
	font-size: 16px;
	font-weight: 400;
}

.acoucalc-surface__name small {
	display: block;
	margin-top: 2px;
	font-size: 12px;
	line-height: 1.3;
	color: var(--ac-ink-soft);
}

/*
 * The compact control, 44px against the 48 a field gets on its own.
 *
 * Qualified with `.acoucalc` purely for weight. The base sizes further up are
 * written as `.acoucalc input[type="text"]` — a class, an attribute and an
 * element — and a bare `.acoucalc-input--sm input` is a class and an element,
 * so the attribute selector outscored the modifier and this rule never
 * applied to a single field. The inputs stayed at 48 while every select
 * beside them, written as a descendant pair and so heavy enough, sat at 44:
 * the mismatch QA filed, and the reason it reads as the input being wrong
 * rather than the select.
 */
.acoucalc .acoucalc-input--sm input {
	height: 44px;
	line-height: 42px;
	font-size: 14px;
}

.acoucalc-surface .acoucalc-select select {
	height: 44px;
	font-size: 14px;
}

.acoucalc-add {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 7px;
	height: 44px;
	padding: 0 14px;
	background: #fff;
	border: 1px dashed var(--ac-line-strong);
	border-radius: 22px;
	color: var(--ac-ink);
	font-family: inherit;
	font-size: 13px;
	white-space: nowrap;
	cursor: pointer;
	transition: all 0.18s ease;
}

/* The button fills the track reserved above, so a locale with a longer word
   than "Treatment" clips its label rather than widening the column and
   knocking this row out of line with the ones that have no button. */
.acoucalc-add__label {
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
}

.acoucalc-add:hover {
	border-color: var(--ac-mint);
	color: #0B7A57;
}

/* The "+" is drawn, not typeset. A glyph centred in an 18px circle reads high
   and left of true centre: flexbox centres its line box, but the ink inside
   sits on the baseline with its own side bearings, and none of that is
   symmetric. Two bars centre on the circle itself, in any font, at any size —
   and still cross into an "×" when the parent rotates. The "+" stays in the
   markup as the no-CSS fallback. */
.acoucalc-add__icon {
	position: relative;
	flex: 0 0 auto;
	width: 18px;
	height: 18px;
	border-radius: 50%;
	background: var(--ac-gradient);
	color: #fff;
	font-size: 0;
	line-height: 1;
	transition: transform 0.18s ease;
}

.acoucalc-add__icon::before,
.acoucalc-add__icon::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	width: 8px;
	height: 2px;
	background: currentColor;
	transform: translate(-50%, -50%);
}

.acoucalc-add__icon::after {
	transform: translate(-50%, -50%) rotate(90deg);
}

.acoucalc-add.is-open {
	border-style: solid;
	border-color: var(--ac-ink);
}

.acoucalc-add.is-open .acoucalc-add__icon {
	transform: rotate(45deg);
}

/* custom coefficients */

.acoucalc-custom {
	padding: 16px 20px 20px;
	background: var(--ac-canvas);
	border-top: 1px dashed var(--ac-line-strong);
}

.acoucalc-custom__title {
	margin: 0 0 12px;
	font-size: 12px;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--ac-ink-soft);
}

.acoucalc-custom__grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(92px, 1fr));
	gap: 10px;
}

.acoucalc-custom__grid input {
	height: 40px;
	line-height: 38px;
	padding: 0 10px;
	font-size: 14px;
}

/* treatment */

.acoucalc-treatment {
	padding: 16px 20px;
	background: linear-gradient(90deg, rgba(27, 218, 88, 0.06), rgba(9, 163, 181, 0.06));
	border-top: 1px solid var(--ac-line);
}

.acoucalc-treatment__row {
	display: grid;
	grid-template-columns: minmax(150px, 1.1fr) 130px minmax(200px, 1.6fr) var(--ac-treat-col);
	gap: 14px;
	align-items: center;
}

.acoucalc-treatment__tag {
	display: inline-flex;
	align-items: center;
	align-self: center;
	height: 26px;
	padding: 0 12px;
	border-radius: 13px;
	background: var(--ac-gradient);
	color: #fff;
	font-size: 11px;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	justify-self: start;
}

/* This row shares the surface row's tracks, so its last column is the same
   reserved width the "+ Treatment" button fills. Centred in that track the
   button floated on an invisible line — the pill's midpoint — with 58px of
   nothing between it and the product select. Ending the track puts its right
   edge on the pill's right edge, which is also the card's content edge and the
   line every header cell and row already stops at. A row's destructive action
   belongs on that edge, not adrift in the middle of a reserved column. */
.acoucalc-remove {
	position: relative;
	justify-self: end;
	width: 36px;
	height: 36px;
	background: #fff;
	border: 1px solid var(--ac-line-strong);
	border-radius: 50%;
	color: var(--ac-ink-soft);
	font-size: 0;
	line-height: 1;
	cursor: pointer;
	transition: all 0.18s ease;
}

/* Drawn, not typeset — the same argument as the "+" above, and this button is
   where it bites hardest: it sets no font-family, so "×" is rendered in
   whatever form-control face the platform hands over. Measured at 20px across
   the faces Chrome will pick, that glyph's ink is 8.1–11.3px tall and its
   centre lands anywhere from 0.05px above the button's centre to 0.55px below
   — the same markup reading centred on one machine and visibly high or low on
   the next, which is exactly what a 36px circle with one mark in it shows off.
   Two bars have no baseline and no side bearings, so they land dead centre in
   any face at any size. 13px of bar leaves the mark ~10.6px across the
   diagonal, inside the range the glyph spanned, so the button keeps its
   weight. "&times;" stays in the markup as the no-CSS fallback. */
.acoucalc-remove::before,
.acoucalc-remove::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	width: 13px;
	height: 2px;
	background: currentColor;
	transform: translate(-50%, -50%) rotate(45deg);
}

.acoucalc-remove::after {
	transform: translate(-50%, -50%) rotate(-45deg);
}

.acoucalc-remove:hover {
	border-color: var(--ac-danger);
	color: var(--ac-danger);
}

/* The same button at row-name scale: it belongs to the name it sits beside,
   not to the row's last column, so it is sized to the text rather than to the
   treatment track. */
.acoucalc-remove--xs {
	flex: 0 0 auto;
	justify-self: auto;
	width: 24px;
	height: 24px;
}

.acoucalc-remove--xs::before,
.acoucalc-remove--xs::after {
	width: 9px;
}

.acoucalc-treatment__note {
	margin: 10px 0 0;
	font-size: 12px;
	color: var(--ac-ink-soft);
}

/* ── results ─────────────────────────────────────────────── */

.acoucalc-empty {
	margin: 0;
	padding: 36px 0;
	text-align: center;
	color: var(--ac-ink-soft);
	font-size: 15px;
}

.acoucalc-kpi {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 22px;
	padding: 26px 28px;
	margin-bottom: 26px;
	background: var(--ac-canvas);
	border: 1px solid var(--ac-line);
	border-radius: var(--ac-radius-sm);
}

.acoucalc-kpi__label {
	display: block;
	margin-bottom: 4px;
	font-size: 11px;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--ac-ink-soft);
}

/* The untreated figure is the baseline, not the headline. Set in the lighter
   weight and the muted ink so the eye lands on the treated block first: the
   two used to be the same size, and near-black beat gradient teal every time. */
.acoucalc-kpi__value {
	display: block;
	font-family: var(--font-500, "Keiner 500", sans-serif);
	font-size: clamp(28px, 3.4vw, 38px);
	line-height: 1;
	letter-spacing: -0.03em;
	font-variant-numeric: tabular-nums;
	color: var(--ac-ink-soft);
}

/* The treated figure is what the calculator is for, and it carries that on
   type alone — no card, no border, no lift. The heavy weight, half again the
   size of the figure it improves on, in the brand gradient, is already the
   loudest thing in the row; a panel around it only fenced it off from the
   baseline it is meant to be read against. */
.acoucalc-kpi__block--accent {
	position: relative;
}

.acoucalc-kpi__block--accent .acoucalc-kpi__label {
	font-family: var(--font-600, "Keiner 600", sans-serif);
	color: var(--ac-teal-ink);
}

.acoucalc-kpi__block--accent .acoucalc-kpi__value {
	font-family: var(--font-700, "Keiner 700", sans-serif);
	font-size: clamp(46px, 6vw, 64px);
	letter-spacing: -0.035em;
	/* The same teal-into-green ramp the wave under it draws, and running the
	   same way across the strip: #09A3B5 at the left, #1BDA58 at the right.
	   The figure and its wave are one object, so they take one colour. The
	   flat colour is what a browser without background-clip:text keeps. */
	color: #12BF86;
	/* sRGB first, then the same ramp interpolated the way the bars mix it.
	   A browser without oklab gradients keeps the line above — which it must,
	   because -webkit-text-fill-color below would otherwise leave the figure
	   invisible rather than merely a shade duller through the middle. */
	background: linear-gradient(270deg, #1BDA58 0%, #09A3B5 100%);
	background: linear-gradient(270deg in oklab, #1BDA58 0%, #09A3B5 100%);
	-webkit-background-clip: text;
	background-clip: text;
	-webkit-text-fill-color: transparent;
}

/* Nothing to celebrate until a treatment is chosen: the figure drops back to
   the muted placeholder weight. */
.acoucalc-kpi__block--accent.is-empty .acoucalc-kpi__label {
	font-family: var(--font-500, "Keiner 500", sans-serif);
	color: var(--ac-ink-soft);
}

.acoucalc-kpi__block--accent.is-empty .acoucalc-kpi__value {
	color: var(--ac-line-strong);
	background: none;
	-webkit-text-fill-color: currentColor;
}

.acoucalc-kpi__unit {
	display: block;
	margin-top: 5px;
	font-size: 12px;
	color: var(--ac-ink-soft);
}

/* The treated tail as a waveform, in the idiom the home page already uses for
   sound on this site: bars that breathe on a staggered loop. Tall on the left,
   gone by the right — the decay the figure above it measures. Bars are laid
   out by the flex row; each carries its own height and its index, and the
   index drives both the colour step along the brand ramp and the delay that
   keeps the breathing from moving as one block. */
.acoucalc-kpi__wave {
	display: flex;
	align-items: flex-end;
	gap: 3px;
	/* The box is the strip, not the column it sits in. Left to stretch, each one
	   takes its block's width — 109px of bars and then a different amount of
	   nothing after them — which costs nothing visually but means the two are
	   not the same object, and every later rule that touches the box (the fade
	   on the empty state, the print hide) would be measuring two things. */
	width: max-content;
	height: 20px;
	margin-top: 14px;
}

.acoucalc-kpi__wave i {
	/* Fixed, not fluid. These bars used to divide up whatever width their block
	   happened to be, which was fine while only one block had a strip; with one
	   in each, the untreated block — shorter, because its figure is smaller —
	   drew the same 16 bars narrower, and two strips at different scales cannot
	   be compared. A fixed bar and a fixed gap make both exactly 109px. The
	   treated strip already sat at this width, so it does not move. */
	flex: 0 0 4px;
	/*
	 * Says the same thing as the basis above, and has to, because Gecko does
	 * not count a flex basis when it resolves the strip's `max-content` width:
	 * it measured the 15 gaps and none of the 16 bars, called the box 45px, and
	 * the 109px of bars then ran on out of it. The untreated block is the
	 * narrower of the two, so its strip overflowed far enough to lie under the
	 * treated one and the pair read as a single band with a colour change in
	 * it. A width the bar actually carries is counted by both engines.
	 */
	width: 4px;
	height: var(--ac-bar);
	border-radius: 2px;
	transform-origin: bottom center;
	/* Teal into green across the strip, the same direction the brand gradient
	   runs. The flat colour is what a browser without color-mix() keeps. */
	background: #12BF86;
	background: color-mix(in oklab, #09A3B5, #1BDA58 calc(var(--ac-i) * 6.6%));
	animation: acoucalc-wave 3.2s ease-in-out infinite;
	animation-delay: calc(var(--ac-i) * 0.09s);
}

/* The untreated strip. Same bars, same width, same height — the only things
   that differ are the three that carry the meaning: the envelope stays up
   instead of falling away, the motion is faster and swings harder, and there
   is no colour in it. Colour arrives with the treatment, which is the one
   thing on this row worth looking at, and a grey that ramped or faded would
   read as a decay the untreated room does not have. */
.acoucalc-kpi__wave--busy i {
	background: #9AA09A;
	animation-name: acoucalc-wave-busy;
	animation-duration: 1.35s;
	animation-delay: calc(var(--ac-i) * 0.045s);
}

/* Both strips have to sit on one line or the comparison is doing arithmetic
   the reader should not have to do. The row centres its blocks, and the
   treated block is the taller of the two, so the untreated one is given the
   full height and its strip pushed to the bottom of it — landing on the line
   the treated strip already ends on. The treated block is left alone: it sets
   the height, and its own 14px gap still holds. */
.acoucalc-kpi__block:not(.acoucalc-kpi__block--accent) {
	align-self: stretch;
	display: flex;
	flex-direction: column;
}

/* Carried on the block so the narrow-screen rule below, which resets the top
   margin on every strip to close up the gap, cannot take the shared line away
   with it — the two blocks still sit side by side down there. */
.acoucalc-kpi__block .acoucalc-kpi__wave--busy {
	margin-top: auto;
}

/* No treatment chosen, nothing decaying: the tail sits out until there is a
   figure for it to belong to. The untreated strip stays — an untreated room is
   the one thing the calculator does know at that point — and because the tail
   only goes transparent rather than away, it keeps holding the line they
   share. */
.acoucalc-kpi__block--accent.is-empty .acoucalc-kpi__wave {
	opacity: 0;
}

.acoucalc-kpi__arrow {
	color: var(--ac-teal-ink);
	opacity: 0.55;
}

/* The arrow points forward into the accent block, so it cannot be reached with
   a sibling selector from the block that is empty. :has() on the row can; in a
   browser without it the arrow simply stays teal, which is no worse than the
   grey it used to be. */
.acoucalc-kpi:has(.acoucalc-kpi__block--accent.is-empty) .acoucalc-kpi__arrow {
	color: var(--ac-line-strong);
	opacity: 1;
}

.acoucalc-kpi__verdict {
	margin-left: auto;
	padding: 9px 16px;
	border-radius: 18px;
	font-size: 13px;
	background: #EDEFF1;
	color: var(--ac-ink-soft);
}

.acoucalc-kpi__verdict:empty {
	display: none;
}

.acoucalc-kpi__verdict.is-ok {
	background: rgba(27, 218, 88, 0.14);
	color: #0B7A34;
}

.acoucalc-kpi__verdict.is-high {
	background: rgba(178, 32, 32, 0.1);
	color: var(--ac-danger);
}

.acoucalc-kpi__verdict.is-low {
	background: rgba(9, 163, 181, 0.12);
	color: #06707C;
}

/* chart */

.acoucalc-chart {
	margin: 0 0 26px;
}

.acoucalc-chart svg {
	display: block;
	width: 100%;
	height: auto;
	overflow: visible;
}

.acoucalc-chart__grid {
	stroke: var(--ac-line);
	stroke-width: 1;
}

.acoucalc-chart__band {
	fill: rgba(27, 218, 88, 0.10);
	stroke: rgba(27, 218, 88, 0.35);
	stroke-dasharray: 4 4;
}

.acoucalc-chart__tick {
	fill: var(--ac-ink-soft);
	font-family: var(--font-400, "Keiner 400", sans-serif);
	font-size: 12px;
}

.acoucalc-chart__axis {
	fill: #868D95;
	font-size: 11px;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

.acoucalc-chart__line {
	fill: none;
	stroke-width: 2.5;
	stroke-linecap: round;
	stroke-linejoin: round;
}

.acoucalc-chart__line.is-base {
	stroke: #868D95;
	stroke-dasharray: 6 5;
}

.acoucalc-chart__dot {
	stroke: #fff;
	stroke-width: 2;
}

.acoucalc-chart__dot.is-base {
	fill: #868D95;
}

.acoucalc-chart__dot.is-treated {
	fill: var(--ac-mint);
}

.acoucalc-legend {
	display: flex;
	flex-wrap: wrap;
	gap: 20px;
	margin-top: 14px;
	font-size: 13px;
	color: var(--ac-ink-soft);
}

.acoucalc-legend__item {
	display: inline-flex;
	align-items: center;
	gap: 8px;
}

.acoucalc-legend__item::before {
	content: "";
	width: 18px;
	height: 3px;
	border-radius: 2px;
}

.acoucalc-legend__item.is-base::before {
	background: repeating-linear-gradient(90deg, #868D95 0 6px, transparent 6px 11px);
}

.acoucalc-legend__item.is-treated::before {
	background: var(--ac-gradient);
}

.acoucalc-legend__item.is-band::before {
	height: 12px;
	border-radius: 3px;
	background: rgba(27, 218, 88, 0.18);
	border: 1px dashed rgba(27, 218, 88, 0.5);
}

/* table */

.acoucalc-table-wrap {
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
}

.acoucalc-table {
	width: 100%;
	min-width: 560px;
	border-collapse: collapse;
	font-variant-numeric: tabular-nums;
}

.acoucalc-table th,
.acoucalc-table td {
	padding: 12px 14px;
	text-align: right;
	border-bottom: 1px solid var(--ac-line);
}

.acoucalc-table thead th {
	font-family: var(--font-500, "Keiner 500", sans-serif);
	font-size: 11px;
	font-weight: 400;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--ac-ink-soft);
	border-bottom: 1.5px solid var(--ac-ink);
}

.acoucalc-table thead th:first-child,
.acoucalc-table tbody th {
	text-align: left;
}

.acoucalc-table tbody th {
	font-family: var(--font-500, "Keiner 500", sans-serif);
	font-size: 14px;
	font-weight: 400;
}

.acoucalc-table td {
	font-size: 15px;
}

.acoucalc-table__row.is-accent td,
.acoucalc-table__row.is-accent th {
	font-family: var(--font-600, "Keiner 600", sans-serif);
	color: #0B7A57;
}

.acoucalc-hint {
	margin: 18px 0 0;
	padding: 12px 16px;
	background: rgba(9, 163, 181, 0.08);
	border-left: 3px solid var(--ac-teal);
	border-radius: 0 var(--ac-radius-sm) var(--ac-radius-sm) 0;
	font-size: 13px;
	color: #06707C;
}

/* ── result actions ──────────────────────────────────────── */

.acoucalc-result__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 12px;
	margin-top: 26px;
	padding-top: 22px;
	border-top: 1px solid var(--ac-line);
}

.acoucalc-btn__icon {
	margin-right: 10px;
	flex: none;
}

/* ── report ──────────────────────────────────────────────── */

/* The lead panel is the one dark surface in the calculator, so it carries its
   own scale: a copy column that states what arrives by email, and the form as
   a raised card inside it rather than fields floating on the panel. */
.acoucalc-report {
	display: grid;
	grid-template-columns: minmax(260px, 0.9fr) minmax(320px, 1.1fr);
	gap: 44px;
	align-items: start;
	padding: 40px;
	margin-bottom: 20px;
	/* Flat theme ink. The corner washes that used to sit here mixed two more
	   greens into a panel the theme paints in one colour; the brand shows up
	   on this surface where the theme puts it — the gradient rule below, the
	   green button, the tick circles — and nowhere else. */
	background: var(--ac-ink);
	border-radius: var(--ac-radius);
	box-shadow:
		inset 0 0 0 1px rgba(255, 255, 255, 0.07),
		0 18px 44px -28px rgba(33, 33, 33, 0.55);
	color: #fff;
	position: relative;
	overflow: hidden;
}

.acoucalc-report::before {
	content: "";
	position: absolute;
	inset: 0 0 auto 0;
	height: 3px;
	background: var(--ac-gradient);
}

.acoucalc-report__copy h3 {
	margin: 0 0 14px;
	font-family: var(--font-600, "Keiner 600", sans-serif);
	font-size: clamp(22px, 2.2vw, 28px);
	line-height: 1.15;
	letter-spacing: -0.02em;
	color: #fff;
}

.acoucalc-report__copy p {
	margin: 0;
	max-width: 42ch;
	font-size: 15px;
	line-height: 1.55;
	color: rgba(255, 255, 255, 0.64);
}

.acoucalc-report__points {
	margin: 22px 0 0;
	padding: 22px 0 0;
	border-top: 1px solid rgba(255, 255, 255, 0.1);
	list-style: none;
	display: grid;
	gap: 12px;
}

.acoucalc-report__points li {
	position: relative;
	padding-left: 28px;
	font-size: 14px;
	line-height: 1.45;
	color: rgba(255, 255, 255, 0.8);
}

/* Tick as a background image rather than a glyph: no icon font to load, and
   it keeps its weight when the theme swaps the type stack. */
.acoucalc-report__points li::before {
	content: "";
	position: absolute;
	top: 3px;
	left: 0;
	width: 18px;
	height: 18px;
	border-radius: 50%;
	background-color: rgba(27, 218, 88, 0.16);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 10'%3E%3Cpath d='M1.2 5.2 4.4 8.4 10.8 1.6' fill='none' stroke='%231BDA58' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: center;
	background-size: 10px 9px;
}

.acoucalc-report__form {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 18px 16px;
	align-content: start;
	padding: 26px;
	background: rgba(255, 255, 255, 0.05);
	border: 1px solid rgba(255, 255, 255, 0.1);
	border-radius: var(--ac-radius);
}

.acoucalc-report__form .acoucalc-field {
	margin-bottom: 0;
	min-width: 0;
}

.acoucalc-report__form .acoucalc-field--full {
	grid-column: 1 / -1;
}

/* The theme gives every `form label` a 31px line-height, which pushes the
   caps-label a third of a line off its field. Two classes deep to win. */
.acoucalc-report__form .acoucalc-field > label {
	margin-bottom: 7px;
	font-size: 11px;
	line-height: 1.2;
	letter-spacing: 0.08em;
	color: rgba(255, 255, 255, 0.5);
}

/* The theme appends the required asterisk; tint it so it reads as a marker
   rather than as part of the label. */
.acoucalc-report__form .acoucalc-field > label::after {
	margin-left: 3px;
	color: var(--ac-green);
}

.acoucalc-report__form input[type="text"],
.acoucalc-report__form input[type="email"] {
	background: rgba(255, 255, 255, 0.04);
	border: 1px solid rgba(255, 255, 255, 0.16);
	border-radius: 10px;
	color: #fff;
}

.acoucalc-report__form input[type="text"]:hover,
.acoucalc-report__form input[type="email"]:hover {
	border-color: rgba(255, 255, 255, 0.3);
}

.acoucalc-report__form input[type="text"]:focus,
.acoucalc-report__form input[type="email"]:focus {
	background: rgba(255, 255, 255, 0.08);
	border-color: var(--ac-green);
	box-shadow: 0 0 0 3px rgba(27, 218, 88, 0.2);
}

/* This form sits on --ac-ink, not white, so it cannot use --ac-ink-faint.
   At 0.35 the white washed out to 3.2:1 against the panel; 0.5 gives
   5.0:1 and still sits well below the field's own text. */
.acoucalc-report__form input::placeholder {
	color: rgba(255, 255, 255, 0.5);
}

/* Chrome paints autofilled fields with an opaque light background and dark
   text. The inset shadow repaints the field; the fill-color the text. */
.acoucalc-report__form input:-webkit-autofill,
.acoucalc-report__form input:-webkit-autofill:hover,
.acoucalc-report__form input:-webkit-autofill:focus {
	-webkit-text-fill-color: #fff;
	-webkit-box-shadow: inset 0 0 0 100px #2C2C2C;
	caret-color: #fff;
}

/* ── consent ─────────────────────────────────────────────── */

/* The theme styles every `label:has(input[type=checkbox])` at (0,2,2) and
   paints it #212121 — the same ink as this panel, so the sentence disappears.
   The three classes below outrank it; the same reason the box is restyled
   here rather than inheriting the theme's white-on-white square. */
.acoucalc .acoucalc-report__form label.acoucalc-consent {
	grid-column: 1 / -1;
	display: flex;
	align-items: flex-start;
	gap: 10px;
	margin: 0;
	font-family: inherit;
	font-size: 13px;
	font-weight: 400;
	line-height: 1.45;
	color: rgba(255, 255, 255, 0.72);
	cursor: pointer;
	transition: color 0.18s ease;
}

.acoucalc .acoucalc-report__form label.acoucalc-consent:hover {
	color: rgba(255, 255, 255, 0.92);
}

.acoucalc .acoucalc-report__form .acoucalc-consent input[type="checkbox"] {
	flex: 0 0 auto;
	width: 20px;
	height: 20px;
	margin: 0;
	background: rgba(255, 255, 255, 0.06);
	background-image: none;
	border: 1px solid rgba(255, 255, 255, 0.3);
	border-radius: 6px;
	-webkit-appearance: none;
	appearance: none;
	cursor: pointer;
	transition: background-color 0.18s ease, border-color 0.18s ease;
}

.acoucalc .acoucalc-report__form .acoucalc-consent:hover input[type="checkbox"] {
	border-color: rgba(255, 255, 255, 0.5);
}

.acoucalc .acoucalc-report__form .acoucalc-consent input[type="checkbox"]:checked {
	background-color: var(--ac-green);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 10'%3E%3Cpath d='M1.2 5.2 4.4 8.4 10.8 1.6' fill='none' stroke='%23212121' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: center;
	background-size: 11px 9px;
	border-color: var(--ac-green);
}

.acoucalc .acoucalc-report__form .acoucalc-consent input[type="checkbox"]:focus-visible {
	outline: none;
	box-shadow: 0 0 0 3px rgba(27, 218, 88, 0.35);
}

.acoucalc-report__actions {
	grid-column: 1 / -1;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 12px;
	margin-top: 2px;
}

.acoucalc-report__actions .acoucalc-btn--primary {
	min-width: 210px;
}

.acoucalc-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	/* The theme's button, to the pixel: .btn-primary/.btn-secondary in
	   style.scss and the configurator's own bordered button both measure
	   56 / 0 25px / 28px / 16px, and drop to 48px high under 575px. The
	   calculator sat at 52 / 28 / 26 / 15, which read as a near-miss of the
	   site's button rather than as a different one. */
	height: 56px;
	padding: 0 25px;
	border: 0;
	border-radius: 28px;
	font-family: inherit;
	font-size: 16px;
	font-weight: 400;
	cursor: pointer;
	transition: all 0.25s ease;
}

@media screen and (max-width: 575px) {

	.acoucalc-btn {
		height: 48px;
	}
}

/* The theme rings its buttons in brand green on keyboard focus — the
   configurator's bordered button takes `outline: 2px solid #1BDA58`. These
   carried no focus rule at all, so they fell back to the browser default,
   which is easy to lose against a light card. */
.acoucalc-btn:focus-visible {
	outline: 2px solid var(--ac-green);
	outline-offset: 2px;
}

.acoucalc-btn--primary {
	/* z-index:0 makes this a stacking context, so the ::before gradient can sit
	   at -1: above the button's own background, below its text node. */
	position: relative;
	z-index: 0;
	background: var(--ac-green);
	color: var(--ac-ink);
	overflow: hidden;
}

.acoucalc-btn--primary::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: var(--ac-gradient);
	opacity: 0;
	transition: opacity 0.35s ease;
}

.acoucalc-btn--primary:hover::before {
	opacity: 1;
}

.acoucalc-btn--primary:disabled {
	opacity: 0.55;
	cursor: default;
}

.acoucalc-btn--ghost {
	background: transparent;
	border: 1px solid rgba(255, 255, 255, 0.25);
	color: #fff;
}

.acoucalc-btn--ghost:hover {
	border-color: #fff;
}

/* The light-background twin of --ghost, for the result panel. */
.acoucalc-btn--outline {
	background: var(--ac-surface);
	border: 1px solid var(--ac-line-strong);
	color: var(--ac-ink);
}

.acoucalc-btn--outline:hover {
	border-color: var(--ac-teal-ink);
	color: var(--ac-teal-ink);
}

.acoucalc-report__status {
	grid-column: 1 / -1;
	margin: 0;
	font-size: 13px;
	line-height: 1.45;
	color: rgba(255, 255, 255, 0.6);
}

/* Empty until the first submit resolves. It stays rendered — a live region
   that is display:none when it is written to may not be announced — so the
   negative margin cancels the grid row-gap instead. */
.acoucalc-report__status:empty {
	margin-top: -18px;
}

.acoucalc-report__status.is-error {
	color: #FF8B8B;
}

.acoucalc-report__status.is-success {
	color: var(--ac-green);
}

.acoucalc-disclaimer {
	margin: 0;
	font-size: 12px;
	line-height: 1.55;
	color: var(--ac-ink-soft);
}

/* The report renders here and prints itself. Kept off-screen rather than
   display:none — a hidden iframe has no layout, so it has nothing to print. */

.acoucalc-print-frame {
	position: fixed;
	left: -10000px;
	top: 0;
	width: 794px;
	height: 1123px;
	border: 0;
	opacity: 0;
	pointer-events: none;
}

/* ── motion ──────────────────────────────────────────────── */

/*
 * Everything in this section is decoration. Drop the whole block and the
 * calculator still works, still reads the same and still lays out the same —
 * which is exactly what the reduced-motion query at the end of it does, and
 * what the script does too: it reads the same media query before it tweens
 * anything and writes final values straight into the DOM instead.
 *
 * The rule the section follows: motion is only ever attached to a change the
 * reader is meant to notice. Figures count to their new value, a panel that
 * arrives rises into place, a line on the chart moves to its new shape. Nothing
 * loops, nothing moves on its own, and nothing moves for longer than the half
 * second it takes to read what changed.
 */

@keyframes acoucalc-rise {
	from {
		opacity: 0;
		transform: translateY(14px);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

@keyframes acoucalc-pop {
	from {
		opacity: 0;
		transform: scale(0.9);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

@keyframes acoucalc-fade {
	from {
		opacity: 0;
	}

	to {
		opacity: 1;
	}
}

/* A figure that has just changed lifts a hair and settles. Two pixels: enough
   to catch the eye at the edge of vision, small enough that a reader watching
   the number itself does not see it move. */
@keyframes acoucalc-tick {
	0% {
		transform: none;
	}

	30% {
		transform: translateY(-2px) scale(1.04);
	}

	100% {
		transform: none;
	}
}

/* The same lift, plus a wash of brand ink, for the derived figures — they sit
   in a quiet grey strip where a pure transform is too easy to miss. */
@keyframes acoucalc-tick-ink {
	0% {
		transform: none;
		color: var(--ac-ink);
	}

	30% {
		transform: translateY(-2px) scale(1.04);
		color: var(--ac-teal-ink);
	}

	100% {
		transform: none;
		color: var(--ac-ink);
	}
}

/* One ring, pushed outward and faded — the treated card has just gone from a
   placeholder to a real number, which is the moment the whole tool exists for.
   The card's resting shadows come in by variable so the two cannot drift. */
@keyframes acoucalc-wave {
	0%,
	100% {
		transform: scaleY(1);
	}

	50% {
		transform: scaleY(0.72);
	}
}

/* Four stops rather than two: a breath in and out reads as calm, which is the
   treated strip's job. This one has to read as a room that never settles, so
   it drops hard, half recovers, drops again, and never returns to rest on the
   same beat twice. */
@keyframes acoucalc-wave-busy {
	0%,
	100% {
		transform: scaleY(1);
	}

	22% {
		transform: scaleY(0.52);
	}

	44% {
		transform: scaleY(0.88);
	}

	68% {
		transform: scaleY(0.44);
	}

	85% {
		transform: scaleY(0.8);
	}
}

@keyframes acoucalc-wave-strike {
	from {
		transform: scaleY(0.04);
		opacity: 0;
	}

	40% {
		opacity: 1;
	}

	to {
		transform: scaleY(1);
		opacity: 1;
	}
}

/* ── press & hover ───────────────────────────────────────── */

/*
 * Overrides the `transition: all` these controls carry above — `all` cannot
 * name transform, and a press that does not answer is the single cheapest way
 * for an interface to feel dead.
 */
.acoucalc-chip,
.acoucalc-add,
.acoucalc-remove,
.acoucalc-btn,
.acoucalc-toggle button {
	transition:
		background-color var(--ac-dur-fast) var(--ac-ease),
		border-color var(--ac-dur-fast) var(--ac-ease),
		color var(--ac-dur-fast) var(--ac-ease),
		box-shadow var(--ac-dur-fast) var(--ac-ease),
		transform var(--ac-dur-fast) var(--ac-ease);
}

.acoucalc-chip:active,
.acoucalc-add:active,
.acoucalc-btn:active,
.acoucalc-toggle button:active {
	transform: scale(0.96);
}

.acoucalc-remove:active {
	transform: scale(0.9);
}

.acoucalc-btn--primary:hover,
.acoucalc-btn--outline:hover {
	transform: translateY(-1px);
}

.acoucalc-btn--outline:hover {
	box-shadow: 0 6px 18px -10px rgba(6, 112, 124, 0.6);
}

.acoucalc-btn--primary:disabled:hover {
	transform: none;
}

/* ── segmented control ───────────────────────────────────── */

/*
 * A toggle is a segmented control, so the selected state slides between its
 * buttons rather than blinking from one to the other. Core renders no toggle
 * of its own any more; the m/ft pair is a feature's, and the machinery is
 * here so it slides too. The pill is one element per control, measured and
 * moved by the script; the class it also sets is what hands the white
 * background over from the button to the pill, so with no script the control
 * keeps the plain highlight it had before.
 */
/*
 * Pinned to the track's content box rather than given a height of its own.
 *
 * A fixed 34px was right for exactly one of the two layouts. The touch block
 * takes the buttons to 40px for the target size, and the pill went on being
 * 34: six pixels shorter than the segment it is meant to *be*, sitting flush
 * with the top of it, so on a phone the white shape floated high in the track
 * with a band of grey under it and read as a sticker rather than as the
 * selected half of the control.
 *
 * Top and bottom instead of a height, because the containing block of an
 * absolutely positioned child is its positioned ancestor's padding box: 3px
 * off each edge of that is precisely the content box, which is the row the
 * buttons are laid out in. The pill is therefore the button's box at whatever
 * height the button happens to be, and a future rule that changes one cannot
 * leave the other behind. The 3px repeats the track's own padding, and the
 * radius repeats the button's, so the two shapes are the same shape.
 */
.acoucalc-toggle__thumb {
	position: absolute;
	top: 3px;
	bottom: 3px;
	left: 3px;
	border-radius: 18px;
	background: #fff;
	box-shadow: 0 1px 3px rgba(33, 33, 33, 0.12);
	pointer-events: none;
	/* It slides on every model switch, and transform is the half that can be
	   handed to the compositor. */
	will-change: transform;
	transition:
		transform var(--ac-dur) var(--ac-ease),
		width var(--ac-dur) var(--ac-ease);
}

.acoucalc-toggle.has-thumb button {
	position: relative;
	z-index: 1;
}

.acoucalc-toggle.has-thumb button.is-active {
	background: transparent;
	box-shadow: none;
}

/* The very first placement must not slide in from the left edge. */
.acoucalc-toggle__thumb.is-placing {
	transition: none;
}

/* ── room figure ─────────────────────────────────────────── */

/*
 * The figures already cross-fade. Focus-pulling the outgoing one is what makes
 * it read as a change of subject rather than two drawings dissolving.
 */
.acoucalc-room__figure svg {
	filter: blur(3px);
	/*
	 * The cross-fade moves opacity, transform and a 3px blur together. On its
	 * own layer the blur is composited from a cached texture; without one it
	 * is re-rasterised every frame, and a full-width SVG re-blurred 20 times
	 * is where this dissolve stutters on integrated graphics.
	 */
	will-change: opacity, transform, filter;
}

.acoucalc-room__figure svg.is-active {
	filter: none;
}

.acoucalc-room__figure svg,
.acoucalc-room__figure svg.is-active {
	transition-property: opacity, transform, visibility, filter;
}

/* ── figures that change ─────────────────────────────────── */

.acoucalc-kpi__value.is-ticking {
	animation: acoucalc-tick 0.44s var(--ac-ease-spring);
}

.acoucalc-derived dd [data-out].is-ticking {
	animation: acoucalc-tick-ink 0.6s var(--ac-ease-spring);
}

/* The treated figure arriving with a real number in it: the number pops, and
   the tail is struck under it, drawn left to right at roughly the speed a room
   actually empties. Each bar overshoots its height and settles, so the strip
   lands as a decay rather than a bar chart sliding up. */
.acoucalc-kpi__block--accent.is-arriving .acoucalc-kpi__wave i {
	animation: acoucalc-wave-strike 0.62s var(--ac-ease-spring) both;
	animation-delay: calc(var(--ac-i) * 0.035s);
}

.acoucalc-kpi__block--accent.is-arriving .acoucalc-kpi__value {
	animation: acoucalc-pop 0.5s var(--ac-ease-spring);
}

.acoucalc-kpi__verdict {
	transition:
		background-color var(--ac-dur) var(--ac-ease),
		color var(--ac-dur) var(--ac-ease);
}

.acoucalc-kpi__verdict.is-changed {
	animation: acoucalc-pop 0.42s var(--ac-ease-spring);
}

/* ── things that come and go ─────────────────────────────── */

/*
 * Two primitives, both driven from JS so that "does this respect reduced
 * motion" is answered once rather than per selector.
 *
 * is-faded is the pair to slide(): for a control with no height of its own to
 * animate, where collapsing the box would drag the line it sits on. The
 * transition is carried by is-fadeable, which fade() puts on for you, so the
 * helper works on any element without this file having to name it.
 */
.acoucalc .is-fadeable {
	transition:
		opacity var(--ac-dur-fast) var(--ac-ease),
		transform var(--ac-dur-fast) var(--ac-ease);
}

.acoucalc .is-fadeable.is-faded {
	opacity: 0;
	transform: scale(0.82);
}

/*
 * is-swapping is for a note whose words change while it is already on screen.
 * The box often does not move at all — two messages can be the same height —
 * so the change has to be carried by the text or it happens between frames and
 * reads as a glitch rather than as an answer. An animation, not a transition,
 * because it has to be able to run again on the same element a keystroke
 * later; and animations outrank inline styles, so this runs over the top of a
 * slide() that is adjusting the height underneath it.
 */
.acoucalc .is-swapping {
	animation: acoucalc-swap var(--ac-dur) var(--ac-ease);
}

@keyframes acoucalc-swap {
	from {
		opacity: 0;
		transform: translateY(-3px);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

/* ── panels arriving ─────────────────────────────────────── */

/*
 * The result panel comes in as a sequence rather than a slab: headline, chart,
 * table, actions, each a frame or two behind the last. Six steps is as far as
 * the stagger goes — past that the wait costs more than the choreography buys,
 * so anything a feature adds below the sixth child lands with it.
 */
.acoucalc-result.is-entering > * {
	animation: acoucalc-rise var(--ac-dur-slow) var(--ac-ease) both;
}

.acoucalc-result.is-entering > *:nth-child(2) {
	animation-delay: 0.06s;
}

.acoucalc-result.is-entering > *:nth-child(3) {
	animation-delay: 0.12s;
}

.acoucalc-result.is-entering > *:nth-child(4) {
	animation-delay: 0.18s;
}

.acoucalc-result.is-entering > *:nth-child(5) {
	animation-delay: 0.24s;
}

.acoucalc-result.is-entering > *:nth-child(n + 6) {
	animation-delay: 0.3s;
}

.acoucalc-empty.is-entering,
.acoucalc-report.is-entering {
	animation: acoucalc-rise var(--ac-dur-slow) var(--ac-ease) both;
}


/* The surface a treatment has been added to, held apart from the ones without
   one for as long as the treatment is open. */
.acoucalc-surface {
	transition: background-color var(--ac-dur) var(--ac-ease);
}

.acoucalc-surface.is-treated {
	background: rgba(18, 191, 134, 0.035);
}

/* The room the add button leaves over itself grows while the panel above it is
   still opening, so the two are one movement rather than a slide followed by a
   step. */
.acoucalc-surfaces__add {
	transition: padding-top var(--ac-dur) var(--ac-ease);
}

/* ── table ───────────────────────────────────────────────── */

/*
 * Cells count to their new figures in place, so a row only animates when the
 * row itself is new — the treated row appearing once a product is chosen.
 */
.acoucalc-table__row.is-entering {
	animation: acoucalc-rise 0.42s var(--ac-ease) both;
}

.acoucalc-table__row.is-entering:nth-child(2) {
	animation-delay: 0.07s;
}

/* ── chart ───────────────────────────────────────────────── */

/*
 * The axis fades rather than snaps when the scale steps — the gridlines are
 * redrawn at new positions and a cut there reads as a glitch.
 */
.acoucalc-chart__axes.is-rescaling,
.acoucalc-chart__band.is-entering {
	animation: acoucalc-fade var(--ac-dur-slow) var(--ac-ease) both;
}

.acoucalc-chart__dot.is-appearing {
	animation: acoucalc-fade 0.3s var(--ac-ease) both;
}

/* ── reveal ──────────────────────────────────────────────── */

/*
 * A step below the fold at load lifts in when it is scrolled to. The script
 * only ever marks steps that are off screen at that moment, so nothing already
 * in front of the reader is hidden and re-shown — which means no flash if the
 * script arrives late, and nothing at all to undo if it never arrives.
 */
.acoucalc-step.is-pending {
	opacity: 0;
}

.acoucalc-step.is-revealing {
	animation: acoucalc-rise 0.62s var(--ac-ease) both;
}

/* ── reduced motion ──────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
	.acoucalc *,
	.acoucalc *::before,
	.acoucalc *::after {
		animation-duration: 0.01ms !important;
		animation-delay: 0s !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		transition-delay: 0s !important;
	}

	.acoucalc-chip:active,
	.acoucalc-add:active,
	.acoucalc-btn:active,
	.acoucalc-remove:active,
	.acoucalc-toggle button:active,
	.acoucalc-btn--primary:hover,
	.acoucalc-btn--outline:hover {
		transform: none;
	}

	.acoucalc-room__figure svg {
		filter: none;
		will-change: auto;
	}

	/* The script does not mark anything under reduced motion, but a stylesheet
	   that can leave content at opacity 0 has to be able to undo it. */
	.acoucalc-step.is-pending {
		opacity: 1;
	}
}

/* ── responsive ──────────────────────────────────────────── */

@media (max-width: 900px) {
	.acoucalc-report {
		grid-template-columns: 1fr;
		gap: 28px;
		padding: 28px;
	}

	/* Stacked, the copy column already reads top to bottom — the rule above
	   the points only adds a second horizontal line next to the form card. */
	.acoucalc-report__points {
		margin-top: 18px;
		padding-top: 0;
		border-top: 0;
	}
}

@media (max-width: 782px) {
	.acoucalc-step__body,
	.acoucalc-step__head {
		padding: 20px;
	}

	.acoucalc-surfaces__head {
		display: none;
	}

	.acoucalc-surface__row,
	.acoucalc-treatment__row {
		grid-template-columns: 1fr 1fr;
		gap: 12px;
	}

	.acoucalc-surface__name,
	.acoucalc-treatment__tag {
		grid-column: 1 / -1;
	}

	.acoucalc-surface .acoucalc-select,
	.acoucalc-treatment .acoucalc-select {
		grid-column: 1 / -1;
	}

	/* Two columns here, and the button is the fourth item: left to auto-flow it
	   lands in column one and its "end" is the middle of the row — the same
	   floating it does on the wide layout, half a screen from any edge. Given
	   the whole row it ends where the fields above it end. */
	.acoucalc-remove {
		grid-column: 1 / -1;
	}

	.acoucalc-add {
		width: 100%;
	}

	/* The row's own remove sits with the name, not in the grid, so the
	   full-width rule above it does not apply. */
	.acoucalc-remove--xs {
		grid-column: auto;
	}

	/*
	 * The treatment panel's own close button goes on the touch layouts.
	 *
	 * It never did anything the button above it does not: `remove-treatment`
	 * runs the same toggleTreatment( toggle, false ) that clicking the open
	 * "Treatment" toggle runs, and that toggle sits 12px above this row with
	 * a word on it, a 44px height, its "+" already rotated into an "×", and
	 * aria-expanded="true". On the wide layout the duplication pays for
	 * itself: the treatment row is a table row there and its fourth column is
	 * the row-action column every surface row above it also fills, so the
	 * button reads as part of a column rather than as a second way to shut
	 * the same panel. Stacked, there is no such column and no such reading —
	 * it was an unlabelled circle floating in the middle of a row, and the
	 * only question it raised was whether it would throw the numbers away.
	 *
	 * Two controls for one action, and this is the weaker of the two: no
	 * label, no state, and not where the panel was opened from. Closing a
	 * disclosure belongs on the control that opened it. `display: none` takes
	 * it out of the accessibility tree along with the layout, which is the
	 * point — nothing is left to tab onto that has nothing of its own to do.
	 */
	.acoucalc-treatment__row .acoucalc-remove {
		display: none;
	}

	/*
	 * What is left is the pill, the treated area, and the product beneath —
	 * the shape the surface row above it already has, where the name carries
	 * the row and its area sits right. The two rows now read as one pattern
	 * instead of the treatment row trailing an extra line with one mark on it.
	 */
	.acoucalc-treatment__row {
		grid-template-columns: auto minmax(0, 1fr) 130px;
		grid-template-areas:
			"tag . area"
			"product product product";
	}

	.acoucalc-treatment__tag {
		grid-area: tag;
	}

	.acoucalc-treatment__row .acoucalc-input {
		grid-area: area;
	}

	.acoucalc-treatment__row .acoucalc-select {
		grid-area: product;
	}

	.acoucalc-split {
		width: 100%;
		justify-content: center;
	}

	.acoucalc-room {
		grid-template-columns: 1fr;
		gap: 20px;
	}

	.acoucalc-room__figure {
		max-width: 260px;
		margin: 0 auto;
	}

	.acoucalc-kpi {
		gap: 16px;
		padding: 20px;
	}

	.acoucalc-kpi__arrow {
		display: none;
	}

	.acoucalc-kpi__wave {
		height: 16px;
		margin-top: 10px;
	}

	.acoucalc-kpi__verdict {
		margin-left: 0;
		width: 100%;
	}

	.acoucalc-report {
		padding: 22px;
	}

	.acoucalc-report__form {
		grid-template-columns: 1fr;
		padding: 20px;
	}

	.acoucalc-report__actions .acoucalc-btn--primary {
		width: 100%;
	}

	/*
	 * iOS Safari zooms the page in on any field it focuses that sets its
	 * type below 16px, and it does not zoom back out: the reader is left on
	 * a page a third too wide, panning sideways to find the next field. The
	 * room is eight fields deep, so it happens on the first tap and lasts
	 * the rest of the visit. 14 and 15px are the sizes this design wants and
	 * a pointer deserves, and they stay on the wide layout; here every field
	 * goes to 16, which is the only figure that stops the zoom.
	 */
	.acoucalc input[type="text"],
	.acoucalc input[type="email"],
	.acoucalc select,
	.acoucalc textarea,
	.acoucalc-input--sm input,
	.acoucalc-surface .acoucalc-select select,
	.acoucalc-select--inline select {
		font-size: 16px;
	}

	/*
	 * Touch targets. The wide layout sizes these to their type, which is
	 * right for a cursor that lands where it is pointed. A fingertip is
	 * about 9 mm across and covers what it is aiming at, which is why both
	 * platform guidelines settle on 44px; below that the reader misses and
	 * has to look at what they hit. Everything the reader has to press is
	 * taken to 44 here, and only here.
	 */
	.acoucalc-chip {
		height: 44px;
	}

	/* 40 plus the toggle's own 3px of padding on each side. */
	.acoucalc-toggle button {
		height: 40px;
		padding: 0 20px;
	}

	.acoucalc-split {
		height: 44px;
		padding: 0 18px;
		border-radius: 22px;
		font-size: 13px;
	}

	.acoucalc-remove {
		width: 44px;
		height: 44px;
	}

	/*
	 * The row's own remove is drawn at the scale of the name beside it, and
	 * a 24px circle is a 24px target. Rather than swell the mark, the button
	 * grows to 44 and *paints* the circle instead of being it: the ring and
	 * fill become a radial gradient centred in a box two-thirds of which is
	 * transparent. The eye gets the small mark the wide layout draws, the
	 * finger gets the whole 44. The two bars centre on the button, so they
	 * land in the middle of the circle either way, and the ring colour is
	 * held in a custom property so the hover state can still redden it.
	 */
	.acoucalc-remove--xs {
		--xs-ring: var(--ac-line-strong);
		width: 44px;
		height: 44px;
		border: 0;
		background: radial-gradient(
			circle at center,
			#fff 0 11.5px,
			var(--xs-ring) 11.5px 12.5px,
			rgba(255, 255, 255, 0) 12.5px
		);
	}

	.acoucalc-remove--xs:hover {
		--xs-ring: var(--ac-danger);
	}

	/*
	 * The band table still has 560px of columns between 601 and 782px, where
	 * the card can be narrower than that, and a box that scrolls sideways on
	 * a touch screen shows no scrollbar at rest — it just looks like a table
	 * with two columns in it. The shadow is the affordance. Opaque `local`
	 * cover gradients scroll with the content and sit over `scroll` shadows
	 * fixed to the box, so each edge shows a shadow only while there is
	 * something past it, and both fade as the reader reaches that end — no
	 * script, and nothing shows at all on a card wide enough not to scroll.
	 *
	 * Below 600px there is nothing to scroll: the table turns on its side.
	 */
	.acoucalc-table-wrap {
		background:
			linear-gradient(to right, #fff 40%, rgba(255, 255, 255, 0)) 0 0 / 34px 100% no-repeat local,
			linear-gradient(to left, #fff 40%, rgba(255, 255, 255, 0)) 100% 0 / 34px 100% no-repeat local,
			radial-gradient(farthest-side at 0 50%, rgba(33, 33, 33, 0.16), rgba(33, 33, 33, 0)) 0 0 / 15px 100% no-repeat scroll,
			radial-gradient(farthest-side at 100% 50%, rgba(33, 33, 33, 0.16), rgba(33, 33, 33, 0)) 100% 0 / 15px 100% no-repeat scroll;
	}
}

/*
 * Phones. The wide layout nests four framed boxes to reach a control —
 * canvas, step card, surface list, row padding — and on a 390px screen the
 * four of them charge 139px, better than a third of the width, before the
 * first field gets any. Stacked, they also draw three concentric rounded
 * outlines around a single column that has nothing beside it to be separated
 * from.
 *
 * The step card is the one frame that carries meaning: it is what "step 2"
 * looks like. The rest give up their borders and their padding here and let
 * the hairlines they already own do the structuring, so everything inside a
 * step shares one 16px gutter measured from the screen rather than each
 * level adding another of its own.
 *
 * Screen only. Everything here is about a small display rather than a narrow
 * page, and A4 can measure under 600px once the margins are set — on paper
 * the 782px layout above is still the right one, and the print block already
 * says what it wants changed about it.
 */
@media screen and (max-width: 600px) {

	/* Nothing sits beside the calculator at this width, so the outer inset is
	   only holding the step cards off the edge — 12px does that. The radius
	   eases rather than goes: 20px outside the step card's own read as a
	   double border rather than depth, but squaring it off is only right when
	   the card is flush to the viewport. A host container with side padding —
	   this theme has one — leaves a square card sitting visibly unfinished
	   against the page, so it keeps the standard radius at this width. */
	.acoucalc {
		padding: 16px 12px;
		border-radius: var(--ac-radius);
	}

	/* The gutter, set once. Everything below measures from this. */
	.acoucalc-step__head,
	.acoucalc-step__body {
		padding: 16px;
	}

	/*
	 * The surface list is a bordered, rounded box drawn inside a bordered,
	 * rounded box. Flattened and pulled back out to the step body's edges it
	 * gives its rows the 42px the two frames were charging, and the group
	 * hairlines it already carries keep the sections apart. The rules kept
	 * top and bottom are what still separate the list from the fields above
	 * it and the button below.
	 */
	.acoucalc-surfaces {
		margin: 0 -16px;
		border-width: 1px 0;
		border-radius: 0;
	}

	/* Re-hung on the shared gutter now that the box around them is gone. */
	.acoucalc-surface__row,
	.acoucalc-treatment,
	.acoucalc-surfaces__add {
		padding-left: 16px;
		padding-right: 16px;
	}

	/*
	 * Two equal columns left the area field alone in the first one with a
	 * dead half-screen beside it — the single loudest piece of the squeeze,
	 * repeated down every row. The surface's name *is* that number's label,
	 * so the two share a line: name left, its area right, material below
	 * across both. Same four children in the same order on a treatment row,
	 * so the same grid reads it.
	 */
	.acoucalc-surface__row,
	.acoucalc-treatment__row {
		gap: 12px;
		align-items: center;
	}

	.acoucalc-surface__row {
		grid-template-columns: minmax(0, 1fr) 104px;
	}

	/* The same three areas the touch layout gives this row, on the narrower
	   area column the rest of this block measures to. */
	.acoucalc-treatment__row {
		grid-template-columns: auto minmax(0, 1fr) 104px;
	}

	/* Undoes the full-width span the 782px layout gives this. */
	.acoucalc-surface__name {
		grid-column: 1;
	}

	/* Held to the surface's own row rather than to `.acoucalc-surface`: the
	   treatment panel is nested inside the surface, so a descendant selector
	   here reaches into it and drops its area field back into column two, on
	   top of the remove button the touch layout just put there. */
	.acoucalc-surface__row > .acoucalc-input {
		grid-column: 2;
	}

	/* The unit sits inside a 104px box now, so the field needs less room
	   reserved for it than the wide layout's 42px. */
	.acoucalc-surface .acoucalc-input input,
	.acoucalc-treatment .acoucalc-input input {
		padding-right: 34px;
	}

	.acoucalc-unit {
		right: 10px;
	}

	/*
	 * The result's own frames. The KPI block and the chart are the step's
	 * whole content rather than a panel within it, so they run to the step
	 * body's edges on the same margin as the surface list; the KPI keeps its
	 * canvas fill and its rules, and loses only the rounding that was
	 * echoing the card around it.
	 */
	.acoucalc-kpi {
		margin: 0 -16px 20px;
		padding: 20px 16px;
		border-width: 1px 0;
		border-radius: 0;
	}

	/*
	 * The derived figures are the same argument one step earlier: a bordered,
	 * rounded box of four cells, drawn inside the bordered, rounded step card,
	 * two frames deep before a figure gets any width. Flattened out to the
	 * step body's edges it keeps the hairline grid that is doing the actual
	 * separating and gives each cell back the 34px the frame was charging.
	 */
	.acoucalc-derived {
		margin: 0 -16px;
		border-width: 1px 0;
		border-radius: 0;
	}

	/* Re-hung on the shared gutter, like the surface rows above. */
	.acoucalc-derived__item {
		padding: 16px;
	}

	/*
	 * The report is the one dark panel on the page and reads as its own
	 * thing, so it keeps its shape — but the form inside it was a rounded,
	 * outlined card on a rounded, outlined card in the same 14px radius, two
	 * frames saying the same thing. The form drops to a hairline above it.
	 */
	/*
	 * Turned on its side by the script: three columns instead of seven, so
	 * nothing scrolls. Full-bleed like the KPI block above it — the table's
	 * own rules are all the structure it needs, and a frame around it would
	 * be the third one between the screen edge and a figure.
	 */
	.acoucalc-table-wrap {
		margin: 0 -16px;
	}

	.acoucalc-table {
		min-width: 0;
	}

	.acoucalc-table th,
	.acoucalc-table td {
		padding: 12px 8px;
	}

	.acoucalc-table th:first-child,
	.acoucalc-table td:first-child {
		padding-left: 16px;
	}

	.acoucalc-table th:last-child,
	.acoucalc-table td:last-child {
		padding-right: 16px;
	}

	/* Upright, the treated figures are a column rather than a row, so the
	   accent travels with the cells instead of the <tr>. */
	.acoucalc-table th.is-accent,
	.acoucalc-table td.is-accent {
		font-family: var(--font-600, "Keiner 600", sans-serif);
		color: #0B7A57;
	}

	.acoucalc-table thead th.is-accent {
		font-family: var(--font-500, "Keiner 500", sans-serif);
	}

	/* The band is the row's label now, and a band name is a figure too. */
	.acoucalc-table tbody th {
		color: var(--ac-ink-soft);
		font-size: 13px;
	}

	.acoucalc-report {
		padding: 24px 16px;
	}

	.acoucalc-report__form {
		padding: 22px 0 0;
		background: none;
		border-width: 1px 0 0;
		border-radius: 0;
	}

	/* Pushed right, the toggle ended up alone on a line of its own with its
	   left edge in the middle of nowhere. Left with the rest of the head it
	   lines up with the title above it and the fields below. */
	.acoucalc-step__controls {
		margin-left: 0;
	}

	/* The step's note is the last thing in a flex head that has already
	   wrapped twice; letting it size to its own content stops it claiming a
	   260px basis it cannot have. */
	.acoucalc-step__note {
		flex-basis: 100%;
	}

	/* Full width, like every other control the reader presses here. The
	   treatment toggle is the row's fourth item and auto-flows back into the
	   first column, so on its own it stops short of the select above it — it
	   needs the whole row, not just 100% of one track. */
	.acoucalc-split {
		width: 100%;
		justify-content: center;
	}

	.acoucalc-surface__row .acoucalc-add {
		grid-column: 1 / -1;
	}
}

/* ── print ───────────────────────────────────────────────── */

@media print {

	/* The touch layout's scroll shadow is an affordance for a finger, and the
	   print width can match its media query. Nothing scrolls on paper, so it
	   would just be a smudge down the edge of the table — suppressed here for
	   readers who have background graphics switched on. */
	.acoucalc-table-wrap {
		background: none;
	}
	/* Nothing animates onto paper, and nothing may print at the opacity it was
	   left at mid-transition. */
	.acoucalc *,
	.acoucalc *::before,
	.acoucalc *::after {
		animation: none !important;
		transition: none !important;
	}

	.acoucalc-step.is-pending {
		opacity: 1 !important;
	}

	.acoucalc {
		max-width: none;
		font-size: 12px;
	}

	.acoucalc-step,
	.acoucalc-kpi,
	.acoucalc-surfaces {
		box-shadow: none;
		border-color: #999;
		break-inside: avoid;
	}

	.acoucalc-kpi__wave,
	.acoucalc-report,
	.acoucalc-result__actions,
	.acoucalc-print-frame,
	.acoucalc-add,
	.acoucalc-remove,
	.acoucalc-split,
	.acoucalc-surfaces__add,
	.acoucalc-shape,
	.acoucalc-toggle,
	/* A menu left open when the print dialog opens would land over the page. */
	.acoucalc-select-layer {
		display: none !important;
	}

	.acoucalc-chart__line.is-treated {
		stroke: #12BF86;
	}
}
