/*
 * Tristopic — work sphere page.
 *
 * Loaded on the front page only. Tokens come from theme.json; nothing here
 * hardcodes a colour or a spacing step.
 *
 * Layering, bottom to top:
 *   0  .tristopic-stage      the WebGL canvas
 *   1  .tristopic-index      the static work grid (the real, indexable page)
 *   2  .tristopic-hud        fixed chrome: mark, statement, clocks, CTA, nav
 *   3  .tristopic-overlay    the project view
 */

/* ---------------------------------------------------------------- the page --- */

.tristopic-sphere-page {
	min-height: 100svh;
}

/* While the sphere runs it owns the viewport, so the document must not scroll. */
.tristopic-gallery-active {
	overflow: hidden;
	height: 100svh;
}

/* Floating over the canvas rather than pushing it down, and above the project
   overlay so the header stays reachable while a project is open. */
:root {
	/*
	 * The colophon strip: one line of micro type on the bottom edge, plus
	 * whatever the hardware reserves for a home indicator. The strip above it
	 * and the project card both hold off by this much.
	 */
	--tristopic-colophon-h: calc(1.25rem + env(safe-area-inset-bottom, 0px));
}

.tristopic-bar--floating {
	position: fixed;
	inset: 0 0 auto;
	z-index: 60;

	/* Transparent over the sphere, so the grid runs right up under the type. */
	background: none;
	backdrop-filter: none;
	-webkit-backdrop-filter: none;
	border-bottom: 0;
}

/*
 * The same treatment the bar gets at the top, for the same reason: fixed over
 * the canvas, and no ground behind it. A strip of ink across the foot would cut
 * the sphere off.
 *
 * Fixed rather than sticky because there is nothing here to stick to — the
 * gallery is one canvas the height of the viewport, not a page that scrolls.
 */
.tristopic-footer--floating {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 60;
	margin-top: 0;
	background: none;

	/* Nothing in it is clickable, and the canvas underneath is dragged. */
	pointer-events: none;
}

/*
 * The ambient step is for a solid ink ground. It was chosen at 4.60:1 against
 * ink, which leaves it nothing in hand over a tile that could be any colour the
 * work happens to be. Over the canvas the clock and the date take the furniture
 * step instead, and keep the ambient one on every page with a real ground.
 */
.tristopic-footer--floating .tristopic-colophon__time,
.tristopic-footer--floating .tristopic-colophon__updated {
	color: var(--wp--preset--color--paper-dim);
}

/* No rule across the bottom of the sphere: nothing separates it from the work. */
.tristopic-footer--floating .tristopic-colophon__strip {
	margin-top: 0;
	border-top: 0;
}

.tristopic-gallery-active .tristopic-stage {
	position: fixed;
	inset: 0;
	z-index: 0;
	display: block;
	pointer-events: auto;
	background: var(--wp--preset--color--ink);
}

.tristopic-stage__canvas {
	display: block;
	width: 100%;
	height: 100%;
	cursor: grab;
	touch-action: none; /* we handle drag ourselves */
}

/*
 * The canvas keeps a ring, and is the one place that should. It is a drag
 * surface with no text to recolour, so there is nothing else that could show a
 * keyboard user they have reached it. Inset, so it reads as the stage being
 * live rather than as a box around a control.
 */
.tristopic-stage__canvas:focus-visible {
	outline: 1px solid var(--wp--preset--color--paper-dim);
	outline-offset: -4px;
}

/* --------------------------------------------------------------------- HUD --- */

/*
 * One control, on the right, just above the colophon. This was a three-column
 * grid balancing a clock against a positioning line; both have gone — the clock
 * to the colophon, the line because the work says it — so it is a row with one
 * thing in it now.
 */
.tristopic-hud {
	position: fixed;
	left: 0;
	right: 0;
	/* Clear of the colophon, which is now the thing on the bottom edge. */
	bottom: var(--tristopic-colophon-h);
	/*
	 * Above the overlay, like the bar at the top. These are the only things at
	 * the foot of the gallery and losing them whenever a card opened made the
	 * screen look truncated — they are furniture, not content, so a card
	 * covering them was never the intent.
	 */
	z-index: 60;
	display: flex;
	justify-content: flex-end;
	align-items: center;
	padding: 0 var(--tristopic-chrome-inset);
	/*
	 * No safe-area padding: this no longer sits on the bottom edge, and the
	 * colophon token it stands on already accounts for the home indicator.
	 * Keeping it here would have reserved that space twice.
	 */
	background: none;
	pointer-events: none;
}

.tristopic-hud > * {
	pointer-events: auto;
}

