/*
Theme Name: G[ai]A-ALFA
Theme URI: https://gaia.web.uma.pt/
Description: Child theme of Twenty Twenty-Five carrying the G[ai]A-ALFA visual identity. Palette extracted from the project brand kit (Assets/02_Color Palette). Accent colours are used as surfaces and rules only -- never as text -- because they do not meet WCAG AA contrast on white.
Author: ITI/LARSyS
Template: twentytwentyfive
Version: 0.1.0
Requires at least: 6.7
Tested up to: 7.1
Requires PHP: 7.2
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: gaia-alfa
*/

/* Styling lives in theme.json. Use this file only for what theme.json cannot express. */

/* Pillar accent rule: a 4px top border in the pillar colour over a pale surface. */
.gaia-pillar-card { border-top: 4px solid var(--wp--preset--color--primary); }
.gaia-pillar-card.is-pillar-energy { border-top-color: var(--wp--preset--color--accent-green); }
.gaia-pillar-card.is-pillar-health { border-top-color: var(--wp--preset--color--accent-red); }
.gaia-pillar-card.is-pillar-civic  { border-top-color: var(--wp--preset--color--accent-yellow); }
.gaia-pillar-card.is-pillar-ethics { border-top-color: var(--wp--preset--color--accent-blue); }

/* Stat figures in the numbers strip. */
.gaia-stat__figure { font-variant-numeric: tabular-nums; line-height: 1; }

/* Keep wide tables scrollable instead of breaking the page on small screens. */
.gaia-table-scroll { overflow-x: auto; }
.gaia-table-scroll table { min-width: 36rem; }

/* Striped tables.

   The stripe is `--gaia-stripe`, one step lighter than `primary-100` along the brand's
   own purple ramp. That ramp holds hue and saturation steady and moves only lightness
   (400 60.2%, 300 64.3%, 200 80.2%, 100 84.3%, all at H240 S33%), so the stripe is the
   same formula taken one step further, to 93% — #E7E7F3. It lives here rather than in
   theme.json because theme.json is a faithful copy of the brand .ase file; promote it
   to a `primary-50` preset if it is wanted in the editor's colour picker.

   Why not `primary-100` (#CACAE4) itself: at 1.61:1 against white it reads as a solid
   band rather than a stripe, and it drags the brand purple down to 4.35:1 — under AA
   for the 14px type these tables use. #E7E7F3 is 1.23:1 against white, close to core's
   grey in weight but unmistakably lavender, and leaves every foreground with room:

     contrast body text  14.2:1      primary links  5.69:1      neutral-600  5.71:1

   Core prints its grey in two places — the odd rows and the rule under the last row —
   so both are replaced; override only the first and the table ends on a grey line. */
:root {
	--gaia-stripe: #E7E7F3;
}
.wp-block-table.is-style-stripes tbody tr:nth-child(odd) {
	background-color: var(--gaia-stripe);
}
.wp-block-table.is-style-stripes {
	border-bottom-color: var(--gaia-stripe);
}

/* Keyboard focus. The brand purple is the only palette colour that reads as a focus
   ring on both the white page and the black hero bed. */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
	outline: 3px solid var(--wp--preset--color--primary);
	outline-offset: 2px;
}

/* Hero video. The bed is pure black because the footage's own background is, so any
   lighter token would draw a visible rectangle around it. */
.gaia-hero {
	background-color: #000000;
}

/* Zero the block margins only. A blanket `margin: 0` here silently undoes the
   full-bleed, because it also cancels the negative margin `alignfull` relies on. */
.gaia-hero .wp-block-video {
	margin-block: 0;
}
.gaia-hero > .wp-block-video.alignfull {
	margin-inline: calc(var(--wp--style--root--padding-left, 1.5rem) * -1)
		calc(var(--wp--style--root--padding-right, 1.5rem) * -1);
	max-width: none;
}
.gaia-hero .wp-block-video video {
	display: block;
	width: 100%;
	height: auto;
	background-color: #000000;
}

