/*  noahchevan.com — one stylesheet, no dependencies, no build step.

    Replaces YAstyle.css (a repurposed WordPress theme whose nav sprites
    pointed at a long-dead third-party domain) and the previous site.css.
    Everything the site uses now lives here.
*/

/* ------------------------------------------------------------------ *
 *  Tokens
 * ------------------------------------------------------------------ */

:root {
	/* The original pairing was #FCE4E4 / #E41114, which measures 3.95:1 —
	   below the 4.5:1 WCAG AA floor for body text. The red is darkened
	   four steps along the same hue to reach 4.91:1. Beside the original
	   the shift is imperceptible; on a contrast checker it is the
	   difference between failing and passing. */
	--pink: #FCE4E4;
	--red: #C80F12;
	--blue: #0139FF; /* taken from the character artwork; used for focus */

	/* Type scale. clamp() means no font-size media queries anywhere. */
	--step--1: clamp(0.82rem, 0.79rem + 0.14vw, 0.9rem);
	--step-0:  clamp(1rem, 0.96rem + 0.2vw, 1.125rem);
	--step-1:  clamp(1.13rem, 1.06rem + 0.32vw, 1.35rem);
	--step-2:  clamp(1.6rem, 1.35rem + 1.3vw, 2.6rem);

	--gap: clamp(1.5rem, 1rem + 2.5vw, 3rem);
	--pad: clamp(1.25rem, 1rem + 2vw, 2.5rem);
}

/* ------------------------------------------------------------------ *
 *  Reset
 * ------------------------------------------------------------------ */

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

body,
h1,
p {
	margin: 0;
}

img {
	display: block;
	max-width: 100%;
	height: auto;
}

html {
	-webkit-text-size-adjust: 100%;
}

/* ------------------------------------------------------------------ *
 *  Page frame
 *
 *  The character strip and the text are one composition: side by side on
 *  wide viewports, centred as a unit, with the strip capped to the
 *  viewport height so decoration never causes a scrollbar.
 * ------------------------------------------------------------------ */

body {
	min-height: 100vh;
	min-height: 100svh; /* excludes mobile browser chrome; ignored where unsupported */
	margin: 0 auto;
	padding: var(--pad);

	display: flex;
	align-items: center;
	justify-content: center;
	gap: var(--gap);

	background: var(--pink);
	color: var(--red);
	font-family: "Helvetica Neue", Helvetica, Arial, "Liberation Sans", sans-serif;
	font-size: var(--step-0);
	line-height: 1.55;
	-webkit-font-smoothing: antialiased;
}

/* ------------------------------------------------------------------ *
 *  Character strip
 *
 *  A background image rather than an <img>, for two reasons: the browser
 *  fetches only the file whose media query matches, and the
 *  reduced-motion swap stays a stylesheet concern instead of leaking
 *  into the markup. The element is decorative and aria-hidden.
 *
 *  background-size: contain guarantees the artwork is only ever scaled
 *  proportionally — never stretched, never cropped.
 * ------------------------------------------------------------------ */

.strip {
	flex: 0 0 auto;
	width: 120px;
	height: min(744px, calc(100svh - 5rem));
	background: url("tweedyhotstuff_banner_18_3_29.gif") no-repeat center / contain;
}

/* Second copy, below the text. Only ever shown on small viewports. */
.strip--bottom {
	display: none;
}

@media (prefers-reduced-motion: reduce) {
	.strip {
		background-image: url("banner-vertical-static.png");
	}
}

/* ------------------------------------------------------------------ *
 *  Text column
 * ------------------------------------------------------------------ */

.masthead {
	flex: 1 1 auto;
	max-width: 34rem; /* ~66 characters at the body size */
}

h1 {
	font-size: var(--step-2);
	line-height: 1.05;
	letter-spacing: -0.02em;
	font-weight: 700;
}

.roles {
	margin-top: 0.4em;
	font-size: var(--step-1);
	line-height: 1.35;
}

