/*
Theme Name: F.A.B Garden Buildings
Theme URI: http://localhost:8092
Author: Miles Clark
Description: Block theme for F.A.B Garden Buildings of Chesterfield, Derbyshire. Timber garden rooms, offices, bars, sheds, workshops and carpentry. A warm paper, cedar and forest-green layout built around square photo tiles.
Version: 1.0.0
Requires at least: 6.5
Tested up to: 6.8
Requires PHP: 8.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: fab-garden-buildings
Tags: full-site-editing, business, one-column, block-patterns
*/

/* Most styling lives in theme.json. Only what the editor cannot express belongs here. */

/* ===========================================================================
   A NOTE ON IMAGE SIZES - read this before changing any layout below.

   Every photograph supplied by the business is 206x206px (they came off a
   Facebook post, not a camera roll). That is the single biggest constraint on
   this design, and the layout is built around it rather than fighting it:

     - No full-bleed photo heroes and no core/cover with a photo background.
       A 206px image stretched across 1240px is a blurred mess. The dark bands
       on this site are solid forest green with type on them instead.
     - Photos are only ever shown in SQUARE tiles at or near their native size
       (see .fgb-gallery-grid below: ~190px columns, so pixels map about 1:1).
       Square also happens to be the one shape every single photo already is.
     - Service cards run horizontally - a small square thumbnail beside the
       text - rather than as a wide image with text beneath it, again to keep
       the photo near its native width.

   If the business ever supplies the original full-size photographs, the
   sensible changes are: raise --fgb-tile-min, and swap the hero and the
   mid-page bands for core/cover blocks. Nothing else here needs to move.
   =========================================================================== */

:root {
	/* Gallery tile floor. Kept close to the 206px source width on purpose. */
	--fgb-tile-min: 190px;
}

body {
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

/* ---------------------------------------------------------- page shell --- */

/* Let <main> start flush against the header.

   WordPress generates this from the blockGap in theme.json:

       :where(.wp-site-blocks) > * { margin-block-start: 1.75rem; margin-block-end: 0; }

   which puts 28px between every top-level block - header, main, footer. On a
   page whose first section is a dark band (the forest hero on the home page,
   or the dark band on Carpentry) that 28px shows up as a strip of paper
   background wedged between the sticky header and the top of the band, which
   reads as a rendering fault rather than as spacing.

   Zeroing it here rather than dropping blockGap in theme.json, because
   blockGap is doing real work everywhere else - it is the vertical rhythm
   between every stacked block on the site. This only detaches <main> from it.

   Safe because every page template supplies its own top spacing: the content
   pages open with a group carrying its own padding-top, and the archive and
   single templates set an inline margin-top on <main> itself, which is an
   inline style and so still wins over this rule.

   The matching gap above <footer> is deliberately left alone: the content
   above it sits on the paper background anyway, so there is no seam there -
   just 28px of breathing room before the dark footer, which is wanted. */
.wp-site-blocks > main {
	margin-block-start: 0;
}

/* --------------------------------------------------------------- header --- */

/* The header follows you down the page: on a site whose job is to get someone
   to ask for a quote, the quote button should never be more than a glance away. */
.fgb-header {
	position: sticky;
	top: 0;
	z-index: 20;
}

/* The frosted-glass backdrop lives on a pseudo-element, not on .fgb-header
   itself, because backdrop-filter (like transform/filter/perspective) makes an
   element a new "containing block" for any descendant with position:fixed. The
   mobile nav's full-screen menu is exactly that - core's own
   .wp-block-navigation__responsive-container uses position:fixed to cover the
   viewport - and it sits inside .fgb-header. With the filter on .fgb-header
   directly, that menu gets pinned to the header's own short box instead of the
   screen: you tap the hamburger and get a stubby bar with two links in it. */
.fgb-header::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	backdrop-filter: saturate(180%) blur(12px);
	-webkit-backdrop-filter: saturate(180%) blur(12px);
	background-color: rgba(250, 248, 243, 0.9);
}

.fgb-site-title a,
.wp-block-navigation .wp-block-navigation-item__content {
	text-decoration: none;
}

