/* =========================================================================
   netex · engines/freeze-frame.css · bible S7 (Frame Hunt, Field Case 01)
   The 9:16 reel frame (Ink screen, 1px rule, Indigo print shadow), code-drawn reel chrome, the 47° scan
   sweep on pause, the near-miss bracket, the HUD and the hit ticket. Loaded by the PHP mount before the
   markup (no CLS); the engine skips its own injection when this file is already on the page.
   ========================================================================= */
@layer reset, tokens, base, components, layout, pages, utilities;

@layer pages {

.ff {
	--ff-w: min(100%, 480px, calc((100svh - var(--header-h) - 11rem) * 9 / 16));
	container-type: inline-size;
	color: var(--fg);
}
.ff__in { display: grid; gap: var(--s-6) var(--gutter); align-items: start; }
.ff__stage { position: relative; width: var(--ff-w); min-width: 220px; justify-self: start; }
/* The AI label hangs under the reel's bottom-left corner (outside the reel, which is a button). */
.ff__stage:has(> .nx-ailabel) { padding-bottom: 30px; }
.ff__stage > .nx-ailabel { left: 0; bottom: 0; }
.ff__reel {
	position: relative;
	aspect-ratio: 9 / 16;
	background: var(--ink);
	outline: var(--bw) solid var(--rule-dark);
	box-shadow: var(--shadow-print);
	cursor: pointer;
	-webkit-user-select: none;
	user-select: none;
	touch-action: manipulation;
}
.ff__reel:focus-visible { outline: var(--bw-focus) solid var(--focus); outline-offset: var(--focus-offset); }
.ff__screen { position: absolute; inset: 0; overflow: hidden; background: var(--ink); }
.ff__screen picture, .ff__screen img, .ff__screen video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.ff__screen video { opacity: 0; transition: opacity 240ms var(--ease-mech); }
.ff.is-video .ff__screen video { opacity: 1; }

/* Reel chrome, drawn in code (no fake phone chrome, no platform marks). */
.ff__chrome { position: absolute; inset: 0; pointer-events: none; color: var(--paper); font: 500 .6875rem/1.3 var(--f-mono); letter-spacing: .04em; }
.ff__progress { position: absolute; left: 10px; right: 10px; top: 10px; height: 2px; background: rgb(241 238 230 / .28); overflow: hidden; }
.ff__progress i { display: block; height: 100%; background: var(--paper); transform-origin: left; transform: scaleX(var(--ff-p, 0)); }
.ff__handle { position: absolute; left: 10px; top: 20px; padding: 2px 6px; background: rgb(8 9 14 / .55); }
.ff__cap {
	position: absolute;
	left: 10px;
	right: 10px;
	bottom: 40px;
	padding: 6px 8px;
	background: rgb(8 9 14 / .62);
	font: 400 .75rem/1.35 var(--f-sans);
	letter-spacing: 0;
	text-wrap: pretty;
}
.ff .nx-ailabel { z-index: 3; }

/* The 47° scan sweep that crosses the paused frame (cause: you paused · effect: the frame is checked). */
.ff__screen { container-type: size; }
.ff__scan {
	/* A true 47° band across a 9:16 frame: its run is 0.9325 × the frame height. */
	position: absolute;
	top: 0;
	left: 0;
	height: 100%;
	width: calc(93.25cqh + 24cqw);
	pointer-events: none;
	opacity: 0;
	z-index: 2;
	background: rgb(8 9 14 / .38);
	clip-path: polygon(93.25cqh 0, 100% 0, 24cqw 100%, 0 100%);
	transform: translateX(-100%);
}
.ff__scan::after {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--cyan);
	clip-path: polygon(calc(100% - 2px) 0, 100% 0, 24cqw 100%, calc(24cqw - 2px) 100%);
}
.ff.is-scanning .ff__scan { opacity: 1; animation: ff-scan 520ms linear both; }
/* A slow server: the sweep keeps crossing until the verdict arrives (never a spinner, never a blank wait). */
.ff.is-judging .ff__scan { opacity: 1; animation: ff-scan 520ms linear infinite; }
@keyframes ff-scan { from { transform: translateX(-100%); } to { transform: translateX(100cqw); } }

/* Near-miss ghost bracket: crop marks around the frame with the distance stamped. */
.ff__bracket { position: absolute; inset: 14% 10%; z-index: 2; pointer-events: none; opacity: 0; }
.ff__bracket::before, .ff__bracket::after, .ff__bracket i::before, .ff__bracket i::after {
	content: "";
	position: absolute;
	width: 18px;
	height: 18px;
	border: 0 solid var(--paper);
}
.ff__bracket::before { left: 0; top: 0; border-left-width: 2px; border-top-width: 2px; }
.ff__bracket::after { right: 0; top: 0; border-right-width: 2px; border-top-width: 2px; }
.ff__bracket i::before { left: 0; bottom: 0; border-left-width: 2px; border-bottom-width: 2px; }
.ff__bracket i::after { right: 0; bottom: 0; border-right-width: 2px; border-bottom-width: 2px; }
/* The distance sits on the bracket's top edge, clear of the verdict stamp near the bottom of the frame. */
.ff__bracket b {
	position: absolute;
	left: 50%;
	top: -2px;
	transform: translate(-50%, -50%);
	padding: 2px 8px;
	background: var(--paper);
	color: var(--ink);
	font: 600 .75rem/1.3 var(--f-mono);
	white-space: nowrap;
}
.ff.is-near .ff__bracket { opacity: 1; animation: nx-stamp var(--dur-stamp) var(--ease-stamp) both; }

