/*
Theme Name: Hawk Line Holding
Theme URI: https://pluginslab.com/pl-hawkline-holding
Author: Pluginslab
Author URI: https://pluginslab.com
Description: Minimal block-based holding theme for the Hawk Line group (parent / Resellers / ITAD). One shared token system; per-brand identity (accent, logo, label, enquiries address) via style variations. Phase 1 placeholder presence; the foundation Phase 2 builds on. Ships a full template set (front-page holding screen plus index/page/single/search/archive/404) so simple content can be published whenever the client is ready.
Version: 0.7.2
Requires at least: 6.7
Requires PHP: 8.2
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: pl-hawkline-holding
Tags: full-site-editing, block-styles, custom-colors, custom-typography, one-column
*/

/* ============================================================
   Colour contract
   ------------------------------------------------------------
   The brand accent is a DECORATIVE token only. Against the
   purple-500 surface it measures 4.41:1 (parent teal), 3.07:1
   (Resellers yellow) and 1.45:1 (ITAD magenta) — all below the
   4.5:1 WCAG AA threshold for text, and magenta is below the
   3:1 non-text threshold too.

   So: accent may fill shapes and back solid buttons, but it must
   never colour text, borders or focus rings. Those use white,
   purple-100 (4.78:1) or teal-400, all of which hold up on every
   brand variation.
   ============================================================ */

/* ============================================================
   Holding screen
   The logo image is injected by functions.php via
   get_theme_file_uri() so the URL survives subdirectory installs
   and theme-folder renames; the active style variation supplies
   the filename through settings.custom.brand.logo.
   ============================================================ */

.hl-holding {
	min-height: 100vh;
	min-height: 100svh;
	text-align: center;
}

/* Brand logo — background image so style variations can swap it.
   A visually-hidden <h1> carries the brand name for a11y + SEO,
   and takes over entirely in forced-colors mode (see below). */
.hl-logo {
	width: min(86vw, 340px);
	height: 92px;
	margin-inline: auto;
	background-repeat: no-repeat;
	background-position: center;
	background-size: contain;
}

.hl-eyebrow {
	margin: 0;
	text-transform: uppercase;
	letter-spacing: 0.18em;
	font-weight: 600;
	color: var(--wp--preset--color--white);
}