/* The logo mark and the spelled-out business name trade places. The full row -
   logo, name, seven nav links and the quote button - needs about 1300px once
   the root side padding is counted; any narrower and the flex row wraps the nav
   onto a second line under a lonely name. So below 1320px the name goes and
   the mark carries the brand on its own. */
.fgb-site-title {
	white-space: nowrap;
}

@media (max-width: 1320px) {
	.fgb-site-title {
		display: none;
	}
}

/* Core's own breakpoint for collapsing the nav into the hamburger is a
   hardcoded 600px (wp-includes/blocks/navigation/style.css). Pin it to 1080px
   instead: logo, seven links and the quote button need roughly 1040px in a
   single row, and below that the links wrap across two or three lines. */
@media (max-width: 1080px) {
	.fgb-header .wp-block-navigation__responsive-container:not(.is-menu-open) {
		display: none !important;
	}

	.fgb-header .wp-block-navigation__responsive-container-open {
		display: flex !important;
	}
}

.fgb-site-icon-img {
	display: block;
}

/* Nav links grow an underline from the middle rather than blinking one on. */
.wp-block-navigation .wp-block-navigation-item__content {
	position: relative;
	padding-bottom: 2px;
}

.wp-block-navigation .wp-block-navigation-item__content::after {
	content: "";
	position: absolute;
	left: 50%;
	right: 50%;
	bottom: 0;
	height: 1px;
	background: var(--wp--preset--color--cedar);
	transition: left 0.22s ease, right 0.22s ease;
}

.wp-block-navigation .wp-block-navigation-item__content:hover::after,
.wp-block-navigation .current-menu-item > .wp-block-navigation-item__content::after {
	left: 0;
	right: 0;
}

/* The overlay menu inherits the dark canvas, where that hairline reads as a
   stray mark rather than an underline. */
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content::after {
	display: none;
}

/* --------------------------------------------------------------- eyebrow --- */

/* Small-caps label that sits above a heading. Used throughout the content. */
.fgb-eyebrow {
	text-transform: uppercase;
	letter-spacing: 0.16em;
	font-weight: 600;
	margin-bottom: 0.6rem !important;
}

/* --------------------------------------------------------------- buttons --- */

.wp-block-button.is-style-outline > .wp-block-button__link {
	border-width: 1px;
	border-color: var(--wp--preset--color--forest);
	color: var(--wp--preset--color--forest);
	background-color: transparent;
}

.wp-block-button.is-style-outline > .wp-block-button__link:hover,
.wp-block-button.is-style-outline > .wp-block-button__link:focus {
	background-color: var(--wp--preset--color--forest);
	border-color: var(--wp--preset--color--forest);
	color: var(--wp--preset--color--chalk);
}

/* On the dark bands the outline has to invert. */
.has-forest-background-color .wp-block-button.is-style-outline > .wp-block-button__link {
	border-color: var(--wp--preset--color--chalk);
	color: var(--wp--preset--color--chalk);
}

.has-forest-background-color .wp-block-button.is-style-outline > .wp-block-button__link:hover,
.has-forest-background-color .wp-block-button.is-style-outline > .wp-block-button__link:focus {
	background-color: var(--wp--preset--color--chalk);
	color: var(--wp--preset--color--forest);
}

.wp-element-button,
.wp-block-button__link {
	transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}

/* A visible focus ring everywhere, since the buttons are pill-shaped and the
   browser default outline can sit awkwardly against the radius. */
a:focus-visible,
button:focus-visible,
.wp-block-button__link:focus-visible {
	outline: 2px solid var(--wp--preset--color--cedar);
	outline-offset: 3px;
}

/* ----------------------------------------------------------------- cards --- */

.fgb-card {
	background: var(--wp--preset--color--chalk);
	border: 1px solid var(--wp--preset--color--sand);
	border-radius: 6px;
	padding: var(--wp--preset--spacing--40);
	height: 100%;
	transition: transform 0.25s ease, box-shadow 0.25s ease;
}

