/* ═══════════════════════════════════════════════════════════════════════════
   Nexus — News & Notice Board
   Shortcodes: [nexus_latest_news]  [nexus_latest_notices]

   Every class is prefixed .nx-board / .nx-row / .nx-btn / .nx-badge / .nx-pill
   and every rule is scoped under .nx-board, so nothing here can reach theme
   markup. Colour, radius and spacing come from tokens on .nx-board — no raw
   hex below the token block.

   Motion is owned by nexus-board.js (Motion 12, transform + opacity only).
   The only transitions declared here are colour/shadow ones, so the JS and the
   stylesheet never animate the same property.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Tokens ──────────────────────────────────────────────────────────────── */
.nx-board {
	/* Ink */
	--nx-ink:            #0d2137; /* deep navy, headings            15.3:1 on white */
	--nx-ink-2:          #3c4f63; /* slate, body copy                8.4:1 on white */
	--nx-muted:          #5e7086; /* meta                            5.1:1 on white */

	/* Accents */
	--nx-accent-news:    #b3423a; /* softened red                    5.2:1 on tile  */
	--nx-accent-notice:  #1d4ed8; /* institutional blue                            */
	--nx-primary:        #1a7476; /* teal, links + focus ring        5.5:1 on white */
	--nx-primary-deep:   #0b4547;
	--nx-cta:            #f0d060; /* gold, Download            10.8:1 against --nx-ink */
	--nx-cta-hover:      #e8c23f;

	/* Surfaces */
	--nx-surface:        #ffffff;
	--nx-bg:             #f6f8fa;
	--nx-tile:           #f2f6f9;
	--nx-line:           #e4eaf0;
	--nx-line-strong:    #d3dde6;

	/* File-type tints — always paired with a text label, never colour-only */
	--nx-pdf-bg:         #fef3f2;  --nx-pdf-fg:   #b42318; /* 6.1:1 */
	--nx-img-bg:         #eff4ff;  --nx-img-fg:   #175cd3; /* 5.4:1 */
	--nx-doc-bg:         #f2f4f7;  --nx-doc-fg:   #364152; /* 8.9:1 */
	--nx-link-bg:        #eef7f7;  --nx-link-fg:  #0f6b6d; /* 5.7:1 */
	--nx-new-bg:         #ecfdf3;  --nx-new-fg:   #05603a; /* 7.5:1 */

	/* Elevation — one scale, two steps */
	--nx-shadow-1: 0 1px 2px rgba(13, 33, 55, .05), 0 8px 24px -12px rgba(13, 33, 55, .12);
	--nx-shadow-2: 0 2px 6px rgba(13, 33, 55, .07), 0 18px 36px -18px rgba(13, 33, 55, .22);

	/* Radius */
	--nx-r-card: 20px;
	--nx-r-tile: 12px;
	--nx-r-btn:  10px;

	/* Spacing (4/8 scale) */
	--nx-sp-1: 4px;
	--nx-sp-2: 8px;
	--nx-sp-3: 12px;
	--nx-sp-4: 16px;
	--nx-sp-5: 20px;
	--nx-sp-6: 24px;
	--nx-sp-8: 32px;

	/* Keeps the notice action column identical on every row */
	--nx-actions-w: 208px;

	box-sizing: border-box;
	display: block;
	/* width + min-width matter when the panel is a flex or grid item: the card
	   below is a size container, so without them `margin-inline: auto` would
	   size the panel to fit-content instead of filling its column. */
	width: 100%;
	min-width: 0;
	max-width: 1200px;
	margin-inline: auto;
	color: var(--nx-ink-2);
}

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

/* ── Two-panel layout ─────────────────────────────────────────────────────
   Each shortcode renders one self-contained panel, so it works alone inside
   an Elementor column. Wrap both shortcodes in <div class="nx-board-grid">
   to get the side-by-side pair without a builder. */
.nx-board-grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: clamp(24px, 4vw, 48px);
	max-width: 1200px;
	margin-inline: auto;
	padding-inline: 16px;
}

.nx-board-grid > .nx-board {
	max-width: none;
	padding-inline: 0;
}

@media (min-width: 1024px) {
	.nx-board-grid { grid-template-columns: 1fr 1fr; }
}

/* ── Panel header ─────────────────────────────────────────────────────────── */
.nx-board__head {
	display: flex;
	align-items: flex-end;
	justify-content: space-between;
	gap: var(--nx-sp-4);
	margin-bottom: var(--nx-sp-5);
}

