/*!
Theme Name: Blocksy Child
Theme URI: https://creativethemes.com/blocksy/
Description: Child theme of Blocksy. All site-specific design and content overrides live here. Do not edit the Blocksy parent.
Author: mysite
Template: blocksy
Version: 0.1.0
License: GNU General Public License v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: blocksy-child
*/

/*
 * Intentionally empty.
 *
 * The child theme inherits the Blocksy parent completely and changes nothing
 * visually until rules are added below. Blocksy's real styling comes from its
 * static bundles (ct-main-styles => /static/bundle/main.min.css) plus the
 * dynamic CSS it prints in wp_head from Customizer options, not from this file.
 *
 * Add child overrides under here. They load after ct-main-styles (see
 * functions.php), so a plain selector wins without !important.
 */

/* ======================================================================
 * Header & buttons: intentionally NOT restyled here.
 * The header (height, background, colours, sticky, the CTA button, toggles)
 * and site buttons are owned entirely by the Blocksy Customizer, so every
 * setting there takes effect. The child theme adds no header overrides.
 * ==================================================================== */

/* ==========================================================================
   Shared page canvas texture.
   The rounded-square grid the homepage uses behind its header and hero. Kept
   here as a token so any view can sit on the same canvas (the contact page
   does) without a second copy of the SVG drifting out of sync.
   ========================================================================== */
:root {
	--ld-grid-tile: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='76' height='76'%3E%3Crect x='1' y='1' width='70' height='70' rx='16' ry='16' fill='none' stroke='%23111518' stroke-width='1'/%3E%3C/svg%3E");
}

/* ==========================================================================
   Blocks given a background colour in the block editor.
   --------------------------------------------------------------------------
   WordPress paints the colour but does not make room inside it:

     - a list keeps `list-style-position: outside`, so its bullets are drawn in
       the left padding. With core's 1.25em that puts them about 6px from the
       edge of the coloured box, or visually outside it.
     - core's padding is lopsided (1.25em block, 2.375em inline), so a coloured
       list and a coloured paragraph never line up with each other.

   Both get the same padding scale here, and lists get an extra marker column on
   the inline start so bullets and numbers clear the edge. Markers stay
   `outside` on purpose: `inside` would make wrapped lines run back under the
   bullet instead of aligning with the text above.

   Applies to every editor-rendered content area (posts, pages and the legal
   pages), so a coloured block behaves the same wherever it is written. It lives
   in the global stylesheet rather than a per-view file for that reason.
   ========================================================================== */
.entry-content,
.ld-legal__content {
	--ld-fill-pad-y: clamp(1.15rem, 2.2vw, 1.5rem);
	--ld-fill-pad-x: clamp(1.25rem, 2.6vw, 1.75rem);
}

:is(.entry-content, .ld-legal__content) :is(ul, ol).has-background,
:is(.entry-content, .ld-legal__content) p.has-background {
	padding: var(--ld-fill-pad-y) var(--ld-fill-pad-x);
	margin-block: 1.6em;
}

:is(.entry-content, .ld-legal__content) :is(ul, ol).has-background {
	/* padding box + a marker column, so bullets and numbers clear the edge */
	padding-inline-start: calc(var(--ld-fill-pad-x) + 1.15em);
}

/* A nested list inside an already-filled list must not indent twice. */
:is(.entry-content, .ld-legal__content) :is(ul, ol).has-background :is(ul, ol) {
	padding-inline-start: 1.15em;
}

/* ==========================================================================
   Table of contents — ONE component, used by the legal pages and blog posts.
   --------------------------------------------------------------------------
   The design the legal pages introduced: a numbered list, quiet type, no card
   and no shadow. It lives here (global stylesheet) rather than in a per-view
   file so the two places cannot drift apart, in the same spirit as the single
   date / breadcrumb / footer rules in CLAUDE.md.

   Split of responsibilities:
     - this file owns the LOOK (title, numbering, links, active state)
     - each view owns the CONTAINER at its own breakpoint, because they differ:
       the legal sidebar appears at 960px, the post rail at 1180px. Each strips
       the mobile card down to the hairline rule (see legal.css / single.css).

   Default (narrow screens) is a self-contained boxed card, since there is no
   sidebar to sit in.
   ========================================================================== */