/* ------------------------------------------------------------------ Wordmark */
.gaia-wordmark {
	display: block;
	width: auto;
	height: 1em;
	fill: currentColor;
}

/* Header and footer site title. */
.wp-block-site-title.has-gaia-wordmark a {
	display: inline-block;
	line-height: 0;
}
.wp-block-site-title.has-gaia-wordmark .gaia-wordmark {
	height: 1.1em;
}

/* Header lockup: the symbol, then the wordmark. The brand's own lockup file sets
   the two to the *same ink height* and separates them by 0.36 of it (measured off
   01_Logo/Logo_with_Acronym: symbol 151x150, acronym 679x150, 54px apart), so the
   symbol's viewBox is cropped to its ink and both are given the same height. The
   footer does not use this — it carries the symbol as the site logo instead. */
.wp-block-site-title.has-gaia-mark a {
	display: inline-flex;
	align-items: center;
	gap: 0.4em;
}
.gaia-mark {
	display: block;
	flex: none;
	width: auto;
	height: 1.1em;
	fill: currentColor;
}

/* Hero: the lockup is the headline, so scale it to the column rather than to
   the font size, and cap it so it never outgrows the text block beneath it. */
.gaia-hero .has-gaia-wordmark {
	line-height: 0;
}
.gaia-hero .has-gaia-wordmark .gaia-wordmark {
	height: auto;
	width: min(100%, 30rem);
	margin-inline: auto;
}

/* Visually hidden, still announced and still indexed. */
.screen-reader-text {
	border: 0;
	clip-path: inset(50%);
	height: 1px;
	margin: -1px;
	overflow: hidden;
	padding: 0;
	position: absolute;
	width: 1px;
	white-space: nowrap;
}

/* -------------------------------------------------------------- Publications
   teachPress [tplist] output. Class names taken from the plugin's own templates
   (teachpress/core + templates), scoped under .gaia-publications so nothing
   leaks into the rest of the site. */
.gaia-publications .teachpress_publication_list,
.gaia-publications .tp_pub_list {
	list-style: none;
	margin: 0;
	padding: 0;
}

/* One row per publication. */
.gaia-publications .tp_publication,
.gaia-publications .teachpress_publication_list > li {
	padding-block: var(--wp--preset--spacing--30);
	border-block-start: 1px solid var(--wp--preset--color--neutral-300);
}
.gaia-publications .teachpress_publication_list > li:first-child {
	border-block-start: 0;
}

/* Title carries the weight; the display face keeps it in family with headings. */
.gaia-publications .tp_pub_title {
	font-family: var(--wp--preset--font-family--display);
	font-weight: 600;
	line-height: 1.3;
}
.gaia-publications .tp_pub_title a,
.gaia-publications .tp_title_link {
	color: var(--wp--preset--color--contrast);
	text-decoration: none;
}
.gaia-publications .tp_pub_title a:hover,
.gaia-publications .tp_title_link:hover {
	color: var(--wp--preset--color--primary);
	text-decoration: underline;
}

/* Authors and venue sit back from the title. */
.gaia-publications .tp_pub_author {
	color: var(--wp--preset--color--neutral-600);
	font-size: var(--wp--preset--font-size--small);
}
.gaia-publications .tp_pub_additional,
.gaia-publications .tp_pub_info {
	color: var(--wp--preset--color--neutral-600);
	font-size: var(--wp--preset--font-size--small);
}

/* Year headings when headline="1" groups the list. */
.gaia-publications h3 {
	font-size: var(--wp--preset--font-size--large);
	margin-block: var(--wp--preset--spacing--50) var(--wp--preset--spacing--20);
}

/* The DOI / BibTeX / abstract controls -- present but quiet. */
.gaia-publications .tp_pub_menu {
	font-size: var(--wp--preset--font-size--small);
}
.gaia-publications .tp_pub_menu a,
.gaia-publications .teachpress_link {
	color: var(--wp--preset--color--primary);
}
.gaia-publications .tp_abstract,
.gaia-publications .tp_bibtex {
	font-size: var(--wp--preset--font-size--small);
	background: var(--wp--preset--color--surface-blue);
	padding: var(--wp--preset--spacing--30);
	margin-block-start: var(--wp--preset--spacing--20);
}
.gaia-publications .tp_bibtex pre {
	white-space: pre-wrap;
	word-break: break-word;
	margin: 0;
	font-family: var(--wp--preset--font-family--mono);
}