.nx-board__eyebrow {
	margin: 0 0 var(--nx-sp-2);
	font-size: 12px;
	line-height: 1.2;
	font-weight: 600;
	letter-spacing: .08em;
	text-transform: uppercase;
	color: var(--nx-muted);
}

.nx-board--news .nx-board__eyebrow   { color: var(--nx-accent-news); }
.nx-board--notice .nx-board__eyebrow { color: var(--nx-accent-notice); }

.nx-board__title {
	margin: 0;
	font-size: clamp(22px, 2.4vw, 28px);
	font-weight: 700;
	line-height: 1.1;
	letter-spacing: -.02em;
	color: var(--nx-ink);
}

.nx-board__viewall {
	display: inline-flex;
	align-items: center;
	gap: var(--nx-sp-1);
	flex: none;
	padding-bottom: 2px;
	font-size: 14px;
	font-weight: 600;
	line-height: 1.2;
	color: var(--nx-primary);
	text-decoration: none;
	border-radius: var(--nx-sp-1);
	transition: color .18s ease;
}

.nx-board__viewall:hover,
.nx-board__viewall:focus-visible { color: var(--nx-primary-deep); }
.nx-board__viewall svg { flex: none; }

/* ── Card ─────────────────────────────────────────────────────────────────── */
.nx-board__card {
	background: var(--nx-surface);
	border: 1px solid var(--nx-line);
	border-radius: var(--nx-r-card);
	box-shadow: var(--nx-shadow-1);
	overflow: hidden;
	/* Rows respond to the card's own width, not the viewport's, so a panel
	   sitting in a half-width column lays out like a narrow panel even on a
	   wide screen. */
	container-type: inline-size;
	container-name: nx-panel;
}

.nx-board__list {
	list-style: none;
	margin: 0;
	padding: 0;
}

.nx-board__list > li + li { border-top: 1px solid var(--nx-line); }

/* ── Row ──────────────────────────────────────────────────────────────────── */
.nx-row {
	position: relative;
	display: flex;
	gap: var(--nx-sp-4);
	align-items: flex-start;
	padding: var(--nx-sp-5);
	background: var(--nx-surface);
	transition: background-color .18s ease;
}

/* Elevation on hover fades through a pseudo-element so box-shadow is never
   animated on the row itself (the row's transform belongs to Motion). */
.nx-row::before {
	content: "";
	position: absolute;
	inset: -1px;
	border-radius: var(--nx-r-tile);
	box-shadow: var(--nx-shadow-2);
	opacity: 0;
	pointer-events: none;
	transition: opacity .2s ease;
}

.nx-row__main {
	flex: 1 1 auto;
	min-width: 0; /* lets long unbroken titles wrap instead of overflowing */
}

/* ── Row meta line ───────────────────────────────────────────────────────── */
.nx-row__meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--nx-sp-2);
	margin: 0 0 var(--nx-sp-2);
	font-size: 13px;
	line-height: 1.3;
	color: var(--nx-muted);
}

.nx-row__meta time { font-variant-numeric: tabular-nums; }