/* View switch. */
.tristopic-hud__views {
	display: flex;
	gap: 0.25rem;
}

.tristopic-hud__views button {
	display: grid;
	place-items: center;
	width: 2rem;
	height: 2rem;
	border: 0;
	border-radius: 999px;
	background: transparent;

	/*
	 * The furniture grey, not the hairline grey. At ink-line this measured
	 * 1.40:1 — below the 3:1 WCAG asks of a control, and visible only on hover.
	 * A phone has no hover, so the one button that opens the sphere was
	 * invisible on the devices most visitors arrive with. paper-faint is 4.59:1
	 * against ink: still quiet, which was the point, but actually there.
	 */
	color: var(--wp--preset--color--paper-faint);
	cursor: pointer;
	transition: color var(--wp--custom--duration--fast) var(--wp--custom--ease);
}

.tristopic-hud__views svg {
	width: 1rem;
	height: 1rem;
	/* Drawn, not filled: the same hairline the rest of the site is built from. */
	fill: none;
	stroke: currentColor;
	stroke-width: 1;
	stroke-linecap: round;
	stroke-linejoin: round;
	vector-effect: non-scaling-stroke;
}

/*
 * Only one icon is ever shown: the view the button would take you to. In the
 * sphere the grid is offered, and the other way round.
 */
body[data-view="sphere"] .tristopic-hud__views [data-view-icon="sphere"],
body[data-view="index"] .tristopic-hud__views [data-view-icon="index"] {
	display: none;
}

.tristopic-hud__views button:hover,
.tristopic-hud__views button:focus-visible {
	color: var(--wp--preset--color--accent);
}

/*
 * A 2rem button is under the 44px a thumb wants. The box grows on touch
 * screens without the icon or the strip changing size.
 */
@media (pointer: coarse) {
	.tristopic-hud__views button {
		width: 2.75rem;
		height: 2.75rem;
	}
}

/* ------------------------------------------------------------ static index --- */

/*
 * This is the real page: server-rendered, crawlable, keyboard-navigable. The
 * sphere is drawn on top of it. Switching to index view simply hides the canvas.
 */
.tristopic-index {
	position: relative;
	z-index: 1;
	padding-block: calc(var(--wp--preset--spacing--50) + 2rem) var(--wp--preset--spacing--50);
}

/*
 * Both views are the same canvas. "Index" simply eases the curvature to zero,
 * so the flat grid is still dragged around rather than scrolled — there is no
 * scrollbar in either mode.
 *
 * The server-rendered index stays in the document for crawlers and assistive
 * technology, visually hidden whenever the canvas is running.
 */
.tristopic-gallery-active .tristopic-index {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

.tristopic-index__list {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(min(18rem, 100%), 1fr));
	gap: var(--wp--preset--spacing--30);
	margin: 0;
	padding: 0;
	list-style: none;
}

.tristopic-index__item a {
	display: grid;
	gap: 0.6rem;
	text-decoration: none;
}

.tristopic-index__media {
	aspect-ratio: 1;
	overflow: hidden;
	background: var(--wp--preset--color--ink-raised);
}

.tristopic-index__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform var(--wp--custom--duration--slow) var(--wp--custom--ease);
}

.tristopic-index__item a:hover .tristopic-index__media img {
	transform: scale(1.05);
}

.tristopic-index__title {
	font-size: var(--wp--preset--font-size--body);
	font-weight: 500;
	margin: 0;
}

/* --------------------------------------------------------------- overlay ---- */

/*
 * The [hidden] rule must come with the display rule and must win.
 *
 * `hidden` is only a user-agent `display: none`, so ANY author `display` here
 * beats it. Without this the overlay stays in the layout at inset:0 with
 * opacity:0 — invisible, full-screen, and swallowing every click, drag and
 * button press on the page.
 */
.tristopic-overlay[hidden] {
	display: none !important;
}

/* Belt and braces: while fading out it must not intercept pointer events. */
.tristopic-overlay:not(.is-open) {
	pointer-events: none;
}

.tristopic-overlay.is-open {
	pointer-events: auto;
}

.tristopic-overlay {
	/*
	 * What the chrome at the foot needs — the view-switch strip and the
	 * colophon under it — plus the gap the card keeps from every other edge.
	 * Measured, not guessed: the strip is 44px at its tallest, on a phone,
	 * where the view switch is the tallest thing in it.
	 */
	--tristopic-hud-clear: calc(2.75rem + var(--tristopic-colophon-h) + var(--wp--preset--spacing--10));

	position: fixed;
	inset: 0;
	z-index: 50;   /* under the bar (60), over the sphere furniture (40) */
	display: grid;
	place-items: center;
	/* Clear of the bar above and, now that it stays visible, the strip below. */
	padding: calc(var(--wp--preset--spacing--30) + 1.5rem) var(--wp--preset--spacing--20)
		var(--tristopic-hud-clear);
	background: rgb(from var(--wp--preset--color--ink) r g b / 0.82);
	backdrop-filter: blur(18px);
	-webkit-backdrop-filter: blur(18px);
	opacity: 0;
	transition: opacity 240ms ease-out;
}