/* Numbered lists keep their counter aligned. */
.gaia-publications .tp_pub_number {
	color: var(--wp--preset--color--neutral-600);
	font-variant-numeric: tabular-nums;
}

/* Empty state for the publication list, until the first paper lands. */
.gaia-publications__empty {
	color: var(--wp--preset--color--neutral-600);
	font-style: italic;
	padding: var(--wp--preset--spacing--40);
	background: var(--wp--preset--color--surface-blue);
}

/* ------------------------------------------------------------- Scroll hint
   Fixed to the viewport, not the hero: the hero is taller than most screens,
   so anything anchored to its bottom edge would itself be below the fold and
   defeat the point. Fades out as soon as the visitor starts scrolling. */
.gaia-scroll-hint {
	position: fixed;
	inset-inline: 0;
	bottom: clamp(1rem, 3vh, 2.25rem);
	z-index: 5;
	display: flex;
	justify-content: flex-end;
	padding-inline-end: clamp(1.25rem, 4vw, 3.5rem);
	pointer-events: none; /* never intercepts a click on the hero */
	opacity: 1;
	transition: opacity 400ms ease;
}
.gaia-scroll-hint.is-gone {
	opacity: 0;
}

/* A thin rule with a travelling dot: reads as an indicator, not a button. */
.gaia-scroll-hint__track {
	position: relative;
	display: block;
	width: 1px;
	height: 2.75rem;
	background: rgba(255, 255, 255, 0.22);
	/* The footage behind this varies, so keep the mark legible over bright frames. */
	filter: drop-shadow(0 0 6px rgba(0, 0, 0, 0.65));
}
.gaia-scroll-hint__dot {
	position: absolute;
	inset-inline-start: -1px;
	top: 0;
	width: 3px;
	height: 0.75rem;
	border-radius: 2px;
	background: var(--wp--preset--color--primary-200);
	animation: gaia-scroll-hint-travel 2.1s cubic-bezier(0.65, 0, 0.35, 1) infinite;
}

@keyframes gaia-scroll-hint-travel {
	0%        { transform: translateY(0);     opacity: 0; }
	18%       { opacity: 1; }
	72%       { opacity: 1; }
	100%      { transform: translateY(2rem);  opacity: 0; }
}

/* Motion the visitor did not ask for: hold the dot still at the top instead. */
@media (prefers-reduced-motion: reduce) {
	.gaia-scroll-hint__dot {
		animation: none;
		opacity: 1;
	}
}

/* ------------------------------------------------- Wordmark over the video
   The wordmark is lifted out of flow-order position so it sits on the lower
   part of the footage rather than on the black bed below it.

   White over this video measures 2.19:1 at the animation's brightest point --
   an AA failure -- so a scrim is not decoration here, it is what makes the
   overlay legible. The gradient is near-solid where the wordmark sits and
   fades to nothing further up, which also softens the video's bottom edge
   into the black section beneath. */
.gaia-hero > .wp-block-video.alignfull {
	position: relative;
}
.gaia-hero > .wp-block-video.alignfull::after {
	content: "";
	position: absolute;
	inset-inline: 0;
	bottom: 0;
	height: 48%;
	pointer-events: none;
	background: linear-gradient(
		to top,
		#000 0%,
		rgba(0, 0, 0, 0.94) 28%,
		rgba(0, 0, 0, 0.72) 48%,
		rgba(0, 0, 0, 0.34) 70%,
		transparent 100%
	);
}

/* Everything in the hero that is not the video has to be lifted above it.
   The figure is position:relative, and in CSS painting order a positioned
   element paints ABOVE static in-flow siblings — so the scrim would otherwise
   cover the tagline, the intro copy and the buttons. Raising only the wordmark
   leaves the rest buried. */
