/* ==================================================================
   COMPONENTS — reusable UI patterns.

   Rule of thumb for "does this belong here or in pages.css?":
   if you could imagine using this class on more than one page (even
   if today it only appears on one), it's a component. If it only
   makes sense in the context of one specific page's content, it's a
   page style.

   Every value below should trace back to a token in tokens.css.
   No hex codes, no raw pixel numbers outside the spacing/radius
   scale. That's what makes this file safe to skim without re-reading
   the whole thing every time.
   ================================================================== */

/* tokens.css is intentionally NOT re-imported here — see the note in
   reset.css. main.css already loads it earlier in the cascade. */


/* ------------------------------------------------------------------
   Accessibility utilities
   Global focus styling (so every interactive element gets a
   consistent, visible focus ring against the dark background,
   regardless of browser/OS defaults) plus the skip-link, which is
   the first focusable element on every page and lets keyboard users
   jump past the nav straight to <main>.
   ------------------------------------------------------------------ */

:focus-visible {
	outline: var(--space-3xs) solid var(--colour-secondary);
	outline-offset: var(--space-3xs);
	border-radius: var(--radius-sm);
}

.skip-link {
	position: absolute;
	top: var(--space-sm);
	left: var(--space-sm);
	z-index: 1000;
	padding: var(--space-2xs) var(--space-sm);
	background: var(--colour-surface-subtle);
	color: var(--colour-tertiary);
	border-radius: var(--radius-sm);
	text-decoration: none;
	font-size: var(--font-size-body-md);
	transform: translateY(-200%);
	transition: var(--hover-transition);
}

.skip-link:focus-visible {
	transform: translateY(0);
}


/* ------------------------------------------------------------------
   Layout shell
   The wrapper every "inner page" (as opposed to the homepage) sits
   inside: the scrollable area next to the side nav, plus the sticky
   title bar at its top.
   ------------------------------------------------------------------ */

.content-general {
	width: 100%;
	display: flex;
	flex-direction: column;
	justify-content: stretch;
	margin-left: var(--nav-width);
}

.content {
	padding: var(--space-2xl);
	display: flex;
	flex-direction: column;
	justify-content: center;
	gap: var(--space-lg);
	max-width: var(--max-content-width);
	margin: 0 auto;
	/* Centres the column on wide/ultrawide screens. The side nav
	   occupies var(--nav-width) on the left; the flex body layout
	   means this auto-margin distributes the remaining space evenly
	   on both sides of the content column. */
	width: 100%;
}

.content h2 {
	scroll-margin-top: 140px;
	/* Sized for the desktop sticky title bar height. Overridden
	   below for mobile where the top-bar is ~56px. */
}

@media (max-width: 900px) {
	.content h2 {
		scroll-margin-top: 72px;
	}
}

.page-title-box {
	padding: var(--space-lg);
	border-bottom: 1px solid var(--colour-surface-subtle);
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	gap: var(--space-sm);
	justify-content: flex-start;
	align-items: center;
	position: sticky;
	top: 0;
	z-index: 10;
	background: var(--colour-surface-background);
	overflow: hidden;
}

.page-title-box h1 {
	min-width: 0;
	word-break: break-word;
}

@media (max-width: 900px) {
	.content-general {
		margin-left: 0;
	}

	.content {
		padding: var(--space-lg);
	}

	/* Tighten the title box at tablet — the side nav is gone so
	   --space-lg (32px) padding is excessive. Also prevent wrapping
	   so the arrow stays inline with the title at these widths. */
	.page-title-box {
		padding: var(--space-sm) var(--space-md);
		flex-wrap: nowrap;
	}
}

@media (max-width: 600px) {
	.content {
		padding: var(--space-md);
		gap: var(--space-md);
	}

	.page-title-box {
		padding: var(--space-xs) var(--space-md);
	}
}

@media (max-width: 400px) {
	.content {
		padding: var(--space-sm);
	}

	.page-title-box {
		padding: var(--space-xs) var(--space-sm);
	}
}


/* ------------------------------------------------------------------
   Buttons
   Usage: <a class="button primary md">…</a>
   - colour variant: primary | secondary | tertiary
   - size variant (icon buttons): md | sm
   - state: disabled
   - .button.text is the filled, text-label CTA style (e.g. "View
     project" on the homepage) — same family, different look.
   ------------------------------------------------------------------ */

