/*
Theme Name: BSP Base
Theme URI: https://web.vk.al
Author: BSP Platform
Description: BSP base block theme — a curated child of Twenty Twenty-Five. Platform-managed; users choose BSP appearance styles, never raw WordPress themes.
Requires at least: 6.7
Tested up to: 7.1
Requires PHP: 8.1
Version: 0.2.1
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Template: twentytwentyfive
Text Domain: bsp
Tags: block-patterns, full-site-editing, blog
*/

/*
 * Structure (templates, parts, patterns) is inherited from the parent theme.
 * All visual identity comes from the BSP style variations in styles/, applied
 * per blog as user global-styles by bsp-core. Only truly global tweaks belong
 * here — and every tweak must be palette-derived, never a literal colour.
 */

/* Keep long inline code and URLs from overflowing narrow content columns. */
.wp-block-code { overflow-x: auto; }
.wp-block-code code { font-family: var(--wp--preset--font-family--fira-code, monospace); }

/* Featured images should never escape their container. */
.wp-post-image { max-width: 100%; height: auto; }

/* Dividers: the parent theme paints separators with accent-6 (a 15%
   currentColor wash). Give them the same derived hairline the rest of the
   sheet uses so every divider in a BSP layout carries one consistent weight. */
.wp-block-separator:not(.is-style-dots) { color: var(--bsp-skin-line); }

/* Page-list menus render as plain lists — no bullets, no indent. */
.wp-block-page-list { list-style: none; margin: 0; padding: 0; }
.wp-block-page-list li { margin: 0; }
.wp-block-navigation ul.wp-block-page-list { padding-left: 0; }

/* -----------------------------------------------------------------------
 * BSP skins (v0.1.6): layout utilities for the portal-family styles.
 * These classes are referenced from block templates; the palette comes
 * from each style variation, so every skin stays palette-driven.
 * -------------------------------------------------------------------- */

/* Palette-derived design tokens (v0.2.1).
 *
 * Every surface, hairline and chip colour used by the skins below is derived
 * here, once, from the active style variation's palette. No literal colour is
 * allowed further down: that is what kept 18 farm sites visually coherent and
 * what stops a hard-coded blue/pink from colliding with a style's palette.
 * The `--bsp-skin-` prefix is deliberate — bsp-core's landing shell owns the
 * unrelated `--bsp-*` namespace.
 */