.gaia-hero > *:not(.wp-block-video) {
	position: relative;
	z-index: 2;
}

/* Negative margin rather than absolute positioning: it keeps the wordmark in
   flow, so the tagline and buttons travel up with it and the hero simply gets
   shorter. Absolute positioning would collapse the space and strand them. */
.gaia-hero .has-gaia-wordmark {
	margin-block-start: calc(-1 * var(--gaia-wordmark-lift, 11vw));
}

/* ------------------------------------------------------------- White links
   theme.json links are `primary` (#6332DB): 6.98:1 on white, but only 3.01:1
   on black, which fails AA anywhere in the hero. This variation switches them
   to white (21:1 on black).

   `.is-style-white-links` comes from the editor's Styles panel;
   `.has-white-links` is the same thing typed by hand into Advanced →
   Additional CSS class(es). Both are supported so neither route surprises
   anyone. */
.is-style-white-links a,
.has-white-links a,
.is-style-white-links a:visited,
.has-white-links a:visited {
	color: var(--wp--preset--color--base);
	/* Never rely on colour alone to signal a link (WCAG 1.4.1). */
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.18em;
	text-decoration-color: rgba(255, 255, 255, 0.55);
}
.is-style-white-links a:hover,
.has-white-links a:hover,
.is-style-white-links a:focus-visible,
.has-white-links a:focus-visible {
	text-decoration-color: currentColor;
	text-decoration-thickness: 2px;
}

/* ----------------------------------------------------------- Sticky header
   The header template part is transparent by default, which is fine while it
   sits on the white body but would put dark nav text straight onto the black
   hero once it starts travelling over it. So the background is explicit.

   Tag-qualified on purpose: `.wp-block-template-part` is also the footer's
   class, and `header` keeps this off it. */
header.wp-block-template-part {
	position: sticky;
	top: 0;
	z-index: 100; /* above the hero content, which sits at z-index 2 */
	background-color: var(--wp--preset--color--base);
	border-block-end: 1px solid var(--wp--preset--color--neutral-300);
}

/* The admin bar is fixed on desktop, so the header has to start below it.
   At 782px and under WordPress switches it to position:absolute and it
   scrolls away, so the offset must not apply there or it leaves a gap. */
body.admin-bar header.wp-block-template-part {
	top: 32px;
}
@media screen and (max-width: 782px) {
	body.admin-bar header.wp-block-template-part {
		top: 0;
	}
}

/* A sticky header hides whatever an in-page anchor jumps to, so reserve its
   height when scrolling to a target. The pages carry real anchors (#context,
   #objectives, #publications ...), so this is not hypothetical.
   WordPress already reserves the admin bar's 32px; the header is on top of
   that, and below 782px the admin bar scrolls away so it drops out again. */
html {
	scroll-padding-top: calc(var(--gaia-sticky-header-h, 3.7rem) + 1rem);
}
html:has(body.admin-bar) {
	scroll-padding-top: calc(var(--gaia-sticky-header-h, 3.7rem) + 1rem + 32px);
}
@media screen and (max-width: 782px) {
	html:has(body.admin-bar) {
		scroll-padding-top: calc(var(--gaia-sticky-header-h, 3.7rem) + 1rem);
	}
}

/* The Project page opens with its framing paragraphs beside a short looping
   video of the mark breaking up. The loop is white-on-black, so on the page it
   reads as a black square: keep it modest, so it sits beside the text as a
   companion rather than competing with it. */
.gaia-loop-video {
	margin: 0 auto;
	width: 100%;
	max-width: 22rem;
}
.gaia-loop-video video {
	display: block;
	width: 100%;
	height: auto;
	/* The footage's own background is true black; anything lighter behind it
	   would show as a rim while the first frame loads. */
	background-color: var(--wp--preset--color--black);
}

/* Stacked (one column) below 782px: WordPress drops the columns to full width,
   and a square at full width would push the first heading off the screen. */
@media (max-width: 781px) {
	.gaia-loop-video {
		max-width: 15rem;
	}
}