.button {
	display: inline-block;
	align-content: center;
	transition: var(--hover-transition);
}

.button:hover {
	opacity: var(--hover-opacity);
}

.button.md svg {
	width: 32px;
	height: 32px;
}

/* Icon-only buttons (nav social links, burger, back-to-projects arrow)
   previously had a 32x32px hit area — exactly the icon's own size,
   with zero padding. Below the ~44x44px minimum recommended touch
   target. This keeps the icon's visual size the same and just adds
   clickable space around it. */
.button.md {
	padding: 6px;
}

.button.sm svg {
	width: 24px;
	height: 24px;
}

.button.primary {
	color: var(--colour-primary);
	fill: var(--colour-primary);
}

.button.secondary {
	color: var(--colour-secondary);
	fill: var(--colour-secondary);
}

.button.tertiary {
	color: var(--colour-tertiary);
	fill: var(--colour-tertiary);
}

.button.disabled {
	opacity: 0.5;
	pointer-events: none;
	cursor: not-allowed;
}

.button.text {
	width: fit-content;
	padding: var(--space-xs) var(--space-md);
	background: var(--colour-secondary);
	color: var(--colour-surface-background);
	font-size: var(--font-size-body-md);
	font-weight: var(--font-weight-bold);
	border-radius: var(--radius-sm);
	text-decoration: none;
	cursor: pointer;
	box-shadow: var(--shadow-control);
}

/* .button.text.outline — a lower-emphasis sibling to .button.text, for
   secondary CTAs that shouldn't compete with the filled primary action
   (e.g. "More about me" next to "Check out my work" on the homepage). */
.button.text.outline {
	background: transparent;
	color: var(--colour-secondary);
	border: 1px solid var(--colour-secondary);
}

.button-row {
	display: flex;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: var(--space-sm);
	width: 100%;
}

.button-row .button.text {
	min-width: 120px;
	text-align: center;
}


/* ------------------------------------------------------------------
   Nav (desktop side nav)
   ------------------------------------------------------------------ */

.whole-nav {
	width: var(--nav-width);
	height: 100vh;
	position: fixed;
	padding: var(--space-lg);
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	border-right: 1px solid var(--colour-surface-subtle);
}

.whole-nav h3 {
	font-size: var(--font-size-header-lg);
	font-weight: var(--font-weight-bold);
	color: var(--colour-tertiary);
}

.nav-list {
	display: flex;
	flex-direction: column;
	gap: var(--space-lg);
	align-items: flex-end;
}

.nav-list a {
	color: var(--colour-tertiary);
	font-size: var(--font-size-body-md);
	text-decoration: none;
	border-bottom: 3px solid transparent;
	transition: var(--hover-transition);
}

.nav-list a:hover {
	opacity: var(--hover-opacity);
}

.nav-list a.active {
	border-bottom: 3px solid var(--colour-secondary);
}

.social-buttons-container {
	display: flex;
	flex-direction: row;
	justify-content: flex-start;
	gap: var(--space-sm);
	width: fit-content;
}

/* Groups the vibe toggle with the social buttons at the bottom of the
   nav, so they read as one cluster rather than being spread apart by
   .whole-nav's justify-content: space-between. Same idea for the
   mobile drawer's .drawer-footer below, which js/vibe.js builds by
   wrapping the existing .drawer-social in place. */
.nav-footer,
.drawer-footer {
	display: flex;
	flex-direction: column;
	gap: var(--space-sm);
}

.nav-footer {
	align-items: flex-end;
}

.drawer-footer {
	align-items: flex-start;
}


/* ------------------------------------------------------------------
   Vibe toggle
   Segmented control that flips the site between the default vibe and
   a muted "corporate" vibe (see the data-vibe block in tokens.css and
   js/vibe.js, which drives this markup and persists the choice).
   Usage: a single fixed markup block, injected by js/vibe.js into
   both the desktop nav (inside .nav-footer) and the mobile drawer
   (inside .drawer-footer) — see vibeToggleMarkup() in vibe.js.
   ------------------------------------------------------------------ */

.vibe-toggle-group {
	display: flex;
	flex-direction: column;
	gap: var(--space-2xs);
}

