/*
Theme Name: opendoorslowly
Theme URI: https://opendoorslowly.com
Author: Stephen Wahl
Description: Block theme for the opendoorslowly | stephen wahl portfolio. Black canvas, image-led tiles and banners, condensed type.
Version: 0.1.26
Requires at least: 6.5
Requires PHP: 7.4
License: GNU General Public License v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: ods-wahl
*/

:root {
	--ods-side: clamp(1rem, 2.9vw, 3.3rem);
	--ods-gap: clamp(1rem, 3vw, 3.4rem);
	--ods-charcoal: #262626;
}

html { background: #000; }
body { margin: 0; -webkit-font-smoothing: antialiased; }
.wp-site-blocks { padding: 0; }
.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }

a:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }

/* Header ---------------------------------------------------------------- */
.ods-site-header {
	position: sticky;
	top: 0;
	z-index: 100;
	background: rgba(0, 0, 0, 0.9);
}
body.home .ods-site-header { background: var(--ods-charcoal); }
.admin-bar .ods-site-header { top: 32px; }
@media (max-width: 782px) { .admin-bar .ods-site-header { top: 46px; } }

.ods-header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	padding: clamp(0.75rem, 1.9vw, 1.9rem) var(--ods-side);
}
.ods-header > * { margin: 0; }
.ods-logo { display: block; line-height: 0; }
.ods-logo img { display: block; width: clamp(170px, 29vw, 525px); height: auto; }

.ods-nav { display: flex; gap: clamp(0.9rem, 1.6vw, 1.75rem); }
.ods-nav a {
	font-weight: 300;
	font-size: clamp(1.1rem, 1.41vw, 1.65rem);
	letter-spacing: 0.02em;
	text-transform: uppercase;
	color: #fff;
	text-decoration: none;
	padding-bottom: 3px;
	border-bottom: 1px solid transparent;
}
.ods-nav a:hover,
.ods-nav a.is-current { border-bottom-color: #fff; }

/* Tiles (child-page index, 4 up) ------------------------------------------ */
.ods-tiles {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: var(--ods-gap);
	padding: clamp(1.5rem, 3.5vw, 4rem) var(--ods-side) clamp(1rem, 2.5vw, 3rem);
}
@media (max-width: 999px) { .ods-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 559px) { .ods-tiles { grid-template-columns: 1fr; } }

.ods-tile {
	position: relative;
	display: block;
	aspect-ratio: 3 / 2;
	overflow: hidden;
	background: #111;
	color: #fff;
	text-decoration: none;
}
.ods-tile__img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	filter: brightness(0.72);
	transition: filter 0.35s ease;
}
.ods-tile:hover .ods-tile__img,
.ods-tile:focus-visible .ods-tile__img { filter: brightness(0.95); }
.ods-tile__title {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 0 0.5rem;
	text-align: center;
	font-size: clamp(1.5rem, 2.3vw, 2.6rem);
	font-weight: 300;
	line-height: 1.05;
	letter-spacing: 0.01em;
}