.intro {
	margin-top: 1.15em;
	max-width: 32rem;
	text-wrap: pretty;
}

/* ------------------------------------------------------------------ *
 *  Links — three deliberate tiers
 *
 *    .primary    the reel and the music page: what this site exists to show
 *    .secondary  the CV
 *    .contact    the email address
 * ------------------------------------------------------------------ */

a {
	color: inherit;
}

a:focus-visible {
	outline: 3px solid var(--blue);
	outline-offset: 3px;
	border-radius: 1px;
}

.actions {
	margin-top: 1.9em;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 0.8em;
}

.primary {
	font-size: var(--step-1);
	font-weight: 700;
	text-decoration: none;
	padding: 0.4em 0;
	border-bottom: 3px solid currentColor;
	transition: background-color 0.12s linear, color 0.12s linear;
}

.primary:hover {
	background: var(--red);
	color: var(--pink);
}

.secondary,
.contact a,
.back {
	display: inline-block;
	padding: 0.3em 0;
	text-decoration: underline;
	text-underline-offset: 0.18em;
	text-decoration-thickness: 1px;
	transition: background-color 0.12s linear, color 0.12s linear;
}

.secondary:hover,
.contact a:hover,
.back:hover {
	background: var(--red);
	color: var(--pink);
}

.note {
	font-size: var(--step--1);
}

.contact {
	margin-top: 1.9em;
}

@media (prefers-reduced-motion: reduce) {
	.primary,
	.secondary,
	.contact a,
	.back {
		transition: none;
	}
}

/* ------------------------------------------------------------------ *
 *  Reel page
 * ------------------------------------------------------------------ */

/* A 16:9 player below roughly 40rem stops being watchable, so this page
   gets a wider column than the homepage. */
.page--reel .masthead {
	max-width: 46rem;
}

.video {
	margin-top: 1.3em;
	width: 100%;
	aspect-ratio: 16 / 9;
}

.video iframe {
	display: block;
	width: 100%;
	height: 100%;
	border: 0;
}

.back {
	margin-top: 1.3em;
}

/* ------------------------------------------------------------------ *
 *  Music & video page
 *
 *  Same vertical strip + side-by-side composition, same natural
 *  document scroll, as the homepage and reel page — just top-aligned
 *  instead of vertically centred, since the entry list runs well past
 *  one viewport and a centred strip would land in the middle of the
 *  scroll. The narrow/short breakpoint below still applies unchanged,
 *  same as it does for every other page.
 * ------------------------------------------------------------------ */

.page--music {
	align-items: flex-start;
}

.page--music .masthead {
	max-width: 42rem;
}

.back--top {
	display: block;
	margin-top: 0.6em;
}

.entries {
	margin-top: var(--gap);
	display: flex;
	flex-direction: column;
}

.entry {
	padding: var(--pad) 0;
	border-bottom: 1px solid currentColor;
}

.entry:first-child {
	padding-top: 0;
}

.entry:last-child {
	border-bottom: 0;
	padding-bottom: 0;
}

.entry h2 {
	font-size: var(--step-1);
	font-weight: 700;
	line-height: 1.2;
}

.entry .caption {
	margin-top: 0.4em;
}

.entry .video,
.entry .embed {
	margin-top: 0.9em;
}

.entry .secondary {
	margin-top: 0.9em;
}

/* The film has no embeddable player, so its poster stands in as the
   link-out — image and label travel together as one clickable unit. */
.entry .poster {
	display: inline-block;
	margin-top: 0.9em;
}

.entry .poster img {
	max-width: 11rem;
	border: 3px solid currentColor;
}

.entry .poster .label {
	display: inline-block;
	margin-top: 0.5em;
	text-decoration: underline;
	text-underline-offset: 0.18em;
	text-decoration-thickness: 1px;
	transition: background-color 0.12s linear, color 0.12s linear;
}

.entry .poster:hover .label {
	background: var(--red);
	color: var(--pink);
}

