/*
Theme Name: Studio by Intertwine
Theme URI: https://intertwinehq.com/themes/studio
Author: Intertwine
Author URI: https://intertwinehq.com
Description: A complete site for studios and agencies that produce creative work at volume: video, photography, advertising, and content production. Built for a booked call rather than a signup, so every button on the page goes to one form. Ships as a finished website, not a blank canvas. Every word and image is a default, so you install it and the site is already built, then change what you want in wp-admin without deleting anything first. Colour and typography are one palette away from being yours. Requires Fields by Intertwine and Templates by Intertwine, both free.
Version: 1.0.0
Requires at least: 6.7
Tested up to: 7.0
Requires PHP: 8.2
License: GNU General Public License v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: studio-by-intertwine
Tags: portfolio, business, photography, one-column, block-patterns, full-site-editing, custom-colors, custom-menu, editor-style, featured-images, template-editing, translation-ready
*/

/*
 * Chrome, typeface, and the design layer over the plugin's layout.
 *
 * The Templates plugin's stylesheet is layout only. This file loads after it
 * and supplies what a layout sheet cannot know: the type scale, the ground,
 * the grain, and the way the accent is allowed to be used.
 *
 * Every colour here resolves back to a --wp--preset--* value, so the palette in
 * theme.json stays the single place a colour is decided. Rebranding this theme
 * is a palette swap, and that promise breaks the moment a hex appears below.
 *
 * The design has one committed idea: the page is a lineage. Work descends from
 * one source, drawn literally under the asset sheet and again in the chain
 * diagram, and the whole page is set against a reserved left column that the
 * section numerals sit in. That column is why the layout reads as a document
 * with a margin rather than as a centred web page.
 */

:root {
	--sd-ground:   var( --wp--preset--color--base );
	--sd-raise:    var( --wp--preset--color--raise );
	--sd-ink:      var( --wp--preset--color--contrast );
	--sd-ink-2:    var( --wp--preset--color--muted );
	--sd-faint:    var( --wp--preset--color--faint );
	--sd-line:     var( --wp--preset--color--line );
	--sd-line-2:   var( --wp--preset--color--line-strong );
	--sd-accent:   var( --wp--preset--color--accent-1 );
	--sd-accent-2: var( --wp--preset--color--accent-2 );

	--sd-display: var( --wp--preset--font-family--display );
	--sd-body:    var( --wp--preset--font-family--sans );
	--sd-mono:    var( --wp--preset--font-family--mono );
	--sd-overlay: var( --wp--preset--font-family--overlay );

	/* The reserved left column. It holds the section numerals and it is what
	   gives every band the same asymmetric left edge. */
	--sd-rail: 4rem;
	--sd-gut:  clamp( 1.15rem, 4vw, 4rem );
	--sd-wide: 108rem;
}

/* ── ground ──────────────────────────────────────────────── */

/*
 * Border-box everywhere.
 *
 * WordPress does not set this globally, and this theme leans on `width: 100%`
 * with horizontal padding in several places, which under the default
 * content-box sizing overflows by exactly the padding. Setting it once here is
 * cheaper than remembering it at every call site.
 */
*,
*::before,
*::after {
	box-sizing: border-box;
}

body {
	background: var( --sd-ground );
	color: var( --sd-ink );
	overflow-x: hidden;
}

/*
 * Film grain over the whole document.
 *
 * Inline SVG rather than an image file so it costs no request and cannot 404
 * after a move. It sits above everything and takes no pointer events, so it
 * never interferes with a click.
 */
body::after {
	content: "";
	position: fixed;
	inset: 0;
	z-index: 95;
	pointer-events: none;
	opacity: 0.055;
	background-image: url( "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3'/></filter><rect width='220' height='220' filter='url(%23n)'/></svg>" );
}

/* ── shared section furniture ────────────────────────────── */

.itwt-section {
	position: relative;
}

/*
 * An anchored section stops clear of the fixed header.
 *
 * Without this a jump link lands the section flush with the top of the
 * viewport, which is underneath the header, so the first thing a visitor sees
 * after clicking "Work" is the second line of the section they asked for. The
 * heading is there; it is behind the bar.
 *
 * Applied by attribute rather than to a list of classes, so any section that
 * gains an id gets the behaviour without anyone remembering to add it.
 */
.itwt-section[id] {
	scroll-margin-top: 5.5rem;
}

.sd-inner {
	max-width: var( --sd-wide );
	margin: 0 auto;
	padding-left: var( --sd-gut );
	padding-right: var( --sd-gut );
}

@media ( min-width: 62rem ) {
	.sd-inner {
		padding-left: calc( var( --sd-gut ) + var( --sd-rail ) );
	}
}