:root {
	/* Card surface: the palette's base, carrying a trace of the accent hue so
	   cards never sit as raw white on a tinted page. */
	--bsp-skin-surface: color-mix(in srgb, var(--wp--preset--color--base, #fff) 93%, var(--wp--preset--color--accent-3, currentColor));
	--bsp-skin-surface-soft: color-mix(in srgb, var(--wp--preset--color--base, #fff) 97%, var(--wp--preset--color--accent-3, currentColor));
	/* Featured surface (ranked-posts box): same accent, a touch stronger. */
	--bsp-skin-feature: color-mix(in srgb, var(--wp--preset--color--base, #fff) 90%, var(--wp--preset--color--accent-3, currentColor));
	--bsp-skin-feature-line: color-mix(in srgb, var(--wp--preset--color--accent-3, currentColor) 52%, var(--wp--preset--color--base, #fff));
	/* Hairlines: the palette's muted role, mixed into the surface. */
	--bsp-skin-line: color-mix(in srgb, var(--wp--preset--color--accent-4, #888) 48%, var(--wp--preset--color--base, #fff));
	--bsp-skin-line-soft: color-mix(in srgb, var(--wp--preset--color--accent-4, #888) 34%, transparent);
	/* Accent chip + the AA-safe text pair that belongs on it. */
	--bsp-skin-tint: color-mix(in srgb, var(--wp--preset--color--accent-3, currentColor) 12%, var(--wp--preset--color--base, #fff));
	--bsp-skin-tint-text: color-mix(in srgb, var(--wp--preset--color--accent-3, currentColor) 62%, var(--wp--preset--color--contrast, #000));
}

/* Two-column feed + sidebar layout */
.bsp-cols {
	display: grid;
	grid-template-columns: minmax(0, 1fr) 300px;
	gap: 2.2rem;
	align-items: start;
}
.bsp-cols-home { grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); }

/* Grid items must stretch — never shrink to fit-content.
 *
 * Every .bsp-cols group is declared with layout:constrained, so WordPress core
 * emits this rule for each of its direct children:
 *   .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)) {
 *       max-width: var(--wp--style--global--content-size);   // 46rem = 736px
 *       margin-left: auto !important; margin-right: auto !important;
 *   }
 * A grid item stretches via `justify-self: stretch`, and that stretch is
 * cancelled the moment one inline margin is `auto`: the item collapses to its
 * fit-content width and parks itself in the middle of its track. On a 1280px
 * viewport that squeezed .bsp-col-main down to 142px inside its 829.8px track
 * (measured x=394 = 50 + (829.8 − 142) / 2 — dead centre), and the
 * auto-fill post grid inside it could then only resolve a single 142px track.
 * Same defect bites the nested sidebar groups (constrained groups in a 300px
 * track), which drift to fit-content and centre as well.
 * `!important` is mandatory: core's own margin declaration is important too.
 * Only the grid children are touched; .alignleft/.alignright/.alignfull/
 * .aligncenter children keep their intentional float/centring margins. */
.bsp-cols > :not(.alignleft):not(.alignright):not(.alignfull):not(.aligncenter),
.bsp-cols-home > :not(.alignleft):not(.alignright):not(.alignfull):not(.aligncenter),
.bsp-col-main > :not(.alignleft):not(.alignright):not(.alignfull):not(.aligncenter),
.bsp-col-side > :not(.alignleft):not(.alignright):not(.alignfull):not(.aligncenter),
.bsp-side > :not(.alignleft):not(.alignright):not(.alignfull):not(.aligncenter) {
	box-sizing: border-box;
	width: 100%;
	max-width: none;
	min-width: 0;
	margin-left: 0 !important;
	margin-right: 0 !important;
}

/* Phones: one column, sidebar follows the main column (DOM order is
   main → side in every BSP template, so no order override is needed).
   minmax(0, 1fr) instead of 1fr keeps long unbreakable content from
   blowing the track past the viewport. */
@media (max-width: 960px) {
	.bsp-cols,
	.bsp-cols-home { grid-template-columns: minmax(0, 1fr); }
}

/* Section titles with an accent tick, portal style */
.bsp-section-title {
	display: flex;
	align-items: center;
	gap: 0.6rem;
}
.bsp-section-title::before {
	content: "";
	flex: none;
	width: 5px;
	height: 1.05em;
	background: var(--wp--preset--color--accent-3, currentColor);
	border-radius: 1px;
}

/* Weekly Top 10 ranking with numbered badges */
.bsp-rank ul.wp-block-post-template {
	list-style: none;
	margin: 0;
	padding: 0;
	counter-reset: bsprank;
}
.bsp-rank ul.wp-block-post-template > li {
	counter-increment: bsprank;
	display: flex;
	gap: 0.65rem;
	align-items: flex-start;
	padding: 0.45rem 0;
	border-bottom: 1px dashed var(--bsp-skin-line-soft);
}
.bsp-rank ul.wp-block-post-template > li:last-child { border-bottom: none; }
.bsp-rank ul.wp-block-post-template > li::before {
	content: counter(bsprank);
	flex: none;
	min-width: 1.55em;
	height: 1.55em;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	background: var(--wp--preset--color--accent-5, #eee);
	color: var(--wp--preset--color--contrast, inherit);
	font-weight: 800;
	font-size: 0.72em;
	border-radius: 2px;
	margin-top: 0.15em;
}
/* Top-3 badges: accent fill, palette-base text. The old literal white was the
   only non-palette colour in this sheet, and it was invisible on light accents
   (white on pixnet's orange = 3.01:1, on photo's amber = 2.15:1). */
.bsp-rank ul.wp-block-post-template > li:nth-child(-n+3)::before {
	background: var(--wp--preset--color--accent-3, currentColor);
	color: var(--wp--preset--color--base, #fff);
}

/* Ranked-posts box: the parts paint a 2px full-strength accent-3 outline and a
   near-base accent fill through inline styles. Re-derive both from the palette
   tokens instead, so the box keeps its extra weight (2px, tinted fill) without
   the raw saturated edge. `!important` is required to beat the part's inline
   border-color/background, and the 3-class selector keeps this above the
   generic sidebar-card rule whichever column it lands in. Border *colour* now
   comes from the shared frame rule below; only the fill is set here. Border
   *width* is deliberately left alone so the parts keep their 1px/2px choice. */
.wp-block-group.bsp-widget.bsp-rank-box {
	background-color: var(--bsp-skin-feature) !important;
	border-color: var(--bsp-skin-feature-line) !important;
}

/* Sidebar widgets read as cards on every style: palette surface + palette
   frame. Widgets that carry their own `has-background` (magazine accent-5,
   neon accent-1, reader/portal accent-1 …) keep that tinted fill, because
   their inline background wins. The frame is forced with !important so that no
   card can dissolve into the page and so that neighbouring cards can never
   meet with only a 15%-currentColor wash between them. */
.bsp-col-side > .bsp-widget,
.bsp-side > .bsp-widget {
	background-color: var(--bsp-skin-surface);
	border-width: 1px;
	border-style: solid;
	border-color: var(--bsp-skin-feature-line) !important;
	border-radius: 8px;
	padding: 1.1rem 1.2rem;
}

/* Stacked sidebar blocks keep a real gap so borders never butt together.
   Non-important on purpose: the parts' inline margin-top (1.4rem) wins. */
.bsp-side > * + *,
.bsp-col-side > * + .bsp-widget { margin-block-start: 1.3rem; }

/* ONE frame colour for every boxed block — sidebar widget, profile card,
   reader card, comment form.

   All of them are authored with a 1px `accent-6` frame, and every style
   variation defines accent-6 as `color-mix(in srgb, currentColor 15%,
   transparent)`: a wash that is not palette-derived at all and therefore
   resolves to the same neutral grey in all twenty palettes. That is what put a
   grey profile card directly above a palette-coloured ranked box, on a page
   whose section rules are palette-coloured too — the odd one out was the grey.
   Frames now take the same accent the ranked box uses, so a widget frame, a
   card frame and a section rule all carry one colour; only the frame *width*
   distinguishes them.

   The neutral hairlines that share this role on purpose (feed separators,
   header rules, the archive-title underline) are deliberately NOT listed here:
   a frame has to read as a frame, and painting every divider in the accent
   would flatten that distinction the other way. */
.bsp-widget,
.bsp-profile,
.bsp-card-reader,
.bsp-comment,
.cn-card,
.cn-profile { border-color: var(--bsp-skin-feature-line) !important; }

/* Feed rows lift on hover */
.bsp-feed-item { transition: background 0.15s ease; }
.bsp-feed-item:hover { background: var(--bsp-skin-surface-soft); }

/* Sidebar widget internals (v0.2.1): plain lists, palette-aware rows. */
.bsp-widget ul,
.bsp-widget ol { list-style: none; margin: 0; padding: 0; }

/* Categories list, dashed rows */
.bsp-cat-list ul { margin: 0; padding: 0; list-style: none; }
.bsp-cat-list li {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	padding: 0.35rem 0;
	border-bottom: 1px dashed var(--bsp-skin-line-soft);
	font-size: 0.9rem;
}
.bsp-cat-list li:last-child { border-bottom: none; }

/* Tag cloud chips */
.bsp-tags .wp-block-tag-cloud a,
.bsp-tags a.wp-block-tag-cloud__tag {
	display: inline-block;
	margin: 0 4px 8px 0;
	padding: 2px 11px;
	border: 1px solid var(--bsp-skin-line-soft);
	border-radius: 999px;
	text-decoration: none;
	white-space: nowrap;
	max-width: 100%;
}
/* Hover used to paint the chip with accent-1 while the link kept accent-3:
   on photo that is amber on amber (1.31:1), on pixnet 2.75:1 — the chip text
   vanished. Use the derived tint pair instead: >= 5.2:1 on every palette. */
.bsp-tags .wp-block-tag-cloud a:hover,
.bsp-tags a.wp-block-tag-cloud__tag:hover {
	background: var(--bsp-skin-tint);
	border-color: var(--bsp-skin-line);
	color: var(--bsp-skin-tint-text);
	text-decoration: none;
}

/* Lead story: keep the featured image tight */
.bsp-lead-story .wp-post-image { border-radius: 4px; }

/* WP block-support quirk: a group with only a bottom border still gets
 * has-border-color (solid style + medium width on every side). Zero the
 * non-bottom sides for bottom-rule layouts. */
.bsp-feed-item,
.bsp-diary-entry {
	border-top-width: 0;
	border-left-width: 0;
	border-right-width: 0;
	border-top-style: none;
	border-left-style: none;
	border-right-style: none;
}

/* ---- CN-family styles (v0.1.17): digit/deal/devblog/essay/codehub/
 * column/itblog/opensource share the portal utilities above plus a few
 * structural classes of their own. ---- */

/* Blog head card: big site title over an accent rule */
.cn-head .wp-block-site-title a { text-decoration: none; }

/* Tenant-home masthead (portal/minimal/magazine/photo/gourmet home templates).
   The page's single h1 is the site title, so it has to read as the blog's name
   rather than as a link. Each template pins its own block typography; only the
   link decoration is shared here. */
.bsp-home-head .wp-block-site-title a { text-decoration: none; }

/* Card grids (deal) get a quiet lift on hover */
.cn-card { transition: box-shadow 0.15s ease, transform 0.15s ease; }
.cn-card:hover {
	box-shadow: 0 6px 18px color-mix(in srgb, var(--wp--preset--color--accent-3, currentColor) 14%, transparent);
	transform: translateY(-2px);
}

/* Grid queries need breathing room between cards */
.wp-block-query.cn-grid,
.wp-block-query:has(.cn-card) { display: block; }
.wp-block-post-template.is-layout-grid { gap: 1.1rem; }

/* Profile widget in CN sidebars */
.cn-profile .wp-block-site-title a { text-decoration: none; }

/* Category list rows: count right-aligned like CN portals */
.bsp-cat-list li { display: flex; justify-content: space-between; }

/* -----------------------------------------------------------------------
 * Layout hardening (v0.2.1): behaviour at 320 / 768 / 1280 for all styles.
 * -------------------------------------------------------------------- */

/* Nothing inside a feed or a rail may push the page sideways. */
.bsp-cols { overflow-wrap: break-word; }
.bsp-col-main .wp-block-code,
.bsp-col-main .wp-block-preformatted,
.bsp-col-main .wp-block-table { overflow-x: auto; }
.bsp-col-main img,
.bsp-col-side img,
.bsp-col-main iframe,
.bsp-col-main video,
.bsp-col-main embed,
.bsp-col-main object { max-width: 100%; }
.bsp-col-main iframe,
.bsp-col-main video { height: auto; }

/* Section and rank titles get a palette hairline underneath: the title band
   and the feed below it otherwise read as one single block (the user's
   "corners butted together"). The rule is derived, never a literal colour. */
.bsp-section-title,
.bsp-rank-title {
	padding-block-end: 0.5rem;
	border-bottom: 1px solid var(--bsp-skin-line-soft);
}

/* Feed rows: the parts draw a 1px accent-6 (15% currentColor) bottom rule,
   which all but vanishes on tinted pages. Force the derived hairline so
   consecutive entries are visibly separated instead of butting together. */
.bsp-feed-item,
.bsp-diary-entry { border-bottom-color: var(--bsp-skin-line) !important; }

/* Safety net for two stacked BSP grids (today every template ships exactly one
   .bsp-cols, but templates are owned by another layer): they must not sit
   flush, since the constrained layout only gives them a collapsed 1.2rem. */
.bsp-cols + .bsp-cols,
.bsp-cols + .bsp-cols-home,
.bsp-cols-home + .bsp-cols { margin-block-start: 2.4rem; }

/* Small phones: chips wrap instead of overflowing the rail. */
@media (max-width: 480px) {
	.bsp-tags .wp-block-tag-cloud a,
	.bsp-tags a.wp-block-tag-cloud__tag {
		white-space: normal;
		overflow-wrap: anywhere;
	}
}

/* 961–1100px: a fixed 300px rail plus the 2.2rem gap leaves the feed column
   too thin for the auto-fill 220px card grid, which then drops from 3 tracks
   to 2. Relax the rail (and the gap) in that band only; .bsp-cols-home keeps
   its proportional 1.5fr/1fr tracks because its rail is not fixed. */
@media (min-width: 961px) and (max-width: 1100px) {
	.bsp-cols:not(.bsp-cols-home) {
		grid-template-columns: minmax(0, 1fr) 260px;
		gap: 1.8rem;
	}
}