.ld-toc {
	--ldt-text: #35393d;
	--ldt-muted: #6f6a5e;
	--ldt-accent: var(--palette-color-1, #FE4A22);
	--ldt-hair: #e7e3dc;
	--ldt-surface: #F9F9FB;

	margin: 0 0 2.5rem;
	padding: 1.1rem 1.25rem;
	background: var(--ldt-surface);
	border: 1px solid var(--ldt-hair);
	border-radius: 14px;
}

.ld-toc__title {
	margin: 0 0 .7rem;
	font-size: .72rem;
	font-weight: 700;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--ldt-muted);
}

.ld-toc__list {
	margin: 0;
	padding: 0;
	list-style: none;
	counter-reset: ld-toc;
	display: grid;
	gap: .5rem;
}

.ld-toc__list li { counter-increment: ld-toc; }

.ld-toc__list a {
	display: block;
	font-size: .9rem;
	line-height: 1.35;
	color: var(--ldt-text);
	text-decoration: none;
	transition: color .15s ease;
}

.ld-toc__list a::before {
	content: counter(ld-toc) ".";
	margin-right: .4rem;
	color: var(--ldt-muted);
	font-variant-numeric: tabular-nums;   /* numbers keep a straight left edge */
	transition: color .15s ease;
}

.ld-toc__list a:hover { color: var(--ldt-accent); }

.ld-toc__list a:focus-visible {
	outline: 2px solid var(--ldt-accent);
	outline-offset: 3px;
	border-radius: 2px;
}

/* Reading position, set by single-post.js on posts. Colour plus weight, so it
   does not depend on colour alone. */
.ld-toc__list a.is-active,
.ld-toc__list a.is-active::before {
	color: var(--ldt-accent);
}
.ld-toc__list a.is-active { font-weight: 600; }

@media (prefers-reduced-motion: reduce) {
	.ld-toc__list a,
	.ld-toc__list a::before { transition: none; }
}

/* ==========================================================================
   LinoDash — site footer (dark halftone wordmark)
   --------------------------------------------------------------------------
   Markup: template-parts/site-footer.php, injected through Blocksy's
   `blocksy:builder:footer:custom-output` filter, so the <footer id="footer">
   wrapper is Blocksy's but everything inside it is ours. Blocksy's Customizer
   footer rows render nothing while that filter is active — style the footer
   HERE, not in the Customizer.

   Design: a black band — the brand's dark surface, same black as the header bar
   — carrying a fine dot texture, one row of links at the top, and an oversized
   LINODASH wordmark filled with the same halftone. The wordmark is shown in
   full: every letter complete, nothing cropped at any width. It is decorative
   (aria-hidden) — real text, so it stays crisp at any zoom and any pixel
   density, but it carries no meaning a screen reader needs.

   Tuning — the knobs below:
     --ldf-bg        footer canvas colour
     --ldf-dot       texture dot colour (whole footer) — keep it near-invisible,
                     it must not compete with the wordmark's own dot grid
     --ldf-mark-dot  wordmark dot colour — the only "loud" value here
     --ldf-mark-size wordmark size; in vw so it always spans the viewport
   ========================================================================== */
#footer {
	--ldf-bg: #000;
	--ldf-ink: #f2f4f6;
	--ldf-dot: rgba(255, 255, 255, .04);
	--ldf-mark-dot: rgba(255, 255, 255, .22);
	--ldf-mark-size: 18vw;
	--ldf-accent: var(--theme-palette-color-1, #FE4A22);

	position: relative;
	overflow: hidden;
	border-top: 1px solid rgba(255, 255, 255, .06);
	background-color: var(--ldf-bg);
	color: var(--ldf-ink);
	isolation: isolate;
}

/* Texture layer: fine dot grid across the whole footer + a soft light wash at
   the top edge, so the band reads as a lit surface rather than flat fill. */
#footer::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 0;
	pointer-events: none;
	background-image:
		radial-gradient(circle at center, var(--ldf-dot) 1px, transparent 1.15px),
		linear-gradient(to bottom, rgba(255, 255, 255, .05), transparent 22%);
	background-size: 6px 6px, 100% 100%;
}

.ld-footer { position: relative; }

