/**
 * Animart Visualizer — front end.
 *
 * Tokens are the ones recorded in CLAUDE.md §6, read from the live Elementor
 * kit (post 9). Everything is scoped under .animart-viz so nothing leaks into
 * the theme, and the theme's global .elementor-button override — a rainbow
 * gradient border — is deliberately NOT reused: §6 calls for a flat #ED2079
 * primary action, and this surface is meant to read as newer.
 *
 * No gradients, no heavy shadows, no rounded cards, no glassmorphism.
 */

.animart-viz {
	/* Palette — CLAUDE.md §6, read from the live Elementor kit (post 9). */
	--avz-bg: #000000;
	--avz-panel: #252525;
	--avz-pink: #ED2079;
	--avz-pink-hover: #FA4392;          /* --the7-links-hover-color */
	--avz-text: #FFFFFF;                /* --the7-title-color */
	--avz-muted: #B0B0B0;               /* --the7-secondary-text-color */

	/*
	 * One border colour, not two. The theme's divider is rgba(0,0,0,0.12),
	 * which is invisible on black, so this is the same 0.12 alpha inverted
	 * rather than a value invented for this plugin.
	 */
	--avz-line: rgba(255, 255, 255, 0.12);

	/* Scrims over imagery. Heavy for chrome, light for veils, and a middle
	   step used only where a blur is doing part of the work. */
	--avz-scrim: rgba(0, 0, 0, 0.82);
	--avz-scrim-blur: rgba(0, 0, 0, 0.68);
	--avz-scrim-soft: rgba(0, 0, 0, 0.55);

	/* A single pink wash, for hover and notice backgrounds. */
	--avz-pink-wash: rgba(237, 32, 121, 0.08);
	--avz-white-wash: rgba(255, 255, 255, 0.06);

	--avz-head: "Lato", Helvetica, Arial, sans-serif;
	--avz-body: "Inter", Helvetica, Arial, sans-serif;

	/*
	 * 3px, taken from the kit's --the7-input-border-radius and
	 * --the7-btn-*-border-radius. Every input and button on the site carries
	 * it; squaring these off was a divergence, not a decision.
	 *
	 * (css-vars.css says 1px, but the Elementor kit loads after it and wins.)
	 */
	--avz-radius: 3px;

	/* One border width everywhere. */
	--avz-border: 1px;

	/* Input metrics from the kit: --the7-*-input-padding, --the7-input-height. */
	--avz-field-pad: 9px 14px;

	--avz-gap: 28px;
	--avz-pad: 24px;

	display: grid;
	grid-template-columns: minmax(0, 1fr) 380px;
	gap: var(--avz-gap);
	align-items: start;

	max-width: 1300px;
	margin: 0 auto;
	padding: 0 20px 60px;

	color: var(--avz-text);
	font-family: var(--avz-body);
	font-size: 16px;
	line-height: 1.6;
	text-align: left;

	/* Native widgets — select popup, scrollbars, caret — follow this. */
	color-scheme: dark;
}

.animart-viz *,
.animart-viz *::before,
.animart-viz *::after {
	box-sizing: border-box;
}

/**
 * The hidden attribute must win.
 *
 * `[hidden] { display: none }` comes from the user-agent stylesheet, and ANY
 * author rule outranks it. Several elements below are laid out with
 * `display: flex` — the modal, the progress overlay, the stage image, the
 * product badge, the before/after toggle — so without this they stay painted
 * even while `hidden` is set, and toggling `node.hidden` in JS does nothing
 * visible.
 *
 * !important is deliberate: it has to beat every display rule in this file
 * regardless of source order or specificity, and "hidden means hidden" is not
 * a rule anything here should be able to opt out of.
 */
.animart-viz [hidden] {
	display: none !important;
}

/* Stage ------------------------------------------------------------------ */

.avz-main {
	display: flex;
	flex-direction: column;
	gap: 12px;
	min-width: 0;
}

.avz-stage {
	position: relative;
	background: var(--avz-panel);
	border: var(--avz-border) solid var(--avz-line);
	min-height: 460px;
	display: flex;
	align-items: center;
	justify-content: center;
	overflow: hidden;
}

.avz-stage-empty {
	width: 100%;
	padding: 40px;
}

.avz-drop {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 14px;
	min-height: 360px;
	padding: 32px;
	border: var(--avz-border) dashed var(--avz-line);
	cursor: pointer;
	text-align: center;
	transition: border-color 0.18s ease, background-color 0.18s ease;
}

.avz-drop:hover,
.avz-drop.is-over {
	border-color: var(--avz-pink);
	background: var(--avz-pink-wash);
}

.avz-drop-mark {
	width: 34px;
	height: 34px;
	border: var(--avz-border) solid var(--avz-muted);
	position: relative;
}

.avz-drop-mark::before,
.avz-drop-mark::after {
	content: "";
	position: absolute;
	background: var(--avz-muted);
}

.avz-drop-mark::before {
	left: 50%;
	top: 9px;
	bottom: 9px;
	width: 1px;
	transform: translateX(-50%);
}

.avz-drop-mark::after {
	top: 50%;
	left: 9px;
	right: 9px;
	height: 1px;
	transform: translateY(-50%);
}

.avz-drop:hover .avz-drop-mark,
.avz-drop.is-over .avz-drop-mark {
	border-color: var(--avz-pink);
}

.avz-drop-title {
	font-family: var(--avz-head);
	font-weight: 700;
	font-size: 18px;
	letter-spacing: 0.02em;
}

.avz-drop-hint {
	color: var(--avz-muted);
	font-size: 14px;
	max-width: 32ch;
}