/* Verdict stamp on the frame (the HUD line carries the accessible text). */
.ff__stampmark {
	position: absolute;
	left: 10px;
	bottom: 96px;
	z-index: 3;
	max-width: calc(100% - 20px);
	padding: 4px 9px;
	background: var(--ink);
	color: var(--paper);
	border: var(--bw) solid rgb(241 238 230 / .4);
	font: 600 .75rem/1.3 var(--f-mono);
	letter-spacing: .06em;
	text-transform: uppercase;
	pointer-events: none;
}
.ff__stampmark:empty { display: none; }
.ff__stampmark.is-hit { background: var(--paper); color: var(--ink); border-color: var(--paper); }

.ff__start { position: absolute; left: 50%; top: 50%; z-index: 4; transform: translate(-50%, -50%); white-space: nowrap; }
.ff__stage:has(> .nx-ailabel) > .ff__start { top: calc(50% - 15px); }
.ff__start[hidden] { display: none; }
.ff.is-loading .ff__start .nx-btn__label::after { content: "…"; }
.ff__start .nx-btn__arrow { width: .9em; height: .9em; }

/* ---- HUD ------------------------------------------------------------------ */
.ff__hud { display: grid; gap: var(--s-5); align-content: start; min-width: 0; container-type: inline-size; }
@container (max-width: 360px) {
	/* Narrow HUD: the meters wrap whole (never a label broken over two lines). */
	.ff__meters { display: flex; flex-wrap: wrap; column-gap: var(--s-5); }
	.ff__meter dt { white-space: nowrap; }
	.ff__meter dd { font-size: 1.0625rem; }
	.ff__modes { display: grid; width: 100%; }
	.ff__modes > * + * { border-left: 0; border-top: var(--bw) solid var(--rule); }
	.ff__modes > button { text-align: left; }
}
.ff__intro { display: grid; gap: var(--s-4); }
.ff__meters { display: grid; grid-template-columns: repeat(3, minmax(0, max-content)); gap: var(--s-2) var(--s-6); margin: 0; }
.ff--mini .ff__meters { grid-template-columns: repeat(2, minmax(0, max-content)); }
.ff__meter { display: grid; gap: var(--s-1); }
.ff__meter dt { font: 500 .6875rem/1.3 var(--f-mono); letter-spacing: var(--tr-label); text-transform: uppercase; color: var(--fg-2); }
.ff__meter dd { margin: 0; font: 600 1.375rem/1 var(--f-mono); font-variant-numeric: tabular-nums; color: var(--fg); white-space: nowrap; }
.ff__meter--attempts dd { font-size: clamp(2rem, 1.4rem + 2vw, 3rem); }
.ff__meter dd.is-dot { font-family: var(--f-dot); font-weight: 500; font-variation-settings: "ELSH" 2; letter-spacing: .02em; }
.ff__msg {
	position: relative;
	min-height: 2.7em;
	max-width: 34ch;
	font: var(--w-h3) var(--t-h4)/1.3 var(--f-sans);
	color: var(--fg);
	text-wrap: balance;
}
.ff__msg:empty { min-height: 2.7em; }
/* Before the first play the line says how to play, quietly (the start button is the one call to action). */
.ff__msg.is-idle { min-height: 0; max-width: 46ch; font: 400 var(--t-small)/1.5 var(--f-sans); color: var(--fg-2); }
.ff__msg small { display: block; margin-top: var(--s-1); font: 500 .8125rem/1.4 var(--f-mono); color: var(--fg-2); letter-spacing: .02em; }
.ff__controls { display: grid; gap: var(--s-4); }
.ff__controls[hidden] { display: none; }
.ff__row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-3); }
.ff__pausebtn[hidden] { display: none; }
.ff__modes { justify-self: start; }
.ff__modes > button { min-height: 44px; }
.ff__step { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2) var(--s-3); }
.ff__step[hidden] { display: none; }
.ff__scrub { flex: 1 1 100%; display: block; }
.ff__stephelp { flex: 1 1 100%; font: 400 var(--t-small)/1.45 var(--f-sans); color: var(--fg-2); max-width: 46ch; }
.ff__stepnote { display: block; margin-top: var(--s-1); font: 500 .75rem/1.45 var(--f-mono); color: var(--fg-2); }
.ff__more { display: flex; flex-wrap: wrap; gap: var(--s-1) var(--s-5); }
.ff__outro { display: grid; gap: var(--s-3); padding-top: var(--s-4); border-top: var(--bw) solid var(--rule); }
.ff__hint { font: 500 .6875rem/1.5 var(--f-mono); letter-spacing: .03em; color: var(--fg-2); max-width: 52ch; }
.ff__pausebtn[aria-pressed="true"] { background: var(--fg); color: var(--bg); }