/* ---- top row: copyright + nav ------------------------------------------ */
.ld-footer__inner {
	position: relative;
	z-index: 2;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: .85rem clamp(1.25rem, 3.2vw, 3.25rem);
	width: 100%;
	max-width: var(--theme-block-wide-max-width, 1140px);
	margin-inline: auto;
	padding: clamp(2rem, 4.5vw, 3.25rem) clamp(1.25rem, 5vw, 2rem) clamp(1.75rem, 3.5vw, 2.5rem);
}

/* Mono, muted — deliberately the quietest thing in the footer. Uses system
   monospace so the design costs no extra webfont request. */
.ld-footer__copy {
	margin: 0;
	font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
	font-size: .8125rem;
	letter-spacing: .01em;
	line-height: 1.4;
	color: color-mix(in srgb, var(--ldf-ink) 58%, transparent);
}

.ld-footer__nav {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: .6rem clamp(1rem, 2.6vw, 2.5rem);
}

.ld-footer__nav a {
	color: color-mix(in srgb, var(--ldf-ink) 92%, transparent);
	font-size: .95rem;
	line-height: 1.4;
	text-decoration: none;
	transition: color .15s ease;
}
.ld-footer__nav a:hover,
.ld-footer__nav a:focus-visible { color: var(--ldf-accent); }
.ld-footer__nav a:focus-visible {
	outline: 2px solid var(--ldf-accent);
	outline-offset: 4px;
	border-radius: 2px;
}

/* ---- oversized wordmark ------------------------------------------------
   Sized in vw so it spans the viewport at every width, and shown COMPLETE —
   every letter fully visible, never cropped. line-height 1 plus the bottom
   padding below give the glyphs their own space, so nothing is clipped by the
   footer's overflow:hidden (which is only there to stop the nowrap wordmark
   from ever forcing a horizontal scrollbar). */
.ld-footer__mark {
	position: relative;
	z-index: 1;
	text-align: center;
	/* The vw terms run well past the usual clamp ceilings on purpose: the
	   wordmark itself is sized in vw, so fixed rem caps would let the type keep
	   growing on a wide monitor while its breathing room stood still — at 1920
	   the letters ended up 1px off the footer's bottom edge. */
	padding: clamp(.75rem, 2.2vw, 3rem) clamp(.5rem, 2vw, 1.5rem) clamp(1.25rem, 3.6vw, 4.5rem);
	user-select: none;
}

.ld-footer__mark span {
	display: block;
	/* Trims the empty descender space the line box reserves below the baseline —
	   the wordmark is all caps, so there is nothing down there to lose. This
	   closes the gap under the letters WITHOUT cropping them: every glyph still
	   sits complete above the footer's bottom padding. */
	margin-bottom: -.11em;
	font-family: "Bricolage Grotesque", "Space Grotesk", var(--theme-font-family, sans-serif);
	font-size: var(--ldf-mark-size);
	/* 700, not 800: the site loads Bricolage Grotesque at 600/700 only, and
	   asking for a weight that is not loaded makes the browser synthesise bold
	   by smearing the glyphs — the single biggest thing working against a crisp
	   halftone at this size. */
	font-weight: 700;
	line-height: 1;
	letter-spacing: -.012em;
	white-space: nowrap;
	/* Solid faint fill is the fallback; the dot grid replaces it below wherever
	   background-clip:text is supported (every current browser). */
	color: color-mix(in srgb, var(--ldf-mark-dot) 55%, transparent);
	/* Crispness, two parts:
	   1. The grid is sized in em, so dots-per-letter is identical at every
	      viewport — a fixed px grid gives ~5 dot rows per glyph on a phone and
	      the letterforms stop reading. The max() floors keep the dots from
	      shrinking below ~2px across on small screens, where a sub-pixel dot
	      renders as grey mush rather than a dot.
	   2. round() snaps the tile to whole pixels, so the pattern never lands on
	      a fractional grid and shimmer/moiré across the wordmark. The plain em
	      declaration above it is the fallback for engines without round(). */
	background-image: radial-gradient(
		circle at center,
		var(--ldf-mark-dot) max(1px, .0088em),
		transparent max(1.15px, .0101em)
	);
	background-size: max(5px, .05em) max(5px, .05em);
	background-size: max(5px, round(nearest, .05em, 1px)) max(5px, round(nearest, .05em, 1px));
	background-position: center bottom;
}

@supports ((background-clip: text) or (-webkit-background-clip: text)) {
	.ld-footer__mark span {
		-webkit-background-clip: text;
		        background-clip: text;
		color: transparent;
		-webkit-text-fill-color: transparent;
	}
}