/* ── Row title & copy ────────────────────────────────────────────────────── */
.nx-row__title {
	margin: 0 0 var(--nx-sp-2);
	font-size: 17px;
	font-weight: 600;
	line-height: 1.35;
	letter-spacing: -.005em;
	color: var(--nx-ink);
	/* Robust against all-caps, long words and pasted URLs. */
	overflow-wrap: anywhere;
	display: -webkit-box;
	-webkit-line-clamp: 2;
	line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

.nx-row__title a {
	color: inherit;
	text-decoration: none;
	border-radius: var(--nx-sp-1);
}

.nx-row__title a:hover { color: var(--nx-primary); }

.nx-row__excerpt {
	margin: 0;
	font-size: 15px;
	line-height: 1.55;
	color: var(--nx-ink-2);
	overflow-wrap: anywhere;
	display: -webkit-box;
	-webkit-line-clamp: 2;
	line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

.nx-row--notice .nx-row__excerpt { -webkit-line-clamp: 1; line-clamp: 1; }

.nx-row__more {
	display: inline-flex;
	align-items: center;
	gap: var(--nx-sp-1);
	margin-top: var(--nx-sp-3);
	font-size: 14px;
	font-weight: 600;
	line-height: 1.2;
	color: var(--nx-primary);
}

.nx-row__more svg { flex: none; }

.nx-row__filemeta {
	margin: var(--nx-sp-2) 0 0;
	font-size: 13px;
	line-height: 1.3;
	color: var(--nx-muted);
	font-variant-numeric: tabular-nums;
}

/* ── News: date tile ─────────────────────────────────────────────────────── */
.nx-row__tile {
	flex: none;
	position: relative; /* contains .nx-sr-only */
	width: 56px;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 2px;
	padding: var(--nx-sp-2) var(--nx-sp-1);
	background: var(--nx-tile);
	border-radius: var(--nx-r-tile);
	font-variant-numeric: tabular-nums;
}

.nx-tile__day {
	font-size: 22px;
	font-weight: 700;
	line-height: 1;
	letter-spacing: -.02em;
	color: var(--nx-ink);
}

.nx-tile__mon {
	font-size: 11px;
	font-weight: 600;
	line-height: 1;
	letter-spacing: .06em;
	text-transform: uppercase;
	color: var(--nx-accent-news);
}

/* ── News: thumbnail (≥768px only, box reserved so nothing shifts) ───────── */
.nx-row__thumb {
	display: none;
	flex: none;
	width: 64px;
	height: 64px;
	aspect-ratio: 1 / 1;
	object-fit: cover;
	border-radius: var(--nx-r-tile);
	background: var(--nx-tile);
}

@media (min-width: 768px) {
	.nx-row__thumb { display: block; }
}

/* ── Notice: file-type badge ─────────────────────────────────────────────── */
.nx-badge {
	flex: none;
	width: 56px;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: var(--nx-sp-1);
	padding: var(--nx-sp-2) var(--nx-sp-1);
	border-radius: var(--nx-r-tile);
	background: var(--nx-doc-bg);
	color: var(--nx-doc-fg);
}

.nx-badge--pdf  { background: var(--nx-pdf-bg);  color: var(--nx-pdf-fg); }
.nx-badge--img  { background: var(--nx-img-bg);  color: var(--nx-img-fg); }
.nx-badge--doc  { background: var(--nx-doc-bg);  color: var(--nx-doc-fg); }
.nx-badge--link { background: var(--nx-link-bg); color: var(--nx-link-fg); }

.nx-badge svg { flex: none; }

.nx-badge__label {
	font-size: 10px;
	font-weight: 700;
	line-height: 1;
	letter-spacing: .06em;
}

/* ── Notice: "New" pill ──────────────────────────────────────────────────── */
.nx-pill {
	display: inline-flex;
	align-items: center;
	padding: 2px var(--nx-sp-2);
	border-radius: 999px;
	font-size: 11px;
	font-weight: 700;
	line-height: 1.5;
	letter-spacing: .04em;
	text-transform: uppercase;
	background: var(--nx-new-bg);
	color: var(--nx-new-fg);
}

.nx-pill--expired {
	background: var(--nx-doc-bg);
	color: var(--nx-doc-fg);
}

/* ── Notice: action column ───────────────────────────────────────────────
   Always two equal slots, so View sits in the same place whether or not a
   Download button follows it. The column never changes width between rows. */
.nx-row__actions {
	position: relative;
	z-index: 1; /* above the news stretched-link pattern, and clickable */
	flex: none;
	width: var(--nx-actions-w);
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: var(--nx-sp-2);
	align-items: start;
}

.nx-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--nx-sp-1);
	min-height: 44px;
	padding: 0 var(--nx-sp-3);
	border: 1px solid transparent;
	border-radius: var(--nx-r-btn);
	font-size: 14px;
	font-weight: 600;
	line-height: 1.2;
	text-align: center;
	text-decoration: none;
	cursor: pointer;
	transition: background-color .18s ease, border-color .18s ease, color .18s ease;
}

.nx-btn svg { flex: none; }

.nx-btn--view {
	grid-column: 1;
	background: var(--nx-surface);
	border-color: var(--nx-line-strong);
	color: var(--nx-ink-2);
}

.nx-btn--view:hover {
	border-color: var(--nx-primary);
	color: var(--nx-primary);
}

.nx-btn--dl {
	grid-column: 2;
	background: var(--nx-cta);
	border-color: var(--nx-cta);
	color: var(--nx-ink);
}

.nx-btn--dl:hover {
	background: var(--nx-cta-hover);
	border-color: var(--nx-cta-hover);
}

/* Visually hidden, still read aloud. Own class — never relies on the theme
   providing .screen-reader-text. */