.fgb-card:hover {
	transform: translateY(-3px);
	box-shadow: 0 18px 40px -28px rgba(28, 48, 37, 0.55);
}

/* A card with a photo and text. The photo is capped at the 206px the source
   file actually contains rather than stretched to the card width, which is the
   whole point of this class (see the note at the top of this file).

   Photo ABOVE text, not beside it. Side-by-side was the first instinct - it
   keeps the photo nearest its native size - but these cards sit three across
   in a 1240px row, so each card is only ~280px wide. Taking 150px of that for
   the image left the copy in a ~110px ribbon, with headings breaking mid-phrase
   over three lines. Stacking gives the text the full card width and costs the
   image nothing, because 206px still fits comfortably inside 280px.

   A container query would let this flip back to a row in a genuinely wide card,
   but every place the class is used today is a narrow column, so the simpler
   rule is the honest one. */
.fgb-media-card {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--30);
	align-items: flex-start;
}

.fgb-media-card > .wp-block-image,
.fgb-media-card > figure {
	width: 100%;
	max-width: 206px;
	margin: 0;
}

.fgb-media-card img {
	aspect-ratio: 1;
	object-fit: cover;
	width: 100%;
	border-radius: 4px;
	display: block;
}

/* ------------------------------------------------------------ photo tiles --- */

/* The gallery. auto-fill with a ~190px floor means the browser fits as many
   near-native-size tiles per row as the container allows: six across on a wide
   desktop, two on a phone, and no tile ever blown up far past the 206px the
   source file actually contains. */
.fgb-gallery-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(var(--fgb-tile-min), 1fr));
	gap: 14px;
	margin: var(--wp--preset--spacing--40) 0;
}

.fgb-gallery-item {
	margin: 0;
	position: relative;
	overflow: hidden;
	border-radius: 5px;
	background: var(--wp--preset--color--oat);
	line-height: 0;
}

.fgb-gallery-item img {
	width: 100%;
	aspect-ratio: 1;
	object-fit: cover;
	display: block;
	transition: transform 0.5s ease;
}

.fgb-gallery-item:hover img {
	transform: scale(1.05);
}

/* The caption is the photo's media-library title, so the owner controls it by
   renaming the image - no page editing needed. */
.fgb-gallery-item figcaption {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	padding: 2.2rem 0.7rem 0.55rem;
	font-family: var(--wp--preset--font-family--body);
	font-size: 0.75rem;
	font-weight: 500;
	line-height: 1.35;
	color: #fff;
	background: linear-gradient(to top, rgba(20, 34, 26, 0.88), rgba(20, 34, 26, 0));
	opacity: 0;
	transition: opacity 0.25s ease;
}

.fgb-gallery-item:hover figcaption,
.fgb-gallery-item:focus-within figcaption {
	opacity: 1;
}

/* Touch screens have no hover, so there the caption is simply always on. */
@media (hover: none) {
	.fgb-gallery-item figcaption {
		opacity: 1;
	}
}

/* A single square photo dropped into page content. */
.fgb-tile img {
	aspect-ratio: 1;
	object-fit: cover;
	width: 100%;
	border-radius: 5px;
	display: block;
}

/* The hero's small contact-sheet strip of photographs. Deliberately capped at
   the source width so these stay sharp. */
.fgb-strip {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 10px;
	max-width: 420px;
}

.fgb-strip .wp-block-image {
	margin: 0;
}

.fgb-strip img {
	aspect-ratio: 1;
	object-fit: cover;
	width: 100%;
	border-radius: 4px;
	display: block;
}

/* A logo (unlike a photograph) has a deliberate relationship between its mark
   and the space around it, so it is never cropped to fill a box. */
.fgb-logo img {
	aspect-ratio: auto;
	object-fit: contain;
	height: auto;
	width: 100%;
	max-width: 206px;
	border-radius: 0;
}

/* ------------------------------------------------------------- typography --- */

/* A lead paragraph: larger, looser, deliberately short. */
.fgb-lead {
	line-height: 1.6;
	max-width: 36ch;
}

.fgb-measure {
	max-width: 62ch;
}