.sd-band {
	padding-top: clamp( 4.5rem, 11vw, 11rem );
	padding-bottom: clamp( 4.5rem, 11vw, 11rem );
	border-top: 1px solid var( --sd-line );
}

.sd-lab {
	font-family: var( --sd-mono );
	font-size: 0.64rem;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var( --sd-faint );
}

.sd-h {
	font-family: var( --sd-display );
	font-weight: 400;
	font-size: clamp( 2.1rem, 1rem + 4.2vw, 5.6rem );
	line-height: 0.94;
	letter-spacing: -0.026em;
	max-width: 14ch;
	text-wrap: balance;
	margin: 0;
}

/*
 * The accent phrase is upright, not italic.
 *
 * Set in the italic it reads as a script dropped into the middle of a sentence,
 * which is a change of voice rather than an emphasis, and on a face with a true
 * calligraphic italic it looks like two headlines spliced together. Colour and a
 * little extra weight emphasise the words while keeping one speaker.
 */
.sd-h em {
	font-style: normal;
	font-weight: 800;
	color: var( --sd-accent-2 );
}

.sd-p {
	color: var( --sd-ink-2 );
	max-width: 42ch;
	margin: 0;
}

.sd-num {
	display: none;
	font-family: var( --sd-mono );
	font-size: 0.6rem;
	letter-spacing: 0.2em;
	color: var( --sd-faint );
}

@media ( min-width: 62rem ) {
	.sd-num {
		display: block;
		position: absolute;
		left: var( --sd-gut );
		top: clamp( 3rem, 8vw, 7rem );
	}
}

/* ── buttons ─────────────────────────────────────────────── */

.sd-btn {
	display: inline-block;
	padding: 0.68rem 1.35rem;
	background: var( --sd-accent );
	color: var( --sd-ground );
	border: 1px solid var( --sd-accent );
	font-family: var( --sd-body );
	font-size: 0.87rem;
	font-weight: 600;
	text-decoration: none;
	transition: transform 0.3s cubic-bezier( 0.16, 1, 0.3, 1 ), background 0.25s ease, border-color 0.25s ease;
}

.sd-btn:hover,
.sd-btn:focus-visible {
	background: var( --sd-accent-2 );
	border-color: var( --sd-accent-2 );
	transform: translateY( -2px );
}

.sd-btn--ghost {
	background: transparent;
	color: var( --sd-ink );
	border-color: var( --sd-line-2 );
}

.sd-btn--ghost:hover,
.sd-btn--ghost:focus-visible {
	background: var( --sd-raise );
	border-color: var( --sd-ink-2 );
}

/* ── media frames ────────────────────────────────────────── */

.sd-fr {
	position: relative;
	overflow: hidden;
	background: var( --sd-raise );
}

.sd-fr img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 1.2s cubic-bezier( 0.16, 1, 0.3, 1 );
}

.sd-fr:hover img {
	transform: scale( 1.045 );
}

.sd-fr--45 { aspect-ratio: 4 / 5; }
.sd-fr--916 { aspect-ratio: 9 / 16; }
.sd-fr--11 { aspect-ratio: 1; }

.sd-fr__cap {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	padding: 0.95rem 0.8rem 0.75rem;
	font-family: var( --sd-overlay );
	font-size: clamp( 0.62rem, 0.5rem + 0.34vw, 0.92rem );
	line-height: 1.05;
	letter-spacing: 0.035em;
	text-transform: uppercase;
	color: #fff;
	text-shadow: 0 1px 8px rgba( 0, 0, 0, 0.9 );
	background: linear-gradient( 0deg, rgba( 0, 0, 0, 0.7 ), transparent );
}

.sd-fr__meta {
	position: absolute;
	top: 0.55rem;
	left: 0.6rem;
	font-family: var( --sd-mono );
	font-size: 0.54rem;
	letter-spacing: 0.12em;
	color: rgba( 255, 255, 255, 0.86 );
	text-shadow: 0 1px 5px rgba( 0, 0, 0, 0.95 );
}

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

/*
 * Every hiding rule below is scoped to `.js`, which functions.php stamps on the
 * root element from an inline script before first paint.
 *
 * The reason is not tidiness. These rules hide content until a script reveals
 * it, so if the script never arrives, the content is simply gone: a blocked
 * bundle, a CSP, an offline second visit, or a parse error anywhere earlier all
 * produce a page of headings with nothing under them. Scoping the hide to the
 * one condition under which the reveal can happen makes that failure impossible
 * rather than unlikely.
 */
.js .itwt-reveal {
	opacity: 0;
	transform: translateY( 22px );
	transition: opacity 0.9s cubic-bezier( 0.16, 1, 0.3, 1 ), transform 0.9s cubic-bezier( 0.16, 1, 0.3, 1 );
}