/* Banners (Work landing, full-width stacked) ------------------------------- */
.ods-banners {
	display: flex;
	flex-direction: column;
	gap: clamp(1.5rem, 3.6vw, 4.1rem);
	padding: clamp(0.6rem, 1vw, 1.2rem) 6.9% 0;
}
.ods-banner {
	position: relative;
	display: block;
	aspect-ratio: 2 / 1;
	overflow: hidden;
	background: #111;
	text-decoration: none;
}
.ods-banner__img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* The section title is part of each banner image, so the text is kept for screen readers only. */
.ods-banner__title {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* YouTube looping background ---------------------------------------------- */
.ods-ytbg {
	position: relative;
	overflow: hidden;
	container-type: size;
	aspect-ratio: var(--ods-ratio, 16 / 9);
	background: #000;
}
@media (max-width: 700px) { .ods-ytbg { aspect-ratio: var(--ods-ratio-m, 16 / 9); } }
.ods-ytbg iframe {
	position: absolute;
	top: 50%;
	left: 50%;
	width: max(100cqw, 177.78cqh);
	height: max(100cqh, 56.25cqw);
	transform: translate(-50%, -50%) scale(var(--ods-zoom, 1.08));
	border: 0;
	pointer-events: none;
}
.ods-ytbg__overlay {
	position: absolute;
	inset: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	text-align: center;
	pointer-events: none;
	color: #fff;
}
.ods-ytbg__kicker { font-size: clamp(0.9rem, 1.1vw, 1.25rem); font-weight: 300; margin: 0; }
.ods-ytbg__title { font-size: clamp(1.75rem, 2.6vw, 3rem); font-weight: 300; margin: 0; line-height: 1.1; }
/* Hidden until the player reports it is playing (script adds .is-armed, then .is-playing), so YouTube's poster and play button never show. */
.ods-ytbg.is-armed iframe { opacity: 0; transition: opacity 0.5s ease; }
.ods-ytbg.is-armed.is-playing iframe { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .ods-ytbg iframe { display: none; } }

/* Embeds side by side, with a little breathing room between windows. -------- */
.ods-embeds { gap: clamp(0.75rem, 2vw, 2rem) !important; margin: 0 0 clamp(0.75rem, 2vw, 2rem) !important; }
.ods-embeds:last-of-type { margin-bottom: 0 !important; }
.ods-embeds .wp-block-column { margin: 0; }
.ods-embeds figure { margin: 0; }

/* Home: white stage --------------------------------------------------------- */
.ods-stage-white { background: #fff; color: #000; }
.ods-stage-white img { display: block; margin-inline: auto; height: auto; }

/* Home fills one screen under the header: white stage grows, video strip sits at the bottom. */
:root { --ods-header-h: calc(clamp(0.75rem, 1.9vw, 1.9rem) * 2 + clamp(170px, 29vw, 525px) * 0.0934); }
.admin-bar { --ods-admin-h: 32px; }
@media (max-width: 782px) { .admin-bar { --ods-admin-h: 46px; } }
.ods-home {
	display: flex;
	flex-direction: column;
	min-height: calc(100vh - var(--ods-header-h) - var(--ods-admin-h, 0px));
	min-height: calc(100dvh - var(--ods-header-h) - var(--ods-admin-h, 0px));
}
.ods-home > * { margin-block: 0 !important; }
.ods-home .ods-stage-white {
	/* flex-basis:0 (not auto) so the box's share of space comes purely from flex-grow against the row's definite height, rather than from the full-bleed image's own intrinsic aspect ratio. With basis:auto the image's 100%-height child can never resolve to a real number (the box has no definite height yet), so it falls back to the image's natural ratio and the box balloons to match it. */
	flex: 1 1 0;
	/* Flex items default to min-height:auto, which lets tall content (the full-bleed image) push this box past the space the flex layout actually has for it. Pin it to 0 so the box stays within the one-screen layout and the image crops to fit instead of growing the page. */
	min-height: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	overflow: hidden;
	padding: 0;
}
.ods-home .ods-stage-white .wp-block-image { margin: 0; width: 100%; height: 100%; }
/* Full bleed: fills the stage edge to edge, cropped to fit rather than letterboxed. */
.ods-home .ods-stage-white img { width: 100%; height: 100%; object-fit: cover; object-position: center; }
.ods-home .ods-ytbg,
.ods-home .ods-strip { flex: 0 0 auto; }
/* Narrow/portrait viewports: the stage box's aspect ratio no longer resembles the photo's, so a hard cover-crop risks cutting off the wrench's jaw or handle. Fall back to a no-crop fit — the photo's own background is white like the stage, so this reads as extra margin rather than visible letterboxing. */
@media (max-width: 700px) {
	.ods-home .ods-stage-white img { object-fit: contain; }
}

/* Self-hosted video strip: no controls, cropped to fill, centered. */
.ods-strip { position: relative; overflow: hidden; background: #000; }
.ods-strip--ratio { aspect-ratio: var(--ods-ratio, 16 / 9); }
/* Extra breathing room above a ratio-mode strip (e.g. Sound + Motion), on top of the tiles grid's own bottom padding. Height-mode strips (Home's background video) aren't affected, since they don't carry this class. */
.ods-strip--ratio { margin-top: clamp(1rem, 2.5vw, 3rem); }
@media (max-width: 700px) { .ods-strip--ratio { aspect-ratio: var(--ods-ratio-m, 16 / 9); } }
.ods-strip video {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center;
	pointer-events: none;
}
.ods-strip video::-webkit-media-controls,
.ods-strip video::-webkit-media-controls-panel,
.ods-strip video::-webkit-media-controls-start-playback-button { display: none !important; -webkit-appearance: none; }
@media (prefers-reduced-motion: reduce) { .ods-strip video { display: none; } }

/* Optional badge (e.g. a QR code) centered over the bottom of a strip. */
.ods-strip__badge {
	position: absolute;
	left: 50%;
	bottom: 2%;
	transform: translateX(-50%);
	width: auto;
	max-width: 90%;
	pointer-events: none;
}

/* Galleries: dynamic masonry. Column count grows with window width so images run smaller on wide screens; one column on mobile. Built with CSS multi-column layout (no JS) so each column packs top to bottom at its own pace instead of a fixed grid. */
.wp-block-gallery.ods-gallery {
	/* One gap value for both directions — narrower than --ods-gap, which this gallery used to use for its column spacing. */
	--ods-gallery-gap: clamp(0.4rem, 1vw, 1rem);
	display: block;
	column-count: 1;
	column-gap: var(--ods-gallery-gap);
	padding: clamp(1rem, 3vw, 3.5rem) var(--ods-side);
}
.wp-block-gallery.ods-gallery > figure.wp-block-image {
	width: 100% !important;
	/* Equal space above and below every image, matching the column-gap above so the grid reads even in both directions.
	   !important: WP core resets gallery figure margins to 0 via `.wp-block-gallery.has-nested-images figure.wp-block-image:not(#individual-image)`,
	   whose :not(#id) argument counts as ID-level specificity — higher than any class selector, so it beats this rule on specificity alone regardless of source order. */
	margin: var(--ods-gallery-gap) 0 !important;
	break-inside: avoid;
}
.wp-block-gallery.ods-gallery > figure.wp-block-image:first-child { margin-top: 0 !important; }
.wp-block-gallery.ods-gallery > figure.wp-block-image:last-child { margin-bottom: 0 !important; }
.wp-block-gallery.ods-gallery img { display: block; width: 100%; height: auto; }
/* Lightbox is disabled below 560px (see gallery-lightbox.js) — one full-width image per row already shows the image at its largest, so no click affordance here. */
@media (min-width: 560px) {
	.wp-block-gallery.ods-gallery { column-count: 2; }
	.wp-block-gallery.ods-gallery img { cursor: zoom-in; }
}
@media (min-width: 900px) { .wp-block-gallery.ods-gallery { column-count: 3; } }
@media (min-width: 1300px) { .wp-block-gallery.ods-gallery { column-count: 4; } }
@media (min-width: 1700px) { .wp-block-gallery.ods-gallery { column-count: 5; } }

/* Prev/Next gallery links, auto-appended after any leaf gallery page's content (see functions.php).
   Prev sits bottom-left (wraps to the last gallery in the list from the first one), Next sits
   bottom-right (wraps to the first from the last) — just the sibling page's title with a
   leading/trailing arrow, no label text, plain and unornamented like the site's other links. */
.ods-gallery-nav {
	display: flex;
	justify-content: space-between;
	align-items: flex-end;
	gap: 1.5rem;
	padding: clamp(2rem, 5vw, 4rem) var(--ods-side) clamp(3rem, 6vw, 5rem);
}
.ods-gallery-nav__link {
	max-width: 45%;
	color: #fff;
	text-decoration: none;
	font-size: clamp(1.2rem, 2vw, 2.2rem);
	font-weight: 300;
	border-bottom: 1px solid transparent;
}
.ods-gallery-nav__link--prev { text-align: left; }
.ods-gallery-nav__link--next { text-align: right; }
.ods-gallery-nav__link:hover,
.ods-gallery-nav__link:focus-visible { border-bottom-color: #fff; }
/* A section with only two galleries (e.g. Nature) has one other page to link to either way; that
   case renders an empty span in the prev slot instead of a link (see functions.php) so this same
   flex layout keeps the link pinned to the right rather than needing a separate rule here. */

/* Lightbox: click an image to open it full-screen, click or Escape to close. No hover icon or button on the gallery grid — the cursor change there is the only affordance. Inside the open lightbox, the two arrow buttons below are the only added UI. */
.ods-lightbox {
	position: fixed;
	inset: 0;
	z-index: 1000;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: clamp(0.5rem, 2vw, 2rem);
	background: rgba(0, 0, 0, 0.94);
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.25s ease;
}
.ods-lightbox.is-open { opacity: 1; visibility: visible; }
.ods-lightbox img {
	display: block;
	/* Capped at 92vw/88vh but never forced up to it: most of the library's source photos are
	   web-export sized (~1280px wide, well under lightbox display size), so stretching every
	   image up to fill a fixed box made the smaller ones visibly soft. width/height:auto lets
	   each image show at its own resolution — large sources still fill most of the screen,
	   smaller ones display true to their native pixels (sharp) rather than blown up. */
	width: auto;
	height: auto;
	max-width: 92vw;
	max-height: 88vh;
	object-fit: contain;
	cursor: zoom-out;
}
/* Prev/next arrows: plain glyphs, no button chrome, sitting over the dark overlay on either side of the image. */
.ods-lightbox__nav {
	position: absolute;
	top: 0;
	bottom: 0;
	display: flex;
	align-items: center;
	padding: 0 clamp(0.75rem, 3vw, 3rem);
	margin: 0;
	border: 0;
	background: none;
	color: rgba(255, 255, 255, 0.55);
	font-size: clamp(2rem, 4vw, 3.5rem);
	line-height: 1;
	cursor: pointer;
	-webkit-tap-highlight-color: transparent;
	transition: color 0.2s ease;
}
.ods-lightbox__nav:hover,
.ods-lightbox__nav:focus-visible { color: #fff; }
.ods-lightbox__nav--prev { left: 0; }
.ods-lightbox__nav--next { right: 0; }
/* Close (×): top right of the screen, clear of the image itself, as the explicit way to exit. */
.ods-lightbox__close {
	position: absolute;
	top: clamp(0.5rem, 2vw, 1.5rem);
	right: clamp(0.5rem, 2vw, 1.5rem);
	margin: 0;
	padding: 0.2em 0.35em;
	border: 0;
	background: none;
	color: rgba(255, 255, 255, 0.55);
	font-size: clamp(1.75rem, 3vw, 2.5rem);
	line-height: 1;
	cursor: pointer;
	-webkit-tap-highlight-color: transparent;
	transition: color 0.2s ease;
}
.ods-lightbox__close:hover,
.ods-lightbox__close:focus-visible { color: #fff; }
@media (max-width: 700px) {
	.ods-lightbox__nav { font-size: 2rem; padding: 0 0.75rem; }
}
@media (prefers-reduced-motion: reduce) { .ods-lightbox { transition: none; } }

/* Footer -------------------------------------------------------------------- */
.ods-footer {
	padding: clamp(2rem, 5vw, 5.5rem) var(--ods-side) clamp(2rem, 6vw, 6rem);
	text-align: center;
}
.ods-footer__text {
	margin: 0;
	font-family: var(--wp--preset--font-family--source-code-pro);
	font-weight: 400;
	font-size: clamp(0.8rem, 0.9vw, 1rem);
	color: #fff;
}
