/* Mann Studios · the scroll layer's mechanism, and nothing that decides a look.
 *
 * studio.css states the house rule: every visual decision is an Elementor
 * control, never a rule written here. This file does not break it. What is
 * below is the same kind of exception @keyframes is — plumbing CSS has no
 * other home for:
 *
 *   1. The resting state of elements assets/studio-scroll.js is about to
 *      animate. It must be in a stylesheet, not written by the script, or the
 *      browser paints the finished state for a frame and then hides it.
 *   2. The geometry of two elements the script injects (the curtain panel and
 *      the progress bar) — position, size, stacking. Not their colour, not
 *      their speed, not whether they exist: those are controls in
 *      Site Settings > Layout > Scrolling, read here as custom properties.
 *
 * Every rule is gated on an attribute the script writes. Nothing below applies
 * to a page where the script did not run, so a blocked or failed request
 * leaves the page exactly as it is without this file.
 *
 * See studio_kit_scroll_motion() in inc/kit-controls.php for the panel side.
 */

/* ---------------------------------------------------------------------------
 * Curtain.
 *
 * [data-curtain-ready] is written by the script onto the box that holds a
 * picture, once it has decided that box can take a panel. position and
 * overflow are the two things the panel needs from its parent and cannot
 * give itself.
 *
 * overflow:hidden here clips the panel, which is a child. It does not clip
 * this element's own focus ring — an outline is painted outside the border
 * box and is clipped by an ANCESTOR's overflow, never by the element's own.
 * The project stills are role="button" tabindex="0", so that distinction is
 * load-bearing: see the focus-ring rule in the theme notes.
 * ------------------------------------------------------------------------- */
[data-curtain-ready] {
	overflow: hidden;
}

/* Only where the script found the box already static. Most of these boxes are
 * positioned by something else — an Elementor container carrying a background,
 * a plate in project-page.css — and writing position over one of those moves
 * it. So the script marks which boxes need a containing block; this rule is
 * still the only thing that sets one. */
[data-curtain-ready][data-curtain-relative] {
	position: relative;
}

/* The default colour is Gold, on the studio's instruction.
 *
 * Gold is the one colour in this palette that belongs to the studio rather
 * than to a page: it reads against the cream pages and against the dark film
 * pages alike, so a gold sweep is the same gesture everywhere instead of a
 * different one per section. It is also the colour the overlay menu already
 * sweeps in, which is what makes the curtain read as the site doing something
 * rather than as a picture loading.
 *
 * A note worth keeping, because it cost a round to find: Elementor's globals
 * are declared on <body>, never on :root, and this kit names them for their
 * role rather than their shade. Ink is the colour a page is WRITTEN in and
 * Surface is the ground it is written on — so Ink is near-black on the cream
 * pages and #F2EFE9, cream, on the dark film pages. Measured, not assumed.
 * Anything here that reaches for a "black" or a "white" has to say which.
 *
 * `data-curtain--ink` in a picture's CSS Classes field gives that one picture
 * the writing colour instead, which on a dark section is cream and on a light
 * one is near-black. bridge.js turns the class into the attribute.
 */
[data-curtain-panel] {
	position: absolute;
	inset: 0;
	z-index: 2;
	pointer-events: none;
	transform: scaleX( 0 );
	transform-origin: left center;
	background: var( --studio-curtain-ink, var( --e-global-color-gold, #c6a86a ) );
}

[data-curtain-panel][data-curtain-ink] {
	background: var( --e-global-color-ink, #0d0c0a );
}

/* ---------------------------------------------------------------------------
 * Heading lines.
 *
 * The script wraps each line of a heading in a mask and slides the line up
 * from under its lower edge. The padding/margin pair is not spacing: Newsreader
 * paints outside its own box, so a mask at zero inset shaves the tops off
 * ascenders and the tails off descenders. The padding opens room for that ink
 * and the matching negative margin gives the space straight back, so the
 * heading occupies exactly the box it did before it was split.
 *
 * Both wrappers are removed and the heading's original markup restored the
 * moment the reveal finishes, so selection, screen readers and a later resize
 * all see ordinary text.
 * ------------------------------------------------------------------------- */
[data-lines-ready] [data-line] {
	display: block;
	overflow: hidden;
	padding: 0.2em 0.1em 0.26em;
	margin: -0.2em -0.1em -0.26em;
}

[data-lines-ready] [data-line-inner] {
	display: block;
	will-change: transform;
}

/* ---------------------------------------------------------------------------
 * Progress bar.
 *
 * Fixed to the top of the viewport, under the header and far under the
 * overlay menu's panels, which the motion engine stacks at z-index 0 and 1
 * inside a menu that sits above the page. Height and colour are controls.
 * ------------------------------------------------------------------------- */
[data-scroll-progress] {
	position: fixed;
	top: 0;
	left: 0;
	width: 100%;
	height: var( --studio-progress-height, 2px );
	z-index: 5;
	pointer-events: none;
	transform: scaleX( 0 );
	transform-origin: left center;
	background: var( --studio-progress-ink, var( --e-global-color-gold, #c6a86a ) );
}

/* ---------------------------------------------------------------------------
 * Pinned rail. Opt-in: nothing on the site carries [data-rail] until it is
 * typed into a container's CSS Classes field as `data-rail`.
 *
 * Below the desktop breakpoint the script never pins, and the rail is an
 * ordinary horizontally scrollable strip the finger can push. That is also
 * what a reader who has asked for less motion gets at every width.
 * ------------------------------------------------------------------------- */
[data-rail-track] {
	display: flex;
	will-change: transform;
}

[data-rail]:not( [data-rail-pinned] ) [data-rail-track] {
	overflow-x: auto;
	overscroll-behavior-x: contain;
	scroll-snap-type: x proximity;
}

[data-rail]:not( [data-rail-pinned] ) [data-rail-track] > * {
	scroll-snap-align: start;
	flex: 0 0 auto;
}

/* ---------------------------------------------------------------------------
 * Less motion.
 *
 * Cut movement, keep change. The script reads the same preference and never
 * builds a curtain, a split or a pin when it is set — these rules are the
 * belt, for a reader who turns the preference on with the page already open
 * and its panels already in the document.
 * ------------------------------------------------------------------------- */
@media ( prefers-reduced-motion: reduce ) {
	/* studio-scroll.js returns before it does anything when this preference is
	 * on, so nothing ever splits a [data-scrub-lede] statement or fills it in.
	 * The kit control rests it at 22% opacity from the stylesheet, which would
	 * leave the sentence grey for good. gsap-motion.js lands its own
	 * [data-scrub-words] in landScrub(); this is the same landing for the hook
	 * that file does not know about. The word spans are covered too, for a
	 * reader who turns the preference on with the page already open and the
	 * statement already split. */
	[data-scrub-lede],
	[data-scrub-lede] .studio_word {
		opacity: 1 !important;
	}

	[data-curtain-panel] {
		display: none;
	}

	[data-lines-ready] [data-line] {
		overflow: visible;
	}

	[data-lines-ready] [data-line-inner] {
		transform: none !important;
		will-change: auto;
	}

	[data-scroll-progress] {
		display: none;
	}
}