.nav-footer .vibe-toggle-group,
.drawer-footer .vibe-toggle-group {
	align-self: stretch;
	/* Overrides the parent footer's own alignment (flex-end / flex-start,
	   used for the social icons) so the toggle fills the full width of
	   the nav instead of shrink-wrapping to its content. */
}

.vibe-toggle-label {
	font-family: var(--font-family-body);
	font-size: var(--font-size-body-md);
	color: var(--colour-tertiary);
}

.vibe-toggle {
	position: relative;
	display: flex;
	flex-direction: column;
	width: 100%;
	background: var(--colour-surface-subtle);
	border-radius: var(--radius-md);
	padding: var(--space-3xs);
	box-shadow: var(--shadow-control);
}

.vibe-toggle-thumb {
	position: absolute;
	left: var(--space-3xs);
	right: var(--space-3xs);
	background: var(--colour-secondary);
	border-radius: var(--radius-sm);
	box-shadow: var(--shadow-control);
	/* top/height are set directly by js/vibe.js (positionThumb), not
	   CSS — at full width and 14px body-text size, "Unhinged
	   Technicolour" wraps to two lines while "HR Approved" stays on
	   one, so the two rows are genuinely different heights. A fixed
	   50%-of-container split (or a transform-based slide, which
	   assumes equal halves) can't represent that; only measuring the
	   active row's real box and matching it can. */
	transition: top 0.2s ease, height 0.2s ease;
}

/* Corporate gets its own accent for the thumb (and the active nav
   link, just below) instead of reusing the navy secondary colour —
   the navy stays the base for headings/body text, this is just the
   one deliberate spot of colour on top of it. */
:root[data-vibe="corporate"] .vibe-toggle-thumb {
	background: var(--colour-accent);
}

.vibe-toggle-option {
	position: relative;
	z-index: 1;
	display: flex;
	align-items: center;
	justify-content: center;
	text-align: center;
	border: none;
	background: transparent;
	padding: var(--space-xs) var(--space-sm);
	font-family: var(--font-family-body);
	/* Matches the rest of the nav's body text (.nav-list a, p) instead
	   of a shrunk-down caption size — now that the pill fills the nav's
	   full width and wrapping is fine, there's no need to size the text
	   down just to keep it on one line. */
	font-size: var(--font-size-body-md);
	font-weight: var(--font-weight-bold);
	color: var(--colour-tertiary);
	cursor: pointer;
	transition: var(--hover-transition), color 0.2s ease;
}


.vibe-toggle-option:hover {
	opacity: var(--hover-opacity);
}

.vibe-toggle-option[aria-pressed="true"] {
	color: var(--colour-surface-background);
}

:root[data-vibe="corporate"] .nav-list a.active,
:root[data-vibe="corporate"] .drawer-nav-list a.active {
	border-bottom-color: var(--colour-accent);
}

.whole-nav h3 a {
	color: inherit;
	text-decoration: none;
}

/* Hidden at desktop; shown at mobile via the media query below.
   Base rule must come BEFORE the media query — identical specificity
   means last-in-source wins, so if it came after, display:none would
   override the show rule even at mobile widths. */
.burger-button {
	display: none;
	background: none;
	border: none;
	cursor: pointer;
}

@media (max-width: 900px) {

	/* Burger button — fixed to top-right so it's always in the same
	   position regardless of scroll, and independent of the fetched
	   nav content. z-index 201 keeps it above the sticky nav bar (200). */
	.burger-button {
		display: inline-flex;
		align-items: center;
		justify-content: center;
		position: fixed;
		top: 6px;
		right: var(--space-sm);
		z-index: 201;
	}

	.whole-nav {
		width: 100%;
		min-width: unset;
		height: auto;
		min-height: 56px;
		position: sticky;
		top: 0;
		flex-direction: row;
		justify-content: space-between;
		align-items: center;
		padding: var(--space-xs) var(--space-sm);
		border-right: none;
		border-bottom: 1px solid var(--colour-surface-subtle);
		z-index: 200;
		background: var(--colour-surface-background);
	}

	/* Nav links, vibe toggle, and social icons are all hidden at
	   mobile — they move into the drawer instead (the drawer gets
	   its own injected copy of the toggle, see js/vibe.js). */
	.whole-nav .nav-list,
	.whole-nav .nav-footer {
		display: none;
	}
}