.avz-stage-image {
	position: relative;
	width: 100%;
	display: flex;
	align-items: center;
	justify-content: center;
}

.avz-stage-image img {
	display: block;
	width: 100%;
	height: auto;
	max-height: 74vh;
	object-fit: contain;
}

/* Product code — visible at all times once a result exists. */
.avz-badge {
	position: absolute;
	left: 0;
	bottom: 0;
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 10px 16px;
	background: var(--avz-scrim);
	border-top: var(--avz-border) solid var(--avz-pink);
	font-family: var(--avz-head);
	font-weight: 700;
	font-size: 13px;
	letter-spacing: 0.14em;
	text-transform: uppercase;
}

.avz-badge-sep {
	color: var(--avz-pink);
}

.avz-badge-surface {
	color: var(--avz-muted);
	letter-spacing: 0.08em;
}

/*
 * The toggle sits directly on the photograph, so it carries its own scrim.
 *
 * The opaque-ish fill is the DEFAULT, not a last resort: where backdrop-filter
 * is unsupported nothing has to change for the labels to stay readable. The
 * blur below is purely additive.
 */
.avz-compare {
	position: absolute;
	top: 0;
	right: 0;
	display: flex;
	background: var(--avz-scrim);
}

/*
 * A functional scrim, not glassmorphism (CLAUDE.md §6). The blur is there to
 * flatten photographic detail so small letterforms hold up over any image —
 * hence no saturation boost, no inner glow, no rounding, no lightened border.
 * The fill only eases from 0.82 to 0.68 because the inactive button's muted
 * label still has to carry contrast against a bright photo. The blur buys
 * some transparency, not a lot.
 */
@supports ( (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) ) {
	.avz-compare {
		background: var(--avz-scrim-blur);
		-webkit-backdrop-filter: blur(10px);
		backdrop-filter: blur(10px);
	}
}

.avz-compare-btn {
	appearance: none;
	/* The container carries the scrim; buttons must not double it. */
	background: transparent;
	border: 0;
	border-left: var(--avz-border) solid var(--avz-line);
	color: var(--avz-muted);
	font-family: var(--avz-head);
	font-weight: 700;
	font-size: 12px;
	letter-spacing: 0.16em;
	padding: 11px 18px;
	cursor: pointer;
	transition: color 0.16s ease;
}

.avz-compare-btn:hover {
	color: var(--avz-text);
}

.avz-compare-btn.is-active {
	color: var(--avz-text);
	border-bottom: var(--avz-border) solid var(--avz-pink);
}

/* Progress — restrained, no spinner, image stays visible behind it. */
.avz-progress {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: flex-end;
	justify-content: center;
	background: var(--avz-scrim-soft);
	padding: 40px;
}

.avz-progress-inner {
	width: min(420px, 100%);
	text-align: center;
}

.avz-progress-bar {
	display: block;
	height: 2px;
	background: var(--avz-line);
	overflow: hidden;
	margin-bottom: 14px;
}

.avz-progress-bar > span {
	display: block;
	width: 34%;
	height: 100%;
	background: var(--avz-pink);
	animation: avz-slide 1.5s ease-in-out infinite;
}

@keyframes avz-slide {
	0%   { transform: translateX(-100%); }
	100% { transform: translateX(295%); }
}

@media (prefers-reduced-motion: reduce) {
	.avz-progress-bar > span {
		animation: none;
		width: 100%;
		opacity: 0.6;
	}
}

.avz-progress-text {
	display: block;
	font-family: var(--avz-head);
	font-size: 14px;
	letter-spacing: 0.1em;
	color: var(--avz-text);
}

.avz-progress-note {
	display: block;
	margin-top: 6px;
	font-size: 12px;
	line-height: 1.5;
	color: var(--avz-muted);
}

/* Panel ------------------------------------------------------------------ */

/*
 * Deliberately NOT sticky and NOT height-capped. Both were what forced the
 * column to grow its own scrollbar, which read as a second, competing scroll
 * region next to the page. The column now flows with the document.
 */
.avz-panel {
	background: var(--avz-panel);
	border: var(--avz-border) solid var(--avz-line);
	padding: var(--avz-pad);
	align-self: start;
}

.avz-panel-head {
	border-bottom: var(--avz-border) solid var(--avz-line);
	padding-bottom: 16px;
	margin-bottom: 4px;
}

.avz-title {
	font-family: var(--avz-head);
	font-weight: 700;
	font-size: 20px;
	letter-spacing: 0.04em;
	margin: 0;
	color: var(--avz-text);
}

/*
 * The registered mark in the heading.
 *
 * A bare <sup> inherits the browser default of font-size: smaller with
 * vertical-align: super, which at 20px leaves the glyph nearly as large as the
 * word it belongs to and pushes the heading's line box taller than the text in
 * it — the panel head then sits a pixel or two low against the quota line
 * beneath. A fixed fraction, an explicit rise and line-height: 0 make it a mark
 * on the word rather than a character in it, and take it out of the line box.
 *
 * letter-spacing is reset because the heading's own 0.04em would otherwise
 * print after the mark, widening the gap before "VISUAL".
 */
.avz-reg {
	font-size: 0.52em;
	vertical-align: 0.42em;
	line-height: 0;
	letter-spacing: 0;
}

.avz-quota {
	margin: 6px 0 0;
	font-size: 13px;
	color: var(--avz-muted);
}

/*
 * Exhausted, and it has to read as a stop rather than as one more grey line.
 *
 * Pink alone was not carrying it: every other count in this column is the
 * same 13px muted text, so "No visualizations left today" arrived looking
 * like a status update and people went on pressing VISUALIZE. Weight is what
 * separates it — the colour was already doing as much as colour can, and
 * leaning on it further would have meant relying on hue alone, which is the
 * one signal some readers do not get.
 */
