/**
 * LANTHORN — tokens, base, and the paper primitives.
 *
 * ==========================================================================
 * The idea
 * ==========================================================================
 *
 * The page is not a sheet of paper with ink on it. The page is a dark stage,
 * and the content is a pile of printed things lying on it: the programme, the
 * ticket, the call sheet, the receipt roll off the box office printer.
 *
 * That inversion is the whole design. Everything below follows from it —
 * separation comes from the edge and shadow of a real object rather than from
 * a hairline rule, and the one bulb burning upstage is the light those objects
 * are lit by rather than a decoration behind them.
 *
 * ==========================================================================
 * Contrast, measured before anything was built on it
 * ==========================================================================
 *
 *   ink       on newsprint  14.02   body
 *   ink-2     on newsprint   7.78   body
 *   ink-3     on newsprint   4.53   body — the floor, do not go lighter
 *   oxblood   on newsprint   6.61   body
 *   green-ink on newsprint   8.93   body
 *   mustard   on newsprint   3.03   RULES AND >=24px TYPE ONLY, never body
 *   ink-3     on ticket      3.88   NOT body — ticket stock uses ink-2
 *   chalk     on stage      11.84   body
 *   chalk-2   on stage       6.14   body
 *   gold      on stage       6.82   body
 *   chalk     on LIT stage    4.97   body — the worst case under the bulb,
 *                                    which is why the shader clamps where it
 *                                    does. See ghost.js.
 */

:root {

	/* ------------------------------------------------------------------
	   The stage — the dark ground everything lies on
	   ------------------------------------------------------------------ */

	--lan-stage:    #0e2a1f;
	--lan-stage-2:  #143528;
	--lan-stage-3:  #0a1e16;

	--lan-chalk:    #e8e2d0;
	--lan-chalk-2:  #a9a492;
	--lan-gold:     #d9a441;

	/* ------------------------------------------------------------------
	   The stock — four papers, because a theatre prints on four papers
	   ------------------------------------------------------------------ */

	--lan-news:     #efe6d2;   /* programme pages, newsprint             */
	--lan-ticket:   #e4d5b2;   /* ticket card, heavier and yellower      */
	--lan-fine:     #f7f2e6;   /* the seating chart, a better stock      */
	--lan-receipt:  #fbf7ee;   /* thermal roll off the box office printer */

	/* ------------------------------------------------------------------
	   The inks
	   ------------------------------------------------------------------ */

	--lan-ink:      #1c1a14;
	--lan-ink-2:    #4a4438;
	--lan-ink-3:    #6e6754;
	--lan-red:      #9b1b12;   /* playbill oxblood                       */
	--lan-green:    #1b4332;
	--lan-mustard:  #b07908;   /* rules and >=24px type only             */

	/* ------------------------------------------------------------------
	   Type
	   ------------------------------------------------------------------ */

	--lan-bill:  'Bevan', 'Rockwell', 'Clarendon', Georgia, serif;
	--lan-text:  'Newsreader', Georgia, 'Times New Roman', serif;
	--lan-mech:  'Courier Prime', 'Courier New', ui-monospace, monospace;

	/*
	 * Seven sizes on 1.28 from a 17px base. The base is larger than the last
	 * design because Newsreader is a text face set on paper, not a UI face.
	 */
	--lan-t-xs:   0.812rem;
	--lan-t-sm:   0.938rem;
	--lan-t-md:   1.062rem;
	--lan-t-lg:   1.36rem;
	--lan-t-xl:   1.74rem;
	--lan-t-2xl:  2.23rem;
	--lan-t-3xl:  2.85rem;

	/* Playbill sizes. Bevan is very heavy, so it needs its own ladder. */
	--lan-t-bill:    clamp( 2.6rem, 6.2vw, 5.4rem );
	--lan-t-bill-lg: clamp( 3.4rem, 8.4vw, 7.2rem );

	--lan-lh-body: 1.58;
	--lan-lh-bill: 0.94;

	/* ------------------------------------------------------------------
	   Space — 4px base
	   ------------------------------------------------------------------ */

	--lan-s-1:  0.25rem;
	--lan-s-2:  0.5rem;
	--lan-s-3:  0.75rem;
	--lan-s-4:  1rem;
	--lan-s-5:  1.5rem;
	--lan-s-6:  2rem;
	--lan-s-8:  3rem;
	--lan-s-10: 4rem;
	--lan-s-12: 5.5rem;
	--lan-s-16: 8rem;

	--lan-measure: 38rem;
	--lan-shell:   80rem;
	--lan-header-h: 5rem;

	/*
	 * Tilts come from a fixed set of three, reused everywhere. A different
	 * random angle per object reads as sloppy; a repeated small set reads as
	 * a pile of things that were put down by a person.
	 */
	--lan-tilt-a: -1.1deg;
	--lan-tilt-b:  0.7deg;
	--lan-tilt-c: -0.4deg;

	--lan-ease: cubic-bezier( 0.2, 0.7, 0.3, 1 );
}