@media (max-width: 400px) {
	.burger-button {
		padding: 4px;
		top: 8px;
	}
}


/* ------------------------------------------------------------------
   Mobile drawer (nav, <900px)
   ------------------------------------------------------------------ */

.drawer-overlay {
	position: fixed;
	inset: 0;
	background: rgba(24, 25, 37, 0.7);
	z-index: 300;
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.3s ease;
}

.drawer-overlay.open {
	opacity: 1;
	pointer-events: auto;
}

/* Prevent body scroll while drawer is open */
body.drawer-open {
	overflow: hidden;
}

.mobile-drawer {
	position: fixed;
	top: 0;
	right: 0;
	width: 280px;
	height: 100vh;
	background: var(--colour-surface-background);
	border-left: 1px solid var(--colour-surface-subtle);
	padding: var(--space-xl) var(--space-lg);
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	z-index: 400;
	transform: translateX(100%);
	transition: transform 0.3s ease;
}

.mobile-drawer.open {
	transform: translateX(0);
}

.drawer-nav-list {
	display: flex;
	flex-direction: column;
	gap: var(--space-lg);
	align-items: flex-start;
}

.drawer-nav-list a {
	color: var(--colour-tertiary);
	font-size: var(--font-size-header-md);
	font-weight: var(--font-weight-bold);
	text-decoration: none;
	border-bottom: 3px solid transparent;
	transition: var(--hover-transition);
	font-family: var(--font-family-body);
}

.drawer-nav-list a:hover {
	opacity: var(--hover-opacity);
}

.drawer-nav-list a.active {
	border-bottom: 3px solid var(--colour-secondary);
}

.drawer-social {
	display: flex;
	flex-direction: row;
	gap: var(--space-sm);
}


/* ------------------------------------------------------------------
   Table of contents (toc)
   A <details>/<summary> element that expands on hover.
   ------------------------------------------------------------------ */

.toc {
	position: fixed;
	top: var(--space-lg);
	right: var(--space-lg);
	width: 160px;
	overflow: hidden;
	background: var(--colour-surface-subtle);
	padding: var(--space-sm) var(--space-md);
	z-index: 100;
	border-radius: var(--radius-md);
	transition: var(--hover-transition);
}

.toc[open] {
	width: 300px;
}

.toc[open] .chevron {
	transform: rotate(90deg);
}

.chevron {
	fill: var(--colour-secondary);
	transition: var(--hover-transition);
}

.toc summary {
	cursor: pointer;
	font-weight: bold;
	font-size: var(--font-size-header-sm);
	color: var(--colour-secondary);
	list-style: none;
	display: flex;
	align-items: center;
	gap: var(--space-2xs);
	transition: var(--hover-transition);
}

.toc summary:hover {
	opacity: var(--hover-opacity);
}

.toc summary svg {
	width: 20px;
	height: 20px;
	fill: var(--colour-secondary);
}

.toc .toc-content {
	max-height: 0;
	overflow: hidden;
	opacity: 0;
	transition: var(--hover-transition);
}

.toc[open] .toc-content {
	max-height: 1000px;
	opacity: 1;
	transition-delay: 0.25s, 0.25s;
}

.toc div {
	padding: 0 var(--space-sm);
}

.toc ul {
	list-style: decimal;
	margin-left: var(--space-sm);
	display: flex;
	flex-direction: column;
	padding: var(--space-2xs) 0 0 0;
	gap: var(--space-2xs);
}

.toc a {
	color: var(--colour-tertiary);
	text-decoration: none;
	font-size: var(--font-size-body-md);
	transition: var(--hover-transition);
}

.toc a:hover {
	opacity: var(--hover-opacity);
}

@media (max-width: 900px) {

	/* No room for a floating toc once the nav is a top bar. */
	.toc {
		display: none;
	}
}