.nx-board .nx-sr-only {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* ── Whole-row link target (news) ────────────────────────────────────────── */
.nx-row__link::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: inherit;
}

/* ── Focus ──────────────────────────────────────────────────────────────────
   Pure CSS, never animated, never removed. */
.nx-board a:focus-visible,
.nx-board button:focus-visible {
	outline: 2px solid var(--nx-primary);
	outline-offset: 2px;
}

/* The stretched link's own focus ring must trace the row, not the text. The
   selector has to out-specify `.nx-board a:focus-visible` above, or both rings
   draw at once. */
.nx-board .nx-row__link:focus-visible { outline: none; }
.nx-board .nx-row__link:focus-visible::after {
	outline: 2px solid var(--nx-primary);
	outline-offset: -3px;
}

/* ── Empty state ─────────────────────────────────────────────────────────── */
.nx-board__empty {
	display: flex;
	align-items: center;
	gap: var(--nx-sp-3);
	margin: 0;
	padding: var(--nx-sp-8) var(--nx-sp-5);
	font-size: 15px;
	line-height: 1.55;
	color: var(--nx-muted);
}

.nx-board__empty svg {
	flex: none;
	color: var(--nx-line-strong);
}

/* ── Hover (fine pointers only) ──────────────────────────────────────────── */
@media (hover: hover) and (pointer: fine) {
	.nx-row:hover { background: var(--nx-bg); }
	.nx-row:hover::before { opacity: 1; }
}

/* ── Reveal, gated on JS ────────────────────────────────────────────────────
   Nothing is hidden unless nexus-board.js has added .nx-motion-ready to
   <html> before first paint. If the script never runs, or Motion fails to
   load, the class is absent (or removed) and every row is already final. */
.nx-motion-ready .nx-board[data-nx-reveal="pending"] .nx-board__head,
.nx-motion-ready .nx-board[data-nx-reveal="pending"] .nx-board__list > li {
	opacity: 0;
}

/* ── Narrow panels ───────────────────────────────────────────────────────
   Below ~620px of card width there isn't room for a 208px action column and
   a readable title beside it, so the actions drop under the text. The column
   keeps its two equal slots, so View stays put from row to row either way.
   Browsers without container-query support simply keep the side-by-side
   layout, which is still usable. */
@container nx-panel (max-width: 620px) {
	.nx-row--notice { flex-wrap: wrap; }

	/* Badge and text keep their columns; only the actions take a new line,
	   indented to line up under the text rather than under the badge. */
	.nx-row--notice .nx-row__main { flex: 1 1 200px; }

	.nx-row--notice .nx-row__actions {
		flex: 0 0 calc(100% - 56px - var(--nx-sp-4));
		width: auto;
		max-width: 320px;
		margin-top: var(--nx-sp-1);
		margin-inline-start: calc(56px + var(--nx-sp-4));
	}
}

/* ── Responsive ──────────────────────────────────────────────────────────── */
@media (max-width: 767px) {
	.nx-board { padding-inline: 16px; }
	.nx-board-grid > .nx-board { padding-inline: 0; }

	.nx-row {
		flex-wrap: wrap;
		padding: var(--nx-sp-4);
		gap: var(--nx-sp-3);
	}

	.nx-row__main { flex: 1 1 100%; width: 100%; }

	/* Tile / badge sit above the text, not beside it. */
	.nx-row__tile,
	.nx-badge {
		flex-direction: row;
		width: auto;
		min-width: 0;
		gap: var(--nx-sp-2);
		padding: var(--nx-sp-1) var(--nx-sp-2);
		align-self: flex-start;
	}

	.nx-row__tile { order: -1; }
	.nx-badge     { order: -1; }
	.nx-tile__day { font-size: 16px; }

	.nx-row__actions {
		flex: 0 0 100%;
		width: 100%;
		max-width: 320px;
		margin-inline-start: 0;
	}
}

/* ── Reduced motion ─────────────────────────────────────────────────────────
   The JS also checks this and skips every transform; these rules make sure
   the CSS side matches even if the script is mid-flight. */
@media (prefers-reduced-motion: reduce) {
	.nx-board *,
	.nx-board *::before,
	.nx-board *::after {
		transition-duration: .01ms !important;
		animation-duration: .01ms !important;
	}

	/* Hover stays a colour/shadow change only. */
	@media (hover: hover) and (pointer: fine) {
		.nx-row:hover::before { opacity: 1; transition: none; }
	}
}
