/*
Theme Name: Seaway
Theme URI: https://www.seawayplumbing.com/
Author: Seaway Plumbing
Description: Native WordPress block theme for Seaway Plumbing. Replaces the proprietary Scorpion platform. All content is editable in the WordPress block editor — no third-party page builder.
Version: 1.9.2
Requires at least: 6.5
Tested up to: 6.7
Requires PHP: 8.1
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: seaway
Tags: full-site-editing, block-templates, blog, one-column
*/

/*
 * theme.json carries the design tokens. Only what it cannot express belongs here, and
 * that is essentially one thing: the masthead floats over the hero rather than sitting
 * above it, which is a positioning relationship between two separate template parts.
 */

/* The masthead overlays whatever follows it, so the hero image runs up behind the logo
   and navigation as it does on the original site. The utility bar stays in normal flow. */
.wp-site-blocks > header {
	position: relative;
	z-index: 20;
}

.seaway-masthead {
	position: absolute;
	inset-inline: 0;
	/* Sits directly under the utility bar. */
	inset-block-start: 100%;
}

/* Clear the overlaid masthead so hero copy is never hidden beneath it. Applied to the
   hero itself rather than to <main>, so the background image still reaches the top. */
/* Hero proportions, measured from the original rather than estimated.
 *
 * Scorpion's hero scales with viewport WIDTH, not height: 898px tall at 1440 wide whether
 * the window is 900 or 1200 tall. 62vw reproduces that (893px at 1440, against a measured
 * 898), clamped so it neither collapses on small laptops nor runs away on ultrawides. */
main .wp-block-post-content > .wp-block-cover:first-of-type {
	min-height: clamp(30rem, 62vw, 68rem);
}

/* Applied to the cover's inner container, not the cover: the cover carries an inline
   padding-top from its own block attributes, which no stylesheet rule can override
   without !important. The inner container has no inline style, so this stays clean.
   The cover centres its own content, so this only needs to clear the masthead — adding
   more on top of that pushes the copy below the centre line rather than down from the
   top. */
main .wp-block-post-content > .wp-block-cover:first-of-type > .wp-block-cover__inner-container {
	padding-block-start: var(--seaway-masthead-height);
}

:root {
	--seaway-masthead-height: 7.5rem;
}

/* Pages that do not open with a hero have nothing dark behind the masthead, so white
   navigation would land on white content. Give those a solid background instead. */
body:not(:has(.wp-block-post-content > .wp-block-cover:first-of-type)) .seaway-masthead {
	position: static;
	background: var(--wp--preset--color--dark) !important;
	padding-block-end: 1rem;
}

/* Keep logo, navigation and the call-to-action on one row, shrinking the logo before
   anything wraps. Below the navigation breakpoint the menu collapses to its own toggle. */
.seaway-masthead {
	align-items: center;
}

.seaway-masthead > .wp-block-site-logo {
	flex: 0 1 auto;
	min-width: 0;
}

.seaway-masthead > .wp-block-site-logo img {
	max-width: 100%;
	height: auto;
}

@media (max-width: 1199px) {
	:root {
		--seaway-masthead-height: 6rem;
	}

	.seaway-masthead > .wp-block-site-logo {
		width: 220px;
	}
}

@media (max-width: 781px) {

	.seaway-masthead {
		position: static;
		padding-block-end: 1rem;
	}

	main .wp-block-post-content > .wp-block-cover:first-of-type > .wp-block-cover__inner-container {
		padding-block-start: 0;
	}
}

/* The hero subtitle: same paragraph block, lighter weight. Registered as a block style so
   it is selectable in the editor rather than being an invisible class. */
.is-style-thin {
	font-weight: 300;
	line-height: 1.5;
}

/* ---------------------------------------------------------------------------------
 * Homepage pass 2
 * ------------------------------------------------------------------------------- */

/* Hero copy is constrained to the half-width column Scorpion declares for it, so it
   wraps clear of the van composited into the background rather than running under it. */