.avz-quota.is-empty {
	color: var(--avz-pink);
	font-weight: 700;
}

/* Steps ------------------------------------------------------------------ */

.avz-step {
	padding: 20px 0;
	border-bottom: var(--avz-border) solid var(--avz-line);
}

.avz-step:last-of-type {
	border-bottom: 0;
}

.avz-step.is-locked {
	opacity: 0.38;
	pointer-events: none;
}

.avz-step-title {
	display: flex;
	align-items: center;
	gap: 10px;
	font-family: var(--avz-head);
	font-weight: 700;
	font-size: 13px;
	letter-spacing: 0.02em;
	color: var(--avz-text);
	margin: 0 0 14px;
}

.avz-step-title--quiet {
	color: var(--avz-muted);
}

.avz-step-num {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 22px;
	height: 22px;
	border: var(--avz-border) solid var(--avz-line);
	border-radius: var(--avz-radius);
	font-size: 11px;
	letter-spacing: 0;
	color: var(--avz-muted);
	flex: 0 0 auto;
}

.avz-step.is-done .avz-step-num {
	background: var(--avz-bg);
	border-color: var(--avz-pink);
	color: var(--avz-pink);
}

/* File input */

.avz-file {
	position: absolute;
	width: 1px;
	height: 1px;
	opacity: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
}

/*
 * One block for both, deliberately. The accepted-formats line is replaced by
 * the filename in the same position, so they have to be the same size and
 * colour — sharing the declarations makes that true by construction rather
 * than by two numbers someone has to keep equal.
 */
.avz-filename,
.avz-formats {
	display: flex;
	align-items: center;
	gap: 8px;
	margin: 10px 0 0;
	font-size: 13px;
	color: var(--avz-muted);
}

.avz-filename span {
	word-break: break-all;
}

.avz-file-clear {
	appearance: none;
	background: none;
	border: 0;
	padding: 4px;
	line-height: 0;
	flex: 0 0 auto;
	color: var(--avz-muted);
	cursor: pointer;
	transition: color 0.16s ease;
}

.avz-file-clear:hover {
	color: var(--avz-text);
}

.avz-file-clear svg {
	width: 11px;
	height: 11px;
	display: block;
}

/* Category chips */

.avz-chips {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	margin-bottom: 14px;
	transition: opacity 0.16s ease;
}

/*
 * While the search box is driving the grid the chips are not what is
 * selecting patterns, so they recede. They stay clickable — clicking one
 * clears the search and takes control back.
 */
.avz-chips.is-overridden {
	opacity: 0.45;
}

.avz-chip {
	appearance: none;
	background: transparent;
	border: var(--avz-border) solid var(--avz-line);
	color: var(--avz-muted);
	font-family: var(--avz-body);
	font-size: 12px;
	letter-spacing: 0.04em;
	padding: 6px 11px;
	cursor: pointer;
	transition: color 0.16s ease, border-color 0.16s ease;
	border-radius: var(--avz-radius);
}

.avz-chip:hover {
	color: var(--avz-text);
	border-color: var(--avz-muted);
}

.avz-chip.is-active {
	color: var(--avz-text);
	border-color: var(--avz-pink);
}

.avz-chip-count {
	color: var(--avz-muted);
	margin-left: 5px;
	font-size: 11px;
}

/* Pattern grid */

.avz-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 8px;
	max-height: 320px;
	overflow-y: auto;
	padding-right: 4px;
}

.avz-card {
	appearance: none;
	padding: 0;
	background: var(--avz-bg);
	border: var(--avz-border) solid transparent;
	cursor: pointer;
	position: relative;
	display: block;
	line-height: 0;
	transition: border-color 0.16s ease;
	border-radius: var(--avz-radius);
}

.avz-card img {
	width: 100%;
	aspect-ratio: 1 / 1;
	object-fit: cover;
	display: block;
	transition: opacity 0.16s ease;
}

.avz-card:hover img {
	opacity: 0.82;
}

