/*
Theme Name: Katalis
Description: Theme for the IA-CEPA ECP Katalis site. Palette and typeface are read from the published site; the layout is a redesign, not a reproduction — see functions.php.
Version: 0.2.0
Author: Katalis
Requires at least: 6.5
Tested up to: 7.1
License: GPL-2.0-or-later
Text Domain: katalis
*/

/*
 * Tokens, measured rather than chosen.
 *
 * Every colour and size below comes from iacepa-katalis.org, read off the rendered pages and
 * recorded in spec/brand.json: navy #000066 as the brand, #086ad5 for actions, #cc0100 as the
 * second accent, #eef4fc as the tint, and a 60/36/18/16/14/12 scale at weights 400 to 700.
 *
 * The two greys are the exception and are derived: #1b1c24 for text is the near-black the
 * project's own documents use, because pure black on white at this measure reads harsher than
 * this site's tone warrants, and the muted grey is set to clear 4.5:1 on white rather than
 * picked by eye.
 */
:root {
	--kx-navy: #000066;
	--kx-blue: #086ad5;
	--kx-red: #cc0100;
	--kx-tint: #eef4fc;

	--kx-ink: #000000;            /* referensi: 90 dari pemakaian --framer-text-color */
	--kx-ink-muted: rgba(0, 0, 0, .7);   /* referensi #000000b3 — 5.9:1 di atas putih */

	/*
	 * The faint grey is computed against the *tint*, not against white, and that correction
	 * came from measuring: it is used for the footer's labels, and the footer sits on #eef4fc.
	 * The first value here was #767a88, described in this comment as "4.5:1 on white". It was
	 * 4.28:1 on white and 3.87:1 on the tint — a token that read as safe because it had been
	 * checked against the wrong surface.
	 *
	 * 5.0:1 on white, 4.5:1 on the tint. The harder surface sets the value.
	 */
	--kx-ink-faint: #6b6f7e;
	--kx-line: #dcdce4;
	--kx-line-soft: #ebebf1;
	--kx-paper: #ffffff;

	/*
	 * Inter first, so a self-hosted copy is used the moment one is added. Nothing is loaded
	 * from a third party: the project this replaces dropped its CDN deliberately, and a font
	 * request to Google is a third-party request on every page.
	 */
	--kx-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

	/*
	 * The scale is no longer this theme's own. Each step points at a preset in tokens.css,
	 * which carries the reference's exact pixel size at each of its four breakpoints — so a
	 * rule written as var(--kx-step-3) renders 36/28/24/20px exactly as the published site
	 * does, and the clamp that used to approximate the display size is gone.
	 */
	--kx-step--1: var(--kx-t14-400-size);   /* 14 / 13 / 12 / 12 */
	--kx-step-0: var(--kx-t16-400-size);    /* 16 / 14 / 13 / 13 */
	--kx-step-1: var(--kx-t18-500-size);    /* 18 / 16 / 14 / 14 */
	--kx-step-2: var(--kx-t26-700-size);    /* 26 / 20 / 16 / 15 — entry titles */
	--kx-step-3: var(--kx-t36-700-size);    /* 36 / 28 / 24 / 20 — section titles */
	--kx-step-4: var(--kx-t60-700-size);    /* 60 / 48 / 38 / 30 — hero titles */

	/* 674px is the measure the published site sets its body text to. */
	--kx-measure: 42rem;
	--kx-shell: 74rem;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
	margin: 0;
	background: var(--kx-paper);
	color: var(--kx-ink);
	font-family: var(--kx-sans);
	font-size: var(--kx-step-0);
	/* 1.7em, the reference's body ratio: 27.2px at 16px, 22.1px at 13px. */
	line-height: var(--kx-t16-400-lh);
	line-height: 1.62;
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
}

img, video, iframe { max-width: 100%; height: auto; }
img { display: block; }

a { color: var(--kx-blue); text-underline-offset: .18em; text-decoration-thickness: 1px; }
a:hover { color: var(--kx-navy); }

/* Keyboard focus has to be visible on every interactive thing, including images-as-links. */
:focus-visible {
	outline: 2px solid var(--kx-blue);
	outline-offset: 2px;
	border-radius: 2px;
}

/* ------------------------------------------------------------------ layout */