.tristopic-overlay.is-open {
	opacity: 1;
}

.tristopic-overlay__panel {
	position: relative;
	display: block;
	width: min(100%, 60rem);
	/*
	 * The overlay has already reserved room for the bar above and the strip
	 * below in its own padding; 100% is what it left, so the card cannot reach
	 * either of them however that sum changes.
	 */
	max-height: 100%;
	overflow: auto;
	padding: var(--wp--preset--spacing--30);

	/* The native scrollbar cut across the panel and looked bolted on. Hidden,
	   but the panel still scrolls by wheel, drag, and keyboard. */
	scrollbar-width: none;
	-ms-overflow-style: none;
	border: var(--wp--custom--line);
	border-radius: 2rem;
	background: var(--wp--preset--color--ink-raised);

	/*
	 * The panel grows out of the tile that was clicked: the script sets
	 * transform-origin to that point, so the scale reads as the tile expanding
	 * rather than a dialog fading in on top of everything.
	 */
	transform: scale(0.34);
	opacity: 0;
	transition:
		transform 520ms cubic-bezier(0.16, 1, 0.3, 1),
		opacity 260ms ease-out;
	will-change: transform;
}

.tristopic-overlay__panel::-webkit-scrollbar {
	width: 0;
	height: 0;
}

.tristopic-overlay.is-open .tristopic-overlay__panel {
	transform: none;
	opacity: 1;
}

/* The contents settle a beat after the panel, so the motion has a sequence. */
.tristopic-overlay__panel > * {
	opacity: 0;
	transform: translateY(10px);
	transition:
		opacity 320ms ease-out 140ms,
		transform 420ms cubic-bezier(0.16, 1, 0.3, 1) 140ms;
}

.tristopic-overlay.is-open .tristopic-overlay__panel > * {
	opacity: 1;
	transform: none;
}

/*
 * Set in the same brackets as the project toggle, on the title's baseline. The
 * ring it replaced was the only circle on the site and read as a control
 * borrowed from somewhere else.
 *
 * The padding is what makes the 44px tap target; the equal negative margin
 * cancels it for layout, so the glyph stays exactly where the baseline puts it
 * and only the target grows.
 */
.tristopic-overlay__close {
	position: relative;
	flex: none;
	padding: 0;
	margin: 0;
	border: 0;
	background: none;
	color: var(--wp--preset--color--paper-dim);
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--micro);
	letter-spacing: var(--wp--custom--tracking--wider);
	text-transform: uppercase;
	cursor: pointer;
	transition: color var(--wp--custom--duration--fast) var(--wp--custom--ease);
}

/*
 * The tap target, held outside the layout. Padding would have to be cancelled
 * by a negative margin, and that margin escapes the panel once its own padding
 * is smaller than the margin -- which is what made the card scroll sideways.
 */
.tristopic-overlay__close::after {
	content: "";
	position: absolute;
	/* top | right | bottom | left — nothing to the right, which is the panel edge. */
	inset: -0.9rem 0 -0.9rem -1.4rem;
}

.tristopic-overlay__close:hover,
.tristopic-overlay__close:focus-visible {
	color: var(--wp--preset--color--accent);
}

.is-overlay-open {
	overflow: hidden;
}

/* ------------------------------------------------------------- responsive --- */

@media (max-width: 599px) {
	/*
	 * The clearance at the top is for the floating bar, which is 17px tall
	 * now that its padding has gone — this was reserving 56px for a bar that
	 * used to be 41px.
	 */
	.tristopic-overlay {
		padding: calc(var(--wp--preset--spacing--10) + 1.25rem)
			var(--wp--preset--spacing--10)
			var(--tristopic-hud-clear);
	}

	/*
	 * 10px, the same as the pages. The card was charging for its edges twice,
	 * once from the overlay and once from itself, and the radius was reading
	 * as most of the margin at this size.
	 */
	.tristopic-overlay__panel {
		padding: 0.625rem;
		border-radius: 1rem;
	}
}

/* No WebGL, or reduced motion: the static index is simply the page. */
@media (prefers-reduced-motion: reduce) {
	.tristopic-stage {
		display: none;
	}
}