.avz-card-code {
	display: block;
	font-family: var(--avz-body);
	font-size: 10px;
	line-height: 1.4;
	letter-spacing: 0.04em;
	color: var(--avz-muted);
	padding: 5px 4px;
	text-align: center;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.avz-card.is-selected {
	border-color: var(--avz-pink);
}

.avz-card.is-selected .avz-card-code {
	color: var(--avz-text);
}

.avz-card.is-selected .avz-card-code {
	color: var(--avz-pink);
	font-weight: 600;
}

/*
 * Source mode. Two exclusive choices — the whole library narrowed by chips,
 * or one of the user's moodboards. Only one of those controls is ever on
 * screen, so the radios are what tells the user the other exists.
 */
.avz-modes {
	display: flex;
	flex-wrap: wrap;
	gap: 6px 18px;
	margin: 0 0 14px;
}

.avz-mode {
	display: flex;
	align-items: center;
	gap: 8px;
	font-size: 13px;
	color: var(--avz-muted);
	cursor: pointer;
	transition: color 0.16s ease;
}

.avz-mode:hover {
	color: var(--avz-text);
}

.avz-radio {
	appearance: none;
	width: 15px;
	height: 15px;
	flex: 0 0 auto;
	border: var(--avz-border) solid var(--avz-muted);
	border-radius: 50%;
	background: var(--avz-bg);
	cursor: pointer;
	position: relative;
}

.avz-radio:checked {
	border-color: var(--avz-pink);
}

.avz-radio:checked::after {
	content: "";
	position: absolute;
	inset: 3px;
	border-radius: 50%;
	background: var(--avz-pink);
}

.avz-radio:checked + span {
	color: var(--avz-text);
}

.avz-board-picker {
	margin: 0 0 14px;
}

/*
 * Loading placeholders.
 *
 * Same footprint as a real card — 1:1 thumbnail plus a code line — so the
 * grid does not jump when the materials replace them. The pulse is slow and
 * low-contrast: it is there to say "loading", not to decorate (§6), and it
 * stops entirely for anyone who prefers reduced motion.
 */
.avz-skeleton {
	display: block;
	line-height: 0;
}

.avz-skeleton-thumb {
	display: block;
	width: 100%;
	aspect-ratio: 1 / 1;
	background: var(--avz-white-wash);
}

.avz-skeleton-line {
	display: block;
	width: 62%;
	height: 8px;
	margin: 6px auto 5px;
	background: var(--avz-white-wash);
}

.avz-grid.is-loading .avz-skeleton {
	animation: avz-pulse 1.6s ease-in-out infinite;
}

.avz-grid.is-loading .avz-skeleton:nth-child(3n+2) {
	animation-delay: 0.2s;
}

.avz-grid.is-loading .avz-skeleton:nth-child(3n+3) {
	animation-delay: 0.4s;
}

@keyframes avz-pulse {
	0%, 100% { opacity: 1; }
	50%      { opacity: 0.45; }
}

@media (prefers-reduced-motion: reduce) {
	.avz-grid.is-loading .avz-skeleton {
		animation: none;
	}
}

.avz-empty {
	color: var(--avz-muted);
	font-size: 13px;
	line-height: 1.5;
	margin: 12px 0 0;
	padding: 12px;
	border: var(--avz-border) dashed var(--avz-line);
}

.avz-selected {
	margin: 12px 0 0;
	font-size: 12px;
	letter-spacing: 0.04em;
}

.avz-selected-label {
	color: var(--avz-muted);
	text-transform: uppercase;
	font-size: 11px;
	letter-spacing: 0.14em;
	margin-right: 8px;
}

.avz-selected-code {
	font-family: var(--avz-head);
	font-weight: 700;
	color: var(--avz-pink);
	letter-spacing: 0.08em;
}

/* Surfaces */

.avz-surfaces {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
}

.avz-surface {
	appearance: none;
	background: transparent;
	border: var(--avz-border) solid var(--avz-line);
	color: var(--avz-muted);
	font-family: var(--avz-body);
	font-size: 13px;
	padding: 8px 13px;
	cursor: pointer;
	transition: color 0.16s ease, border-color 0.16s ease;
	border-radius: var(--avz-radius);
}

.avz-surface:hover {
	color: var(--avz-text);
	border-color: var(--avz-muted);
}

.avz-surface.is-selected {
	color: var(--avz-text);
	border-color: var(--avz-pink);
}

/*
 * Helper note under the surface buttons (Settings → Texts).
 *
 * One step below the chip label (12px), muted, left edge flush with the
 * buttons. The icon is sized to the text and takes its colour, so it reads
 * as part of the note rather than as a control. min-width and overflow-wrap
 * let a long word or URL wrap on a narrow phone instead of widening the panel.
 */
.avz-note {
	display: flex;
	align-items: flex-start;
	gap: 7px;
	margin: 12px 0 0;
	font-family: var(--avz-body);
	font-size: 11px;
	line-height: 1.5;
	color: var(--avz-muted);
}

.avz-note-icon {
	flex: none;
	width: 13px;
	height: 13px;
	margin-top: 1px; /* centres on the first line: (11 × 1.5 − 13) / 2 ≈ 1.75 */
}

.avz-note > span {
	min-width: 0;
	overflow-wrap: anywhere;
}

/*
 * ~12px below the note as well. The step's 20px bottom padding plus the
 * button's 22px margin would leave 42px, so while the note is present both
 * give way. Without :has() the note simply keeps the wider gap.
 */
.avz-step:has( > .avz-note ) {
	padding-bottom: 0;
}

.avz-step:has( > .avz-note ) + .avz-visualize {
	margin-top: 12px;
}

/* Fields ----------------------------------------------------------------- */

.avz-field {
	margin-top: 14px;
}

.avz-label {
	display: block;
	font-size: 11px;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--avz-muted);
	margin-bottom: 7px;
}

/*
 * Form controls.
 *
 * The selectors are scoped to .animart-viz on purpose. The7 emits
 * `input[type="text"] { background: var(--the7-input-bg-color) }` (white) into
 * uploads/the7-css/custom.css, and at 0,1,1 that beats a bare `.avz-input` at
 * 0,1,0 — which is why text and search fields rendered white on the dark UI
 * while textarea and select, which the theme only targets by element name,
 * were already correct. Scoping lifts these to 0,2,x and settles it without
 * !important. Bare element selectors are included so an input added later
 * without the class still inherits the dark treatment.
 *
 * `password` was missing from this list until the account screen added the
 * first password fields on the front end, and it produced BOTH symptoms at
 * once: white boxes, because the theme's rule won, and narrow boxes, because
 * `width: 100%` never applied and the browser fell back to its default size.
 * Any new input type must be added here. The focus and placeholder rules
 * below already use a bare `input`, which is what hid the gap.
 */
.animart-viz .avz-input,
.animart-viz .avz-textarea,
.animart-viz .avz-select,
.animart-viz input[type="text"],
.animart-viz input[type="search"],
.animart-viz input[type="email"],
.animart-viz input[type="number"],
.animart-viz input[type="password"],
.animart-viz textarea,
.animart-viz select {
	width: 100%;
	background: var(--avz-bg);
	border: var(--avz-border) solid var(--avz-line);
	color: var(--avz-text);
	font-family: var(--avz-body);
	font-size: 14px;
	line-height: 1.5;
	padding: var(--avz-field-pad);
	border-radius: var(--avz-radius);
	appearance: none;
	-webkit-appearance: none;
	transition: border-color 0.16s ease;
}