/*
 * 90% of the viewport, with no cap and no gutter padding — the gutter IS the remaining 10%.
 * Measured at 1600, 1920 and 2560: 1440, 1728, 2304. The previous rule capped at 74rem, which
 * matches the reference at no width at all.
 *
 * tokens.css declares --kx-shell-width; this rule is here rather than there because the
 * generated file holds the contract and the theme decides how to spend it.
 */
.kx-shell {
	width: var(--kx-shell-width);
	max-width: none;
	margin-inline: auto;
	padding-inline: 0;
}

.kx-prose { max-width: var(--kx-measure); }

.kx-skip {
	position: absolute;
	left: -9999px;
	top: 0;
	background: var(--kx-navy);
	color: #fff;
	padding: .7rem 1rem;
	z-index: 100;
}
.kx-skip:focus { left: 0; }

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

/* ------------------------------------------------------- utility strip, 49px
 *
 * The gradient is the reference's own: linear-gradient(92deg, #06177f 0%, #086ad5 108%). The
 * 108% stop is not a typo — Framer emits it, and it shifts where the blue lands.
 */
.kx-utility {
	background: linear-gradient(92deg, #06177f 0%, #086ad5 108%);
}

.kx-utility__inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	padding-block: 8px;
	min-height: 49px;
	box-sizing: border-box;
}

.kx-utility__link {
	color: #fff;
	text-decoration: none;
}

.kx-utility__link:hover,
.kx-utility__link:focus-visible {
	color: #fff;
	text-decoration: underline;
}

/* --------------------------------------------------------- navigation, 66px */

.kx-nav {
	background: var(--kx-paper);
}

.kx-nav__inner {
	display: flex;
	align-items: center;
	gap: 1.5rem;
	min-height: 66px;
	box-sizing: border-box;
}

@media (max-width: 1199.98px) {
	.kx-nav__inner { min-height: 67px; }
}

/*
 * Below 810px the bar collapses behind a toggle, because six items and three submenus wrap
 * onto a second line and push the bar to 77px where the reference holds 67px.
 */
@media (max-width: 809.98px) {
	.kx-nav__toggle {
		margin-left: auto;
		cursor: pointer;
		list-style: none;
		padding: .4rem .6rem;
		border: 1px solid var(--kx-line);
		border-radius: 3px;
	}
	.kx-nav__toggle::-webkit-details-marker { display: none; }
	.kx-nav__toggle::marker { content: ''; }

	.kx-nav__collapse:not([open]) .kx-nav__list { display: none; }

	.kx-nav__collapse { margin-left: auto; }

	.kx-nav__list {
		position: absolute;
		right: 0;
		top: 100%;
		z-index: 30;
		flex-direction: column;
		align-items: stretch;
		gap: 0;
		min-width: 15rem;
		margin: 0;
		padding: .5rem 0;
		background: var(--kx-paper);
		border: 1px solid var(--kx-line);
		box-shadow: 0 8px 24px rgba(0, 0, 0, .1);
	}

	.kx-nav__list .kx-nav__link { display: block; padding: .45rem 1rem; border-bottom: 0; }

	/* Submenus open in place rather than floating off a narrow screen. */
	.kx-nav__sub {
		position: static;
		border: 0;
		box-shadow: none;
		min-width: 0;
		padding: 0 0 0 1rem;
	}
	.kx-nav__item--menu:hover .kx-nav__sub { display: none; }
	.kx-nav__menu[open] .kx-nav__sub { display: block; }
}

@media (min-width: 810px) {
	.kx-nav__toggle { display: none; }
}

.kx-brand {
	font-weight: 700;
	font-size: var(--kx-step-1);
	letter-spacing: -.015em;
	color: var(--kx-navy);
	text-decoration: none;
	line-height: 1.15;
}
.kx-brand:hover { color: var(--kx-navy); }
.kx-brand small {
	display: block;
	font-size: .6875rem;
	font-weight: 500;
	letter-spacing: .09em;
	text-transform: uppercase;
	color: var(--kx-ink-faint);
}

.kx-nav__list {
	list-style: none;
	margin: 0 0 0 auto;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: .35rem 1.15rem;
	align-items: center;
}

.kx-nav__item { position: relative; }

.kx-nav__link {
	display: inline-block;
	color: var(--kx-ink);
	text-decoration: none;
	padding-block: .35rem;
	border-bottom: 2px solid transparent;
}