.js .itwt-reveal.is-in {
	opacity: 1;
	transform: none;
}

/*
 * The wipe.
 *
 * The clip is on the image, never on the container, and that is load-bearing
 * rather than stylistic. IntersectionObserver computes a target's intersection
 * against its clipped box, so an element clipped to zero height reports itself
 * as not intersecting, the observer never fires, and the reveal that was
 * supposed to un-clip it never runs. Clipping the child keeps the observed box
 * whole and the effect identical.
 */
.js .sd-clip > img {
	clip-path: inset( 0 0 100% 0 );
	transition: clip-path 1.1s cubic-bezier( 0.76, 0, 0.24, 1 );
}

.js .sd-clip.is-in > img {
	clip-path: inset( 0 0 0 0 );
}

@media ( prefers-reduced-motion: reduce ) {
	.js .itwt-reveal,
	.js .sd-clip > img {
		opacity: 1;
		transform: none;
		clip-path: none;
		transition: none;
	}
}

/* ── site chrome ─────────────────────────────────────────── */

.site-header {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	z-index: 60;
	padding: 0.95rem var( --sd-gut );
	background: rgba( 0, 0, 0, 0.72 );
	backdrop-filter: blur( 16px ) saturate( 130% );
	border-bottom: 1px solid color-mix( in srgb, var( --sd-line-2 ) 90%, transparent );
	box-shadow: 0 1px 0 rgba( 255, 255, 255, 0.04 ) inset, 0 12px 40px rgba( 0, 0, 0, 0.5 );
	transition: background 0.45s ease, border-color 0.45s ease;
}

/*
 * The header is a bar, not a wash.
 *
 * The hero runs real work full-bleed to the top edge, so navigation set over it
 * lands on whatever the footage happens to be doing that second. A 46% wash was
 * the first attempt and it disappeared into any bright frame. This is a proper
 * bar: dark enough to read as a surface, blurred and slightly saturated so the
 * film behind it stays alive underneath, a hairline along the bottom so it has
 * an edge, and a drop shadow so it sits above the page rather than in it.
 *
 * Once the hero is behind you it firms up to the ground colour, because past
 * that point it is sitting over type rather than over film and a translucent
 * bar there just makes the words underneath fuzzy.
 */
.site-header > * {
	position: relative;
}

@media ( min-width: 62rem ) {
	.site-header {
		padding-left: calc( var( --sd-gut ) + var( --sd-rail ) );
	}
}

.site-header.is-stuck {
	background: color-mix( in srgb, var( --sd-ground ) 92%, transparent );
	backdrop-filter: blur( 14px );
	border-bottom-color: var( --sd-line );
}

.site-header__inner {
	max-width: var( --sd-wide );
	margin: 0 auto;
}

.wp-block-site-title {
	font-family: var( --sd-display );
	font-size: 0.95rem;
	font-weight: 400;
	letter-spacing: 0.34em;
	text-transform: uppercase;
}

/*
 * The nav links step aside on a narrow screen.
 *
 * The page has one job, so on a phone the header keeps the mark and the button
 * and drops the two anchors rather than wrapping to a second line and eating a
 * fifth of the first screen. Both destinations are still in the footer, and
 * both are just further down the page anyway.
 */
@media ( max-width: 40rem ) {
	.site-header__nav {
		display: none;
	}
}

.site-header__nav {
	flex-wrap: nowrap;
}

.site-footer {
	border-top: 1px solid var( --sd-line );
	padding: 3rem var( --sd-gut ) 4rem;
}

@media ( min-width: 62rem ) {
	/*
 * The nav links step aside on a narrow screen.
 *
 * The page has one job, so on a phone the header keeps the mark and the button
 * and drops the two anchors rather than wrapping to a second line and eating a
 * fifth of the first screen. Both destinations are still in the footer, and
 * both are just further down the page anyway.
 */
@media ( max-width: 40rem ) {
	.site-header__nav {
		display: none;
	}
}

.site-header__nav {
	flex-wrap: nowrap;
}

.site-footer {
		padding-left: calc( var( --sd-gut ) + var( --sd-rail ) );
	}
}

.site-footer__inner {
	max-width: var( --sd-wide );
	margin: 0 auto;
}

/* Body copy inside the plugin's own generic sections, so a bundled section
   dropped onto a page inherits this theme rather than looking imported. */

.itwt-section p {
	color: var( --sd-ink-2 );
}

.itwt-section h2,
.itwt-section h3 {
	font-family: var( --sd-display );
	font-weight: 400;
	letter-spacing: -0.02em;
}