/*
 * Chrome paints autofilled fields with its own background at a priority no
 * ordinary rule can reach. The inset shadow trick is the standard way to
 * cover it — the moodboard name field is the one likely to be autofilled.
 */
.animart-viz input:-webkit-autofill,
.animart-viz input:-webkit-autofill:hover,
.animart-viz input:-webkit-autofill:focus {
	-webkit-text-fill-color: var(--avz-text);
	-webkit-box-shadow: 0 0 0 1000px var(--avz-bg) inset;
	caret-color: var(--avz-text);
}

.avz-textarea {
	resize: vertical;
	min-height: 62px;
}

.animart-viz .avz-input:focus,
.animart-viz .avz-textarea:focus,
.animart-viz .avz-select:focus,
.animart-viz input:focus,
.animart-viz textarea:focus,
.animart-viz select:focus {
	outline: none;
	/* Border colour only. An inset shadow here made the bottom edge read as
	   2px against 1px on the other three sides. */
	border-color: var(--avz-pink);
}

/* Same grey as .avz-step-title--quiet ("REFINE"), which reads correctly. */
.animart-viz ::placeholder {
	color: var(--avz-muted);
	opacity: 1;
}

.avz-search {
	position: relative;
	margin-bottom: 12px;
}

.avz-input--search {
	padding-right: 34px;
}

.avz-search-clear {
	position: absolute;
	top: 50%;
	right: 4px;
	transform: translateY(-50%);
	appearance: none;
	background: none;
	border: 0;
	padding: 8px;
	line-height: 0;
	color: var(--avz-muted);
	cursor: pointer;
	transition: color 0.16s ease;
}

.avz-search-clear:hover {
	color: var(--avz-text);
}

.avz-search-clear svg {
	width: 12px;
	height: 12px;
	display: block;
}

/* The native clear control is removed by appearance:none; hide any remnant. */
.animart-viz input[type="search"]::-webkit-search-cancel-button,
.animart-viz input[type="search"]::-webkit-search-decoration {
	-webkit-appearance: none;
	appearance: none;
}

/* Buttons ---------------------------------------------------------------- */

.avz-btn {
	appearance: none;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border: var(--avz-border) solid transparent;
	border-radius: var(--avz-radius);
	font-family: var(--avz-head);
	font-weight: 700;
	font-size: 13px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	text-decoration: none;
	padding: 13px 22px;
	cursor: pointer;
	transition: background-color 0.16s ease, color 0.16s ease, border-color 0.16s ease;
}

.avz-btn--block {
	width: 100%;
	margin-top: 10px;
}

.avz-btn--primary {
	background: var(--avz-pink);
	color: var(--avz-text);
}

.avz-btn--primary:hover:not(:disabled) {
	background: var(--avz-pink-hover);
	color: var(--avz-text);
}

.avz-btn--ghost {
	background: transparent;
	border-color: var(--avz-line);
	color: var(--avz-text);
}

.avz-btn--ghost:hover:not(:disabled) {
	border-color: var(--avz-text);
	color: var(--avz-text);
}

.avz-btn--outline {
	background: transparent;
	border-color: var(--avz-pink);
	color: var(--avz-pink);
}

.avz-btn--outline:hover {
	background: var(--avz-pink);
	color: var(--avz-text);
}

.avz-btn:disabled,
.avz-btn.is-disabled {
	opacity: 0.35;
	cursor: not-allowed;
}

.avz-visualize {
	width: 100%;
	margin-top: 22px;
	padding: 16px 22px;
	letter-spacing: 0.2em;
}

/*
 * Stays a quiet text link. The icon is sized to the text and inherits its
 * colour, so adding it does not make the control read as a button.
 */
.avz-restart {
	appearance: none;
	background: none;
	border: 0;
	color: var(--avz-muted);
	font-family: var(--avz-body);
	font-size: 13px;
	cursor: pointer;
	padding: 18px 0 0;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 7px;
	width: 100%;
}

/* Underline on the text only — an underlined icon looks like a mistake. */
.avz-restart span {
	text-decoration: underline;
	text-underline-offset: 3px;
}

.avz-restart-icon {
	width: 1em;
	height: 1em;
	flex: 0 0 auto;
}

.avz-restart:hover {
	color: var(--avz-text);
}

/* Consent ---------------------------------------------------------------- */

.avz-consent {
	border: var(--avz-border) solid var(--avz-line);
	padding: 14px;
	margin-top: 18px;
}

.avz-consent-row {
	display: flex;
	gap: 11px;
	align-items: flex-start;
	cursor: pointer;
}

.avz-check {
	appearance: none;
	width: 17px;
	height: 17px;
	flex: 0 0 auto;
	margin-top: 2px;
	border: var(--avz-border) solid var(--avz-muted);
	background: var(--avz-bg);
	cursor: pointer;
	position: relative;
}

.avz-check:checked {
	border-color: var(--avz-pink);
	background: var(--avz-pink);
}

.avz-check:checked::after {
	content: "";
	position: absolute;
	left: 5px;
	top: 1px;
	width: 5px;
	height: 10px;
	border: solid var(--avz-text);
	border-width: 0 2px 2px 0;
	transform: rotate(45deg);
}

/*
 * The assent and the disclosure stack in one column beside the box, so the
 * checkbox aligns with "I consent" and the explanation reads as its fine
 * print rather than as a second thing to agree to.
 */