/* ------------------------------------------------------------------
   Masonry wall
   Usage:
     <section class="masonry-section">
       <h2>Section title</h2>
       <div class="masonry-wall">
         <figure class="masonry-item">
           <img class="zoomable" src="…" alt="…">
           <figcaption>…</figcaption>  (optional — omit for no caption)
         </figure>
         …
       </div>
     </section>

   A CSS-columns masonry — no JS layout engine, no fixed row heights,
   so portrait and landscape images sit together at their natural
   aspect ratio and the wall just reflows as images are added or
   removed. Pairs with the existing .zoomable/lightbox setup: add
   class="zoomable" to any image in the wall and it opens full-size
   on click, exactly like every other project-page screenshot.

   One trade-off of the pure-CSS approach, worth knowing about: fill
   order is column-first (top-to-bottom, then wraps to the next
   column) rather than strict left-to-right reading order. That's the
   right call here — there's no narrative order to a wall of shots —
   but it's not what you'd want for step-by-step content.
   ------------------------------------------------------------------ */

.masonry-section h2 {
	margin-top: calc(2 * var(--space-lg));
	margin-bottom: var(--space-md);
}

@media (max-width: 600px) {
	.masonry-section h2 {
		margin-top: var(--space-lg);
		margin-bottom: var(--space-sm);
	}
}

.masonry-wall {
	column-count: 4;
	column-gap: var(--space-lg);
	width: 100%;
}

.masonry-item {
	break-inside: avoid;
	margin-bottom: var(--space-lg);
}

.masonry-item img {
	display: block;
	width: 100%;
	border-radius: var(--radius-sm);
}

.masonry-item figcaption {
	/* figcaption's primary-colour italic look already comes from
	   tokens.css — just tightening the spacing here so it reads as
	   part of the tile rather than a full section caption. */
	margin-top: var(--space-2xs);
}

@media (max-width: 900px) {
	.masonry-wall {
		column-count: 3;
	}
}

@media (max-width: 600px) {
	.masonry-wall {
		column-count: 2;
		column-gap: var(--space-md);
	}

	.masonry-item {
		margin-bottom: var(--space-md);
	}
}

@media (max-width: 400px) {
	.masonry-wall {
		column-count: 1;
	}
}


/* ------------------------------------------------------------------
   Table
   Usage: plain <table>/<tr>/<td>/<th> — no class needed.
   (Merged in from the old styles-page-specific.css, which only
   existed to hold this.)
   ------------------------------------------------------------------ */

table {
	border-collapse: collapse;
	width: 100%;
	color: var(--colour-secondary);
	border: 1px solid var(--colour-surface-subtle);
	font-size: var(--font-size-body-md);
}

td {
	border: 1px solid var(--colour-surface-subtle);
	padding: var(--space-2xs);
	text-align: left;
}

th {
	border: 1px solid var(--colour-surface-subtle);
	padding: var(--space-2xs);
	text-align: left;
	background-color: var(--colour-surface-subtle);
}

.comp-matrix {
	width: 100%;
}


/* ------------------------------------------------------------------
   List item / "picture row" pattern (.pli)
   Usage:
     <a class="pli">
       <img src="…">
       <div class="pli-text-container">…</div>
     </a>
   An image-plus-text row that stacks on mobile. Currently used for
   the projects list, but it's generic enough to reuse anywhere you
   need a clickable image + text row.
   ------------------------------------------------------------------ */

.pli {
	padding: var(--space-lg);
	display: flex;
	flex-direction: row;
	gap: var(--space-lg);
	align-items: center;
	border-bottom: 1px solid var(--colour-surface-subtle);
	text-decoration: none;
	transition: var(--hover-transition);
}

.pli:hover {
	background: var(--colour-surface-subtle);
	opacity: 100%;
}

.pli:focus-visible {
	outline: var(--space-3xs) solid var(--colour-secondary);
	outline-offset: -6px;
	/* pulls it inside the row instead of overflowing the edges */
	background: var(--colour-surface-subtle);
	border-radius: 0;
	/* optional: reuse the hover treatment too */
}

.pli img {
	width: 45%;
	aspect-ratio: 16/9;
	object-fit: cover;
	flex-shrink: 0;
	max-width: 640px;
}

.pli-text-container {
	display: flex;
	flex-direction: column;
	justify-content: flex-start;
	gap: var(--space-sm);
	width: 55%;
	max-width: 764px;
}

@media (max-width: 900px) {
	.pli {
		flex-direction: column;
		gap: var(--space-sm);
	}

	.pli img {
		width: 100%;
		max-width: none;
	}

	.pli-text-container {
		width: 100%;
	}
}

@media (max-width: 600px) {
	.pli {
		padding: var(--space-md);
	}
}