.kx-nav__link:hover,
.kx-nav__link:focus-visible {
	color: var(--kx-navy);
	border-bottom-color: var(--kx-line);
}

.kx-nav__link[aria-current="page"] {
	color: var(--kx-navy);
	border-bottom-color: var(--kx-navy);
}

/*
 * The three submenus.
 *
 * details/summary carries the keyboard behaviour and the expanded state; the [open] rule and
 * the :hover rule together give the published site's behaviour without JavaScript. The marker
 * is removed because the reference shows none.
 */
.kx-nav__menu > summary {
	cursor: pointer;
	list-style: none;
}
.kx-nav__menu > summary::-webkit-details-marker { display: none; }
.kx-nav__menu > summary::marker { content: ''; }

.kx-nav__sub {
	list-style: none;
	margin: 0;
	padding: .5rem 0;
	position: absolute;
	top: 100%;
	left: 0;
	min-width: 14rem;
	background: var(--kx-paper);
	border: 1px solid var(--kx-line);
	border-radius: 3px;
	box-shadow: 0 8px 24px rgba(0, 0, 0, .1);
	z-index: 20;
}

.kx-nav__sub li { display: block; }
.kx-nav__sub .kx-nav__link {
	display: block;
	padding: .35rem 1rem;
	border-bottom: 0;
}

.kx-nav__menu:not([open]) .kx-nav__sub { display: none; }
.kx-nav__item--menu:hover .kx-nav__sub { display: block; }

/*
 * The call to action: the only white label in the bar on the published site, on the brand blue.
 */