.avz-consent-body {
	display: flex;
	flex-direction: column;
	gap: 3px;
	min-width: 0;
}

/*
 * Full-strength text where the explanation is muted: this is the line the
 * tick actually belongs to, and it should be the first thing read.
 */
.avz-consent-assent {
	font-size: 13px;
	line-height: 1.55;
	color: var(--avz-text);
}

.avz-consent-text {
	font-size: 13px;
	line-height: 1.55;
	color: var(--avz-muted);
}

/* Alert ------------------------------------------------------------------ */

.avz-alert {
	margin-top: 16px;
	padding: 12px 14px;
	border-left: var(--avz-border) solid var(--avz-pink);
	background: var(--avz-pink-wash);
	font-size: 13px;
	line-height: 1.5;
}

.avz-alert--ok {
	border-left-color: var(--avz-text);
	background: var(--avz-white-wash);
}

/* Result ----------------------------------------------------------------- */

.avz-result-actions {
	display: flex;
	gap: 10px;
}

.avz-result-actions .avz-btn {
	flex: 1;
}

.avz-refine {
	border-bottom: var(--avz-border) solid var(--avz-line);
}

/*
 * What Auto will do, standing where the custom field stands in the other mode.
 *
 * Margin zero, including the bottom, because the gap below both of them is the
 * button's own `.avz-btn--block { margin-top: 10px }` rather than anything
 * either element contributes — the textarea sets no margin at all. Giving this
 * one a bottom margin would move the REFINE button every time the mode changed.
 * A <p> would otherwise bring UA margins to a layout that assumes none.
 */
.avz-refine-note {
	margin: 0;
	font-size: 13px;
	line-height: 1.5;
	color: var(--avz-muted);
}

.avz-cta {
	padding-top: 20px;
}

.avz-cta-lede {
	font-family: var(--avz-head);
	font-weight: 700;
	font-size: 13px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--avz-muted);
	margin: 0 0 4px;
}

/* Modal ------------------------------------------------------------------ */

.avz-modal {
	position: fixed;
	inset: 0;
	z-index: 10000;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 20px;
}

.avz-modal-backdrop {
	position: absolute;
	inset: 0;
	background: var(--avz-scrim);
}

.avz-modal-box {
	position: relative;
	width: min(420px, 100%);
	background: var(--avz-panel);
	border: var(--avz-border) solid var(--avz-line);
	padding: 26px;
}

.avz-modal-title {
	font-family: var(--avz-head);
	font-weight: 700;
	font-size: 15px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	margin: 0 0 18px;
	color: var(--avz-text);
}

/*
 * The saving indicator, riding the top edge of the dialog.
 *
 * Absolutely positioned, and that is the whole reason it sits here rather than
 * in the flow above the buttons: .avz-progress-bar carries a 14px bottom
 * margin, so showing it inline would push the action row down by 16px at the
 * exact moment the user clicks SAVE. Taken out of the flow it costs no layout
 * at all, and a hairline across the head of the dialog reads as the dialog
 * working rather than as a component that has appeared.
 *
 * Inherits height, colour and the sliding animation — including its
 * reduced-motion rule — from .avz-progress-bar.
 */
.avz-modal-progress {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	margin: 0;
	background: transparent;
}

.avz-modal-actions {
	display: flex;
	gap: 10px;
	margin-top: 22px;
}

.avz-modal-actions .avz-btn {
	flex: 1;
	margin-top: 0;
}

/* Signed-out gate -------------------------------------------------------- */

.animart-viz--gate {
	display: block;
	padding-top: 40px;
}

.avz-gate {
	max-width: 620px;
	margin: 0 auto;
	text-align: center;
	border: var(--avz-border) solid var(--avz-line);
	padding: 48px 32px;
}

.avz-gate-title {
	font-family: var(--avz-head);
	font-weight: 700;
	font-size: 24px;
	letter-spacing: 0.02em;
	margin: 0 0 14px;
	color: var(--avz-text);
}

.avz-gate-text {
	color: var(--avz-muted);
	margin: 0 0 26px;
}

.avz-gate-actions {
	margin: 0;
}

/* Focus visibility ------------------------------------------------------- */

.animart-viz :focus-visible {
	outline: 2px solid var(--avz-pink);
	outline-offset: 2px;
}

/* Responsive ------------------------------------------------------------- */

@media (max-width: 1100px) {
	.animart-viz {
		grid-template-columns: minmax(0, 1fr) 330px;
		--avz-gap: 20px;
	}
}

@media (max-width: 768px) {
	.animart-viz {
		grid-template-columns: 1fr;
		padding: 0 16px 40px;
	}

	.avz-stage {
		min-height: 300px;
	}

	.avz-drop {
		min-height: 220px;
	}

	.avz-grid {
		grid-template-columns: repeat(4, 1fr);
		max-height: 260px;
	}
}

@media (max-width: 480px) {
	.avz-grid {
		grid-template-columns: repeat(3, 1fr);
	}
}

/* ---------------------------------------------------------------------------
 * Account screen
 *
 * Layout only. Every colour, font, radius and control style is inherited from
 * the tokens and the field/button/alert rules above, because this screen is
 * the same interface as the visualizer and should not be a second opinion
 * about what a dark input looks like.
 *
 * The shape is the WooCommerce account page: a narrow nav, a wide content
 * area, the pair filling whatever column the shortcode is dropped into and
 * anchored to its left edge. It deliberately sets NO max-width and NO auto
 * margins — an earlier version centred itself inside 940px, which left the
 * form cramped in the middle of an empty page. Page width is the theme's
 * business; this fills what it is given.
 * ------------------------------------------------------------------------ */