/* ==========================================================================
   Reset and base
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html {
	-webkit-text-size-adjust: 100%;
	scroll-behavior: smooth;
}

@media ( prefers-reduced-motion: reduce ) {
	html { scroll-behavior: auto; }
	*, *::before, *::after {
		animation-duration: 0.001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.001ms !important;
	}
}

body {
	margin: 0;
	background: var( --lan-stage );
	color: var( --lan-chalk );
	font-family: var( --lan-text );
	font-size: var( --lan-t-md );
	line-height: var( --lan-lh-body );
	font-optical-sizing: auto;
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
}

img, svg, canvas { max-width: 100%; height: auto; display: block; }

a { color: inherit; }

:focus-visible {
	outline: 3px solid var( --lan-gold );
	outline-offset: 3px;
}

.lan-sr {
	position: absolute;
	width: 1px; height: 1px;
	padding: 0; margin: -1px;
	overflow: hidden;
	clip-path: inset( 50% );
	white-space: nowrap;
}

.lan-skip {
	position: absolute;
	top: -100vh; left: var( --lan-s-4 );
	z-index: 90;
	background: var( --lan-news );
	color: var( --lan-ink );
	padding: var( --lan-s-3 ) var( --lan-s-5 );
	font-family: var( --lan-mech );
	text-decoration: none;
}

.lan-skip:focus { top: var( --lan-s-4 ); }

/*
 * The bulb sits behind everything, fixed to the viewport so it does not
 * rebuild per section. The page above it must NOT be opaque, or the canvas is
 * painted and then covered — a bug this project has shipped before.
 */
#lan-ghost {
	position: fixed;
	inset: 0;
	width: 100%;
	height: 100%;
	z-index: 0;
	pointer-events: none;
}

.lan-page {
	position: relative;
	z-index: 1;
	background: transparent;
	min-height: 100vh;
	display: flex;
	flex-direction: column;
}

.lan-main { flex: 1 0 auto; }

.lan-shell {
	width: min( var( --lan-shell ), 100% - 2 * var( --lan-s-5 ) );
	margin-inline: auto;
}

@media ( min-width: 48em ) {
	.lan-shell { width: min( var( --lan-shell ), 100% - 2 * var( --lan-s-8 ) ); }
}

/* ==========================================================================
   The paper primitives
   ==========================================================================

   Every piece of content on this site is one of these. They are the reason
   there are no hairline rules in the layout: an object separates itself from
   the stage by having an edge, a thickness and a shadow.
   ========================================================================== */