/* Section and page intros: a narrow column of text that keeps the same left
   edge as the full-width content below it. Constraining the wrapper instead
   would centre the text inside the wide container, which reads as a
   misalignment rather than a choice. The !important beats WordPress's own
   constrained-layout rule, which sets `margin-left: auto !important`. */
.fgb-intro > * {
	max-width: 46rem;
	margin-left: 0 !important;
	margin-right: 0 !important;
}

/* Centred intros are a separate, deliberate treatment - leave those alone. */
.fgb-intro > .has-text-align-center {
	max-width: none;
	margin-left: auto !important;
	margin-right: auto !important;
}

/* Tabular figures wherever a price, size or phone number appears. */
.fgb-nums {
	font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------- the hero --- */

.fgb-hero {
	background-color: var(--wp--preset--color--forest);
	/* A very faint woodgrain-ish texture made of CSS gradients, not an image:
	   it gives the flat green band some life at zero download cost, and unlike
	   a 206px photo it cannot pixelate however wide the screen gets. */
	background-image:
		repeating-linear-gradient(
			90deg,
			rgba(255, 255, 255, 0.022) 0 2px,
			rgba(255, 255, 255, 0) 2px 7px
		),
		radial-gradient(
			120% 90% at 78% 8%,
			rgba(217, 154, 98, 0.16) 0%,
			rgba(217, 154, 98, 0) 60%
		);
}

/* ---------------------------------------------------------------- panels --- */

/* The "what you get" strip under the hero. */
.fgb-hairline {
	border-top: 1px solid var(--wp--preset--color--sand);
}

/* FAQ headings sit tight to their answer. */
.fgb-faq h3 {
	margin-bottom: 0.4rem !important;
}

/* ---------------------------------------------------------------- footer --- */

/* The email address is one long unbreakable token and the footer columns are
   narrow. Without this it splits mid-word. */
.fgb-footer a {
	overflow-wrap: break-word;
	word-break: break-word;
}

/* Social icons: the social-links block sizes its icons in em off its own
   font-size, so this one rule covers both places it appears (the footer and
   the mobile nav overlay). Core's own default is 24px. */
.fgb-social {
	font-size: 42px;
}

/* The nav overlay's copy of the icons (see parts/header.html) is part of the
   same list as the page links, so it is always in the markup - but it should
   only show once that list has become the opened full-screen menu, never as an
   extra item in the plain inline row on desktop. */
.fgb-nav-social {
	display: none !important;
}

.wp-block-navigation__responsive-container.is-menu-open .fgb-nav-social {
	display: flex !important;
}

/* Instagram and X do not exist for this business yet. Their icons are here so
   the moment a profile is created it is a one-line URL change in two files
   (parts/header.html and parts/footer.html) - but until then they are dimmed
   and labelled "profile coming soon", so they read as not-yet rather than as
   broken links. Remove this class from both files along with the real URL. */
.fgb-social .fgb-social-soon {
	opacity: 0.4;
}

.fgb-social .fgb-social-soon:hover,
.fgb-social .fgb-social-soon:focus-within {
	opacity: 0.85;
}

/* ------------------------------------------------------------------ misc --- */

/* Core injects its own "Skip to content" link into block themes
   (the_block_template_skip_link() in wp-includes/block-template.php). It ships
   unstyled beyond screen-reader-text, so this is what makes it visible once a
   keyboard user actually focuses it. */
.skip-link:focus {
	position: absolute;
	top: 0.5rem;
	left: 0.5rem;
	z-index: 100;
	width: auto;
	height: auto;
	clip: auto;
	clip-path: none;
	background: var(--wp--preset--color--forest);
	color: var(--wp--preset--color--chalk);
	padding: 0.7rem 1.2rem;
	border-radius: 4px;
	text-decoration: none;
	font-size: 0.9rem;
}

/* Respect the reader who has asked the OS for less movement. */
@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		transition-duration: 0.01ms !important;
		animation-duration: 0.01ms !important;
	}

	.fgb-card:hover,
	.fgb-gallery-item:hover img {
		transform: none;
	}
}