/*
 * `display: block` is the important line, and the reason this screen looked
 * cramped with an empty band beside it.
 *
 * .animart-viz is not a neutral wrapper. It is the visualizer's own layout:
 * `grid-template-columns: minmax(0, 1fr) 380px`, the room preview beside its
 * control column. This screen has a single child, so it was being placed in
 * the 1fr track with 380px reserved and empty to its right, inside a
 * 1300px auto-centred box. Resetting the width alone left the phantom column
 * behind; the grid itself has to go.
 *
 * The tokens on .animart-viz are what we came for, not its layout.
 */
.animart-viz--profile {
	display: block;
	width: 100%;
	max-width: none;
	margin: 0;
	padding: 0 0 40px;
}

.avz-tabs {
	display: grid;
	grid-template-columns: 220px minmax(0, 1fr);
	align-items: start;

	/* The panel is a bordered surface of its own, so the nav is separated by
	   real space rather than by a rule drawn beside another rule. */
	gap: var(--avz-gap);
}

/* Without this a long value inside the panel can force the grid wider than
   its container instead of wrapping. */
.avz-panels {
	min-width: 0;
}

/*
 * No padding override here on purpose.
 *
 * .avz-panel is an existing visualizer component and already carries the
 * background, border and `padding: var(--avz-pad)` every other panel in this
 * interface uses. An earlier version replaced all of that with a single left
 * offset, which is why the first label sat flush against the top edge and the
 * last control against the bottom. Separation from the nav is the grid's gap,
 * not the panel's padding.
 */

/* ---- Fields ------------------------------------------------------------ */

/*
 * Two equal columns. Anything that reads as a single value spans both, so
 * only first and last name pair up — and because the panel is now wide, each
 * half is a real half rather than a small box with empty space beside it.
 *
 * Rhythm comes from row-gap, and .avz-field's own top margin is cancelled
 * inside this screen. Keeping both would compound into an uneven ladder where
 * a full-width field sat further from its neighbour than a paired one.
 */
.animart-viz--profile .avz-profile-grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	column-gap: var(--avz-gap);
	row-gap: 32px;
}

.animart-viz--profile .avz-profile-grid .avz-field {
	margin-top: 0;
}

.animart-viz--profile .avz-profile-grid .avz-field--wide {
	grid-column: 1 / -1;
}

/* Helper text is the only place this screen carries a link, so it is styled
   here rather than as a global anchor rule that could reach the theme. */
.avz-profile-note a {
	color: var(--avz-pink);
	text-decoration: none;
	border-bottom: var(--avz-border) solid transparent;
	transition: border-color 0.16s ease, color 0.16s ease;
}

.avz-profile-note a:hover,
.avz-profile-note a:focus-visible {
	color: var(--avz-pink-hover);
	border-bottom-color: currentColor;
}

/* The one piece of helper text that is an offer of help rather than an
   explanation, so it sits a step above the rest. */
.avz-profile-note--reset {
	font-size: 13px;
}

.avz-profile-note {
	/* About 60 characters. Across a full-width panel this would otherwise set
	   at a measure no one can track back to the start of the next line. */
	max-width: 60ch;
	margin: 8px 0 0;
	font-size: 12px;
	line-height: 1.5;
	color: var(--avz-muted);
}

/*
 * Read-only fields stay legible but stop inviting a cursor. Scoped to
 * .animart-viz, like every other control rule here, so it cannot reach a form
 * belonging to the theme.
 */
.animart-viz [readonly] {
	color: var(--avz-muted);
	cursor: not-allowed;
}

.animart-viz [readonly]:focus {
	border-color: var(--avz-line);
}

/*
 * No rule above the buttons. There was one, and above a single button it read
 * as a line that had come loose rather than a divider between two things.
 * Space does the same job without asking to be explained.
 */
/*
 * The password confirmation carries more than a confirmation — it tells the
 * user their other devices were signed out, which is the sentence they need
 * to actually read. The details panel's "saved" message stays at normal
 * weight; it reports nothing the user did not just ask for.
 */
.avz-panel[data-panel="password"] .avz-alert--ok {
	font-weight: 700;
}

.avz-profile-actions {
	display: flex;
	flex-wrap: wrap;
	gap: 12px;
	margin-top: 36px;
}

/* ---- Tabs -------------------------------------------------------------- */

/*
 * A vertical list beside its panels. The list is the only thing carrying the
 * accent: a selected tab is marked by a pink rule against a faint wash, so the
 * eye finds it without a button-shaped control competing with the real buttons
 * inside the panel.
 *
 * Panels are visible until the script marks the container `is-tabbed`. Without
 * JavaScript the page is simply longer, and both forms still work.
 */

.avz-tablist {
	display: flex;
	flex-direction: column;
	align-self: stretch;
}

.avz-tab {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;

	appearance: none;
	background: transparent;
	border: 0;
	border-left: 2px solid transparent;
	border-radius: 0;

	padding: 14px 18px 14px 16px;
	text-align: left;
	text-decoration: none;
	cursor: pointer;

	font-family: var(--avz-head);
	font-weight: 700;
	font-size: 12px;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--avz-muted);

	transition: color 0.16s ease, background-color 0.16s ease, border-color 0.16s ease;
}

.avz-tab:hover,
.avz-tab:focus-visible {
	color: var(--avz-text);
	background: var(--avz-white-wash);
}

.avz-tab[aria-selected="true"] {
	color: var(--avz-text);
	background: var(--avz-white-wash);
	border-left-color: var(--avz-pink);
}

/* Marks a panel holding a rejected form, so an error on a tab you cannot
   currently see still announces itself. */