.kx-nav__cta {
	background: var(--kx-blue);
	border-radius: 999px;
	padding: .5rem 1rem;
	border-bottom: 0;
}
.kx-nav__cta .kx-nav-item { color: #fff; }
.kx-nav__cta:hover,
.kx-nav__cta:focus-visible {
	background: var(--kx-navy);
	border-bottom-color: transparent;
}

.kx-lang {
	font-size: var(--kx-step--1);
	font-weight: 500;
	white-space: nowrap;
}

/* ------------------------------------------------------------------- type */

h1, h2, h3 {
	color: var(--kx-navy);
	line-height: 1.16;
	letter-spacing: -.018em;
	text-wrap: balance;
	margin: 0;
	font-weight: 700;
}

/*
 * No type here. A page title is t60-700 and an article title is t26-700, and the role
 * class beside .kx-title says which — this declaration beat both, because it is also a
 * single class and it comes later in the file.
 */
.kx-title { margin: 0; text-wrap: balance; }
h2 { font-size: var(--kx-step-3); }
h3 { font-size: var(--kx-step-2); letter-spacing: -.012em; }

.kx-eyebrow {
	margin: 0 0 .45rem;
	font-size: .6875rem;
	font-weight: 600;
	letter-spacing: .1em;
	text-transform: uppercase;
	color: var(--kx-red);
}

/*
 * Layout only for .kx-meta. The same class carries two roles: an article's date is t18-500 in
 * #999999 and a card's is t14-400 in rgba(0,0,0,.7), so size and colour come from the role
 * class beside it and never from here.
 */
.kx-meta {
	margin: 0;
	display: flex;
	flex-wrap: wrap;
	gap: .35rem .5rem;
	align-items: baseline;
}

.kx-byline {
	margin: 0;
	font-size: var(--kx-step--1);
	color: var(--kx-ink-muted);
}

/*
 * Layout only. .kx-lede sits beside a role class — .kx-hero-lede on a hero — and this rule's
 * colour beat it, because both are single classes and this one comes later. The size went for
 * the same reason.
 */
.kx-lede {
	max-width: var(--kx-measure);
}

/* --------------------------------------------------------------- sections */

.kx-section { padding-block: clamp(2.5rem, 6vw, 4.5rem); }
.kx-section + .kx-section { border-top: 1px solid var(--kx-line-soft); }

.kx-section__head {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 1rem;
	margin-bottom: 1.75rem;
	flex-wrap: wrap;
}
/* .kx-section-title owns the size. */

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

.kx-hero {
	background: var(--kx-navy);
	color: #fff;
	padding-block: clamp(3rem, 8vw, 6rem);
}
.kx-hero h1 { color: #fff; }
/* #fff, not 82% white: the reference does not soften it. Colour comes from
   .kx-hero-lede; only the spacing is set here. */
.kx-hero .kx-lede { margin-top: 1rem; }
.kx-hero .kx-eyebrow { color: rgba(255, 255, 255, .72); }

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

.kx-grid {
	display: grid;
	gap: 1.75rem 1.5rem;
	grid-template-columns: repeat(auto-fill, minmax(min(100%, 17rem), 1fr));
}

.kx-card { display: flex; flex-direction: column; gap: .8rem; min-width: 0; }

.kx-card__media {
	display: block;
	aspect-ratio: 3 / 2;
	overflow: hidden;
	border-radius: 3px;
	background: var(--kx-tint);
}
.kx-card__media img { width: 100%; height: 100%; object-fit: cover; }

.kx-card__body { display: flex; flex-direction: column; gap: .45rem; }
/* Type and colour belong to .kx-entry-title, from tokens.css. Declaring them here won
   the cascade — style.css loads second — and rendered card titles at 18px where the
   reference uses 26. */
.kx-card__title { margin: 0; }
.kx-card__title a { color: var(--kx-navy); text-decoration: none; }
.kx-card__title a:hover { text-decoration: underline; }
.kx-card__excerpt { margin: 0; font-size: var(--kx-step--1); color: var(--kx-ink-muted); }

/* ---------------------------------------------------------------- article */

.kx-article { padding-block: clamp(2rem, 5vw, 3.5rem); }
.kx-article__head { display: flex; flex-direction: column; gap: .6rem; }
.kx-article__hero { margin-block: 2rem; }
.kx-article__hero img { width: 100%; border-radius: 4px; }

/*
 * The body is Gutenberg's own markup, converted from Lexical. Only spacing and measure are
 * set here — the block classes are left alone so the editor and the front end agree.
 */
/*
 * No second cap. The reading column's width is set once, by .kx-measure on the article, from
 * the reference's measured 66% of the viewport. A max-width here would win at wide widths and
 * silently narrow the column below the target.
 */
.kx-body { max-width: none; }
.kx-body > * { margin-block: 0 1.15rem; }
.kx-body > *:last-child { margin-bottom: 0; }
.kx-body h2 { font-size: var(--kx-step-2); margin-top: 2.4rem; }
.kx-body h3 { font-size: var(--kx-step-1); margin-top: 2rem; }
.kx-body strong { font-weight: 600; }

.kx-body figure { margin-block: 2rem; }
.kx-body figure img { border-radius: 4px; }
.kx-body figcaption { font-size: var(--kx-step--1); color: var(--kx-ink-faint); margin-top: .5rem; }

.kx-body blockquote {
	margin: 2rem 0;
	padding-left: 1.15rem;
	border-left: 3px solid var(--kx-navy);
	font-size: var(--kx-step-1);
	color: var(--kx-ink);
}
.kx-body blockquote p:last-child { margin-bottom: 0; }

.kx-body .wp-block-embed { margin-block: 2rem; }

.kx-attachments {
	max-width: var(--kx-measure);
	margin-top: 3rem;
	padding-top: 1.25rem;
	border-top: 1px solid var(--kx-line);
}
.kx-attachments h2 { font-size: var(--kx-step-1); margin-bottom: .75rem; }
.kx-attachments ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }
.kx-attachments a { font-size: var(--kx-step--1); }

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

/* ------------------------------------------------------------------- footer
 *
 * Navy #000066 with 40px of vertical padding, measured 382px tall on /en/ at the widest
 * breakpoint and 405px on /id/ — the Indonesian mission sentence is longer, so the height is
 * recorded per locale in spec/nav.json rather than as one number.
 */
.kx-footer {
	margin-top: clamp(3rem, 8vw, 5rem);
	background: var(--kx-navy);
	padding-block: 40px;
	color: #fff;
}

/*
 * Two equal columns with a 100px gap, measured: 670 + 100 + 670 is exactly the 1440 container.
 * The gap is the number that mattered — 4rem looked reasonable and left the footer 175px short
 * at md, because the same 100px becomes vertical space once the columns stack.
 */
.kx-footer__inner {
	display: grid;
	gap: 100px;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	align-items: start;
}

/*
 * From 1199px down the links column spans the full width while the mission column keeps its
 * half — measured 406px wide against the links block's 922px in a 1024px viewport. Collapsing
 * both to one column instead made the mission text wrap on fewer lines and left the footer
 * 95px short of the reference.
 */
@media (max-width: 1199.98px) {
	.kx-footer__links { grid-column: 1 / -1; }
}

@media (max-width: 809.98px) {
	.kx-footer__inner { grid-template-columns: minmax(0, 1fr); }
}

/* 24px, as measured between the mission sentence and the social row. */
.kx-footer__mission { display: grid; gap: 24px; }
.kx-footer__mission p { margin: 0; max-width: 46rem; }

/*
 * Five 40px circles, as the reference has them. Ours were text labels, which is most of the
 * 24–194px the footer measured short of the reference at the narrower breakpoints.
 *
 * The label stays in the markup and is hidden visually rather than removed: it is the link's
 * accessible name, and an icon button with no name is a link that announces nothing.
 */
.kx-footer__social {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: .75rem;
}

.kx-footer__sociallink {
	display: grid;
	place-items: center;
	width: 40px;
	height: 40px;
	border: 1px solid rgba(255, 255, 255, .45);
	border-radius: 999px;
}

.kx-footer__sociallink:hover,
.kx-footer__sociallink:focus-visible {
	background: rgba(255, 255, 255, .12);
	border-color: #fff;
	text-decoration: none;
}

.kx-footer__sociallink .kx-footer-item {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

/* The initial, drawn from the label so nothing has to be shipped as an asset. */
.kx-footer__sociallink::before {
	content: attr(data-initial);
	font-weight: 700;
	font-size: 14px;
	line-height: 1;
	color: #fff;
}

/* 24px between "Useful links" and the list, as measured. */
.kx-footer__links p { margin: 0 0 24px; }
.kx-footer__links ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .4rem; }

.kx-footer a,
.kx-footer__link,
.kx-footer__sociallink {
	color: #fff;
	text-decoration: none;
}

.kx-footer a:hover,
.kx-footer a:focus-visible {
	color: #fff;
	text-decoration: underline;
}

.kx-footer__legal {
	margin-top: 2rem;
}
.kx-footer__legal p { margin: 0; }

/* -------------------------------------------------------------- utilities */

.kx-pagination { margin-top: 3rem; display: flex; gap: .5rem; flex-wrap: wrap; }
.kx-pagination .page-numbers {
	padding: .4rem .75rem;
	border: 1px solid var(--kx-line);
	border-radius: 3px;
	text-decoration: none;
	font-size: var(--kx-step--1);
}
.kx-pagination .page-numbers.current { background: var(--kx-navy); color: #fff; border-color: var(--kx-navy); }

.kx-notice {
	background: var(--kx-tint);
	border-left: 3px solid var(--kx-blue);
	padding: .9rem 1.1rem;
	font-size: var(--kx-step--1);
	color: var(--kx-ink-muted);
	max-width: var(--kx-measure);
}

/*
 * The diagnostics table the placeholder used to show. Kept reachable for the checks but out
 * of the reader's way; the JSON block above it is what the scripts actually parse.
 */
.kx-probe-table { display: none; }

@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* --- term navigation ------------------------------------------------------
 *
 * The row of sibling topics on a term archive. Borrows the pagination's shape rather than
 * inventing a second one: same border, same radius, same hit area, so a reader who has learned
 * one control has learned both.
 *
 * The current term is marked by weight and ground, not colour alone -- it also carries
 * aria-current, and a marker that only a sighted reader gets is not a marker.
 */
.kx-termnav {
	display: flex;
	flex-wrap: wrap;
	gap: .5rem;
	margin: 0 0 clamp(1.5rem, 4vw, 2.5rem);
}

.kx-termnav__item {
	display: inline-block;
	padding: .4rem .85rem;
	border: 1px solid var(--kx-line);
	border-radius: 999px;
	color: var(--kx-ink);
	font-size: var(--kx-step--1);
	text-decoration: none;
}

.kx-termnav__item:hover,
.kx-termnav__item:focus-visible {
	border-color: var(--kx-navy);
	color: var(--kx-navy);
}

.kx-termnav__item.is-here {
	background: var(--kx-navy);
	border-color: var(--kx-navy);
	color: #fff;
	font-weight: 600;
}