.lan-paper {
	position: relative;
	background: var( --lan-news );
	color: var( --lan-ink );
	padding: var( --lan-s-6 );

	/*
	 * Two shadows and a light edge. The tight one is contact — where the
	 * paper touches the stage. The wide one is the cast shadow. The inset
	 * highlight along the top edge is the bulb catching the lip of the sheet,
	 * and it is what actually makes it read as an object on a dark ground:
	 * without it the paper looks like a hole cut in the page.
	 */
	box-shadow:
		0 1px 2px rgba( 0, 0, 0, 0.5 ),
		0 14px 34px -12px rgba( 0, 0, 0, 0.7 ),
		inset 0 1px 0 rgba( 255, 255, 255, 0.55 );
}

/* The tooth of the stock. Cheap, and it stops the fill reading as flat CSS. */
.lan-paper::before {
	content: '';
	position: absolute;
	inset: 0;
	pointer-events: none;
	opacity: 0.5;
	background-image:
		repeating-linear-gradient( 0deg,
			rgba( 28, 26, 20, 0.028 ) 0 1px, transparent 1px 3px ),
		repeating-linear-gradient( 90deg,
			rgba( 28, 26, 20, 0.022 ) 0 1px, transparent 1px 4px );
}

.lan-paper > * { position: relative; }

.lan-paper--fine    { background: var( --lan-fine ); }
.lan-paper--receipt { background: var( --lan-receipt ); }

.lan-paper--ticket {
	background: var( --lan-ticket );
	color: var( --lan-ink );
}

/* Ticket stock is darker, so the muted ink has to step up one. */
.lan-paper--ticket .lan-muted,
.lan-paper--ticket .lan-mech-sm { color: var( --lan-ink-2 ); }

.lan-tilt-a { transform: rotate( var( --lan-tilt-a ) ); }
.lan-tilt-b { transform: rotate( var( --lan-tilt-b ) ); }
.lan-tilt-c { transform: rotate( var( --lan-tilt-c ) ); }

/*
 * A perforated tear line down one edge, drawn rather than imaged: a row of
 * holes punched out of the sheet with a mask, so the stage shows through.
 */