.avz-tab-flag {
	color: var(--avz-pink);
	font-size: 18px;
	line-height: 1;
}

.avz-tab-arrow {
	color: var(--avz-muted);
	font-size: 14px;
}

.avz-tab--link:hover .avz-tab-arrow {
	color: var(--avz-pink);
}

.avz-panel:focus {
	outline: none;
}

/* ---- Password strength ------------------------------------------------- */

/*
 * Neutral until there is something to judge; the scale runs from the palette's
 * own pink through to plain white for a strong password, rather than importing
 * a red/amber/green traffic light that belongs to no other part of this
 * interface.
 */
.avz-strength {
	margin: 8px 0 0;
	font-size: 12px;
	line-height: 1.5;
	color: var(--avz-muted);
	letter-spacing: 0.04em;
}

/*
 * Once there is a verdict it is a verdict, not helper text: a word rather
 * than a sentence, so it carries weight and a step in size. The empty state
 * keeps the quieter note treatment, since "At least 8 characters." is an
 * instruction and should not shout.
 */
.avz-strength[class*="is-score-"] {
	font-weight: 700;
	font-size: 13px;
}

.avz-strength.is-score-0,
.avz-strength.is-score-1 {
	color: var(--avz-pink);
}

.avz-strength.is-score-2 {
	color: var(--avz-muted);
}

.avz-strength.is-score-3,
.avz-strength.is-score-4 {
	color: var(--avz-text);
}

/* ---- Phones ------------------------------------------------------------ */

@media (max-width: 768px) {
	/* The list stacks above the panel, full width, still vertical — three
	   items read better as a short list than as a cramped scrolling row. */
	.avz-tabs {
		grid-template-columns: 1fr;
	}

	.avz-tab {
		border-left: 0;
		border-right: 2px solid transparent;
	}

	.avz-tab[aria-selected="true"] {
		border-left-color: transparent;
		border-right-color: var(--avz-pink);
	}

	.animart-viz--profile .avz-profile-grid {
		grid-template-columns: 1fr;
	}

	.avz-profile-actions {
		flex-direction: column;
	}

	.avz-profile-actions .avz-btn {
		width: 100%;
	}
}

/* ---------------------------------------------------------------------------
 * Rotating progress phrases
 *
 * Below the image container, not over it: the photograph is the subject and
 * §7 says nothing may compete with it.
 *
 * NOT uppercased, deliberately, though every other Lato label here is. One of
 * the supplied phrases is "apticon®-izing", and the brand is lowercase (§6) —
 * transforming it would print APTICON®-IZING and get the client's own name
 * wrong. The list is theirs to edit, so the styling has to survive whatever
 * they put in it.
 * ------------------------------------------------------------------------ */

.avz-phrases {
	/* Space is reserved whether or not a phrase is showing, so the actions
	   below do not jump when the rotation starts and stops. */
	min-height: 1.5em;
	margin: 14px 0 0;

	text-align: center;
	font-family: var(--avz-head);
	font-weight: 700;
	font-size: 15px;
	letter-spacing: 0.04em;
	line-height: 1.5;
	color: var(--avz-pink);
}

.avz-phrases span {
	display: inline-block;
	opacity: 1;
	transition: opacity 0.32s ease;
}

/* The script adds this, swaps the text at the midpoint, then removes it —
   which is what makes one phrase read as becoming the next. */
.avz-phrases.is-fading span {
	opacity: 0;
}

/*
 * The shimmer: a light travelling left to right through the letters, running
 * continuously while a visualization is being generated. The text stays fully
 * visible throughout — this is a highlight moving across it, not a fade.
 *
 * Done by clipping a moving gradient to the glyphs. That requires
 * `color: transparent`, which is why the whole thing sits inside @supports:
 * where background-clip on text is unavailable, transparent text over a black
 * panel would be an invisible phrase rather than a plain one. Without support
 * the rule never applies and the phrase stays flat pink.
 *
 * DIRECTION. background-position percentages are relative to the difference
 * between the image and the box, and the image here is twice the box — so a
 * position of 100% shifts the gradient a full box-width to the left, and
 * animating 100% down to 0% walks the visible window from the gradient's right
 * half to its left half. The highlight sits at the middle, so it crosses the
 * text left to right. Reversing the keyframes reverses the sweep.
 */
@supports ( (-webkit-background-clip: text) or (background-clip: text) ) {
	.avz-phrases span {
		background-image: linear-gradient(
			100deg,
			var(--avz-pink) 42%,
			#FFFFFF 50%,
			var(--avz-pink) 58%
		);
		background-size: 200% 100%;
		background-repeat: no-repeat;

		-webkit-background-clip: text;
		background-clip: text;
		color: transparent;
		-webkit-text-fill-color: transparent;

		animation: avz-shimmer 2.6s linear infinite;
	}

	/*
	 * No shimmer where motion is unwelcome — and the paint has to be undone as
	 * well as the movement, or a stopped gradient would leave one word lit and
	 * the rest dark. Back to flat pink text.
	 */
	@media (prefers-reduced-motion: reduce) {
		.avz-phrases span {
			animation: none;
			background-image: none;
			color: var(--avz-pink);
			-webkit-text-fill-color: var(--avz-pink);
		}
	}
}

@keyframes avz-shimmer {
	from {
		background-position: 100% 0;
	}

	to {
		background-position: 0% 0;
	}
}

/*
 * No fade on the change where motion is unwelcome either. The phrases still
 * rotate — only the transition goes, so nobody loses the information. The
 * script checks the same query and skips the midpoint swap, so the two cannot
 * disagree.
 */
@media (prefers-reduced-motion: reduce) {
	.avz-phrases span {
		transition: none;
	}
}