.wp-block-post-content .seaway-half {
	/* The original runs its hero content in a 90%-wide wrapper — measured 72px in at 1440
	   and 64px at 1280, i.e. 5vw either side — with the copy taking half of that. Anchoring
	   at 0 put the headline hard against the viewport edge instead.
	   Core sets these margins with !important (`.is-layout-constrained > :where(...)`), so
	   matching it is the only way to anchor left short of an alignment that would float. */
	max-width: 45vw;
	margin-inline-start: calc(5vw - var(--wp--style--root--padding-left, 1rem)) !important;
	margin-inline-end: auto !important;
}

/* The hero headline is larger than a page heading: 59px at 1440 and 54px at 1280 on the
   original, roughly 4.1vw. The x-large preset tops out at 47px, which is right for page
   titles and too small here, so the hero gets its own fluid size. */
main .wp-block-post-content > .wp-block-cover:first-of-type h1 {
	font-size: clamp(2.25rem, 4.1vw, 4.5rem);
	line-height: 1.05;
}

/* A supporting heading inside a section: the original's 28.8px at regular weight, not a
   second 47px headline competing with the section title above it. */
.is-style-subheading {
	font-size: var(--wp--preset--font-size--large);
	font-weight: 400;
	line-height: 1.5;
}

/* Section titles sit centred above their content. */
.is-style-section-title {
	text-align: center;
}

/* Service areas: two columns of red bullets, collapsing on narrow screens. */
.seaway-location-list {
	columns: 2;
	column-gap: var(--wp--preset--spacing--40);
}

.seaway-location-list li {
	break-inside: avoid;
}

.seaway-location-list li::marker {
	color: var(--wp--preset--color--primary);
}

/* Cards centre their badge, title and price; the benefit list stays left-aligned so it
   remains readable as a list rather than a centred block of text. */
.seaway-card {
	text-align: center;
	height: 100%;
}

.seaway-card ul,
.seaway-card ol {
	text-align: left;
}

/* Quote carousel. A scroll container of ordinary blocks: swipes on touch, scrolls with a
   trackpad, and is keyboard and screen-reader navigable without any JavaScript. */
.seaway-carousel {
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scroll-padding-inline: var(--wp--preset--spacing--30);
	/* The strip advances on its own, on swipe and from the dots, and snaps one testimonial
	   at a time — a visible scrollbar only advertises that this is a scroll container.
	   Hidden in both engines; the container stays scrollable and keyboard reachable. */
	scrollbar-width: none;
	-ms-overflow-style: none;
	/* Was spacing--20, which reserved room under the strip for a scrollbar that is now
	   hidden. With nothing to clear, it only pushed the dots away from the quotes. */
	padding-bottom: 0;
}

.seaway-carousel::-webkit-scrollbar {
	display: none;
}

/* One quote at a time, filling its column. A fractional card width made sense for a
   full-width strip but not inside the 37.5% column this sits in, where it showed slivers
   of the neighbours rather than a single testimonial. */
.seaway-carousel > * {
	scroll-snap-align: start;
	flex: 0 0 100%;
	scroll-margin: 0;
}

/* Dots below the strip. Ordinary anchors pointing at each slide, so they scroll the
   container natively and are reachable by keyboard.
   Which dot is currently in view cannot be observed in CSS, so assets/js/carousel.js adds
   `is-enhanced` and tracks it. Until then — or if that script never loads — the first dot
   stays highlighted and the dots still navigate. */
.seaway-carousel-dots {
	display: flex;
	gap: 0.75rem;
	/* Tight to the quotes. The dots are a control for the strip directly above them, so a
	   full section gap read as though they belonged to whatever came next. This also
	   overrides the block gap core would otherwise apply between the two siblings. */
	margin-block-start: 0.85rem;
}