@media (max-width: 400px) {
	.pli {
		padding: var(--space-sm);
		gap: var(--space-xs);
	}
}


/* ------------------------------------------------------------------
   Attribute list (tag pills — e.g. "Figma", "UX research")
   Usage: <ul class="attribute-list"><li><p>Tag</p></li>…
   ------------------------------------------------------------------ */

.attribute-list {
	display: flex;
	flex-flow: row wrap;
	justify-content: flex-start;
	gap: var(--space-sm);
}

.attribute-list p {
	color: var(--colour-primary);
	font-size: var(--font-size-body-sm);
}


/* ------------------------------------------------------------------
   TL;DR box (project page summary callout)
   ------------------------------------------------------------------ */

.tldr {
	display: flex;
	flex-direction: row;
	gap: var(--space-lg);
	justify-content: flex-start;
	padding: var(--space-lg);
	border: var(--colour-surface-subtle) 1px solid;
	align-content: center;
}

.tldr-title-box {
	display: flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
}

.tldr-title-box h2 {
	transform: rotate(-45deg);
	white-space: nowrap;
	margin: 0;
}

.tldr p {
	color: var(--colour-secondary);
}

.tldr sub {
	color: var(--colour-primary);
	font-size: var(--font-size-body-xs);
}

@media (max-width: 900px) {
	.tldr {
		flex-direction: column;
		gap: var(--space-sm);
	}

	.tldr-title-box h2 {
		transform: none;
	}
}


/* ------------------------------------------------------------------
   Glance stats (project page "at a glance" numbers)
   ------------------------------------------------------------------ */

.glance-stats {
	display: flex;
	gap: var(--space-lg);
	width: 100%;
	padding-left: 0;
}

.glance-stats li {
	list-style: none;
	flex: 1;
	color: var(--colour-secondary);
}

.sub-header {
	color: var(--colour-primary);
	font-size: var(--font-size-body-md);
	/* font-weight: var(--font-weight-bold); */
	text-transform: uppercase;

}

@media (max-width: 900px) {
	.glance-stats {
		flex-direction: column;
		gap: var(--space-xs);
	}
}


/* ------------------------------------------------------------------
   Lightbox
   Usage: add class="zoomable" to any <img> you want to open large
   on click. That's the only thing you touch per-image — the
   <dialog>, the backdrop, and the click handling are all wired up
   once by js/lightbox.js (loaded the same way as js/nav.js).
 
   The backdrop colour is --void written out as rgba() rather than
   var(--colour-surface-background), because CSS can't feed a var()
   into rgba()'s alpha channel unless the token is stored as raw
   numbers. .drawer-overlay already does the same thing a few
   sections up — this just matches that existing precedent.
   ------------------------------------------------------------------ */

.zoomable {
	cursor: zoom-in;
	transition: var(--hover-transition);
}

.zoomable:hover {
	opacity: var(--hover-opacity);
}

.lightbox {
	position: fixed;
	inset: 0;
	margin: auto;
	border: none;
	padding: 0;
	background: transparent;
	max-width: 90vw;
	max-height: 90vh;
	outline: none;
}

.lightbox::backdrop {
	background: rgba(24, 25, 37, 0.85);
}

.lightbox img {
	display: block;
	width: 90vw;
	height: 90vh;
	object-fit: contain;
	cursor: zoom-out;
}

@media (max-width: 600px) {
	.lightbox {
		max-width: 96vw;
		max-height: 80vh;
	}

	.lightbox img {
		width: 96vw;
		height: 80vh;
	}
}


/* ------------------------------------------------------------------
   Generic layout helpers
   Low-level building blocks for stacking content — reach for these
   before writing a one-off flex wrapper.
   ------------------------------------------------------------------ */

.titleandtext {
	display: flex;
	flex-direction: column;
	gap: var(--space-2xs);
	justify-content: stretch;
	width: 100%;
}

.section-row {
	display: flex;
	flex-direction: row;
	gap: var(--space-2xl);
	justify-content: flex-start;
	height: fit-content;
	width: 100%;
}

th {
	color: var(--colour-tertiary);
}

td {
	color: var(--colour-tertiary);
}