/* The accent lives here — a decorative rule, not text. */
.hl-eyebrow::before {
	content: "";
	display: block;
	width: 40px;
	height: 3px;
	margin: 0 auto var(--wp--preset--spacing--20, 20px);
	border-radius: var(--wp--custom--border-radius--pill, 9999px);
	background: var(--wp--custom--brand--accent, #00ffd5);
}

.hl-tagline {
	max-width: 34ch;
	margin-inline: auto;
	color: var(--wp--preset--color--purple-100);
}

.hl-contact a {
	text-underline-offset: 0.2em;
}

/* Shared contact line (patterns/contact-line.php) — sized per context. */
.hl-holding .hl-contact {
	margin-top: var(--wp--preset--spacing--16);
	font-size: var(--wp--preset--font-size--md);
}

.hl-footer .hl-contact {
	font-size: var(--wp--preset--font-size--sm);
}

.hl-copyright {
	margin-bottom: 0;
	color: var(--wp--preset--color--purple-100);
}

/* Visually hidden but available to screen readers + crawlers. */
.hl-visually-hidden {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* Accessibility — focus rings on the dark purple surface.
   Deliberately teal-400 rather than the brand accent: this is the one
   token that passes the 3:1 non-text threshold on all three brands. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
	outline: 2px solid var(--wp--preset--color--teal-400);
	outline-offset: 3px;
}

/* Background images are dropped in forced-colors mode, so the logo would
   vanish with nothing in its place. Swap in the visually-hidden brand name. */
@media (forced-colors: active) {
	.hl-logo {
		display: none;
	}

	.hl-visually-hidden {
		position: static !important;
		width: auto;
		height: auto;
		margin: 0;
		overflow: visible;
		clip: auto;
		clip-path: none;
		white-space: normal;
	}
}

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/* ============================================================
   Content chrome — header, footer, and simple content pages.
   Shares the purple brand surface; lets the client publish
   real pages/posts on top of the Phase 1 foundation.
   ============================================================ */

/* The popover's inner container carries a hardcoded `1px solid #ddd` from the
   plugin. The block's border support styles the outer element, so no attribute
   reaches this wrapper — hence one rule rather than a block setting. */
.hl-menu-popover .pl-popover-container {
	border: 0;
}

/* tel: and mailto: links in the footer are not underlined in the design. There is no
   block control for an inline link's decoration, and elements.link typography is not
   applied to static blocks, so this is the only route. */
.hl-footer__contact a {
	text-decoration: none;
}

.hl-footer__contact a:hover,
.hl-footer__contact a:focus-visible {
	text-decoration: underline;
}

/* Footer links carry a trailing arrow — the designer's own 20×10 vector, exported and
   inlined as a mask rather than a background image, so `currentColor` fills it and the
   arrow follows the link colour instead of being frozen white. core/navigation-link has
   no icon attribute, hence generated content. Source: assets/icons/arrow-right.svg */
.hl-footer__nav a::after {
	content: "";
	display: inline-block;
	width: 20px;
	height: 10px;
	margin-left: var(--wp--preset--spacing--12, 12px);
	flex-shrink: 0;
	background-color: currentColor;
	-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 10'%3E%3Cpath d='M15.0125 3.75H0V6.25H15.0125V10L20 5L15.0125 0V3.75Z'/%3E%3C/svg%3E") no-repeat center / contain;
	mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 10'%3E%3Cpath d='M15.0125 3.75H0V6.25H15.0125V10L20 5L15.0125 0V3.75Z'/%3E%3C/svg%3E") no-repeat center / contain;
}

/* The two contact CTAs carry a leading glyph. core/button has no icon attribute and its
   label is RichText, which strips an inline <img> on save, so the icon is generated
   content. Masked rather than a background image so `currentColor` fills it and the glyph
   follows the button label on every brand. Sources: assets/icons/phone.svg, mail.svg */
.hl-btn-icon .wp-block-button__link {
	display: inline-flex;
	align-items: center;
	gap: var(--wp--preset--spacing--8, 8px);
}

.hl-btn-icon .wp-block-button__link::before {
	content: "";
	flex-shrink: 0;
	width: 20px;
	height: 20px;
	background-color: currentColor;
	-webkit-mask: var(--hl-btn-icon) no-repeat center / contain;
	mask: var(--hl-btn-icon) no-repeat center / contain;
}

.hl-btn-icon--phone {
	--hl-btn-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M4.02222 8.65556C5.62222 11.8 8.2 14.3667 11.3444 15.9778L13.7889 13.5333C14.0889 13.2333 14.5333 13.1333 14.9222 13.2667C16.1667 13.6778 17.5111 13.9 18.8889 13.9C19.5 13.9 20 14.4 20 15.0111V18.8889C20 19.5 19.5 20 18.8889 20C8.45555 20 0 11.5444 0 1.11111C0 0.5 0.5 0 1.11111 0H5C5.61111 0 6.11111 0.5 6.11111 1.11111C6.11111 2.5 6.33333 3.83333 6.74444 5.07778C6.86667 5.46667 6.77778 5.9 6.46667 6.21111L4.02222 8.65556Z'/%3E%3C/svg%3E");
}

.hl-btn-icon--mail {
	--hl-btn-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 16'%3E%3Cpath d='M18 0H2C0.9 0 0.00999999 0.9 0.00999999 2L0 14C0 15.1 0.9 16 2 16H18C19.1 16 20 15.1 20 14V2C20 0.9 19.1 0 18 0ZM18 4L10 9L2 4V2L10 7L18 2V4Z'/%3E%3C/svg%3E");
}

.hl-btn-icon--mail .wp-block-button__link::before {
	height: 16px;
}

/* core/cover sets position:relative, which puts it in the positioned paint layer —
   above any later sibling that is not itself positioned. The portrait row overlaps
   the cover, so without this it renders behind and its top half is clipped. There is
   no block attribute for position or z-index; this is the only route. */
.hl-story__portraits {
	position: relative;
	z-index: 1;
}

/* Portrait row on mobile. The row carries is-not-stacked-on-mobile so it holds one
   line on desktop, and core enforces that with `flex-wrap:nowrap !important` — which is
   why a plain override does nothing here. core/columns offers stack-to-one or hold-the-
   line and nothing between, so three-per-row has to be forced, !important included. */
@media (max-width: 905px) {
	.hl-story__portraits .wp-block-columns {
		flex-wrap: wrap !important;
		justify-content: center;
	}

	.hl-story__portraits .wp-block-column {
		flex: 0 0 calc(33.333% - var(--wp--preset--spacing--20, 20px)) !important;
	}

	/* The row overlaps the panel below it by a fixed -76px, which is measured for a single
	   line of portraits. Once they wrap onto two rows that pull-up lands on the copy, so
	   the overlap is dropped for the wrapped layout. The block sets its margin inline,
	   hence !important. */
	.hl-story__portraits {
		margin-bottom: var(--wp--preset--spacing--32, 32px) !important;
	}
}

/* Cards that are inset on desktop but full-bleed on a phone. The design puts the story
   card inside the 1280 band at 1440, and edge to edge on the 400px artboard — an
   alignment that changes with viewport, which no block attribute expresses. Cancelling
   the gutter with a negative margin is the edge case; the token keeps it exact, so the
   card lands on the screen edge rather than near it. */
@media (max-width: 905px) {
	.hl-bleed-mobile {
		/* core centres aligned children of a constrained layout with
		   `margin-left/right: auto !important`, so this has to match it. */
		margin-left: calc(var(--wp--custom--gutter) * -1) !important;
		margin-right: calc(var(--wp--custom--gutter) * -1) !important;
		max-width: none;
	}
}

/* Buttons that go full width on a phone. core/button has a width attribute, but it is
   a fixed 25/50/75/100 that applies at every viewport — there is no mobile-only option —
   so the class is the only way to keep the button hugging its label on desktop. Width is
   100% of the container, so it still respects whatever padding the section sets. */
@media (max-width: 905px) {
	.hl-btn-mobile-full,
	.hl-btn-mobile-full .wp-block-button__link {
		width: 100%;
	}
}

/* Facility map on mobile. The map keeps its 1440/459 ratio, which at 390px wide leaves
   it about 124px tall — too shallow to read as a location. core/image has no minHeight
   attribute (only a fixed height, which would apply at every viewport), so the floor is
   here; object-fit crops rather than stretches. */
@media (max-width: 905px) {
	.hl-visit__map img,
	.hl-divisions__map img {
		min-height: 450px;
		object-fit: cover;
	}
}

/* ── Story timeline ───────────────────────────────────────────────────────
   A rail with a hollow marker at each milestone. Nothing in the block API draws a
   line between siblings, so both are pseudo-elements.

   The geometry is three custom properties rather than three sets of hardcoded
   offsets: the marker is centred on the rail by calculation, so the two cannot
   drift apart when the indent changes.

   The line is drawn per entry, not once down the container — that way the last
   entry simply omits it and the rail ends at Today instead of running past it. */
.hl-timeline__rail {
	--hl-rail-x: 145px;
	--hl-rail-w: 3px;
	--hl-marker: 50px;
	--hl-rail-indent: 260px;

	position: relative;
	padding-left: var(--hl-rail-indent);
}

.hl-timeline__entry {
	position: relative;
}

/* Marker: centred on the rail, filled with the page surface so the line stops at it. */
.hl-timeline__entry::before {
	content: "";
	position: absolute;
	z-index: 1;
	top: 0;
	left: calc(var(--hl-rail-x) + (var(--hl-rail-w) / 2) - (var(--hl-marker) / 2) - var(--hl-rail-indent));
	width: var(--hl-marker);
	height: var(--hl-marker);
	border: 3px solid var(--wp--preset--color--white, #FFFFFF);
	border-radius: var(--wp--custom--border-radius--pill, 9999px);
	background: var(--wp--preset--color--purple-500, #7841E5);
	box-sizing: border-box;
}

/* Line: from this marker to the next one, so it spans the entry plus the gap below. */
.hl-timeline__entry::after {
	content: "";
	position: absolute;
	top: 0;
	left: calc(var(--hl-rail-x) - var(--hl-rail-indent));
	width: var(--hl-rail-w);
	height: calc(100% + var(--wp--preset--spacing--48, 48px));
	background: var(--wp--preset--color--white, #FFFFFF);
}

.hl-timeline__entry:last-child::after {
	display: none;
}

/* The rail costs 260px of indent, which a phone does not have. */
@media (max-width: 905px) {
	.hl-timeline__rail {
		--hl-rail-x: 11px;
		--hl-marker: 24px;
		--hl-rail-indent: var(--wp--preset--spacing--40, 40px);
	}

	.hl-timeline__entry::before {
		top: 4px;
	}
}

/* ── Mailing list signup ──────────────────────────────────────────────────
   Straight HTML for now: there is no signup block, and the contact block from
   0.4.0 routes enquiries rather than collecting list opt-ins. The markup carries
   real labels and a fieldset so it is usable before it is wired to anything. */
.hl-signup__row {
	display: flex;
	gap: var(--wp--preset--spacing--12, 12px);
}

.hl-signup__row > * {
	flex: 1 1 0;
	min-width: 0;
}

.hl-signup label {
	display: block;
	margin-bottom: var(--wp--preset--spacing--4, 4px);
	font-size: var(--wp--preset--font-size--ui, 18px);
	font-weight: 600;
	color: var(--wp--preset--color--black, #000000);
}

.hl-signup input[type="text"],
.hl-signup input[type="email"] {
	/* border-box or the padding is added to 100%, which overflows the panel and, through
	   it, the page — every full-width section then sits shifted by the difference. */
	box-sizing: border-box;
	width: 100%;
	padding: var(--wp--preset--spacing--12, 12px);
	font-family: inherit;
	font-size: var(--wp--preset--font-size--md, 16px);
	color: var(--wp--preset--color--black, #000000);
	background: var(--wp--preset--color--white, #FFFFFF);
	border: 1px solid var(--wp--preset--color--gray-300, #CCCCD4);
	border-radius: var(--wp--custom--border-radius--md, 8px);
}

.hl-signup fieldset {
	margin: 0;
	padding: 0;
	border: 0;
}

.hl-signup legend {
	padding: 0;
	margin-bottom: var(--wp--preset--spacing--12, 12px);
	font-size: var(--wp--preset--font-size--ui, 18px);
	color: var(--wp--preset--color--black, #000000);
}

.hl-signup__interests {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: var(--wp--preset--spacing--12, 12px);
}

.hl-signup__interests label {
	display: flex;
	align-items: center;
	gap: var(--wp--preset--spacing--8, 8px);
	margin: 0;
}

.hl-signup__submit {
	display: inline-block;
	padding: var(--wp--preset--spacing--12, 12px) var(--wp--preset--spacing--24, 24px);
	font-family: inherit;
	font-size: var(--wp--preset--font-size--ui, 18px);
	font-weight: 500;
	line-height: 1;
	color: var(--wp--custom--brand--accent, #FFAE00);
	background: var(--wp--preset--color--purple-950, #0B0430);
	border: 0;
	border-radius: var(--wp--custom--border-radius--pill, 9999px);
	cursor: pointer;
}

@media (max-width: 905px) {
	.hl-signup__row,
	.hl-signup__interests {
		grid-template-columns: 1fr;
		flex-direction: column;
	}
}

/* ── Site header ──────────────────────────────────────────────────────────
   Structure, spacing and the mobile menu are block attributes in
   parts/header.html — nav is core/navigation, the hamburger is
   pl/mobile-menu-toggle + pl/popover, and desktop/mobile swap via the
   visibility extension's pl-*-hide classes. Nothing here duplicates that.

   What remains is the one thing blocks cannot express: the CTA's fill and
   label are per-brand tokens resolved by the active style variation, so a
   preset colour would need a different button per install. */


/* Brand accent text — eyebrows and section headings. Per-brand like the CTA styles,
   and for the same reason: the design tints these with the brand on every site. It uses
   brand.on-surface, not brand.accent, because the accent is a fill-only token; as text
   on purple it is 4.41:1 teal, 3.07:1 yellow and 1.45:1 magenta. on-surface holds the
   value each brand can legibly use instead. */
/* :root prefix so this outranks `.hl-main :where(p, li)`, which sets body copy to
   purple-100 at the same specificity and later in the file. */
:root .is-style-hl-accent-text {
	color: var(--wp--custom--brand--on-surface, var(--wp--preset--color--teal-300, #66FFE4));
}

.wp-block-button.is-style-hl-cta .wp-block-button__link {
	color: var(--wp--custom--brand--on-accent, var(--wp--preset--color--purple-600, #6433C9));
	background-color: var(--wp--custom--brand--accent, #00FFD5);
	border-radius: var(--wp--custom--border-radius--pill, 9999px);
	padding: var(--wp--preset--spacing--12, 12px) var(--wp--preset--spacing--24, 24px);
	font-weight: 500;
	line-height: 1;
}

.wp-block-button.is-style-hl-cta-dark .wp-block-button__link {
	color: var(--wp--custom--brand--accent, #00FFD5);
	background-color: var(--wp--preset--color--purple-950, #0B0430);
	border-radius: var(--wp--custom--border-radius--pill, 9999px);
	padding: var(--wp--preset--spacing--12, 12px) var(--wp--preset--spacing--24, 24px);
	font-weight: 500;
	line-height: 1;
}

.wp-block-button.is-style-hl-cta-dark .wp-block-button__link:hover {
	filter: brightness(1.15);
}

.wp-block-button.is-style-hl-cta .wp-block-button__link:hover {
	filter: brightness(1.08);
}

/* Content column — readable measure on the brand surface. */
.hl-main {
	min-height: 60vh;
}

.hl-main :where(p, li) {
	color: var(--wp--preset--color--purple-100);
}

.hl-main a {
	color: var(--wp--preset--color--white);
	text-underline-offset: 0.2em;
}

.hl-main a:hover {
	color: var(--wp--preset--color--purple-100);
	text-decoration-thickness: 2px;
}

.hl-meta {
	color: var(--wp--preset--color--purple-100);
}

/* Search field — legible on the dark surface. */
.hl-search .wp-block-search__input {
	color: var(--wp--preset--color--gray-900);
	background: var(--wp--preset--color--white);
	border: 0;
}

/* Accent as a solid fill is fine; the label is black so it clears 4.5:1
   on all three accents (5.35:1 on ITAD magenta, the tightest of them). */
.hl-search .wp-block-search__button {
	background: var(--wp--custom--brand--accent, #00ffd5);
	color: var(--wp--preset--color--black);
	border: 0;
	font-weight: 700;
}



/* ── Design review fixes, Rob 2026-08-18 ──────────────────────────────────
   Three items from his pass over the built sites. The other five in his list
   need values from him or from Gal and are not guessed at here. */

/* The divisions band has square bottom corners precisely because the map sits
   flush beneath it. On the Resellers pages the map is a *sibling* of the
   block, so the wrapper's bottom margin opens a gap the design does not have.
   On the parent the map lives *inside* the block, so its bottom margin falls
   below the map and must stay: hence the sibling test rather than a blanket
   reset. */
.hl-divisions:has(+ .hl-visit__map) {
	/* !important because WordPress emits this margin as an inline style on the
	   block itself, which a stylesheet rule cannot otherwise reach. */
	margin-bottom: 0 !important;
}

/* The timeline markers read as solid dots. They were painted flat purple so
   the rail would appear to stop at them, but the page surface became a
   gradient, so that fill no longer matches its background anywhere down the
   page. Hollow the marker out and start the rail below it instead of behind
   it, which gets the same "line stops here" result honestly. */
.hl-timeline__entry::before {
	background: transparent;
}

.hl-timeline__entry::after {
	top: var(--hl-marker);
	height: calc(100% + var(--wp--preset--spacing--48, 48px) - var(--hl-marker));
}

/* The circle portraits are tall crops (around 320x479) squared off with
   object-fit: cover, so a centred crop lands on the torso and the heads sit at
   different heights. Bias the crop upward. */
.hl-story__circle img {
	object-position: 50% 28%;
}