.lan-perf-right {
	-webkit-mask-image:
		radial-gradient( circle 5px at 100% 0, transparent 98%, #000 100% ),
		linear-gradient( #000, #000 );
	mask-image:
		radial-gradient( circle 4.5px at right 0 top 0, transparent 98%, #000 100% ),
		linear-gradient( #000, #000 );
	-webkit-mask-size: 100% 14px, 100% 100%;
	mask-size: 100% 14px, 100% 100%;
	-webkit-mask-repeat: repeat-y, no-repeat;
	mask-repeat: repeat-y, no-repeat;
	-webkit-mask-composite: source-in;
	mask-composite: intersect;
}

/*
 * A torn bottom edge for the receipt roll. Uneven on purpose — a straight
 * tear is a cut, and a box office printer does not cut.
 */
.lan-torn-bottom {
	-webkit-mask-image:
		linear-gradient( #000, #000 ),
		radial-gradient( circle 7px at 8px 100%, transparent 98%, #000 100% );
	mask-image:
		linear-gradient( #000, #000 ),
		radial-gradient( circle 7px at 8px 100%, transparent 98%, #000 100% );
	-webkit-mask-size: 100% calc( 100% - 7px ), 16px 14px;
	mask-size: 100% calc( 100% - 7px ), 16px 14px;
	-webkit-mask-position: top left, bottom left;
	mask-position: top left, bottom left;
	-webkit-mask-repeat: no-repeat, repeat-x;
	mask-repeat: no-repeat, repeat-x;
}

/* A fold crease — one bright line, one shadow line, offset by a pixel. */
.lan-fold::after {
	content: '';
	position: absolute;
	top: 0; bottom: 0;
	left: var( --lan-fold-at, 50% );
	width: 3px;
	pointer-events: none;
	background: linear-gradient( 90deg,
		rgba( 28, 26, 20, 0.14 ) 0 1px,
		rgba( 255, 255, 255, 0.65 ) 1px 2px,
		rgba( 28, 26, 20, 0.07 ) 2px 3px );
}

/*
 * A rubber stamp. Slightly rotated, slightly transparent, double ruled —
 * the ink never sits evenly and it is never quite square to the page.
 */
.lan-stamp {
	display: inline-block;
	font-family: var( --lan-mech );
	font-weight: 700;
	font-size: var( --lan-t-xs );
	color: var( --lan-red );
	border: 2px solid var( --lan-red );
	box-shadow: inset 0 0 0 1px rgba( 155, 27, 18, 0.35 );
	padding: 0.3em 0.7em;
	transform: rotate( -3.5deg );
	opacity: 0.86;
	line-height: 1.2;
}

.lan-stamp--green {
	color: var( --lan-green );
	border-color: var( --lan-green );
	box-shadow: inset 0 0 0 1px rgba( 27, 67, 50, 0.35 );
	transform: rotate( 2.5deg );
}

/* ==========================================================================
   Type
   ========================================================================== */

.lan-bill,
.lan-h1,
.lan-poster {
	font-family: var( --lan-bill );
	font-weight: 400;
	line-height: var( --lan-lh-bill );
	letter-spacing: -0.005em;
	margin: 0;
	text-wrap: balance;
}

.lan-h1     { font-size: var( --lan-t-bill ); }
.lan-poster { font-size: var( --lan-t-bill-lg ); }

.lan-h2, .lan-h3, .lan-h4 {
	font-family: var( --lan-text );
	font-weight: 600;
	line-height: 1.16;
	margin: 0;
	text-wrap: balance;
}

.lan-h2 { font-size: var( --lan-t-2xl ); }
.lan-h3 { font-size: var( --lan-t-xl ); }
.lan-h4 { font-size: var( --lan-t-lg ); }

.lan-lede {
	font-size: var( --lan-t-lg );
	line-height: 1.44;
	max-width: 34ch;
	margin: var( --lan-s-5 ) 0 0;
}

/*
 * Machine-printed text. Note what is NOT here: no letter-spacing, no
 * text-transform. This face earns its place by being what a box office
 * printer would have produced, not by being decorated into a label.
 */
.lan-mech,
.lan-mech-sm {
	font-family: var( --lan-mech );
	letter-spacing: 0;
}

.lan-mech    { font-size: var( --lan-t-sm ); }
.lan-mech-sm { font-size: var( --lan-t-xs ); }

/*
 * ==========================================================================
 * Which ground am I on?
 * ==========================================================================
 *
 * This theme has two grounds — the dark stage and the papers — and the bug
 * that keeps coming back is an ink colour landing on the stage, where it is
 * invisible. A measured pass over every text node found six of them, none of
 * which were obvious by eye.
 *
 * So the default is the stage, always, and ink is switched on only inside a
 * printed object. Getting it the other way round means every new block is
 * invisible until somebody notices; this way the worst case is a chalk label
 * on paper, which is merely pale.
 *
 * The list of printed objects lives in sections.css next to their layout.
 */

.lan-muted { color: var( --lan-chalk-2 ); }

.lan-label {
	font-family: var( --lan-mech );
	font-size: var( --lan-t-sm );
	color: var( --lan-gold );
	margin: 0 0 var( --lan-s-3 );
}

/* ==========================================================================
   Prose
   ========================================================================== */

.lan-prose { max-width: var( --lan-measure ); }
.lan-prose > * + * { margin-top: var( --lan-s-5 ); }

.lan-prose p { line-height: var( --lan-lh-body ); }

.lan-prose h2 {
	font-family: var( --lan-bill );
	font-weight: 400;
	font-size: var( --lan-t-2xl );
	line-height: 1.02;
	margin-top: var( --lan-s-10 );
}

.lan-prose h3 {
	font-family: var( --lan-text );
	font-weight: 600;
	font-size: var( --lan-t-lg );
	margin-top: var( --lan-s-8 );
}

.lan-prose a {
	color: var( --lan-red );
	text-decoration-thickness: 1px;
	text-underline-offset: 0.18em;
}

.lan-prose blockquote {
	margin-inline: 0;
	padding: var( --lan-s-5 ) var( --lan-s-6 );
	background: rgba( 27, 67, 50, 0.07 );
	border-left: 4px solid var( --lan-green );
	font-size: var( --lan-t-lg );
	line-height: 1.42;
	color: var( --lan-ink-2 );
}

.lan-prose ul, .lan-prose ol { padding-left: var( --lan-s-5 ); }
.lan-prose li + li { margin-top: var( --lan-s-2 ); }

/* ==========================================================================
   Buttons — printed, not styled
   ========================================================================== */

.lan-btn {
	display: inline-block;
	font-family: var( --lan-mech );
	font-size: var( --lan-t-sm );
	line-height: 1;
	padding: var( --lan-s-3 ) var( --lan-s-5 );
	text-decoration: none;
	background: var( --lan-ticket );
	color: var( --lan-ink );
	border: 0;
	cursor: pointer;
	box-shadow:
		0 1px 2px rgba( 0, 0, 0, 0.45 ),
		0 6px 14px -6px rgba( 0, 0, 0, 0.6 ),
		inset 0 1px 0 rgba( 255, 255, 255, 0.5 );
	transition: transform 180ms var( --lan-ease ), box-shadow 180ms var( --lan-ease );
}

.lan-btn:hover {
	transform: translateY( -2px );
	box-shadow:
		0 2px 3px rgba( 0, 0, 0, 0.45 ),
		0 12px 22px -8px rgba( 0, 0, 0, 0.65 ),
		inset 0 1px 0 rgba( 255, 255, 255, 0.5 );
}

.lan-btn:active { transform: translateY( 0 ); }

.lan-btn--solid {
	background: var( --lan-red );
	color: var( --lan-news );
	box-shadow:
		0 1px 2px rgba( 0, 0, 0, 0.5 ),
		0 6px 14px -6px rgba( 0, 0, 0, 0.6 ),
		inset 0 1px 0 rgba( 255, 255, 255, 0.22 );
}

.lan-btn--sm { padding: var( --lan-s-2 ) var( --lan-s-4 ); font-size: var( --lan-t-xs ); }

.lan-input {
	font-family: var( --lan-mech );
	font-size: var( --lan-t-sm );
	padding: var( --lan-s-3 ) var( --lan-s-4 );
	background: var( --lan-receipt );
	color: var( --lan-ink );
	border: 0;
	width: 100%;
	box-shadow: inset 0 1px 3px rgba( 28, 26, 20, 0.28 );
}

/* ==========================================================================
   Reveal
   ==========================================================================

   Paper is put down on a table, so it arrives with a small drop and settle
   rather than a fade-up. Content is present and readable with no JavaScript.
   ========================================================================== */

html:not( .lan-js ) .lan-reveal { opacity: 1; transform: none; }

.lan-js .lan-reveal {
	opacity: 0;
	transform: translateY( 14px ) rotate( 0deg ) scale( 0.995 );
	transition:
		opacity 460ms var( --lan-ease ),
		transform 620ms var( --lan-ease );
}

.lan-js .lan-reveal.is-in { opacity: 1; transform: none; }

@media ( prefers-reduced-motion: reduce ) {
	.lan-js .lan-reveal { opacity: 1; transform: none; transition: none; }
}

.lan-row {
	display: flex;
	flex-wrap: wrap;
	gap: var( --lan-s-4 );
	align-items: center;
}

.lan-section        { padding-block: var( --lan-s-12 ); }
.lan-section--tight { padding-block: var( --lan-s-8 ); }

@media ( min-width: 64em ) {
	.lan-section { padding-block: var( --lan-s-16 ); }
}