@media (max-width: 768px) {

	/* Wide tables (e.g. the MSc platform comparison) can't compress
	   to fit a phone screen without becoming unreadable. Make them
	   independently scrollable rather than breaking the page layout. */
	table {
		display: block;
		overflow-x: auto;
		-webkit-overflow-scrolling: touch;
		max-width: 100%;
	}
}



.image-grid {
	display: grid;
	width: 100%;
}

.image-grid.one-up {
	grid-template-columns: repeat(1, minmax(0, 1fr));
	border: 1px solid var(--colour-surface-subtle);
}

.image-grid.two-up {
	grid-template-columns: repeat(2, minmax(0, 1fr));
	border: 1px solid var(--colour-surface-subtle);
}

.image-grid.three-up {
	grid-template-columns: repeat(3, minmax(0, 1fr));
	border: 1px solid var(--colour-surface-subtle);
}

.image-grid.four-up {
	grid-template-columns: repeat(4, minmax(0, 1fr));
	border: 1px solid var(--colour-surface-subtle);
}



.image-card {
	display: flex;
	flex-direction: column;
	gap: var(--space-xs);
	padding: var(--space-md);
}

.image-card img {
	width: auto;
	height: auto;
	max-height: 600px;
	display: block;
	object-fit: contain;
	border-radius: var(--radius-sm);
}


.text-grid {
	display: grid;
	width: 100%;
}

.text-grid.two-up {
	grid-template-columns: repeat(2, minmax(0, 1fr));
	column-gap: var(--space-2xl);
}

.text-grid.two-up-asym {
	grid-template-columns: minmax(0, 6fr) minmax(0, 4fr);
	column-gap: var(--space-2xl);
}

.text-card {
	display: flex;
	flex-direction: column;
}

@media (max-width: 600px) {

	.text-grid.two-up,
	.text-grid.two-up-asym {
		grid-template-columns: 1fr;
		column-gap: 0;
		row-gap: var(--space-lg);
	}
}




@media (max-width: 900px) {

	.image-grid.two-up,
	.image-grid.three-up,
	.image-grid.four-up,
	.split-image {
		grid-template-columns: 1fr;
		flex-direction: column;
	}
}

@media (max-width: 768px) {
	.image-grid.four-up {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 600px) {
	.image-grid.four-up {
		grid-template-columns: 1fr;
	}

	.image-card {
		padding: var(--space-sm);
	}
}

.section-col {
	display: flex;
	flex-direction: column;
	gap: var(--space-lg);
	justify-content: flex-start;
}

.equal-list {
	display: flex;
	width: 100%;
	gap: var(--space-xl);
	padding-left: 40px;
}

.equal-list li {
	flex: 1;
}

@media (max-width: 600px) {
	.equal-list {
		flex-direction: column;
		gap: var(--space-md);
		padding-left: 0;
	}
}

@media (max-width: 900px) {
	.section-row {
		flex-direction: column;
		gap: var(--space-lg);
	}
}


/* ------------------------------------------------------------------
   Tooltip
   Usage: wrap any inline element with .tooltip, add a sibling
   <span class="tooltip-text">Your text here</span>
   ------------------------------------------------------------------ */

.tooltip {
	position: relative;
	display: inline-block;
	cursor: help;
	border-bottom: 1px dashed var(--colour-accent);
}

.tooltip-text {
	visibility: hidden;
	opacity: 0;
	position: absolute;
	bottom: calc(100% + 8px);
	left: 50%;
	transform: translateX(-50%);
	background: var(--colour-accent);
	color: var(--white);
	font-size: var(--font-size-body-sm);
	line-height: 1.4;
	padding: var(--space-2xs) var(--space-xs);
	border-radius: var(--radius-sm);
	width: max-content;
	max-width: 240px;
	white-space: normal;
	pointer-events: none;
	transition: opacity 0.15s ease, visibility 0.15s ease;
	z-index: 500;
}

/* Arrow pointing down toward the trigger */
.tooltip-text::after {
	content: '';
	position: absolute;
	top: 100%;
	left: 50%;
	transform: translateX(-50%);
	border: 6px solid transparent;
	border-top-color: var(--colour-accent);
}

.tooltip:hover .tooltip-text,
.tooltip:focus-within .tooltip-text,
.tooltip.tooltip-active .tooltip-text {
	visibility: visible;
	opacity: 1;
}

abbr.tooltip {
	text-decoration: none;
}