/* ---- Hit ticket: a paper sheet that wipes in at 47° ------------------------ */
.ff__result { display: grid; gap: var(--s-4); max-width: 34rem; }
.ff__result[hidden] { display: none; }
.ff__ticket {
	position: relative;
	isolation: isolate;
	display: grid;
	gap: var(--s-3);
	padding: var(--s-5) var(--s-5) calc(var(--s-5) + var(--ch-sheet) * .4);
	color: var(--ink);
	--fg: var(--ink); --fg-2: var(--steel-dark); --fg-3: var(--steel-dark); --bg: var(--paper); --bg-2: var(--paper-2);
	--rule: var(--rule-light); --link: var(--cyan-deep); --focus: var(--indigo); --sig: var(--cyan-deep); --leak: var(--molten-deep);
	color-scheme: light;
	filter: drop-shadow(8px 8px 0 var(--indigo));
}
.ff__ticket::before { content: ""; position: absolute; inset: 0; z-index: -1; background: var(--paper); clip-path: var(--clip-sheet); }
.ff__result.is-in .ff__ticket { animation: nx-wipe-in var(--dur-cut) var(--ease-cut) backwards; }
.ff__hit { --flar: 100; --volm: 100; font: 820 clamp(2rem, 1.4rem + 2.4vw, 3rem)/1 var(--f-sans); font-variation-settings: "FLAR" 100, "VOLM" 100; letter-spacing: -.02em; }
.ff__hitline { font: 500 .8125rem/1.45 var(--f-mono); color: var(--fg-2); }
.ff__hitline:empty { display: none; }
.ff__coupon {
	position: relative;
	display: inline-flex;
	align-items: center;
	gap: var(--s-3);
	justify-self: start;
	padding: 6px 18px 6px 14px;
	background: var(--molten);
	color: var(--ink);
	clip-path: var(--clip-ui);
}
.ff__coupon b { font: 820 1.75rem/1 var(--f-sans); letter-spacing: -.02em; }
.ff__coupon i { width: 0; height: 1.6em; border-left: 2px dashed rgb(8 9 14 / .55); }
.ff__code { display: grid; gap: var(--s-1); }
.ff__code[hidden] { display: none; }
.ff__codelabel { font: 500 .6875rem/1.3 var(--f-mono); letter-spacing: var(--tr-label); text-transform: uppercase; color: var(--fg-2); }
.ff__codeval { font: 600 clamp(1.5rem, 1.1rem + 1.4vw, 2.125rem)/1.1 var(--f-mono); letter-spacing: .06em; color: var(--ink); min-height: 1.1em; }
.ff__codeval:empty::before { content: "NX-····-··"; color: var(--paper-3); }
.ff__codebody { font: 400 var(--t-small)/1.5 var(--f-sans); color: var(--ink); max-width: 46ch; }
.ff__codebody:empty { display: none; }
.ff__codeactions[hidden], .ff__booknote[hidden], .ff__retry[hidden] { display: none; }
.ff__retry { justify-self: start; }
.ff__after { gap: var(--s-2) var(--s-5); }
.ff__text { color: var(--fg-2); }
.js .ff__text { display: none; }

/* ---- Layout: reel beside the HUD when there is room -------------------------- */
/* Tablet: the reel takes at most half the width so the HUD keeps its meters on one line, and the page
   intro (Frame Hunt) runs full width above them (beside a 440 px reel it broke out of a 225 px column). */
@container (min-width: 600px) {
	.ff__in { grid-template-columns: minmax(220px, min(var(--ff-w), 50cqi)) minmax(0, 1fr); grid-template-areas: "stage hud"; column-gap: clamp(var(--s-6), 4cqi, var(--s-9)); }
	.ff--intro .ff__in { grid-template-areas: "intro intro" "stage hud"; grid-template-rows: auto 1fr; }
	.ff__stage { grid-area: stage; width: 100%; position: sticky; top: calc(var(--header-h) + var(--s-5)); }
	.ff__intro { grid-area: intro; }
	.ff__hud { grid-area: hud; }
}
@container (min-width: 900px) {
	.ff__in { --ff-w: min(480px, calc((100svh - var(--header-h) - 6rem) * 9 / 16)); grid-template-columns: minmax(240px, var(--ff-w)) minmax(0, 1fr); }
	.ff--intro .ff__in { grid-template-areas: "stage intro" "stage hud"; }
}

/* ---- Reduced motion: no sweep, no stamps; states are instant ---------------- */
html.rm .ff.is-scanning .ff__scan, html.rm .ff.is-judging .ff__scan { animation: none; opacity: 0; }
html.rm .ff.is-judging .ff__msg:empty::after { content: "…"; font: 600 1.25rem/1 var(--f-mono); color: var(--fg-2); }
html.rm .ff__result.is-in .ff__ticket { animation: none; }

@media (hover: hover) {
	.ff.is-playing .ff__reel:hover { outline-color: var(--paper); }
}

} /* end @layer pages */