/* Narrow screens: stack the copyright above the links and give the row a little
   more breathing space; the wordmark keeps scaling with the viewport. */
@media (max-width: 600px) {
	#footer { --ldf-mark-size: 19.5vw; }
	.ld-footer__inner { display: block; }
	.ld-footer__copy { margin-bottom: 1.1rem; }
	.ld-footer__nav { gap: .75rem 1.4rem; }
}

/* ==========================================================================
   LinoDash: sticky floating header (dark navbar geometry)
   --------------------------------------------------------------------------
   Purpose: make the dark navbar read as a floating, contained, softly-rounded
   bar (visible gap above it, page background showing to its left and right,
   moderate corner rounding) rather than a bar flush to the top and edges, and
   keep it pinned there while the reader scrolls. This is PURELY container
   geometry and stickiness. The navbar's content, colours and menu items are
   left exactly as the Customizer sets them.

   Why this override exists: the Blocksy Customizer's header options for a top
   offset, a contained/floating width and a sticky row didn't produce the wanted
   result, so the geometry is owned here and tuned via the knobs below. Blocksy's
   own sticky feature stays OFF, because it swaps in a duplicate stuck row that
   would fight these rules. Same single-source principle as the date, breadcrumb
   and footer rules in CLAUDE.md: the header's position has one owner, this block.

   Structure: the dark bar is Blocksy's boxed header row, painted on
   `#header .ct-container`. The gap above it is PADDING on #header, not margin,
   so the gap travels with the bar when it sticks. #header itself stays
   transparent, so the gap reveals whatever canvas the view paints, and content
   scrolls behind it. That is how a floating pill behaves everywhere.

   Sticky mechanics: #header is a flex child of #main-container, which the
   parent theme gives `overflow: clip`. Clip, unlike hidden, does NOT create a
   scroll container, so the header still sticks to the viewport (verified on
   staging). It needs a z-index because both the homepage and single-post
   canvases put `z-index: 1` on every #main-container child, which would
   otherwise let the article paint over the header. 100 sits well under Blocksy's
   offcanvas drawer (999999), so the mobile menu still covers the bar.

   The knobs:
     --ld-header-top-gap   space above the bar, and while stuck, from the
                           viewport top
     --ld-header-side-gap  minimum space to the viewport edges (and the mobile
                           inset); on wide screens the max-width below dominates
     --ld-header-radius    corner radius on all four corners (soft rectangle)
     --ld-header-bar-h     height of the dark bar. Measured, not enforced: it
                           only feeds the clearance below. 60px is the tallest
                           the Customizer's row gets (phones shrink it to 54),
                           so clearance can be a few pixels generous on a phone.
                           That is the safe direction to be wrong in.
     --ld-header-clear     TOTAL space a stuck header occupies plus breathing
                           room. Anything that must not slide underneath it
                           (in-page anchors, the sticky rails on posts and legal
                           pages) offsets by this one token, so the header can be
                           retuned above without hunting through view files.
   ========================================================================== */
:root {
	--ld-header-top-gap: 24px;
	--ld-header-side-gap: 28px;
	--ld-header-radius: 12px;
	--ld-header-bar-h: 60px;
	--ld-admin-bar: 0px;
	--ld-header-clear: calc(var(--ld-admin-bar) + var(--ld-header-top-gap) + var(--ld-header-bar-h) + 12px);
}

/* Logged-in editors: WordPress's admin bar is fixed over the top 32px, so the
   stuck header starts below it instead of under it. Set on the ROOT (via :has,
   because the class lives on <body>) so the clearance token above sees it too.
   Under 600px WordPress stops fixing the admin bar, it scrolls away with the
   page, so the offset goes back to zero there. */
html:has(body.admin-bar) { --ld-admin-bar: 32px; }
@media (max-width: 782px) { html:has(body.admin-bar) { --ld-admin-bar: 46px; } }
@media (max-width: 600px) { html:has(body.admin-bar) { --ld-admin-bar: 0px; } }

/* Sticky + the top gap. Padding rather than margin: the gap has to be part of
   the sticky box, or the bar would dock flush to the viewport edge when stuck. */