@media (prefers-reduced-motion: reduce) {
	.entry .poster .label {
		transition: none;
	}
}

/* Bandcamp, Audiomack and Instagram bring fixed-height players rather
   than a 16:9 shape, so they get their own natural sizing instead of
   the reel page's aspect-ratio box. */
.embed iframe {
	display: block;
	width: 100%;
	border: 0;
}

.embed--bandcamp {
	max-width: 30rem;
}

.embed--bandcamp iframe {
	height: 120px;
}

/* The album player (with cover art) is taller than the track player. */
.embed--bandcamp-album {
	max-width: 350px;
}

.embed--bandcamp-album iframe {
	height: 470px;
}

.embed--audiomack {
	max-width: 30rem;
}

.embed--audiomack iframe {
	height: 400px;
}

.embed--instagram {
	max-width: 28rem;
}

.embed--instagram iframe {
	height: 760px;
}

/* A subtle staggered fade-in, skipped entirely under reduced motion —
   the media query means browsers without a preference set (or that
   don't support the feature) get no animation at all rather than
   entries stuck at opacity: 0. */
@media (prefers-reduced-motion: no-preference) {
	.entry {
		opacity: 0;
		animation: entry-in 0.4s ease-out forwards;
	}

	.entry:nth-child(1) { animation-delay: 0s; }
	.entry:nth-child(2) { animation-delay: 0.06s; }
	.entry:nth-child(3) { animation-delay: 0.12s; }
	.entry:nth-child(4) { animation-delay: 0.18s; }
	.entry:nth-child(5) { animation-delay: 0.24s; }
	.entry:nth-child(6) { animation-delay: 0.3s; }
	.entry:nth-child(7) { animation-delay: 0.36s; }
	.entry:nth-child(8) { animation-delay: 0.42s; }
	.entry:nth-child(9) { animation-delay: 0.48s; }

	@keyframes entry-in {
		from {
			opacity: 0;
			transform: translateY(8px);
		}
		to {
			opacity: 1;
			transform: none;
		}
	}
}

/* ------------------------------------------------------------------ *
 *  Narrow or short viewports
 *
 *  Two conditions, not one: width catches phones held upright, height
 *  catches phones held sideways — plenty of width there, nowhere near
 *  enough height for a 744px vertical strip.
 *
 *  The strip turns horizontal and bookends the text, top and bottom.
 * ------------------------------------------------------------------ */

@media (max-width: 46em), (max-height: 34em) {
	body {
		display: block;
		min-height: 0;
	}

	.masthead,
	.page--reel .masthead,
	.page--music .masthead {
		max-width: none;
	}

	.strip {
		width: 100%;
		max-width: 40rem;
		height: auto;
		aspect-ratio: 649 / 116;
		background-image: url("tweedyhotstuff_banner_h.gif");
		margin-bottom: 1.75rem;
	}

	.strip--bottom {
		display: block;
		margin-bottom: 0;
		margin-top: 2.25rem;
	}

	/* Comfortable thumb targets — 44px is the floor Apple's HIG and
	   WCAG 2.2 target size both land on. */
	.primary,
	.secondary,
	.contact a,
	.back {
		/* inline-flex, not flex: these stay in the text flow and only wrap
		   when they genuinely need to, so "Get in touch —" does not leave a
		   dangling dash at the end of a line. Children of .actions are
		   blockified by the flex parent regardless, which is what we want
		   there. */
		display: inline-flex;
		align-items: center;
		min-height: 44px;
		/* These become flex containers, so the whitespace between the label
		   and the "(PDF…)" note collapses. gap puts it back. wrap keeps the
		   pair from overflowing the narrowest phones. */
		flex-wrap: wrap;
		gap: 0 0.35em;
	}

	.actions {
		gap: 0.4em;
	}
}

@media (max-width: 46em) and (prefers-reduced-motion: reduce),
       (max-height: 34em) and (prefers-reduced-motion: reduce) {
	.strip {
		background-image: url("banner-horizontal-static.png");
	}
}