/* Rebalance the testimonial row: quotes narrower, the card grid wider.
 *
 * Scorpion's own three-8ths / five-8ths classes drive these widths and are used on roughly
 * 200 pages, so the width map itself cannot move. Scoping to the row that actually contains
 * a carousel keeps the change to this one layout.
 *
 * `!important` is required because the widths are inline `style="flex-basis:37.5%"` on the
 * columns. Confined to >=782px because core stacks columns below that with its own
 * `flex-basis: 100% !important` — without the guard this would win and break mobile. */
@media (min-width: 782px) {

	/* The card grid begins on the page's centre line: its first icon's left edge lands at
	   50%. Working back — the icon sits one card-padding in from the column edge, so the
	   right column must start at `50% - card padding`, which fixes its width at
	   `50% + card padding` and leaves the rest, minus the gap, to the testimonial.
	   Expressed in calc rather than as fixed percentages so it holds at any width, and so
	   opening --sq-col-gap takes space from the testimonial without moving the centre
	   line. */
	.wp-block-columns:has(.seaway-carousel) > .wp-block-column:first-child {
		flex-basis: calc(50% - var(--sq-card-pad) - var(--sq-col-gap)) !important;
	}

	.wp-block-columns:has(.seaway-carousel) > .wp-block-column:last-child {
		flex-basis: calc(50% + var(--sq-card-pad)) !important;
	}

	/* Pinned to two columns. The block's own `minimumColumnWidth: 22rem` auto-fills, and at
	   the narrower width this column now has (604px at 1440) that resolves to ONE column —
	   which would stack all six cards into a single tall strip. */
	.wp-block-group.alignfull:has(.seaway-carousel) .is-layout-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

/* ---------------------------------------------------------------------------------
 * Testimonial band — collapsed spacing baseline
 *
 * Every margin and padding in this section is cut to roughly a tenth of what it was: a
 * deliberate floor to build back up from, not a finished design. Each variable records the
 * value it replaced, so dialling one back is a single-number edit rather than a re-measure.
 *
 * `!important` appears twice and is unavoidable there: the band's vertical padding and the
 * cards' padding are inline `style` attributes emitted with the block, and nothing short of
 * !important outranks an inline style. Fixing it at source instead would move the padding on
 * every band and every card on the site, which is not what was asked for.
 * ------------------------------------------------------------------------------- */

.wp-block-group.alignfull:has(.seaway-carousel) {
	/* Dialling back up from the 10% floor. Each line carries the floor it left and the
	   original it started from, so both directions stay one edit away. */
	--sq-band-pad: 30px;      /* floor 0.66rem;  original 6.625rem — 106px */
	--sq-gap: 0.15rem;        /* columns + carousel; original 1.5rem — 24px */
	--sq-grid-gap: 10px;      /* right-hand card grid, split off from --sq-gap so the two
	                             columns can stay tight while the cards breathe */
	--sq-col-gap: 40px;       /* testimonial ↔ card grid; split off from --sq-gap so this
	                             one can open up without moving the carousel's own gap */
	--sq-card-pad: 0.25rem;   /* floor; original 2.5rem — 40px */
	--sq-dot-gap: 15px;       /* floor 0.1rem;   original 0.85rem — 13.6px */

	padding-top: var(--sq-band-pad) !important;
	padding-bottom: var(--sq-band-pad) !important;
}

.wp-block-group.alignfull:has(.seaway-carousel) .seaway-carousel {
	gap: var(--sq-gap);
}

.wp-block-group.alignfull:has(.seaway-carousel) .wp-block-columns {
	gap: var(--sq-col-gap);
}

.wp-block-group.alignfull:has(.seaway-carousel) .is-layout-grid {
	gap: var(--sq-grid-gap);
}

.wp-block-group.alignfull:has(.seaway-carousel) .seaway-card {
	padding: var(--sq-card-pad) !important;
}

/* Block-to-block rhythm inside the cards. Core sets this with `:where()`, which carries no
   specificity, so an ordinary selector is enough — no !important needed. */
.wp-block-group.alignfull:has(.seaway-carousel) :is(.seaway-card, .wp-block-quote) > * + * {
	margin-block-start: var(--sq-gap);
}

/* core/quote ships its own indent and rule. Both are spacing inside the testimonial, so
   both come out at this baseline. */
.wp-block-group.alignfull:has(.seaway-carousel) .wp-block-quote {
	margin: 0;
	padding: 0;
	border: 0;
}

.wp-block-group.alignfull:has(.seaway-carousel) .seaway-carousel-dots {
	margin-block-start: var(--sq-dot-gap);
}

/* Testimonials read as quoted prose rather than centred display text: ranged left, and set
   in the muted grey so the quote sits behind the section around it.
   `!important` on the colour is forced, not sloppy — core emits `.has-contrast-color` with
   !important of its own, and that class is on the block. */
.wp-block-group.alignfull:has(.seaway-carousel) .seaway-carousel > .seaway-card {
	text-align: left;
	color: var(--wp--preset--color--muted) !important;
}

/* Feature cards run icon-left, text-right.
 *
 * The icon is core's `.aligncenter` figure — `display: table` with auto side margins, which
 * measured 181px either side. Both have to be undone or the icon keeps centring itself
 * inside the row it is now a flex item of. */
.wp-block-group.alignfull:has(.seaway-carousel) .is-layout-grid > .seaway-card {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	text-align: left;
}

.wp-block-group.alignfull:has(.seaway-carousel) .is-layout-grid > .seaway-card > .wp-block-image {
	display: block;
	flex: 0 0 auto;
	margin: 0;
}

/* 5px down from the 1.8rem headings elsewhere, in dark grey rather than black — these are
   reassurance labels beside an icon, not section headings, and at full weight and full
   black they were competing with the testimonial next to them. */
.wp-block-group.alignfull:has(.seaway-carousel) .is-layout-grid > .seaway-card > h3 {
	flex: 1 1 auto;
	font-size: calc(1.8rem - 5px);
	color: var(--wp--preset--color--gray);
}

/* The block rhythm set in the baseline above would land as a top margin on the heading now
   that these cards are a row, pushing it out of line with the icon. `gap` spaces them. */
.wp-block-group.alignfull:has(.seaway-carousel) .is-layout-grid > .seaway-card > * + * {
	margin-block-start: 0;
}

/* ---------------------------------------------------------------------------------
 * Homepage pass 4
 * ------------------------------------------------------------------------------- */

/* Plan cards: every Learn More button sits on a common baseline at the foot of its card,
   centred — rather than trailing whichever benefit list happened to be shortest. The card
   becomes a column so `margin-block-start: auto` can push the button down; the cards are
   already equal height from the grid, so the buttons land in a row. */
.seaway-card:has(.seaway-price) {
	display: flex;
	flex-direction: column;
}

.seaway-card:has(.seaway-price) > .wp-block-buttons {
	margin-block-start: auto;
	justify-content: center;
}

/* A floated image inside a constrained wrapper is excluded by core from the content-width
   clamp — `.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull))`
   is what gets the max-width, and an aligned image is explicitly not it. So the Ocean Reef
   badge floated to the *band's* padding edge, measured 96px past the copy beside it. Pull
   it back by the same gutter the constrained content uses, so the two edges line up. */
.wp-block-post-content .is-layout-constrained > .alignright {
	margin-inline-end: max(0px, calc((100% - var(--wp--style--global--content-size)) / 2));
}

.wp-block-post-content .is-layout-constrained > .alignleft {
	margin-inline-start: max(0px, calc((100% - var(--wp--style--global--content-size)) / 2));
}

/* The closing contact band is a centred call to action, so the supporting line and the
   button beneath it sit under the heading rather than ranging left. */
.seaway-contact-cta .wp-block-cover__inner-container > p,
.seaway-contact-cta .wp-block-cover__inner-container > .wp-block-buttons {
	text-align: center;
	justify-content: center;
}

/* Footer links look like links. Both the Links column and the two Map & Directions lines
   take the site red.
 *
 * The navigation selector repeats `.wp-block-navigation-item__content` on purpose. Core
 * pins those links to `color: inherit` using that same doubled class — a deliberate
 * specificity hack on its side, scoring (0,3,0) — so an ordinary descendant selector loses
 * and only the underline lands. Matching its shape beats it at (0,4,1) without !important,
 * and breaks only if core drops the hack, at which point this simply stops being needed. */
.wp-site-blocks > footer .wp-block-navigation .wp-block-navigation-item__content.wp-block-navigation-item__content,
.wp-site-blocks > footer .seaway-map-link a {
	color: var(--wp--preset--color--primary);
	/* The red is the affordance; an underline on top of it reads as heavy against the dark
	   panel, and these sit in obvious link lists rather than in running prose. */
	text-decoration: none;
}

.seaway-carousel-dots a {
	width: 0.85rem;
	height: 0.85rem;
	border-radius: 50%;
	background: var(--wp--preset--color--contrast);
	overflow: hidden;
	text-indent: -999em;
	flex: 0 0 auto;
	transition: background-color 0.15s ease;
}

.seaway-carousel-dots a:first-child,
.seaway-carousel-dots a:hover,
.seaway-carousel-dots a:focus {
	background: var(--wp--preset--color--primary);
}

/* Once the script is running it owns the active state, so drop the first-dot fallback. */
.seaway-carousel-dots.is-enhanced a:first-child {
	background: var(--wp--preset--color--contrast);
}

.seaway-carousel-dots.is-enhanced a.is-active,
.seaway-carousel-dots.is-enhanced a:hover,
.seaway-carousel-dots.is-enhanced a:focus {
	background: var(--wp--preset--color--primary);
}

@media (max-width: 781px) {
	.wp-block-post-content .seaway-half {
		max-width: 100%;
		margin-inline-start: 0 !important;
	}

	.seaway-location-list {
		columns: 1;
	}

	.seaway-carousel > * {
		flex-basis: 100%;
	}
}

/* ---- Tablet header -------------------------------------------------------------
 * Below 1024px the masthead becomes: menu button left, logo centred, call button right.
 *
 * core/navigation collapses to its overlay at a fixed 600px and exposes no way to change
 * that, so the rules below re-create the collapsed state up to 1024px by overriding
 * core's own `@media (min-width: 600px)` declarations. That makes this the one part of
 * the theme coupled to core's markup — if a WordPress update renames
 * `.wp-block-navigation__responsive-container`, this is what breaks, and the symptom will
 * be a full menu reappearing at tablet width rather than an error. */
@media (max-width: 1023px) {
	.wp-site-blocks .seaway-masthead {
		display: grid;
		grid-template-columns: 1fr auto 1fr;
		align-items: center;
		padding-bottom: 1rem;
	}

	.seaway-masthead > .wp-block-navigation {
		grid-row: 1;
		grid-column: 1;
		justify-self: start;
	}

	.seaway-masthead > .wp-block-site-logo {
		grid-row: 1;
		grid-column: 2;
		justify-self: center;
		width: 200px;
	}

	.seaway-masthead > .wp-block-buttons {
		grid-row: 1;
		grid-column: 3;
		justify-self: end;
	}

	/* Both header rows collapse into the single hamburger row; the utility links are
	   reachable from the menu, and the phone from the call button. */
	.wp-site-blocks .seaway-utility-bar {
		display: none;
	}



	/* Force core's responsive overlay on at this width. */
	.seaway-masthead .wp-block-navigation__responsive-container:not(.is-menu-open) {
		display: none;
	}

	.seaway-masthead .wp-block-navigation__responsive-container-open {
		display: flex;
	}

	.seaway-masthead .wp-block-navigation__responsive-container.is-menu-open {
		display: flex;
	}

	/* Swap the wide "Contact Us" button for a round call button. */
	.seaway-masthead .seaway-header-cta {
		display: none;
	}

	.seaway-masthead .seaway-phone-cta {
		display: flex;
	}
}

@media (min-width: 1024px) {
	.seaway-masthead .seaway-phone-cta {
		display: none;
	}
}

/* The background artwork scales with the viewport, so the van encroaches on the copy well
   before the layout stacks. Give the text less room across the tablet range only — below
   782px the hero stacks and the copy takes the full width. */
@media (min-width: 782px) and (max-width: 1023px) {
	.wp-block-post-content .seaway-half {
		max-width: 42vw;
	}
}

/* The round call button: the number stays in the markup for screen readers and is
   replaced visually by the phone icon. */
.seaway-masthead .seaway-phone-cta .wp-block-button__link {
	width: 3rem;
	height: 3rem;
	padding: 0;
	border-radius: 50%;
	overflow: hidden;
	text-indent: -999em;
	background-image: url( "assets/icons/phone.svg" );
	background-repeat: no-repeat;
	background-position: center;
	background-size: 1.4rem 1.4rem;
}

/* The Plumber in Miami image gives way to the copy on narrower screens, matching the
   original. Hidden in the theme rather than dropped from the content, so it stays in the
   page and returns on desktop. */
@media (max-width: 1023px) {
	.wp-block-columns .wp-block-column:has(> .wp-block-image:only-child) {
		display: none;
	}
}

/* ---------------------------------------------------------------------------------
 * Homepage pass 3
 * ------------------------------------------------------------------------------- */

/* The masthead is absolutely positioned, so <header> occupies only the red utility bar's
   height — but core still gives every top-level block a block-gap margin, and on <main>
   that opened a white strip between the bar and the hero image. The bar is a solid band
   the hero is meant to run straight up against. */
.wp-site-blocks > main {
	margin-block-start: 0;
}

/* Service tiles fill red from the bottom on hover, as on the original, where Scorpion did
   it with `btn-clr-hvr` on an <a> wrapping the whole card.
   The fill is a background-image layer rather than a pseudo-element: a pseudo-element
   would have to be positioned, which makes it the containing block for the stretched link
   below and collapses the click target to the heading alone. */
.seaway-card--link {
	position: relative;
	background-image: linear-gradient(
		var(--wp--preset--color--primary),
		var(--wp--preset--color--primary)
	);
	background-repeat: no-repeat;
	background-position: bottom;
	background-size: 100% 0;
	transition: background-size 0.3s ease, color 0.25s ease;
}

.seaway-card--link:hover,
.seaway-card--link:focus-within {
	background-size: 100% 100%;
	color: var(--wp--preset--color--base);
}

.seaway-card--link a {
	color: inherit;
	text-decoration: none;
}

/* The icons are single-colour SVGs loaded as <img>, so `fill` cannot reach them. Knocking
   them through to white is the one thing that works on an image regardless of its paint. */
.seaway-card--link:hover .wp-block-image img,
.seaway-card--link:focus-within .wp-block-image img {
	filter: brightness(0) invert(1);
}

/* The whole tile is the click target, without nesting a second link inside the card. */
.seaway-card--link :is(h1, h2, h3, h4, h5, h6) a::after {
	content: "";
	position: absolute;
	inset: 0;
}

/* Nothing should animate for someone who asked for less motion; the hover colour still
   changes, so the affordance survives. */
@media (prefers-reduced-motion: reduce) {
	.seaway-card--link {
		transition: none;
	}
}

/* A section title on a light band is a heading, not a subtitle. theme.json colours every
   h2 muted because Scorpion also uses h2 for the line beneath an h1; a title that opens
   its own section is the other case and takes the body colour. Titles on covers are left
   alone — they sit on artwork and are already light. */
.has-light-background-color .is-style-section-title {
	color: var(--wp--preset--color--contrast);
}

.has-light-background-color .is-style-section-title + .is-style-thin {
	color: var(--wp--preset--color--muted);
}

/* Maintenance-plan cards, identified by the price they carry rather than by a class of
   their own — so a plan added later in the editor picks the treatment up on its own. */
.seaway-card:has(.seaway-price) .wp-block-image img {
	/* Half again the 48px every other card icon uses. */
	width: 72px !important;
	max-width: none;
}

/* The price matches the plan name in size but sits back from it in weight and colour, so
   the card reads as name-then-price rather than as two headings competing. */
.seaway-price {
	font-weight: 300;
	line-height: 1.3;
	color: var(--wp--preset--color--muted);
	margin-block-start: 0.35rem;
}

/* Price and plan name are set together rather than each given 1.8rem separately: theme.json
   runs headings through fluid typography, so a literal 1.8rem on the price alone came out
   28.8px against the heading's 27.3px. Declaring both here pins them to each other, and
   scoping it to plan cards keeps every other card's heading on the fluid scale. */
.seaway-card:has(.seaway-price) :is(h3, .seaway-price) {
	font-size: 1.8rem;
}

.seaway-card ul li::marker {
	color: var(--wp--preset--color--primary);
	font-size: 1.15em;
}

.seaway-card:has(.seaway-price) .wp-block-button__link {
	background-color: var(--wp--preset--color--primary);
	color: var(--wp--preset--color--base);
}

/* ---------------------------------------------------------------------------------
 * Reveal animations
 *
 * Each top-level block eases up into place as it enters the viewport; grid and column
 * children then stagger within it. Scorpion did this site-wide with `data-onvisible`, on
 * 569 elements; this reproduces it from the theme instead, so it needs no re-import and
 * covers pages the client builds later.
 *
 * EVERY rule below is gated on `.seaway-anim`, which functions.php adds to <html> from an
 * inline head script — and only when JavaScript is running and the visitor has not asked
 * for reduced motion. That gate is the whole safety argument: these rules start content at
 * `opacity: 0`, and an unconditional version would render a blank page any time the script
 * that undoes it failed to run. Shared hosts routinely defer or combine scripts. No class,
 * no hiding.
 *
 * Only opacity and transform animate, so none of this triggers layout or moves CLS.
 * ------------------------------------------------------------------------------- */

:root {
	--seaway-anim-duration: 0.6s;
	--seaway-anim-rise: 1.25rem;
	--seaway-anim-stagger: 80ms;
	--seaway-anim-ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

.seaway-anim .wp-block-post-content > *,
.seaway-anim .wp-block-post-content :is(.is-layout-grid, .wp-block-columns) > * {
	opacity: 0;
	transform: translateY(var(--seaway-anim-rise));
	transition:
		opacity var(--seaway-anim-duration) var(--seaway-anim-ease),
		transform var(--seaway-anim-duration) var(--seaway-anim-ease);
}

/* Children carry their position as `--seaway-i`, set once by reveal.js, so the stagger
   keeps working when a card is added in the editor. Top-level blocks have no index and
   fall back to 0, which is why they start immediately. */
.seaway-anim .wp-block-post-content :is(.is-layout-grid, .wp-block-columns) > * {
	transition-delay: calc(var(--seaway-i, 0) * var(--seaway-anim-stagger));
}

/* `.is-revealed` lands on the top-level block. The second selector covers the case where
   that block is itself the grid rather than a wrapper around one. */
.seaway-anim .wp-block-post-content > .is-revealed,
.seaway-anim .wp-block-post-content .is-revealed :is(.is-layout-grid, .wp-block-columns) > *,
.seaway-anim .wp-block-post-content .is-revealed:is(.is-layout-grid, .wp-block-columns) > * {
	opacity: 1;
	transform: none;
}

/* Belt and braces. The flag is already withheld for reduced-motion visitors, so this only
   matters if someone changes the preference after load — but a preference change should
   never be able to leave content stuck at zero opacity. */
@media (prefers-reduced-motion: reduce) {

	.seaway-anim .wp-block-post-content > *,
	.seaway-anim .wp-block-post-content :is(.is-layout-grid, .wp-block-columns) > * {
		opacity: 1;
		transform: none;
		transition: none;
	}
}