#main-container > #header.ct-header {
	position: sticky;
	top: var(--ld-admin-bar);
	z-index: 100;
	margin-top: 0;
	padding-top: var(--ld-header-top-gap);
	transition: transform .28s ease;
}

/* ---- The two scrolled states (classes set by assets/js/header.js) --------
   Both are TRANSFORMS on purpose. The header keeps its full height in the
   layout either way, so nothing below it ever shifts, and the browser animates
   them on the compositor instead of reflowing the page on every scroll frame.

   Docked: the reader has left the top of the page, so the gap closes and the
   bar meets the screen edge. This is what stops article text showing in the
   strip above the pill. The top corners flatten as it lands, because a rounded
   corner against the screen edge leaves two notches of content showing through.
   The bottom corners stay rounded, so it still reads as the same pill.

   Hidden: the reader is scrolling down and wants the screen for the article, so
   the bar leaves. Scrolling up by more than a few pixels brings it back. The
   script holds it on screen while the mobile drawer is open, while focus is
   inside it, and for the length of an in-page jump.

   Without JavaScript neither class is ever set, and the header simply stays
   sticky with its gap. Nothing here is required for it to work. */
#main-container > #header.ld-header--docked {
	transform: translateY(calc(-1 * var(--ld-header-top-gap)));
}

#header.ld-header--docked [data-row] > .ct-container {
	border-start-start-radius: 0 !important;   /* beats the radius set below */
	border-start-end-radius: 0 !important;
}

#main-container > #header.ld-header--hidden {
	transform: translateY(-100%);
}

/* Readers who ask for less motion get the same states without the slide. */
@media (prefers-reduced-motion: reduce) {
	#main-container > #header.ct-header { transition: none; }
}

/* Contained width + soft corners on the dark bar. Centred and capped near the
   page's content width so it floats within the page rather than spanning it;
   on narrower screens it shrinks to keep --ld-header-side-gap on each edge so it
   never touches the sides. The shadow is what separates the bar from the text
   passing underneath it, so it is always on rather than added on scroll (which
   would need JavaScript that WP Rocket delays on cached pages anyway).

   Selector note: the row wrapper is matched deliberately. Blocksy paints its own
   `box-shadow: var(--theme-box-shadow)` on `#header [data-row*="boxed"] > div`,
   which outranks a plain `#header .ct-container`, so the shadow below is only
   applied because this selector carries one more class. Keep it that way. */
#header [data-row] > .ct-container {
	width: auto;   /* override Blocksy's fixed boxed width so the cap below binds */
	max-width: min(var(--theme-block-wide-max-width, 1140px), calc(100% - 2 * var(--ld-header-side-gap)));
	margin-inline: auto;
	border-radius: var(--ld-header-radius) !important;   /* beat the Customizer's larger pill radius */
	box-shadow: 0 10px 30px -14px rgba(10, 12, 14, .55);
}

/* In-page anchors (the post and legal tables of contents, and any #hash link)
   land below the stuck bar instead of under it. One rule on the scrollport
   replaces per-heading scroll-margin in the view stylesheets. */
html { scroll-padding-top: var(--ld-header-clear); }

/* Tablets and small laptops need nothing of their own. Blocksy swaps the
   desktop row for the compact mobile row at 1000px, but both rows are 60px
   tall, so only the menu itself changes. */

/* Phones: same floating treatment at smaller values (gap + side inset ~14px).
   The bar height is left at 60px on purpose even though the row drops to 54px
   on the narrowest screens: the clearance is then 6px generous rather than
   short, and nothing lands under the bar. */
@media (max-width: 767px) {
	:root {
		--ld-header-top-gap: 14px;
		--ld-header-side-gap: 14px;
	}
}

/* Short viewports (phones held sideways, small laptops with a lot of browser
   chrome): a pinned bar costs a bigger share of the screen there, so the gap
   tightens and the bar loses some height rather than eating the reading area. */
@media (max-height: 520px) {
	:root {
		--ld-header-top-gap: 8px;
		--ld-header-bar-h: 46px;
	}
	#header [data-row] > .ct-container { min-height: 46px; }
	#header .site-logo-container img { height: 26px; width: auto; }
}

/* Printing: nothing should be pinned, and the bar's shadow only wastes ink. */
@media print {
	#main-container > #header.ct-header { position: static; padding-top: 0; }
	#header [data-row] > .ct-container { box-shadow: none; }
}
