/* ==========================================================================
   CPE Website 2026 — base layout & component styles
   Companion to theme.json (colors/typography live there as CSS vars).
   ========================================================================== */

* { box-sizing: border-box; }

body {
	margin: 0;
	background: var(--wp--preset--color--bg-page);
	color: var(--wp--preset--color--primary);
}

a { text-decoration: none; color: inherit; }

img { max-width: 100%; display: block; }

.cpe-container {
	max-width: 1440px;
	margin-inline: auto;
}

/* Every Landing section is 50px top + 50px bottom inside a 160px gutter
   (Figma 617:3121 — Frame 17/39/38/37/40/41 all follow this rhythm). The
   margin reset stops WordPress's is-layout-flow block gap from adding a
   second, uneven gutter on top of the padding. */
.cpe-section {
	width: 100%;
	padding: 50px 160px;
	margin-block: 0;
}

.cpe-section-inner {
	display: flex;
	flex-direction: column;
	gap: 20px;
	width: 100%;
}

/* These containers all lay themselves out with `gap`, but every one of them is
   a core/group and therefore also carries `is-layout-flow`, which injects a
   24px margin-block-start between children. Left alone that turns every gap
   into gap+24 and — inside a centred flex row like the header — knocks the
   children off the shared centre line entirely. See CLAUDE.md §8.14. */
.cpe-header > *,
.cpe-brand > *,
.cpe-header-right > *,
.cpe-lang-switch > *,
.cpe-section-inner > *,
.cpe-section-head > *,
.cpe-degree-group > *,
.cpe-degree-label-row > *,
.cpe-program-cards > *,
.cpe-program-card > *,
.cpe-program-info > *,
.cpe-badge-row > *,
.cpe-card-grid > *,
.cpe-scholarship-card > *,
.cpe-faq > *,
.cpe-post-card > *,
.cpe-post-body > *,
.cpe-post-text > *,
.cpe-post-meta > *,
.cpe-hero-cta > * { margin-block: 0; }

/* The page wrapper itself picks up the same stray top margin. */
main,
main > .wp-block-post-content,
main > .wp-block-post-content > * { margin-block: 0; }

.cpe-section-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	width: 100%;
	gap: 20px;
}

.cpe-section-head h2 {
	font-size: 24px;
	line-height: 32px;
	font-weight: 700;
	margin: 0;
	color: var(--wp--preset--color--primary);
}

.cpe-section-head p {
	margin: 0;
}

/* "ดูทั้งหมด" is a plain 16px medium brand-blue link — no arrow glyph and not
   the 20px grey it used to be (Figma 617:3125). */
.cpe-section-head a,
.cpe-see-all a {
	font-size: 16px;
	line-height: 24px;
	font-weight: 500;
	color: var(--wp--preset--color--brand);
	white-space: nowrap;
	padding-block: 3px;
}

.cpe-section-head a:hover,
.cpe-see-all a:hover { color: var(--wp--preset--color--brand-dark); }

.cpe-see-all { margin: 0; }

.cpe-section-heading {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 6px;
}

.cpe-section-heading h2 { margin: 0; }

.cpe-section-tick {
	width: 35px;
	height: 5px;
	border-radius: 100px;
	background: var(--wp--preset--color--surface-muted);
}

.cpe-icon { width: 16px; height: 16px; flex-shrink: 0; display: inline-block; vertical-align: middle; }
.cpe-icon-sm { width: 14px; height: 14px; }
.cpe-icon-lg { width: 24px; height: 24px; }

/* ---------- Header ---------- */

/* Figma 617:3107 — 1440x90: 20px/50px padding around a 50px-tall row, so the
   logo and the nav both sit on the same vertical centre line. */
.cpe-header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 20px;
	width: 100%;
	padding: 20px 50px;
	background: var(--wp--preset--color--white);
	position: relative;
	z-index: 20;
}

.cpe-brand {
	display: flex;
	align-items: center;
	gap: 20px;
	font-size: 20px;
}

/* Real CPE logo (wp:site-logo) in the header — 73x50 per the design. */
.cpe-brand .wp-block-site-logo { line-height: 0; }
.cpe-brand .wp-block-site-logo img {
	width: 73px;
	height: 50px;
	object-fit: contain;
	max-width: none;
}

.cpe-brand-mark {
	font-weight: 700;
	font-size: 28px;
	line-height: 1;
	letter-spacing: -0.02em;
	color: var(--wp--preset--color--brand);
	white-space: nowrap;
	margin: 0;
}

.cpe-brand-name {
	font-weight: 600;
	line-height: 1.3;
	margin: 0;
}

.cpe-header-right {
	display: flex;
	align-items: center;
	gap: 20px;
}

.cpe-nav .wp-block-navigation__container {
	list-style: none;
	display: flex;
	align-items: center;
	gap: 20px;
	margin: 0;
	padding: 0;
}

.cpe-nav .wp-block-navigation-item__content {
	font-size: 16px;
	line-height: 24px;
	font-weight: 500;
	color: var(--wp--preset--color--primary);
	padding: 3px 0;
}

.cpe-nav .wp-block-navigation-item__content:hover { color: var(--wp--preset--color--brand); }

/* Direct child only. `current-menu-item` sits on the <li>, so a descendant
   selector also painted every link inside that item's submenu brand-blue —
   which read as "all submenu entries are active" whenever the parent page was
   the current one. */
.cpe-nav .current-menu-item > .wp-block-navigation-item__content { color: var(--wp--preset--color--brand); }

/* Submenus must be taken out of flow — left in flow they stack inside the
   header and stretch it well past the 90px the design calls for. */
.cpe-nav .wp-block-navigation__submenu-container {
	position: absolute;
	top: 100%;
	left: 0;
	z-index: 30;
	flex-direction: column;
	gap: 0;
	margin: 0;
	padding: 10px 0;
	list-style: none;
	background: var(--wp--preset--color--white);
	border: 1px solid var(--wp--preset--color--border-light);
	border-radius: 10px;
	box-shadow: 0 0 10px 1px rgba(17, 17, 17, 0.05);
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.15s ease;
}

.cpe-nav .has-child { position: relative; }

/* At 400px wide the last menu's dropdown would run off the right edge, so it
   hangs from the right instead. */
.cpe-nav .wp-block-navigation__container > .has-child:last-child > .wp-block-navigation__submenu-container {
	left: auto;
	right: 0;
}

/* The open state has to carry the sizing: core collapses a closed submenu to
   `width:0;height:0;overflow:hidden` and re-opens it at `width:auto` from a
   selector too specific for the base rule above to beat.

   Three selectors, and all three have to out-rank core, which is why they are
   this long. Core's own open rules are (0,5,0):

     .wp-block-navigation .has-child:not(.open-on-click):hover > …container
     .wp-block-navigation .has-child .…submenu__toggle[aria-expanded=true] ~ …container

   The first used to be excluded for us — its `:not(.open-on-click)` did not
   match while the block was set to open on click — so a (0,4,0) selector was
   enough. It no longer is: the parent is a link now, the item carries
   `open-on-hover-click`, and that rule applies. The aria-expanded one never had
   the `:not`, which is what produced the width jump the review reported: the
   click set the attribute, core's (0,5,0) rule won with `width:auto`, and the
   panel resized under the pointer. Matching that state here too means the panel
   is the same 400px however it was opened. */
.cpe-nav.wp-block-navigation .wp-block-navigation__container > .has-child:hover > .wp-block-navigation__submenu-container,
.cpe-nav.wp-block-navigation .wp-block-navigation__container > .has-child:focus-within > .wp-block-navigation__submenu-container,
.cpe-nav.wp-block-navigation .has-child > .wp-block-navigation-submenu__toggle[aria-expanded="true"] ~ .wp-block-navigation__submenu-container {
	opacity: 1;
	visibility: visible;
	width: 400px;
	max-width: calc(100vw - 100px);
	height: auto;
	overflow: visible;
}

.cpe-nav .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
	display: block;
	padding: 8px 20px;
	white-space: normal;
}

/* Language switch (Figma 555:3688): a #f5f5f5 pill track with 3px padding;
   the active language is a #333640 pill with white text. */
.cpe-lang-switch {
	display: flex;
	align-items: center;
	gap: 3px;
	padding: 3px;
	border-radius: 100px;
	background: var(--wp--preset--color--page-background);
	font-size: 16px;
	font-weight: 500;
	line-height: 24px;
}

.cpe-lang-switch p {
	margin: 0;
	color: var(--wp--preset--color--primary);
	padding: 3px 15px;
	border-radius: 100px;
	cursor: pointer;
}

.cpe-lang-switch .active {
	background: var(--wp--preset--color--secondary);
	color: var(--wp--preset--color--white);
}

/* ---------- Hero ---------- */

/* Figma 617:3108 — a full-bleed 810px stage. Slides are stacked on top of each
   other and cross-faded by assets/js/hero-slider.js; each slide is an ordinary
   Group block carrying its own background image, so adding a slide in the
   editor is "duplicate the slide group and swap the image". */
.cpe-hero-slider {
	position: relative;
	width: 100%;
	height: 810px;
	overflow: hidden;
	background: var(--wp--preset--color--border-light);
}

.cpe-hero-slider > * { margin-block: 0; }

.cpe-hero-slide {
	position: absolute;
	inset: 0;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	justify-content: flex-end;
	padding: 0 160px 178px;
	background-size: cover;
	background-position: 50% 50%;
	background-repeat: no-repeat;
}

/* Slides are only stacked once the script has taken over. Until then hide all
   but the first: the slides are absolutely stacked, so the LAST one paints on
   top, and on a cold load (script in the footer) the page showed slide 3 and
   then faded to slide 1 when is-slider-ready arrived. Front end only — in the
   editor every slide must stay reachable. */
body:not(.editor-styles-wrapper):not(.block-editor-page) .cpe-hero-slider:not(.is-slider-ready) > .cpe-hero-slide:not(:first-child) {
	opacity: 0;
	visibility: hidden;
}

.cpe-hero-slider.is-slider-ready .cpe-hero-slide {
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.5s ease;
}

.cpe-hero-slider.is-slider-ready .cpe-hero-slide.is-active {
	opacity: 1;
	visibility: visible;
}

/* The design lightens the photo with a flat 50% #f9f9f9 wash. */
.cpe-hero-slide::before {
	content: "";
	position: absolute;
	inset: 0;
	background: rgba(249, 249, 249, 0.5);
	pointer-events: none;
}

.cpe-hero-dots {
	position: absolute;
	left: 50%;
	bottom: 26px;
	transform: translateX(-50%);
	display: flex;
	align-items: center;
	gap: 5px;
	z-index: 3;
}

.cpe-hero-dot {
	width: 10px;
	height: 10px;
	padding: 0;
	border: none;
	border-radius: 100px;
	background: var(--wp--preset--color--white);
	opacity: 0.6;
	cursor: pointer;
	transition: width 0.3s ease, opacity 0.3s ease;
}

.cpe-hero-dot.is-active {
	width: 31px;
	opacity: 1;
}

.cpe-hero-content {
	position: relative;
	z-index: 2;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 10px;
	text-align: left;
}

.cpe-hero-content > * { margin-block: 0; }

/* Eyebrow → title is a 10px gap; title → buttons is 30px (Figma 617:3109). */
.cpe-hero-content > .cpe-hero-cta { margin-top: 20px; }

.cpe-hero-eyebrow {
	font-size: 24px;
	line-height: 32px;
	font-weight: 700;
	color: var(--wp--preset--color--primary);
	margin: 0;
	filter: drop-shadow(0 0 8px rgba(17, 17, 17, 0.1));
}

.cpe-hero-title {
	font-size: 40px;
	line-height: 52px;
	font-weight: 700;
	color: var(--wp--preset--color--primary);
	margin: 0;
	filter: drop-shadow(0 0 8px rgba(17, 17, 17, 0.1));
}

.cpe-hero-cta {
	display: flex;
	gap: 20px;
	align-items: center;
	flex-wrap: wrap;
	justify-content: flex-start;
}

.cpe-feature-foot .wp-block-buttons {
	margin: 0;
}

.cpe-hero-content .wp-block-buttons.cpe-hero-cta {
	gap: 20px;
	justify-content: flex-start;
	margin: 20px 0 0;
}

.wp-block-button .wp-block-button__link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 10px;
	padding: 10px 20px;
	border-radius: 10px;
	font-size: 20px;
	font-weight: 600;
	white-space: nowrap;
	border: none;
}

.wp-block-button.cpe-btn-dark .wp-block-button__link {
	background: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--white);
}
.wp-block-button.cpe-btn-dark .wp-block-button__link:hover { background: var(--wp--preset--color--brand-dark); color: var(--wp--preset--color--white); }

.wp-block-button.cpe-btn-light .wp-block-button__link {
	background: var(--wp--preset--color--white);
	color: var(--wp--preset--color--primary);
}
.wp-block-button.cpe-btn-light .wp-block-button__link:hover { background: #f0f0f0; color: var(--wp--preset--color--primary); }

/* Hero CTAs: 20px/32px semibold, 8px/20px padding, 6px radius (Figma 617:3113). */
.cpe-hero-slider .wp-block-button__link {
	padding: 8px 20px;
	border-radius: 6px;
	font-size: 20px;
	line-height: 32px;
}

/* In the hero the second CTA ("ติดต่อเรา") is a near-black solid button. */
.cpe-hero-slider .wp-block-button.cpe-btn-light .wp-block-button__link {
	background: #0f1014;
	color: var(--wp--preset--color--white);
}
.cpe-hero-slider .wp-block-button.cpe-btn-light .wp-block-button__link:hover { background: #000; color: var(--wp--preset--color--white); }

.wp-block-button.cpe-btn-outline .wp-block-button__link {
	background: var(--wp--preset--color--white);
	color: var(--wp--preset--color--primary);
	border: 1px solid var(--wp--preset--color--border);
	font-size: 16px;
	font-weight: 500;
}
.wp-block-button.cpe-btn-outline .wp-block-button__link:hover { background: #f0f0f0; }

.wp-block-button.cpe-btn-outline .wp-block-button__link::after {
	content: "";
	width: 16px;
	height: 16px;
	flex-shrink: 0;
	background-color: var(--wp--preset--color--primary);
	-webkit-mask: url("../icons/fi-rr-arrow-small-right.svg") no-repeat center / contain;
	mask: url("../icons/fi-rr-arrow-small-right.svg") no-repeat center / contain;
}

/* ---------- Programs ---------- */

/* Figma 617:3126 — 30px between the degree label row and its cards and
   between cards; 20px between one degree group and the next. */
.cpe-degree-group {
	display: flex;
	flex-direction: column;
	gap: 30px;
	width: 100%;
	margin-block: 0;
}

.cpe-section-inner .cpe-degree-group + .cpe-degree-group { margin-top: 0; }

.cpe-degree-label-row {
	display: flex;
	align-items: center;
	gap: 20px;
	width: 100%;
}

.cpe-degree-label {
	font-size: 16px;
	line-height: 24px;
	font-weight: 500;
	color: var(--wp--preset--color--muted);
	white-space: nowrap;
	margin: 0;
}

hr.cpe-degree-line {
	flex: 1;
	height: 1px;
	margin: 0;
	border: none;
	background: var(--wp--preset--color--border-light);
}

.cpe-program-cards {
	display: flex;
	flex-direction: column;
	gap: 30px;
	width: 100%;
}

/* 100px tall: 20px padding + 18px/24px title + 10px + a 26px tag row. */
.cpe-program-card {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 20px;
	width: 100%;
	min-height: 100px;
	background: var(--wp--preset--color--white);
	border-radius: 15px;
	padding: 20px;
	flex-wrap: wrap;
}

.cpe-program-card:hover { box-shadow: 0 0 10px 1px rgba(17, 17, 17, 0.05); }

.cpe-program-info { display: flex; flex-direction: column; justify-content: center; gap: 10px; }

.cpe-program-title { font-size: 18px; line-height: 24px; font-weight: 600; margin: 0; }

.cpe-badge-row { display: flex; gap: 10px; flex-wrap: wrap; }

/* Tag (Figma 551:3310): brand-tint pill, brand-blue 14px/20px label. */
.cpe-badge {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	padding: 3px 15px;
	border-radius: 100px;
	background: var(--wp--preset--color--brand-tint);
	color: var(--wp--preset--color--brand);
	font-size: 14px;
	line-height: 20px;
	font-weight: 500;
	margin: 0;
}

.cpe-badge::before {
	content: "";
	width: 16px;
	height: 16px;
	flex-shrink: 0;
	background-color: var(--wp--preset--color--brand);
	-webkit-mask: var(--cpe-icon) no-repeat center / contain;
	mask: var(--cpe-icon) no-repeat center / contain;
}

.cpe-badge-duration::before {
	--cpe-icon: url("../icons/fi-rr-clock.svg");
}

.cpe-badge-language::before {
	width: 14px;
	height: 14px;
	--cpe-icon: url("../icons/fi-rr-language-exchange.svg");
}

/* "รายละเอียด ›" — 16px regular in text/tertiary grey (Figma 507:6178). */
.cpe-detail-link {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	font-size: 16px;
	line-height: 24px;
	color: var(--wp--preset--color--muted);
	white-space: nowrap;
	margin: 0;
}

.cpe-detail-link a {
	display: inline-flex;
	align-items: center;
	gap: 10px;
}

.cpe-detail-link a::after {
	content: "";
	width: 16px;
	height: 16px;
	flex-shrink: 0;
	background-color: var(--wp--preset--color--muted);
	-webkit-mask: url("../icons/fi-rr-angle-small-right.svg") no-repeat center / contain;
	mask: url("../icons/fi-rr-angle-small-right.svg") no-repeat center / contain;
}

.cpe-arrow-link a::after {
	background-color: var(--wp--preset--color--muted);
	-webkit-mask: url("../icons/fi-rr-arrow-small-right.svg") no-repeat center / contain;
	mask: url("../icons/fi-rr-arrow-small-right.svg") no-repeat center / contain;
}

/* ---------- Curriculum overview (program list) ---------- */

.cpe-curriculum-group {
	display: flex;
	flex-direction: column;
	gap: 20px;
	width: 100%;
	margin-bottom: 30px;
}

/* Section heading (ปริญญาตรี/โท/เอก) with a rule extending to the right. */
.cpe-curriculum-head {
	display: flex;
	align-items: center;
	gap: 20px;
	width: 100%;
}
.cpe-curriculum-head h2 {
	font-size: 24px;
	font-weight: 700;
	margin: 0;
	white-space: nowrap;
}
.cpe-curriculum-head::after {
	content: "";
	flex: 1;
	height: 1px;
	background: var(--wp--preset--color--border);
}

/* #42 — the curriculum cards wear the same filled badge as everywhere else.
   They had been stripped to plain icon+text on the assumption the listing
   wanted a quieter treatment; the frame (814:8070) shows the Tag component
   unchanged — primary/50 fill, primary/700 label, 15px/3px, full radius —
   which is exactly what .cpe-badge already is, so the override is gone rather
   than replaced. */

/* The third badge on วิทยาศาสตร์ข้อมูลสุขภาพ, "หลักสูตรร่วม 2 สถาบัน", takes the
   external-link glyph the frame gives it. */
.cpe-badge-joint::before {
	--cpe-icon: url("../icons/fi-rr-arrow-up-right-from-square.svg");
}

/* ---------- Program detail page (bachelor/master/doctoral) ---------- */

.cpe-prog-detail { display: flex; flex-direction: column; gap: 40px; width: 100%; }

/* Overview stat bar (ข้อมูลภาพรวม) */
.cpe-overview-box {
	background: var(--wp--preset--color--white);
	border: 1px solid var(--wp--preset--color--border-light);
	border-radius: 15px;
	padding: 20px;
	display: flex;
	flex-direction: column;
	gap: 20px;
	width: 100%;
}
.cpe-overview-label { font-size: 18px; font-weight: 600; margin: 0; }
.cpe-overview-stats {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: 20px;
	width: 100%;
}
.cpe-stat { display: flex; flex-direction: column; gap: 5px; padding: 0 20px; }
.cpe-stat-label {
	display: flex;
	align-items: center;
	gap: 8px;
	font-size: 16px;
	color: var(--wp--preset--color--muted);
	margin: 0;
}
.cpe-stat-label::before {
	content: "";
	width: 16px;
	height: 16px;
	flex-shrink: 0;
	background-color: #727272;
	-webkit-mask: var(--cpe-icon) no-repeat center / contain;
	mask: var(--cpe-icon) no-repeat center / contain;
}
.cpe-stat-value { font-size: 20px; font-weight: 600; margin: 0; }
.cpe-stat-note { font-size: 14px; color: var(--wp--preset--color--muted); margin: 0; }

.cpe-stat-duration::before { --cpe-icon: url("../icons/fi-rr-clock.svg"); }
.cpe-stat-fee::before { --cpe-icon: url("../icons/fi-rr-coins.svg"); }
.cpe-stat-credits::before { --cpe-icon: url("../icons/fi-rr-book.svg"); }
.cpe-stat-lang::before { --cpe-icon: url("../icons/fi-rr-language-exchange.svg"); }
.cpe-stat-format::before { --cpe-icon: url("../icons/fi-rr-document.svg"); }

/* Two-column: sticky TOC + content */
.cpe-prog-layout { display: flex; gap: 50px; align-items: flex-start; width: 100%; }
.cpe-prog-toc {
	position: sticky;
	top: 30px;
	width: 220px;
	flex-shrink: 0;
	display: flex;
	flex-direction: column;
	gap: 15px;
}
.cpe-prog-toc-title { font-size: 16px; font-weight: 600; margin: 0; }
.cpe-prog-toc ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.cpe-prog-toc a {
	display: block;
	padding: 5px 15px;
	border-radius: 8px;
	font-size: 16px;
	color: var(--wp--preset--color--muted-dark);
}
.cpe-prog-toc a:hover { background: var(--wp--preset--color--page-background); color: var(--wp--preset--color--primary); }

.cpe-prog-content { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 40px; }
.cpe-prog-section { scroll-margin-top: 20px; display: flex; flex-direction: column; gap: 20px; }
.cpe-prog-section > h2 { font-size: 20px; font-weight: 600; margin: 0; }

/* ชื่อหลักสูตร rows */
.cpe-name-row { display: flex; gap: 15px; margin: 0; }
.cpe-name-lang { color: var(--wp--preset--color--primary); min-width: 90px; flex-shrink: 0; }

/* Objectives list / paragraph */
.cpe-prog-section ul.cpe-obj-list { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 10px; line-height: 1.6; }
.cpe-obj-text { margin: 0; font-size: 16px; line-height: 1.7; color: var(--wp--preset--color--primary); }

/* Program learning outcomes (numbered) */
.cpe-plo { display: flex; gap: 20px; align-items: flex-start; }
.cpe-plo-num {
	flex-shrink: 0;
	width: 30px;
	height: 30px;
	border-radius: 100px;
	background: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--white);
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 16px;
	font-weight: 600;
}
.cpe-plo-body { display: flex; flex-direction: column; gap: 12px; }
.cpe-plo-title { font-size: 16px; font-weight: 600; margin: 0; line-height: 1.5; }
.cpe-plo-desc { font-size: 16px; color: var(--wp--preset--color--muted-dark); margin: 0; padding-left: 15px; line-height: 1.6; }

/* Info line (ระยะเวลาการศึกษา) */
.cpe-info-line {
	display: flex;
	align-items: center;
	gap: 10px;
	background: var(--wp--preset--color--white);
	border-radius: 10px;
	padding: 15px 30px;
	margin: 0;
	font-size: 16px;
}
.cpe-info-line::before {
	content: "";
	width: 16px; height: 16px; flex-shrink: 0;
	background-color: var(--wp--preset--color--primary);
	-webkit-mask: url("../icons/fi-rr-clock.svg") no-repeat center / contain;
	mask: url("../icons/fi-rr-clock.svg") no-repeat center / contain;
}

/* Spec rows (cost / structure / electives): label left, value right */
.cpe-spec-row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 20px;
	background: var(--wp--preset--color--white);
	border-radius: 10px;
	padding: 15px 30px;
	width: 100%;
}
.cpe-spec-row p { margin: 0; font-size: 16px; }
.cpe-spec-row .cpe-spec-value { color: var(--wp--preset--color--primary); white-space: nowrap; font-weight: 500; }
.cpe-spec-list { display: flex; flex-direction: column; gap: 10px; width: 100%; }
.cpe-spec-row--indent { margin-left: 30px; width: calc(100% - 30px); background: var(--wp--preset--color--page-background); }
.cpe-spec-row--total { background: var(--wp--preset--color--note); font-weight: 600; }
.cpe-spec-row--total p { font-weight: 600; }
/* Plan header (Master/Doctoral structure): bold label, no box, above its sub-rows. */
.cpe-spec-row--plan { background: transparent; padding: 10px 0 0; font-weight: 600; }
.cpe-spec-row--plan p { font-weight: 600; }
.cpe-spec-sub { font-size: 14px; color: var(--wp--preset--color--muted); }

/* Curriculum image + document link */
.cpe-prog-image {
	width: 100%;
	aspect-ratio: 779 / 344;
	background: var(--wp--preset--color--surface-muted);
	border-radius: 15px;
	overflow: hidden;
}
.cpe-prog-image img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cpe-doc-link {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 20px;
	background: var(--wp--preset--color--white);
	border-radius: 10px;
	padding: 15px 30px;
	margin: 0;
}
.cpe-doc-link a { display: inline-flex; align-items: center; gap: 8px; }
.cpe-doc-link a::before {
	content: "";
	width: 16px; height: 16px; flex-shrink: 0;
	background-color: var(--wp--preset--color--primary);
	-webkit-mask: url("../icons/fi-rr-document.svg") no-repeat center / contain;
	mask: url("../icons/fi-rr-document.svg") no-repeat center / contain;
}
.cpe-doc-link a::after {
	content: "";
	width: 16px; height: 16px; flex-shrink: 0;
	background-color: var(--wp--preset--color--muted-dark);
	-webkit-mask: url("../icons/fi-rr-arrow-up-right-from-square.svg") no-repeat center / contain;
	mask: url("../icons/fi-rr-arrow-up-right-from-square.svg") no-repeat center / contain;
}

/* Partner institutions (HDS) */
.cpe-partner-row {
	display: flex;
	align-items: center;
	gap: 20px;
	background: var(--wp--preset--color--white);
	border-radius: 10px;
	padding: 15px 30px;
	flex-wrap: wrap;
}
.cpe-partner-row p { margin: 0; font-size: 16px; }
.cpe-partner-x { color: var(--wp--preset--color--muted); font-size: 20px; }
.cpe-partner-info {
	display: flex;
	flex-direction: column;
	gap: 5px;
	background: var(--wp--preset--color--white);
	border-radius: 10px;
	padding: 15px 30px;
	width: 100%;
}
.cpe-partner-info-title { margin: 0; font-weight: 600; font-size: 16px; }
.cpe-partner-info-desc { margin: 0; font-size: 16px; color: var(--wp--preset--color--muted-dark); line-height: 1.5; }

@media (max-width: 900px) {
	.cpe-overview-stats { grid-template-columns: repeat(2, 1fr); }
	.cpe-prog-layout { flex-direction: column; }
	.cpe-prog-toc { position: static; width: 100%; }
}

/* ---------- Scholarships ---------- */

/* A real grid, not a wrapping flex row: wrapping flex lines size independently,
   which is what made the first card taller than its neighbours whenever its
   title wrapped to a second line. Grid rows are uniform by construction. */
/* Static card grids (scholarships). Query-loop grids keep WordPress's own grid
   layout so the News & Events / Gallery listings — which use wider cards and
   different column counts — are left alone. */
.cpe-card-grid:not(.wp-block-post-template) {
	display: grid;
	/* Figma 617:3147 — the row is 1058px inside the 1120px column, with cards
	   of 353/321/344px. The columns are sized to their content and the row is
	   left-aligned; it does not stretch to fill the section. justify-content
	   must stay `start`, otherwise auto tracks absorb the free space and the
	   cards go back to being equal thirds. */
	grid-template-columns: repeat(3, auto);
	justify-content: start;
	grid-auto-rows: minmax(127px, auto);
	gap: 20px;
	width: 100%;
}

/* Home News/Research loops only: three 320px cards spread across the 1120px
   column (Figma 617:3159). */
.home .cpe-card-grid.wp-block-post-template {
	grid-template-columns: repeat(3, 320px);
	justify-content: space-between;
	gap: 40px 20px;
}

@media (max-width: 1100px) {
	.home .cpe-card-grid.wp-block-post-template {
		grid-template-columns: repeat(auto-fit, minmax(280px, 320px));
		justify-content: start;
	}
}

.cpe-scholarship-card {
	background: var(--wp--preset--color--white);
	border-radius: 15px;
	padding: 20px;
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	gap: 10px;
	height: 100%;
}

.cpe-scholarship-card h3 {
	font-size: 18px;
	line-height: 24px;
	font-weight: 600;
	margin: 0;
}

.cpe-scholarship-card .cpe-detail-link {
	border-top: 1px solid var(--wp--preset--color--border-light);
	padding-top: 5px;
	justify-content: flex-end;
	width: 100%;
}

/* #15 — these have to carry the same :not() as the base rule. Without it they
   are specificity 0,1,0 against the base rule's 0,2,0, and a media query adds
   none, so they lost and the scholarship cards never stacked on mobile. */
@media (max-width: 1100px) {
	.cpe-card-grid:not(.wp-block-post-template) {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (max-width: 700px) {
	.cpe-card-grid:not(.wp-block-post-template) {
		grid-template-columns: 1fr;
	}
}

/* ---------- Student Life feature block ---------- */

/* One unified card (Figma 617:3154): gradient header, inner cells divided by
   #e6e6e6 borders with NO gaps, rounded 20px outer corners. */
.cpe-feature-block {
	width: 100%;
	border-radius: 20px;
	overflow: hidden;
	border: 1px solid var(--wp--preset--color--border-light);
	box-shadow: 0 0 10px 1px rgba(17, 17, 17, 0.05);
}

/* Kill WordPress's is-layout-flow block-gap margins that otherwise split the
   card into separate stacked pieces. */
.cpe-feature-block > *,
.cpe-feature-grid > * { margin-block: 0; }

.cpe-feature-head {
	background: linear-gradient(90deg, var(--wp--preset--color--brand-dark) 0%, var(--wp--preset--color--brand) 55%, var(--wp--preset--color--brand-light) 100%);
	color: var(--wp--preset--color--white);
	padding: 20px 30px;
	display: flex;
	flex-direction: column;
	gap: 10px;
}

.cpe-feature-head p.eyebrow { margin: 0; font-size: 16px; }
.cpe-feature-head h3 { margin: 0; font-size: 40px; font-weight: 700; line-height: 1.3; }
.cpe-feature-head p.tagline { margin: 0; font-size: 16px; }

.cpe-feature-grid {
	display: flex;
	flex-wrap: wrap;
	align-items: stretch;
}

.cpe-feature-cell {
	background: var(--wp--preset--color--white);
	padding: 30px;
	display: flex;
	flex-direction: column;
	gap: 15px;
	flex: 1 1 50%;
	min-width: 320px;
}

/* Internal dividers only — no per-cell rounding, no outer gaps. */
.cpe-feature-grid .cpe-feature-cell { border-bottom: 1px solid var(--wp--preset--color--border-light); }
.cpe-feature-grid .cpe-feature-cell:first-child { border-right: 1px solid var(--wp--preset--color--border-light); }

.cpe-feature-cell.full { flex-basis: 100%; }

.cpe-feature-cell h4 { margin: 0; font-size: 18px; font-weight: 600; }
.cpe-feature-cell p { margin: 0; font-size: 16px; }

.cpe-feature-foot {
	background: var(--wp--preset--color--white);
	border-top: 1px solid var(--wp--preset--color--border-light);
	padding: 20px 30px;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 20px;
	flex-wrap: wrap;
}

.cpe-feature-foot p {
	margin: 0;
}

/* ---------- News / Research cards (Query Loop) ---------- */

/* Figma 617:3160 — 320x322: a 180px image over a 142px body (20px padding,
   18px/24px title, 10px, excerpt, 20px, 24px meta row). */
.cpe-post-card {
	display: flex;
	flex-direction: column;
	border-radius: 15px;
	overflow: hidden;
	background: var(--wp--preset--color--white);
	width: 100%;
	height: 100%;
	min-height: 322px;
}

.cpe-post-thumb {
	position: relative;
	background: var(--wp--preset--color--surface-muted);
	height: 180px;
	width: 100%;
	overflow: hidden;
}

/* --lg: the larger News/Events card used on the News & Events overview and
   listing pages (540x304 image, fixed 224px body) — max-width:380 above is
   for the smaller Home-page cards and must not apply here. */
.cpe-post-card--lg {
	max-width: none;
}

.cpe-post-card--lg .cpe-post-thumb {
	height: 304px;
}

.cpe-post-card--lg .cpe-post-body {
	height: 224px;
	justify-content: space-between;
}

.cpe-post-thumb img { width: 100%; height: 100%; object-fit: cover; }

.cpe-post-tag {
	position: absolute;
	top: 15px;
	left: 15px;
	width: fit-content;
	background: var(--wp--preset--color--brand-tint);
	color: var(--wp--preset--color--brand);
	border-radius: 100px;
	padding: 3px 15px;
	font-size: 14px;
	line-height: 20px;
	font-weight: 500;
}

.cpe-post-body {
	padding: 20px;
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	gap: 20px;
	flex: 1;
	min-height: 142px;
}

/* Title + excerpt grouped at the top of the card; the meta footer is the
   card body's other flex child, pinned to the bottom via space-between. */
.cpe-post-text {
	display: flex;
	flex-direction: column;
	gap: 10px;
	min-width: 0;
}

.cpe-post-body h3 { margin: 0; font-size: 18px; line-height: 24px; font-weight: 600; }
.cpe-post-body .excerpt { margin: 0; font-size: 16px; color: var(--wp--preset--color--muted); }

/* Card title: the design uses an 18px semibold title (not the theme's big
   heading size). post-title renders as an <h2>, so pin it here. Clamp title
   and excerpt to a set number of lines so a long entry can't overflow the
   fixed-height card body and shove the date/รายละเอียด footer out of view. */
.cpe-post-body .wp-block-post-title {
	margin: 0;
	font-size: 18px;
	font-weight: 600;
	line-height: 24px;
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
	overflow: hidden;
}

.cpe-post-body .excerpt {
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 1;
	overflow: hidden;
	line-height: 24px;
}

/* The featured card is taller (matches the 304px image), so it has room for
   a one-line title and a longer, 3-line summary. */
.cpe-post-card--featured .wp-block-post-title { -webkit-line-clamp: 2; }
.cpe-post-card--featured .excerpt { -webkit-line-clamp: 3; }

.cpe-post-meta {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
}

.cpe-post-date {
	display: flex;
	align-items: center;
	gap: 8px;
	font-size: 16px;
	line-height: 24px;
	color: var(--wp--preset--color--muted);
}

.cpe-post-date::before {
	content: "";
	width: 16px;
	height: 16px;
	flex-shrink: 0;
	background-color: #727272;
	-webkit-mask: url("../icons/heroicon-calendar.svg") no-repeat center / contain;
	mask: url("../icons/heroicon-calendar.svg") no-repeat center / contain;
}

.cpe-post-thumb .wp-block-post-featured-image,
.cpe-post-thumb figure {
	margin: 0;
	width: 100%;
	height: 100%;
}

.cpe-post-thumb .wp-block-post-featured-image img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Featured single-card variant (News & Events overview page) — image left, content right */
.cpe-post-card--featured {
	flex-direction: row;
	max-width: none;
	width: 100%;
}

.cpe-post-card--featured .cpe-post-thumb {
	width: 540px;
	height: 304px;
	flex-shrink: 0;
}

.cpe-post-card--featured .cpe-post-body {
	flex: 1;
	align-self: stretch;
	justify-content: space-between;
	padding: 20px 30px;
}

/* Gallery cards (thumb + title only, no tag/date/excerpt) */
.cpe-gallery-card {
	display: flex;
	flex-direction: column;
	border-radius: 15px;
	overflow: hidden;
	background: var(--wp--preset--color--white);
	width: 100%;
}

.cpe-gallery-thumb {
	position: relative;
	background: var(--wp--preset--color--surface-muted);
	height: 304px;
	width: 100%;
	overflow: hidden;
}

.cpe-gallery-thumb .wp-block-post-featured-image,
.cpe-gallery-thumb figure {
	margin: 0;
	width: 100%;
	height: 100%;
}

.cpe-gallery-thumb .wp-block-post-featured-image img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.cpe-gallery-card-title {
	margin: 0;
	padding: 20px;
	font-size: 18px;
	font-weight: 600;
}

/* ---------- Photo grid (cpe/photo-grid block) ---------- */

.cpe-photo-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 20px;
	width: 100%;
}

.cpe-photo-grid-item {
	border-radius: 10px;
	overflow: hidden;
	background: var(--wp--preset--color--surface-muted);
	aspect-ratio: 4 / 3;
}

.cpe-photo-grid-item img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

/* Full-width 3-up photo strip on the Event detail page (matches Figma). */
.cpe-photo-grid--teaser {
	grid-template-columns: repeat(3, 1fr);
	gap: 40px;
}

/* ---------- Single post (News / Events detail) ---------- */

.cpe-single-meta {
	gap: 20px;
	align-items: center;
}

/* Static category pill for the single-post meta row (the card's .cpe-post-tag
   is position:absolute for image overlays and can't be reused here). */
.cpe-cat-pill {
	display: inline-flex;
	align-items: center;
	width: fit-content;
	background: var(--wp--preset--color--page-background);
	border: 1px solid var(--wp--preset--color--border-light);
	border-radius: 100px;
	padding: 5px 15px;
	font-size: 14px;
	font-weight: 500;
	color: var(--wp--preset--color--primary);
}
.cpe-cat-pill a { color: inherit; }

.cpe-single-title {
	font-size: 28px;
	font-weight: 700;
	line-height: 1.4;
	margin: 0;
	text-align: left;
}

.cpe-single-featured-image {
	width: 100%;
	border-radius: 15px;
	overflow: hidden;
	background: var(--wp--preset--color--surface-muted);
	aspect-ratio: 16 / 9;
}

.cpe-single-featured-image img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.cpe-single-content {
	font-size: 16px;
	line-height: 1.8;
	color: var(--wp--preset--color--primary);
}

.cpe-single-content p { margin: 0 0 20px; }

/* ---------- Query pagination (News / Events / Gallery listings) ---------- */

.wp-block-query-pagination.cpe-pagination {
	display: flex;
	flex-direction: row;
	flex-wrap: nowrap;
	justify-content: center;
	align-items: center;
	gap: 10px;
	margin-top: 20px;
}

/* The numbers block lays its own children (1, 2, …) out in a row. */
.cpe-pagination .wp-block-query-pagination-numbers {
	display: flex;
	align-items: center;
	gap: 10px;
}

/* inline-flex (not flex) so each number is an inline pill, not a full-width
   block that stacks vertically. */
.cpe-pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 40px;
	height: 40px;
	padding: 0 8px;
	border-radius: 100px;
	color: var(--wp--preset--color--primary);
	font-size: 16px;
	text-decoration: none;
}

.cpe-pagination a.page-numbers:hover {
	background: var(--wp--preset--color--surface-muted);
}

.cpe-pagination .page-numbers.current {
	background: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--white);
}

/* Prev / next as circular icon buttons matching the numbers. */
.cpe-pagination .wp-block-query-pagination-previous,
.cpe-pagination .wp-block-query-pagination-next {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	padding: 0;
	border-radius: 100px;
	color: var(--wp--preset--color--muted-dark);
	font-size: 20px;
	line-height: 1;
	text-decoration: none;
}

.cpe-pagination .wp-block-query-pagination-previous:hover,
.cpe-pagination .wp-block-query-pagination-next:hover {
	background: var(--wp--preset--color--surface-muted);
}

/* ---------- FAQ accordion ---------- */

.cpe-faq { width: 100%; display: flex; flex-direction: column; gap: 20px; }

/* Figma 579:2056 — 54px tall: 15px/30px padding around an 18px/24px title. */
.cpe-faq-item {
	background: var(--wp--preset--color--white);
	border: 1px solid var(--wp--preset--color--border-light);
	border-radius: 15px;
	padding: 15px 30px;
}

.cpe-faq-item summary {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 20px;
	cursor: pointer;
	font-size: 18px;
	line-height: 24px;
	font-weight: 600;
	list-style: none;
}

.cpe-faq-item summary::-webkit-details-marker { display: none; }

.cpe-faq-item summary::after {
	content: "";
	flex-shrink: 0;
	width: 24px;
	height: 24px;
	background-color: var(--wp--preset--color--primary);
	-webkit-mask: url("../icons/fi-rr-angle-small-down.svg") no-repeat center / contain;
	mask: url("../icons/fi-rr-angle-small-down.svg") no-repeat center / contain;
	transition: transform 0.2s ease;
}

.cpe-faq-item[open] summary::after { transform: rotate(180deg); }

.cpe-faq-item .cpe-faq-answer {
	margin: 16px 0 0;
	font-size: 16px;
	color: var(--wp--preset--color--muted-dark);
}

/* ---------- Footer ---------- */

.cpe-footer {
	width: 100%;
	background: var(--wp--preset--color--brand-dark);
	color: var(--wp--preset--color--white);
	padding: 40px 160px 20px;
	display: flex;
	flex-direction: column;
	gap: 40px;
}

/* Footer text + links are white on the navy CI background. */
.cpe-footer a { color: var(--wp--preset--color--white); }
.cpe-footer a:hover { color: rgba(255,255,255,0.75); }
.cpe-footer .cpe-brand-mark { color: var(--wp--preset--color--white); }

.cpe-footer-top {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 40px;
	flex-wrap: wrap;
}

.cpe-footer-brand { display: flex; flex-direction: column; gap: 30px; }

.cpe-footer-nav {
	display: flex;
	gap: 84px;
	flex-wrap: wrap;
}

.cpe-footer-nav ul {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 20px;
	font-size: 16px;
	font-weight: 500;
}

.cpe-footer-contact {
	display: flex;
	flex-direction: column;
	gap: 30px;
	align-items: flex-start;
}

.wp-block-social-links.cpe-social {
	gap: 0;
	margin: 0;
	padding: 0;
}

.wp-block-social-links.cpe-social .wp-social-link {
	background: var(--wp--preset--color--white);
	color: var(--wp--preset--color--brand-dark);
	width: 28px;
	height: 28px;
}

.wp-block-social-links.cpe-social .wp-social-link svg {
	width: 16px;
	height: 16px;
	fill: var(--wp--preset--color--brand-dark);
}

.cpe-footer-address {
	display: flex;
	flex-direction: column;
	gap: 20px;
	font-size: 16px;
	max-width: 480px;
}

.cpe-footer-copyright {
	font-size: 16px;
	font-weight: 500;
	margin: 0;
}

.cpe-footer-address p {
	margin: 0;
}

/* ---------- Inner page header (breadcrumb + title) ---------- */

.cpe-page-wrap {
	width: 100%;
	max-width: 1440px;
	margin-inline: auto;
	padding: 30px 160px 60px;
	display: flex;
	flex-direction: column;
	gap: 30px;
}

/* The constrained layout puts `margin-inline: auto` on post-content. In a flex
   column that overrides `stretch` and shrink-wraps it to its max-content width,
   so a page whose content is naturally narrow (the month timeline) collapsed to
   ~265px instead of filling the 1120px column. Force it back to full width. */
.cpe-page-wrap > .wp-block-post-content {
	width: 100%;
	max-width: 100%;
	margin-inline: 0;
}

.cpe-breadcrumb {
	display: flex;
	align-items: center;
	justify-content: flex-start;
	gap: 10px;
	font-size: 16px;
	color: var(--wp--preset--color--primary);
	flex-wrap: wrap;
	width: 100%;
}

.cpe-breadcrumb a { color: var(--wp--preset--color--primary); text-decoration: none; }
.cpe-breadcrumb a:hover { color: var(--wp--preset--color--brand); }
.cpe-breadcrumb .current { color: var(--wp--preset--color--primary); }
.cpe-breadcrumb .sep { color: var(--wp--preset--color--muted); }

/* Home crumb = icon button (design 617:7743) instead of the word "หน้าแรก" */
.cpe-breadcrumb .cpe-crumb-home {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 5px;
	border-radius: 10px;
	color: var(--wp--preset--color--primary);
	line-height: 0;
}
.cpe-breadcrumb .cpe-crumb-home:hover { background: var(--wp--preset--color--brand-tint); color: var(--wp--preset--color--brand); }

.cpe-page-title {
	font-size: 32px;
	font-weight: 700;
	text-align: center;
	margin: 0;
}

/* ---------- Service / facility link cards ----------
   Figma 374:1130 (บริการนักศึกษา) and 374:1364 (สิ่งอำนวยความสะดวก): a centred
   grid of white cards, each one an external-service shortcut. Both pages sit
   50px apart between breadcrumb, title and grid. */

.page-slug-student-services .cpe-page-wrap,
.page-slug-facility .cpe-page-wrap { gap: 50px; }

.cpe-service-grid {
	display: grid;
	grid-template-columns: repeat(3, 320px);
	justify-content: center;
	gap: 40px;
	width: 100%;
}

/* The Facility page has only two, wider cards (416px). */
.cpe-service-grid--wide {
	grid-template-columns: repeat(2, 416px);
}

.cpe-service-grid > * { margin-block: 0; }

.cpe-service-card {
	display: flex;
	flex-direction: column;
	gap: 20px;
	padding: 20px;
	border-radius: 15px;
	background: var(--wp--preset--color--white);
	box-shadow: 0 0 10px 1px rgba(17, 17, 17, 0.05);
}

/* The CTA is pinned to the bottom so cards in a row line up even when one
   description runs to an extra line. */
.cpe-service-card > * { margin-block: 0; }
.cpe-service-card > .cpe-service-cta { margin-top: auto; }

.cpe-service-head {
	display: flex;
	align-items: center;
	gap: 15px;
}

.cpe-service-head > * { margin-block: 0; }

.cpe-service-logo {
	width: 40px;
	height: 40px;
	flex-shrink: 0;
	margin: 0;
}

.cpe-service-logo img {
	width: 40px;
	height: 40px;
	border-radius: 8px;
	object-fit: cover;
}

/* Decorative icon tile used by the Facility cards (Figma 377:1496). */
.cpe-service-icon {
	width: 40px;
	height: 40px;
	flex-shrink: 0;
	border-radius: 8px;
	background: var(--wp--preset--color--surface-muted) no-repeat center;
	background-size: 18px 18px;
}

.cpe-service-icon--calendar {
	--cpe-icon: url("../icons/heroicon-calendar.svg");
}

.cpe-service-icon--chip {
	--cpe-icon: url("../icons/fi-rr-microchip.svg");
}

.cpe-service-names {
	display: flex;
	flex-direction: column;
	gap: 5px;
	min-width: 0;
}

.cpe-service-names > * { margin-block: 0; }

.cpe-service-title {
	margin: 0;
	font-size: 20px;
	line-height: 24px;
	font-weight: 600;
	color: var(--wp--preset--color--primary);
}

.cpe-service-sub {
	margin: 0;
	font-size: 16px;
	line-height: 19px;
	color: var(--wp--preset--color--primary);
}

.cpe-service-desc {
	margin: 0;
	font-size: 16px;
	line-height: 19px;
	color: var(--wp--preset--color--primary);
}

.cpe-service-cta { width: 100%; }
.cpe-service-cta .wp-block-button { width: 100%; }

/* "เปิดใช้งาน ↗" — full-width outline button with a trailing external-link
   glyph (Figma 374:1299). */
.wp-block-button.cpe-btn-launch .wp-block-button__link {
	width: 100%;
	padding: 8px 20px;
	border-radius: 10px;
	background: var(--wp--preset--color--white);
	border: 1px solid var(--wp--preset--color--border);
	color: var(--wp--preset--color--primary);
	font-size: 16px;
	line-height: 19px;
	font-weight: 400;
	gap: 10px;
}

.wp-block-button.cpe-btn-launch .wp-block-button__link:hover {
	background: var(--wp--preset--color--brand-tint);
	border-color: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--brand);
}

/* #40 — no icon on เปิดใช้งาน. The button is one component shared by
   สิ่งอำนวยความสะดวก and บริการนักศึกษา, and #40 previously asked for those two
   to match, so the icon goes from both rather than being scoped to one page. */

@media (max-width: 1140px) {
	.cpe-service-grid { grid-template-columns: repeat(2, 320px); }
	.cpe-service-grid--wide { grid-template-columns: repeat(2, minmax(0, 416px)); }
}

@media (max-width: 760px) {
	.cpe-service-grid,
	.cpe-service-grid--wide { grid-template-columns: minmax(0, 320px); }
}

/* ---------- ชีวิตนักศึกษา / Student Life (Figma 346:2214) ---------- */

.page-slug-student-life .cpe-page-wrap { gap: 50px; }

/* Section header → content is 30px on this page (the Landing uses 20px). */
.cpe-life-section {
	display: flex;
	flex-direction: column;
	gap: 30px;
	width: 100%;
}

.cpe-life-section > * { margin-block: 0; }

/* post-content children have their flow margin stripped globally (see the
   reset near the top), so the 50px between sections is set explicitly. */
.cpe-life-section + .cpe-life-section { margin-top: 50px; }

.cpe-life-head-title {
	margin: 0;
	font-size: 24px;
	line-height: 29px;
	font-weight: 700;
	color: var(--wp--preset--color--primary);
	white-space: nowrap;
}

/* --- 1. Timeline of student activities by month --- */

/* Inset by 80px so the three 280px columns land where the design puts them
   (marker centres at 380 / 720 / 1060 across the 1120 column). */
.cpe-timeline {
	position: relative;
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 60px;
	padding-inline: 80px;
	width: 100%;
}

.cpe-timeline > * { margin-block: 0; }

/* The rail runs behind the markers; the markers are opaque and sit on top. */
.cpe-timeline::before {
	content: "";
	position: absolute;
	top: 25px;
	left: 64px;
	right: 64px;
	height: 1px;
	background: var(--wp--preset--color--border);
}

.cpe-timeline-item {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 15px;
	text-align: center;
}

.cpe-timeline-item > * { margin-block: 0; }

.cpe-timeline-dot {
	width: 50px;
	height: 50px;
	border-radius: 100px;
	background: var(--wp--preset--color--brand-tint);
	display: flex;
	align-items: center;
	justify-content: center;
	margin-bottom: 15px;
}

.cpe-timeline-dot::before {
	content: "";
	width: 20px;
	height: 20px;
	border-radius: 6px;
	background: var(--wp--preset--color--brand);
}

.cpe-timeline-month {
	margin: 0;
	font-size: 18px;
	line-height: 22px;
	font-weight: 600;
	color: var(--wp--preset--color--primary);
}

.cpe-timeline-list {
	margin: 0;
	padding-left: 20px;
	display: flex;
	flex-direction: column;
	gap: 0;
	text-align: left;
	font-size: 16px;
	line-height: 24px;
	color: var(--wp--preset--color--primary);
}

/* --- 2. Exchange programme cards --- */

.cpe-exchange-grid {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 30px;
	width: 100%;
}

.cpe-exchange-grid > * { margin-block: 0; }

.cpe-exchange-card {
	display: flex;
	flex-direction: column;
	border-radius: 15px;
	overflow: hidden;
	background: var(--wp--preset--color--white);
	box-shadow: 0 0 10px 1px rgba(17, 17, 17, 0.05);
}

.cpe-exchange-card > * { margin-block: 0; }

.cpe-exchange-thumb {
	position: relative;
	height: 304px;
	width: 100%;
	overflow: hidden;
	background: var(--wp--preset--color--surface-muted);
}

.cpe-exchange-thumb > * { margin-block: 0; }

.cpe-exchange-image,
.cpe-exchange-image img {
	margin: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Country pill over the photo. */
.cpe-exchange-flag {
	position: absolute;
	top: 15px;
	left: 15px;
	margin: 0;
	display: inline-flex;
	align-items: center;
	gap: 5px;
	padding: 5px 15px;
	border-radius: 100px;
	background: var(--wp--preset--color--white);
	font-size: 14px;
	line-height: 17px;
	font-weight: 500;
	color: var(--wp--preset--color--primary);
}

.cpe-exchange-flag::before {
	content: "";
	width: 14px;
	height: 14px;
	flex-shrink: 0;
	background-color: var(--wp--preset--color--brand);
	-webkit-mask: url("../icons/fi-rr-marker.svg") no-repeat center / contain;
	mask: url("../icons/fi-rr-marker.svg") no-repeat center / contain;
}

.cpe-exchange-body {
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	gap: 20px;
	padding: 20px;
	min-height: 224px;
}

.cpe-exchange-body > * { margin-block: 0; }

.cpe-exchange-text {
	display: flex;
	flex-direction: column;
	gap: 20px;
}

.cpe-exchange-text > * { margin-block: 0; }

.cpe-exchange-title {
	margin: 0;
	font-size: 18px;
	line-height: 22px;
	font-weight: 600;
	color: var(--wp--preset--color--primary);
}

.cpe-exchange-desc {
	margin: 0;
	font-size: 16px;
	line-height: 19px;
	color: var(--wp--preset--color--muted-dark);
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 3;
	overflow: hidden;
}

.cpe-exchange-foot {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 20px;
}

.cpe-exchange-foot > * { margin-block: 0; }

/* Tag pills on this page carry no leading icon. */
.cpe-badge--plain { padding: 5px 20px; }
.cpe-badge--plain::before { display: none; }

/* --- 3. Internship link cards --- */

.cpe-intern-grid {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 30px;
	width: 100%;
}

.cpe-intern-grid > * { margin-block: 0; }

.cpe-intern-card {
	display: flex;
	flex-direction: column;
	gap: 20px;
	padding: 30px;
	min-height: 215px;
	border-radius: 15px;
	background: var(--wp--preset--color--white);
	box-shadow: 0 0 10px 1px rgba(17, 17, 17, 0.05);
}

.cpe-intern-card > * { margin-block: 0; }

/* "ดูรายละเอียด →" sits bottom-right regardless of description length. */
.cpe-intern-link {
	margin-top: auto;
	align-self: flex-end;
}

.cpe-intern-icon {
	width: 40px;
	height: 40px;
	flex-shrink: 0;
	border-radius: 8px;
	background: var(--wp--preset--color--brand-tint) no-repeat center;
	background-size: 20px 20px;
}

.cpe-intern-icon--book {
	--cpe-icon: url("../icons/fi-rr-book-alt.svg");
}

.cpe-intern-icon--document {
	--cpe-icon: url("../icons/fi-rr-document.svg");
}

.cpe-intern-icon--building {
	--cpe-icon: url("../icons/fi-rr-building.svg");
}

.cpe-intern-icon--question {
	--cpe-icon: url("../icons/heroicon-question-mark-circle.svg");
}

.cpe-intern-text {
	display: flex;
	flex-direction: column;
	gap: 10px;
}

.cpe-intern-text > * { margin-block: 0; }

.cpe-intern-title {
	margin: 0;
	font-size: 18px;
	line-height: 22px;
	font-weight: 600;
	color: var(--wp--preset--color--primary);
}

.cpe-intern-desc {
	margin: 0;
	font-size: 16px;
	line-height: 19px;
	color: var(--wp--preset--color--muted-dark);
}

@media (max-width: 1000px) {
	.cpe-exchange-grid,
	.cpe-intern-grid { grid-template-columns: 1fr; }
	.cpe-timeline { grid-template-columns: 1fr; gap: 30px; padding-inline: 0; }
	.cpe-timeline::before { display: none; }
}

/* ---------- เรื่องราวของนักศึกษา — vertical timeline (Figma 364:294) ----------
   Months alternate either side of a centre rail; each row is 72px tall with a
   141px stride, so consecutive (opposite-side) markers are 141px apart. */

.page-slug-student-stories .cpe-page-wrap { gap: 50px; }

.cpe-vtimeline {
	position: relative;
	width: 100%;
	padding-block: 30px;
}

.cpe-vtimeline > * { margin-block: 0; }

.cpe-vtimeline::before {
	content: "";
	position: absolute;
	top: 0;
	bottom: 0;
	left: 50%;
	width: 1px;
	transform: translateX(-50%);
	background: var(--wp--preset--color--border);
}

.cpe-vtimeline-item {
	position: relative;
	display: flex;
	align-items: center;
	gap: 50px;
	width: 50%;
	min-height: 72px;
}

.cpe-vtimeline-item > * { margin-block: 0; }

.cpe-vtimeline-item + .cpe-vtimeline-item { margin-top: 69px; }

/* Left-hand months: content first, marker last, the whole row pinned to the
   left half so the marker lands on the rail. */
.cpe-vtimeline-item--left {
	margin-right: 50%;
	flex-direction: row-reverse;
	justify-content: flex-start;
}

.cpe-vtimeline-item--right { margin-left: 50%; }

.cpe-vtimeline-dot {
	width: 50px;
	height: 50px;
	flex-shrink: 0;
	border-radius: 100px;
	background: var(--wp--preset--color--brand-tint);
	display: flex;
	align-items: center;
	justify-content: center;
	margin-inline: -25px;
}

.cpe-vtimeline-dot::before {
	content: "";
	width: 20px;
	height: 20px;
	border-radius: 6px;
	background: var(--wp--preset--color--brand);
}

.cpe-vtimeline-content {
	display: flex;
	align-items: center;
	gap: 30px;
	min-width: 0;
}

.cpe-vtimeline-content > * { margin-block: 0; }

/* Mirror the content order on the left so the month always hugs the rail. */
.cpe-vtimeline-item--left .cpe-vtimeline-content {
	flex-direction: row-reverse;
	margin-left: auto;
}

.cpe-vtimeline-month {
	margin: 0;
	font-size: 18px;
	line-height: 22px;
	font-weight: 600;
	white-space: nowrap;
	color: var(--wp--preset--color--primary);
}

.cpe-vtimeline-list {
	margin: 0;
	padding-left: 20px;
	font-size: 16px;
	line-height: 24px;
	color: var(--wp--preset--color--primary);
}

@media (max-width: 900px) {
	.cpe-vtimeline::before { left: 25px; transform: none; }
	.cpe-vtimeline-item,
	.cpe-vtimeline-item--left,
	.cpe-vtimeline-item--right {
		width: 100%;
		margin-inline: 0;
		flex-direction: row;
		gap: 20px;
	}
	.cpe-vtimeline-item--left .cpe-vtimeline-content {
		flex-direction: row;
		margin-left: 0;
	}
	.cpe-vtimeline-dot { margin-inline: 0; }
	.cpe-vtimeline-item + .cpe-vtimeline-item { margin-top: 30px; }
}

/* ---------- แลกเปลี่ยนต่างประเทศ listing + single programme ---------- */

.page-slug-exchange-programs .cpe-page-wrap { gap: 50px; }

.cpe-page-wrap--programme { gap: 20px; }

/* post-content children have their flow margin stripped globally, so this page
   sets its own rhythm: 50px under the breadcrumb, 20px between tags/title/image
   and 50px before the body copy (Figma 365:1405). */
.cpe-programme-tags { margin: 30px 0 0; }

.cpe-programme-title {
	margin: 20px 0 0;
	font-size: 24px;
	line-height: 32px;
	font-weight: 700;
	text-align: left;
	color: var(--wp--preset--color--primary);
}

/* 1000x562 (16:9), centred inside the 1120 column (Figma 365:1405). */
.cpe-programme-image {
	margin: 20px auto 0;
	width: 100%;
	max-width: 1000px;
}

.cpe-programme-image img {
	width: 100%;
	aspect-ratio: 16 / 9;
	object-fit: cover;
	border-radius: 10px;
	background: var(--wp--preset--color--surface-muted);
}

.cpe-programme-body {
	margin: 50px 0 0;
	font-size: 16px;
	line-height: 24px;
	color: var(--wp--preset--color--primary);
}

/* ---------- ฝึกงาน (Figma 364:684) ---------- */

.page-slug-internship .cpe-page-wrap { gap: 50px; }

.cpe-panel {
	display: flex;
	flex-direction: column;
	gap: 30px;
	width: 100%;
	padding: 30px;
	border-radius: 15px;
	background: var(--wp--preset--color--white);
	box-shadow: 0 0 10px 1px rgba(17, 17, 17, 0.05);
	scroll-margin-top: 110px;
}

.cpe-panel > * { margin-block: 0; }
.cpe-panel + .cpe-panel { margin-top: 50px; }

.cpe-panel-head {
	display: flex;
	align-items: center;
	gap: 20px;
}

.cpe-panel-head > * { margin-block: 0; }

.cpe-panel-icon {
	width: 55px;
	height: 55px;
	flex-shrink: 0;
	border-radius: 10px;
	background: var(--wp--preset--color--brand-tint) no-repeat center;
	background-size: 25px 25px;
}

.cpe-panel-icon--book { --cpe-icon: url("../icons/fi-rr-book-alt.svg"); }
.cpe-panel-icon--document { --cpe-icon: url("../icons/fi-rr-document.svg"); }
.cpe-panel-icon--building { --cpe-icon: url("../icons/fi-rr-building.svg"); }
.cpe-panel-icon--question { --cpe-icon: url("../icons/heroicon-question-mark-circle.svg"); }

.cpe-panel-titles {
	display: flex;
	flex-direction: column;
	gap: 10px;
	min-width: 0;
}

.cpe-panel-titles > * { margin-block: 0; }

.cpe-panel-title {
	margin: 0;
	font-size: 20px;
	line-height: 24px;
	font-weight: 600;
	color: var(--wp--preset--color--primary);
}

.cpe-panel-sub {
	margin: 0;
	font-size: 16px;
	line-height: 19px;
	color: var(--wp--preset--color--muted-dark);
}

.cpe-panel-lead {
	margin: 0;
	font-size: 16px;
	line-height: 24px;
	color: var(--wp--preset--color--primary);
}

/* --- panel 1: the three course facts --- */

.cpe-infobox-row {
	display: grid;
	grid-template-columns: 480fr 200fr 340fr;
	gap: 20px;
	width: 100%;
}

.cpe-infobox-row > * { margin-block: 0; }

.cpe-infobox {
	display: flex;
	flex-direction: column;
	gap: 5px;
	padding: 15px 20px;
	border-radius: 10px;
	background: var(--wp--preset--color--page-background);
}

.cpe-infobox > * { margin-block: 0; }

.cpe-infobox-label {
	display: flex;
	align-items: center;
	gap: 10px;
	margin: 0;
	font-size: 16px;
	line-height: 24px;
	color: var(--wp--preset--color--muted);
}

.cpe-infobox-label::before {
	content: "";
	width: 16px;
	height: 16px;
	flex-shrink: 0;
	background-color: var(--wp--preset--color--muted);
	-webkit-mask: var(--cpe-icon) no-repeat center / contain;
	mask: var(--cpe-icon) no-repeat center / contain;
}

.cpe-infobox-label--course::before { --cpe-icon: url("../icons/fi-rr-book.svg"); }
.cpe-infobox-label--credit::before { --cpe-icon: url("../icons/fi-rr-book-alt.svg"); }
.cpe-infobox-label--clock::before { --cpe-icon: url("../icons/fi-rr-clock.svg"); }

.cpe-infobox-value {
	margin: 0;
	font-size: 20px;
	line-height: 30px;
	font-weight: 600;
	color: var(--wp--preset--color--primary);
}

/* --- panel 2: tabs, document link and numbered steps --- */

.cpe-tabs {
	display: inline-flex;
	align-items: center;
	gap: 15px;
	align-self: flex-start;
	padding: 5px;
	border-radius: 100px;
	background: var(--wp--preset--color--surface-muted);
}

.cpe-tabs > * { margin-block: 0; }

.cpe-tab {
	margin: 0;
	padding: 5px 20px;
	border-radius: 100px;
	font-size: 16px;
	line-height: 24px;
	color: var(--wp--preset--color--primary);
	cursor: pointer;
	white-space: nowrap;
}

.cpe-tab.is-active {
	background: var(--wp--preset--color--brand-light);
	color: var(--wp--preset--color--white);
	font-weight: 500;
}

.cpe-tab-panels > * { margin-block: 0; }

/* Without JS every panel stays visible — tabs.js adds [hidden] only after wiring up. */
.cpe-tab-panel {
	display: flex;
	flex-direction: column;
	gap: 20px;
}

.cpe-tab-panel > * { margin-block: 0; }


.cpe-doc-card {
	margin: 0;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
	width: 400px;
	max-width: 100%;
	padding: 15px 30px;
	border: 1px solid var(--wp--preset--color--border-light);
	border-radius: 10px;
	background: var(--wp--preset--color--white);
	font-size: 16px;
	line-height: 24px;
	font-weight: 500;
}

.cpe-doc-card::before,
.cpe-doc-card::after {
	content: "";
	width: 16px;
	height: 16px;
	flex-shrink: 0;
	background-color: var(--wp--preset--color--primary);
	-webkit-mask: url("../icons/fi-rr-arrow-up-right-from-square.svg") no-repeat center / contain;
	mask: url("../icons/fi-rr-arrow-up-right-from-square.svg") no-repeat center / contain;
}

.cpe-doc-card a { flex: 1; }

.cpe-steps {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: 20px;
	width: 100%;
}

.cpe-steps > * { margin-block: 0; }

/* Connector behind the numbered bullets. */
.cpe-steps::before {
	content: "";
	position: absolute;
	left: 20px;
	top: 20px;
	bottom: 20px;
	width: 1px;
	background: var(--wp--preset--color--border-light);
}

.cpe-step {
	position: relative;
	display: flex;
	align-items: center;
	gap: 20px;
}

.cpe-step > * { margin-block: 0; }

.cpe-step-num {
	margin: 0;
	width: 40px;
	height: 40px;
	flex-shrink: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: 100px;
	background: var(--wp--preset--color--border-light);
	font-size: 16px;
	line-height: 24px;
	color: var(--wp--preset--color--primary);
}

.cpe-step-text {
	margin: 0;
	font-size: 16px;
	line-height: 24px;
	color: var(--wp--preset--color--primary);
}

.cpe-code {
	padding: 0 5px;
	border-radius: 2px;
	background: var(--wp--preset--color--brand-pale);
	font-family: inherit;
	font-size: 16px;
}

/* --- panel 3: partner company logos --- */

.cpe-company-grid {
	display: grid;
	grid-template-columns: repeat(7, 1fr);
	gap: 30px;
	width: 100%;
}

.cpe-company-grid > * { margin-block: 0; }

.cpe-company {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 10px;
	height: 83px;
	padding: 10px;
	border: 1px solid var(--wp--preset--color--border-light);
	border-radius: 10px;
	background: var(--wp--preset--color--white);
}

.cpe-company > * { margin-block: 0; }

.cpe-company-logo { margin: 0; }
.cpe-company-logo img {
	width: 28px;
	height: 28px;
	object-fit: contain;
}

.cpe-company-name {
	margin: 0;
	font-size: 14px;
	line-height: 19px;
	color: var(--wp--preset--color--muted-dark);
	text-align: center;
}

@media (max-width: 1000px) {
	.cpe-infobox-row { grid-template-columns: 1fr; }
	.cpe-company-grid { grid-template-columns: repeat(4, 1fr); }
	.cpe-tabs { flex-wrap: wrap; border-radius: 20px; }
}

@media (max-width: 600px) {
	.cpe-company-grid { grid-template-columns: repeat(2, 1fr); }
}

/* ---------- Staff directory ---------- */

.cpe-staff-controls {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 20px;
	flex-wrap: wrap;
	width: 100%;
}

/* Tabs size to content so the search box sits on the RIGHT of the same row
   (Figma 617-9999). FAQ tabs (no search beside them) keep full width. */
.wp-block-buttons.cpe-staff-tabs {
	gap: 15px;
	margin: 0;
}

.wp-block-buttons.cpe-faq-tabs {
	gap: 15px;
	width: 100%;
	margin: 0;
}

/* cpe/filter-tabs renders a plain .wp-block-buttons (no core is-layout-flex
   class), so set the flex row explicitly. Sized to content — not 100% width —
   so it sits on the left of .cpe-staff-controls with the search box on the
   right of the same row (matches the News/Events listing design). */
.cpe-filter-tabs {
	display: flex;
	flex-wrap: wrap;
	gap: 15px;
	margin: 0;
}

.wp-block-button.cpe-staff-tab .wp-block-button__link,
.wp-block-button.cpe-faq-tab .wp-block-button__link,
.cpe-filter-tab .wp-block-button__link {
	background: var(--wp--preset--color--white);
	border: 1px solid #efeeec;
	border-radius: 100px;
	padding: 5px 20px;
	font-size: 16px;
	font-weight: 400;
	color: var(--wp--preset--color--primary);
	cursor: pointer;
}

.wp-block-button.cpe-staff-tab.is-active .wp-block-button__link,
.wp-block-button.cpe-faq-tab.is-active .wp-block-button__link,
.cpe-filter-tab.is-active .wp-block-button__link {
	background: var(--wp--preset--color--brand);
	border-color: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--white);
}

.cpe-staff-search {
	position: relative;
	width: 300px;
}

.cpe-staff-search-input {
	width: 100%;
	border: 1px solid #efeeec;
	border-radius: 100px;
	padding: 10px 40px 10px 20px;
	font-size: 14px;
	color: var(--wp--preset--color--primary);
	font-family: inherit;
}

.cpe-staff-search-input:focus {
	outline: none;
	border-color: var(--wp--preset--color--muted);
}

.cpe-staff-search::after {
	content: "";
	position: absolute;
	right: 16px;
	top: 50%;
	transform: translateY(-50%);
	width: 16px;
	height: 16px;
	background-color: #6e6e6e;
	-webkit-mask: url("../icons/fi-rr-search.svg") no-repeat center / contain;
	mask: url("../icons/fi-rr-search.svg") no-repeat center / contain;
	pointer-events: none;
}

.cpe-staff-section {
	display: flex;
	flex-direction: column;
	gap: 30px;
	width: 100%;
}

.cpe-staff-section-head {
	display: flex;
	align-items: center;
	gap: 20px;
	width: 100%;
}

.cpe-staff-section-head p {
	font-size: 24px;
	font-weight: 600;
	margin: 0;
	white-space: nowrap;
}

.cpe-staff-section-head::after {
	content: "";
	flex: 1;
	height: 1px;
	background: var(--wp--preset--color--border);
}

.cpe-staff-grid {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: 20px;
	width: 100%;
}

.cpe-staff-card {
	display: flex;
	flex-direction: column;
	border-radius: 10px;
	overflow: hidden;
}

.cpe-staff-photo-wrap {
	background: var(--wp--preset--color--surface-muted);
	aspect-ratio: 1 / 1;
	width: 100%;
	display: flex;
	align-items: center;
	justify-content: center;
	color: var(--wp--preset--color--primary);
	font-size: 16px;
}

.cpe-staff-photo-wrap .cpe-staff-photo {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.cpe-staff-info {
	padding: 20px 10px;
	display: flex;
	flex-direction: column;
	gap: 10px;
}

.cpe-staff-name {
	font-size: 20px;
	font-weight: 500;
	margin: 0;
}

.cpe-staff-position {
	font-size: 14px;
	color: var(--wp--preset--color--muted-dark);
	margin: 0;
	line-height: 1.5;
}

.cpe-staff-contact {
	display: flex;
	flex-direction: column;
	gap: 5px;
	padding-top: 10px;
}

.cpe-staff-contact p {
	margin: 0;
	font-size: 14px;
	display: flex;
	align-items: center;
	gap: 8px;
}

.cpe-staff-phone::before {
	content: "";
	width: 14px;
	height: 14px;
	flex-shrink: 0;
	background-color: var(--wp--preset--color--primary);
	-webkit-mask: url("../icons/heroicon-phone.svg") no-repeat center / contain;
	mask: url("../icons/heroicon-phone.svg") no-repeat center / contain;
}

.cpe-staff-email::before {
	content: "";
	width: 14px;
	height: 14px;
	flex-shrink: 0;
	background-color: var(--wp--preset--color--primary);
	-webkit-mask: url("../icons/heroicon-envelope.svg") no-repeat center / contain;
	mask: url("../icons/heroicon-envelope.svg") no-repeat center / contain;
}

/* ---------- Media placeholders (reused across inner pages) ---------- */

.cpe-media-placeholder {
	background: var(--wp--preset--color--surface-muted);
	display: flex;
	align-items: center;
	justify-content: center;
	text-align: center;
	color: var(--wp--preset--color--primary);
	font-size: 16px;
	padding: 10px;
}

.cpe-media-placeholder p { margin: 0; line-height: 1.5; }

/* ---------- Department History / About Us ---------- */

/* About Us page uses a generous 50px section rhythm (Figma 617:7404) */
.cpe-page-wrap--about { gap: 50px; }

.cpe-history-page {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 50px;
	width: 100%;
}

/* These wrappers are core/group (is-layout-flow) but styled as flex+gap here,
   so cancel WordPress's injected block-gap margins that otherwise stack on the
   gap and stagger flex children (e.g. the gallery row). */
.cpe-history-page > *,
.cpe-history-layout > *,
.cpe-history-aside > *,
.cpe-gallery-row > *,
.cpe-stat-row > * { margin-block: 0; }

.cpe-history-hero {
	width: 1000px;
	max-width: 100%;
	height: 563px;
	margin-inline: auto;
}

/* The cover as editors actually leave it: a plain core/image (no hero class),
   usually the 1024px "large" size, which then sat at its own width inside the
   wider column. Span the column at 16:9 whatever size was picked. */
.cpe-history-page > .wp-block-image {
	width: 100%;
	margin: 0;
}

.cpe-history-page > .wp-block-image img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 16 / 9;
	object-fit: cover;
}

.cpe-history-layout {
	display: flex;
	gap: 50px;
	align-items: flex-start;
	width: 100%;
	flex-wrap: wrap;
}

.cpe-history-aside {
	display: flex;
	flex-direction: column;
	gap: 40px;
	flex-shrink: 0;
	width: 320px;
}

.cpe-info-card {
	background: var(--wp--preset--color--white);
	border-radius: 15px;
	padding: 20px;
	display: flex;
	flex-direction: column;
	gap: 20px;
	width: 100%;
}

.cpe-info-card-head {
	border-bottom: 1px solid #efeeec;
	padding-bottom: 10px;
	width: 100%;
}

.cpe-info-card-head p { margin: 0; font-size: 16px; font-weight: 500; }

.cpe-stat-row { display: flex; gap: 20px; width: 100%; }

.cpe-stat-box {
	background: var(--wp--preset--color--page-background);
	border-radius: 10px;
	padding: 15px 20px;
	flex: 1;
	text-align: center;
}

.cpe-stat-box p { margin: 0; }
.cpe-stat-number { font-size: 20px; font-weight: 700; }
.cpe-stat-label { font-size: 14px; color: var(--wp--preset--color--muted); }

.cpe-history-portrait { width: 320px; height: 240px; }

.cpe-history-body {
	display: flex;
	flex-direction: column;
	gap: 30px;
	flex: 1;
	min-width: 320px;
}

.cpe-history-body p { margin: 0; font-size: 16px; line-height: 1.5; }

.cpe-quote-box {
	background: var(--wp--preset--color--white);
	border-radius: 0 10px 10px 0;
	padding: 20px 30px;
}

.cpe-gallery-row {
	display: flex;
	gap: 40px;
	justify-content: center;
	flex-wrap: wrap;
	width: 100%;
}

.cpe-gallery-item { width: 340px; height: 255px; }

/* Three equal photos across the full column. Editors place them in a Row and
   drag each to a different width (321/342/330px, saved as inline styles), and
   the photos are not all 4:3, so the row came out narrower than the column
   with a shorter middle picture. A grid with fixed 4:3 crops makes the row
   independent of both; !important is only to outrank those inline widths. */
.cpe-gallery-row > .wp-block-group {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 40px;
	width: 100%;
}

.cpe-gallery-row .wp-block-image {
	width: 100%;
	margin: 0;
}

.cpe-gallery-row .wp-block-image img {
	display: block;
	width: 100% !important;
	height: auto !important;
	aspect-ratio: 4 / 3;
	object-fit: cover;
}

@media (max-width: 600px) {
	.cpe-gallery-row > .wp-block-group { grid-template-columns: 1fr; gap: 20px; }
}

/* ---------- Partners ---------- */

.cpe-partners-section {
	display: flex;
	flex-direction: column;
	gap: 20px;
	width: 100%;
}

.cpe-partners-section-head {
	display: flex;
	align-items: center;
	gap: 20px;
	width: 100%;
}

.cpe-partners-section-head p {
	font-size: 24px;
	font-weight: 600;
	margin: 0;
	white-space: nowrap;
}

.cpe-partners-section-head::after {
	content: "";
	flex: 1;
	height: 1px;
	background: var(--wp--preset--color--border);
}

/* Partners = 5-col grid, MOU = 4-col grid (Figma 756-3378). Both are core/group
   (is-layout-flow) styled as grid → cancel injected block-gap margins so the
   first card isn't offset/oversized. */
.cpe-partners-row {
	display: grid;
	grid-template-columns: repeat(5, 1fr);
	gap: 20px;
	width: 100%;
}

.cpe-partners-row > *,
.cpe-mou-grid > * { margin-block: 0; }

.cpe-partner-card {
	background: var(--wp--preset--color--white);
	border: 1px solid var(--wp--preset--color--border-light);
	border-radius: 10px;
	padding: 20px;
	min-height: 110px;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 8px;
}

.cpe-partner-card p { margin: 0; }
.cpe-partner-card .cpe-logo-mark { font-weight: 700; font-size: 20px; color: var(--wp--preset--color--muted); }
.cpe-partner-card .cpe-partner-name { font-size: 16px; text-align: center; }

.cpe-mou-grid {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: 20px;
	width: 100%;
}

.cpe-mou-card {
	background: var(--wp--preset--color--white);
	border: 1px solid var(--wp--preset--color--border-light);
	border-radius: 10px;
	padding: 20px;
	display: flex;
	flex-direction: column;
	align-items: stretch;
	gap: 12px;
	min-height: 120px;
}

.cpe-mou-card .cpe-logo-mark { font-weight: 700; font-size: 20px; margin: 0; text-align: center; color: var(--wp--preset--color--muted); }
.cpe-mou-card .cpe-mou-info { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; }
.cpe-mou-card .cpe-mou-info p { margin: 0; }
.cpe-mou-card .cpe-mou-name { font-size: 16px; }

.cpe-mou-country {
	font-size: 14px;
	color: var(--wp--preset--color--brand);
	background: var(--wp--preset--color--brand-tint);
	border-radius: 100px;
	padding: 4px 12px;
	display: inline-flex;
	align-items: center;
	gap: 6px;
}

.cpe-mou-country::before {
	content: "";
	width: 14px;
	height: 14px;
	flex-shrink: 0;
	background-color: var(--wp--preset--color--brand);
	-webkit-mask: url("../icons/fi-rr-marker.svg") no-repeat center / contain;
	mask: url("../icons/fi-rr-marker.svg") no-repeat center / contain;
}

/* ---------- Contact Us ---------- */

/* Dark card (left) + image (right) as ONE flush rounded card — Figma 772:4412.
   Markup order is [media, card]; row-reverse renders the card on the left. */
.cpe-contact-hero {
	display: flex;
	flex-direction: row-reverse;
	align-items: stretch;
	width: 100%;
	border-radius: 20px;
	overflow: hidden;
	box-shadow: 0 0 10px 1px rgba(17, 17, 17, 0.05);
}

.cpe-contact-hero-media {
	flex: 1;
	min-width: 320px;
	margin: 0;
	min-height: 400px;
}

.cpe-contact-card {
	background: var(--wp--preset--color--secondary);
	color: var(--wp--preset--color--white);
	padding: 40px;
	display: flex;
	flex-direction: column;
	justify-content: center;
	gap: 30px;
	flex: 1;
	min-width: 320px;
}

.cpe-contact-brand {
	display: flex;
	align-items: center;
	gap: 20px;
	margin-bottom: 10px;
}

.cpe-contact-brand .cpe-contact-logo { margin: 0; flex-shrink: 0; }
.cpe-contact-brand .cpe-contact-logo img { width: 64px; height: auto; display: block; }

.cpe-contact-brand-name {
	margin: 0;
	font-size: 18px;
	font-weight: 600;
	line-height: 1.4;
	color: var(--wp--preset--color--white);
}

.cpe-contact-card-row {
	display: flex;
	align-items: center;
	gap: 20px;
}

.cpe-contact-card-row p { margin: 0; font-size: 16px; line-height: 1.5; }

.cpe-contact-card-row::before {
	content: "";
	width: 24px;
	height: 24px;
	flex-shrink: 0;
}

.cpe-contact-location::before {
	background-color: var(--wp--preset--color--white);
	-webkit-mask: url("../icons/fi-rr-marker.svg") no-repeat center / contain;
	mask: url("../icons/fi-rr-marker.svg") no-repeat center / contain;
}

.cpe-contact-phone::before {
	background-color: var(--wp--preset--color--white);
	-webkit-mask: url("../icons/heroicon-phone.svg") no-repeat center / contain;
	mask: url("../icons/heroicon-phone.svg") no-repeat center / contain;
}

.cpe-contact-email::before {
	background-color: var(--wp--preset--color--white);
	-webkit-mask: url("../icons/heroicon-envelope.svg") no-repeat center / contain;
	mask: url("../icons/heroicon-envelope.svg") no-repeat center / contain;
}

.cpe-contact-map {
	width: 100%;
	aspect-ratio: 1241 / 602;
	border-radius: 20px;
	overflow: hidden;
	box-shadow: 0 0 10px 1px rgba(17, 17, 17, 0.05);
}

.cpe-contact-map iframe {
	width: 100%;
	height: 100%;
	border: none;
	display: block;
}

/* ---------- Staff detail (single) ---------- */

.cpe-staff-detail {
	display: flex;
	gap: 50px;
	width: 100%;
	flex-wrap: wrap;
}

.cpe-staff-detail-photo-col {
	width: 390px;
	flex-shrink: 0;
	display: flex;
	flex-direction: column;
	gap: 20px;
	background: var(--wp--preset--color--white);
	border: 1px solid var(--wp--preset--color--border-light);
	border-radius: 15px;
	padding: 20px;
	box-shadow: 0 0 10px 1px rgba(17, 17, 17, 0.05);
	align-self: flex-start;
}

.cpe-staff-photo-frame {
	width: 100%;
	aspect-ratio: 1 / 1;
	background: var(--wp--preset--color--border-light);
	border-radius: 10px;
	overflow: hidden;
	display: flex;
	align-items: center;
	justify-content: center;
}

.cpe-staff-photo-frame img,
.cpe-staff-photo-frame figure,
.cpe-staff-photo-frame .wp-block-post-featured-image {
	width: 100%;
	height: 100%;
	object-fit: cover;
	margin: 0;
}

.cpe-staff-detail-meta {
	display: flex;
	flex-direction: column;
	gap: 15px;
}

.cpe-staff-detail-meta-item {
	display: flex;
	gap: 15px;
	align-items: center;
	border: 1px solid var(--wp--preset--color--border-light);
	border-radius: 10px;
	padding: 15px;
}

.cpe-staff-detail-meta-item p { margin: 0; }
.cpe-staff-detail-meta-item .label { font-size: 14px; color: var(--wp--preset--color--muted); }
.cpe-staff-detail-meta-item .value { font-size: 16px; font-weight: 600; }

.cpe-staff-detail-meta-item::before {
	content: "";
	width: 40px;
	height: 40px;
	flex-shrink: 0;
	border-radius: 8px;
	background-color: var(--wp--preset--color--brand-tint);
	background-repeat: no-repeat;
	background-position: center;
	background-size: 20px 20px;
}

.cpe-meta-room {
	--cpe-icon: url("../icons/fi-rr-door-closed.svg");
}

.cpe-meta-phone {
	--cpe-icon: url("../icons/heroicon-phone.svg");
}

.cpe-meta-email {
	--cpe-icon: url("../icons/heroicon-envelope.svg");
}

.cpe-staff-detail-main {
	flex: 1;
	min-width: 320px;
	display: flex;
	flex-direction: column;
	gap: 30px;
}

.cpe-staff-detail-head { display: flex; flex-direction: column; gap: 5px; }
.cpe-staff-detail-name { font-size: 32px; font-weight: 700; margin: 0; }
.cpe-staff-detail-position { font-size: 16px; color: var(--wp--preset--color--brand); font-weight: 500; margin: 0; line-height: 1.5; }

.cpe-staff-detail-section { display: flex; flex-direction: column; gap: 20px; }
.cpe-staff-detail-section h2 { font-size: 20px; font-weight: 600; margin: 0; }

.cpe-research-tags { display: flex; flex-wrap: wrap; gap: 10px; }

.cpe-research-tag {
	background: var(--wp--preset--color--secondary);
	color: var(--wp--preset--color--white);
	border-radius: 100px;
	padding: 8px 20px;
	font-size: 14px;
	display: inline-block;
}

.cpe-courses-table table {
	width: 100%;
	border-collapse: collapse;
	background: var(--wp--preset--color--white);
	border: 1px solid var(--wp--preset--color--border-light);
	border-radius: 10px;
	overflow: hidden;
	box-shadow: 0 0 10px 1px rgba(17, 17, 17, 0.05);
}

.cpe-courses-table th {
	background: var(--wp--preset--color--brand-pale);
	text-align: left;
	padding: 14px 20px;
	font-size: 14px;
	font-weight: 600;
	color: var(--wp--preset--color--primary);
}

.cpe-courses-table td {
	padding: 14px 20px;
	font-size: 16px;
	border-top: 1px solid var(--wp--preset--color--border-light);
}

.cpe-courses-table td:first-child { color: var(--wp--preset--color--brand); font-weight: 600; }

/* ---------- Editor-only helpers ---------- */

.cpe-editor-placeholder {
	border: 1px dashed var(--wp--preset--color--border);
	border-radius: 6px;
	padding: 12px 16px;
	margin: 0;
	font-style: italic;
	color: var(--wp--preset--color--muted);
	background: var(--wp--preset--color--page-background);
}

/* ---------- Responsive ---------- */

@media (max-width: 1200px) {
	.cpe-hero-slide,
	.cpe-section,
	.cpe-footer,
	.cpe-page-wrap {
		padding-inline: 60px;
	}
	.cpe-staff-grid { grid-template-columns: repeat(3, 1fr); }
	.cpe-partners-row { grid-template-columns: repeat(4, 1fr); }
	.cpe-mou-grid { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 900px) {
	.cpe-header { padding: 16px 24px; }
	.cpe-hero-slide,
	.cpe-section,
	.cpe-footer,
	.cpe-page-wrap {
		padding-inline: 24px;
	}
	.cpe-nav ul { gap: 14px; }
	.cpe-nav a { font-size: 14px; }
	.cpe-hero-title { font-size: 28px; }
	.cpe-feature-cell { flex-basis: 100%; }
	.cpe-scholarship-card { width: 100%; }
	.cpe-post-card { max-width: none; }
	.cpe-footer-top { flex-direction: column; }
	.cpe-program-card { justify-content: flex-start; }
	.cpe-staff-grid { grid-template-columns: repeat(2, 1fr); }
	.cpe-staff-controls { flex-direction: column; align-items: stretch; }
	.cpe-staff-search { width: 100%; }
	.cpe-history-layout { flex-direction: column; }
	.cpe-history-aside { width: 100%; }
	.cpe-history-portrait { width: 100%; }
	.cpe-staff-detail-photo-col { width: 100%; }
	.cpe-post-card--featured { flex-direction: column; }
	.cpe-post-card--featured .cpe-post-thumb { width: 100%; }
	.cpe-photo-grid { grid-template-columns: repeat(2, 1fr); }
	.cpe-partners-row { grid-template-columns: repeat(3, 1fr); }
	.cpe-mou-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 560px) {
	.cpe-staff-grid { grid-template-columns: 1fr; }
	.cpe-partners-row { grid-template-columns: repeat(2, 1fr); }
	.cpe-mou-grid { grid-template-columns: 1fr; }
}

/* ============================================================
   Interactive blocks (cpe/tabs, cpe/faq, cpe/staff-filter)
   ------------------------------------------------------------
   These render real <button> elements instead of the core
   button/paragraph markup their class-convention predecessors used,
   so the shared pill styling is restated against the bare element and
   the browser's default button chrome is cleared. The .wp-block-button
   rules above still apply to cpe/filter-tabs, which is unchanged.
   ============================================================ */

.cpe-tabs .cpe-tab,
.cpe-faq-tabs .cpe-faq-tab,
.cpe-staff-tabs .cpe-staff-tab {
	font: inherit;
	-webkit-appearance: none;
	appearance: none;
	cursor: pointer;
}

.cpe-tabs .cpe-tab {
	border: 0;
	background: transparent;
}

.cpe-faq-tabs,
.cpe-staff-tabs {
	display: flex;
	flex-wrap: wrap;
	gap: 15px;
	margin: 0;
}

.cpe-faq-tabs .cpe-faq-tab,
.cpe-staff-tabs .cpe-staff-tab {
	background: var(--wp--preset--color--white);
	border: 1px solid #efeeec;
	border-radius: 100px;
	padding: 5px 20px;
	font-size: 16px;
	font-weight: 400;
	color: var(--wp--preset--color--primary);
}

.cpe-faq-tabs .cpe-faq-tab.is-active,
.cpe-staff-tabs .cpe-staff-tab.is-active {
	background: var(--wp--preset--color--brand);
	border-color: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--white);
}

.cpe-tabs-wrap {
	display: flex;
	flex-direction: column;
	gap: 20px;
}

/* The scripts hide things with the hidden attribute rather than an inline
   style, so it has to beat the display:flex the panels/sections carry. */
.cpe-tab-panel[hidden],
.cpe-faq-item[hidden],
.cpe-staff-card[hidden],
.cpe-staff-section[hidden] {
	display: none !important;
}

/* Editor-only: the tabs/FAQ blocks stack every child so all of them stay
   reachable while editing — the front end is what collapses them. */
.cpe-tabs-editor .cpe-tab-panel,
.cpe-faq-editor .cpe-faq-item {
	display: block;
}

/* ============================================================
   Staff directory as a core Query Loop
   ------------------------------------------------------------
   The cards used to come out of cpe_staff_card() as one PHP string, so
   nothing inside them could be edited. They are core blocks in a
   core/post-template now, which wraps every card in the <li> that block
   always emits — display:contents hands the grid back its real children
   so .cpe-staff-grid keeps laying the cards out directly.
   ============================================================ */

.cpe-staff-grid > li {
	display: contents;
}

/* A bound paragraph still renders when its meta value is empty, where the
   old PHP simply skipped the row. Collapsing empties keeps a staff member
   with no phone number from showing a blank line. */
.cpe-staff-card p:empty,
.cpe-staff-detail-meta .value:empty {
	display: none;
}

/* core/post-title brings its own block class; the card's rules were
   written for the bare one. */
.cpe-staff-card .wp-block-post-title.cpe-staff-name {
	margin: 0;
}

/* post-featured-image renders nothing at all when a staff member has no
   photo — and none of them do yet — so the grey 1:1 placeholder lives on
   the wrapping group, which is always present and is itself editable. */
.cpe-staff-photo-wrap .wp-block-post-featured-image {
	margin: 0;
	width: 100%;
	height: 100%;
}

.cpe-staff-photo-wrap .wp-block-post-featured-image img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* The Query Loop wrapper stands in for the old .cpe-staff-section div and
   must keep the same column flow. */
.wp-block-query.cpe-staff-section > .wp-block-post-template {
	margin: 0;
	padding: 0;
	list-style: none;
}

/* ============================================================
   Research & Innovation (Figma 925:3057)
   ------------------------------------------------------------
   The cards, grid, tag pill, meta row, detail link and pagination
   are the News listing's, unchanged — the design reuses that card
   wholesale. Only the two things this page does differently need
   rules of their own.
   ============================================================ */

/* Search sits alone on its own row, pushed right — the News listing
   has filter tabs on the left of the same row, this one does not. */
.cpe-research-controls {
	display: flex;
	justify-content: flex-end;
	width: 100%;
	margin: 0;
}

.cpe-no-results {
	color: var(--wp--preset--color--muted);
	padding: 60px 0;
	margin: 0;
}

/* ============================================================
   Design review fixes — Footer, Accordion, FAQ
   Issues #10 #11 #12 #13 #31
   ============================================================ */

/* #11 — footer menu links turn accent/yellow/400 on hover. The list is
   plain <li><a>, so the rule hangs off the link rather than the item. */
.cpe-footer-nav ul a:hover,
.cpe-footer-nav ul a:focus-visible {
	color: var(--wp--preset--color--accent-yellow);
}

/* #13 — the Facebook chip's background is primary/700, not white. The glyph
   flips to white so it stays legible against it. */
.wp-block-social-links.cpe-social .wp-social-link {
	background: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--white);
}

.wp-block-social-links.cpe-social .wp-social-link svg {
	fill: var(--wp--preset--color--white);
}

/* #12 — copyright centred, normal weight; 12px and still centred on mobile. */
.cpe-footer-copyright {
	font-weight: 400;
	text-align: center;
	width: 100%;
}

/* #10 — an open accordion gets a rule between question and answer, and the
   answer takes the primary text colour rather than the muted grey. */
.cpe-faq-item[open] summary {
	border-bottom: 1px solid var(--wp--preset--color--border-light);
	padding-bottom: 15px;
}

.cpe-faq-item .cpe-faq-answer {
	color: var(--wp--preset--color--primary);
}

/* #31 — 50px between the category filter and the list below it. The gap sits
   on the FAQ block's own wrapper so it holds wherever the block is placed. */
.cpe-faq-wrap {
	display: flex;
	flex-direction: column;
	gap: 50px;
}

@media (max-width: 782px) {
	/* #12 (mobile) */
	.cpe-footer-copyright {
		font-size: 12px;
		font-weight: 400;
		text-align: center;
	}
}

/* ============================================================
   Design review fixes — Home & Hero
   Issues #1 #2 #5 #6 #7 #8 #9 #14 #16 #18
   ============================================================ */

/* #1 — card text turns primary/700 on hover, across all three Home card
   shapes so the behaviour is one rule rather than three that drift. */
.cpe-program-card:hover .cpe-program-title,
.cpe-program-card:hover .cpe-detail-link,
.cpe-program-card:hover .cpe-detail-link a,
.cpe-scholarship-card:hover h3,
.cpe-scholarship-card:hover .cpe-detail-link,
.cpe-scholarship-card:hover .cpe-detail-link a,
.cpe-post-card:hover .wp-block-post-title a,
.cpe-post-card:hover .cpe-detail-link,
.cpe-post-card:hover .cpe-detail-link a {
	color: var(--wp--preset--color--brand);
}

/* The chevron is a background image, so recolour it rather than inherit. */
.cpe-program-card:hover .cpe-detail-link a::after,
.cpe-scholarship-card:hover .cpe-detail-link a::after,
.cpe-post-card:hover .cpe-detail-link a::after {
	background-color: var(--wp--preset--color--brand);
	-webkit-mask: url("../icons/fi-rr-angle-small-right.svg") no-repeat center / contain;
	mask: url("../icons/fi-rr-angle-small-right.svg") no-repeat center / contain;
}

/* #2 — the whole card is the click target, not just the "รายละเอียด" link.
   Stretching the existing link over the card keeps a single <a> in the markup:
   no duplicate link for screen readers, and the blocks stay as they are. */
.cpe-program-card,
.cpe-scholarship-card,
.cpe-post-card,
.cpe-feature-cell {
	position: relative;
}

.cpe-program-card .cpe-detail-link a::before,
.cpe-scholarship-card .cpe-detail-link a::before,
.cpe-post-card .wp-block-post-title a::before,
.cpe-feature-cell .cpe-detail-link a::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
}

/* Anything else clickable in the card has to sit above that overlay. */
.cpe-post-card .cpe-detail-link,
.cpe-post-thumb a {
	position: relative;
	z-index: 2;
}

/* The tag is already position:absolute over the thumb (Figma Tag 793:9516 is a
   pill that hugs its label). It only needs lifting above the stretched link,
   not repositioning — setting position:relative here put it back in flow,
   where a block-level <div> stretches to the full card width. */
.cpe-post-card .cpe-post-tag {
	z-index: 2;
}

/* #5 — the featured image fills the thumb: core/post-featured-image wraps the
   img in a <figure> whose margin was leaving white above and to the left, and
   the card's own overflow:hidden then has to do the corner rounding so the
   image corners match the card's instead of staying square. */
.cpe-post-thumb figure,
.cpe-post-thumb .wp-block-post-featured-image {
	margin: 0;
	height: 100%;
	width: 100%;
}

.cpe-post-thumb figure img,
.cpe-post-thumb .wp-block-post-featured-image img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: 0;
}

/* #6 — past 1440px the Home card rows fill the extra width instead of
   staying at three fixed columns. auto-fill with a 320px floor lands on
   4 columns around 1600px and 6 near 2200px. */
@media (min-width: 1441px) {
	.home .cpe-card-grid.wp-block-post-template {
		grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
		justify-content: stretch;
	}
}

/* #7 — Student Life cards take the primary/50 hover background. */
.cpe-feature-cell:hover {
	background: var(--wp--preset--color--brand-tint);
}

/* #8, #9 — "ดู Student Life" is a normal-weight label, and its hover state is
   a primary/100 fill with no border rather than the grey wash it had. */
.wp-block-button.cpe-btn-outline .wp-block-button__link {
	font-weight: 400;
}

.wp-block-button.cpe-btn-outline .wp-block-button__link:hover {
	background: var(--wp--preset--color--brand-hover);
	border-color: transparent;
}

/* #14 — the curriculum section sits on primary/50. */
.home .cpe-section:has(.cpe-degree-group) {
	background: var(--wp--preset--color--brand-tint);
}

/* #16 — reverted. `justify-items: center` shrank each card to its own title
   width and centred it inside its track, so no two cards lined up and rows
   staggered; `align-items: center` also stopped them stretching to equal
   height. The design (617:3147, all cards 127px in a row) wants stretch. */

/* #18 — 30px between one degree group and the next. The container's own flex
   gap supplies 20 of it. */
.cpe-section-inner .cpe-degree-group + .cpe-degree-group {
	margin-top: 10px;
}

/* ============================================================
   Design review fixes — Staff, Gallery, News, Facilities
   Issues #30 #33 #34 #35 #37 #38 #40
   ============================================================ */

/* #30 — square photos, name turns primary/700 on card hover, whole card
   clickable. The overlay hangs off the title link so the card keeps one <a>. */
.cpe-staff-photo-wrap,
.cpe-staff-photo-wrap img,
.cpe-staff-card {
	border-radius: 0;
}

.cpe-staff-card {
	position: relative;
}

.cpe-staff-card .cpe-staff-name a::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
}

.cpe-staff-card .cpe-staff-email {
	position: relative;
	z-index: 2;
}

.cpe-staff-card:hover .cpe-staff-name a {
	color: var(--wp--preset--color--brand);
}

/* #38 — the rule between course rows moves to the bottom of each row, so the
   header is not underlined twice and the last row closes the table. */
.cpe-courses-table td {
	border-top: 0;
	border-bottom: 1px solid var(--wp--preset--color--border-light);
}

/* #35 — gallery images fill their tile: no white surround, square corners. */
.cpe-gallery-card,
.cpe-gallery-thumb,
.cpe-gallery-thumb img,
.cpe-photo-grid-item,
.cpe-photo-grid-img {
	border-radius: 0;
	background: transparent;
}

.cpe-gallery-thumb figure,
.cpe-photo-grid-item figure {
	margin: 0;
}

.cpe-gallery-thumb img,
.cpe-photo-grid-img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* #33 — the section heading sits directly on its rule, and the rule is
   primary/700 rather than the default grey. */
.cpe-section-head {
	padding-bottom: 0;
	gap: 0;
}

.cpe-section-head::after,
.cpe-staff-section-head::after {
	background: var(--wp--preset--color--brand);
}

/* #34 — filter and search share a baseline and a height. Both were sizing
   themselves from their own content, so a one-line filter row and a padded
   input never lined up. */
.cpe-staff-controls,
.cpe-research-controls {
	display: flex;
	align-items: center;
	gap: 20px;
}

.cpe-staff-controls > *,
.cpe-research-controls > * {
	margin-block: 0;
}

.cpe-filter-tabs .cpe-filter-tab .wp-block-button__link,
.cpe-faq-tabs .cpe-faq-tab,
.cpe-staff-tabs .cpe-staff-tab,
.cpe-staff-search .cpe-staff-search-input {
	height: 40px;
	display: inline-flex;
	align-items: center;
	box-sizing: border-box;
}

/* #40 — "เปิดใช้งาน" takes the primary/100 hover fill with no border. */
.cpe-facility-card .wp-block-button__link:hover,
.wp-block-button.cpe-btn-open .wp-block-button__link:hover {
	background: var(--wp--preset--color--brand-hover);
	border-color: transparent;
}

@media (max-width: 782px) {
	/* #37 — on mobile the staff contact lines stack and drop their icons. */
	.cpe-staff-detail-meta {
		flex-direction: column;
	}

	.cpe-staff-detail-meta-item {
		flex-direction: column;
		align-items: flex-start;
	}

	.cpe-staff-detail-meta-item::before,
	.cpe-staff-detail-meta-item::after {
		display: none;
	}
}

/* ============================================================
   Design review fixes — Curriculum, Curriculum detail, Contact
   Issues #21 #23 #24 #25 #26 #27 #28 #29 #32 #39
   ============================================================ */

/* #21 — 50px between degree groups on the curriculum listing, 20px between a
   degree's heading and its cards, and the tag matches Home's pill. */
.cpe-curriculum-group + .cpe-curriculum-group {
	margin-top: 50px;
}

.cpe-curriculum-head {
	margin-bottom: 20px;
}

.cpe-badge {
	background: var(--wp--preset--color--brand-tint);
	color: var(--wp--preset--color--brand);
}

/* #23 — 30px between sections of a curriculum detail page. */
.cpe-prog-section + .cpe-prog-section {
	margin-top: 30px;
}

/* #24 — the table of contents highlights in primary/700 on hover. */
.cpe-prog-toc a:hover,
.cpe-prog-toc a:focus-visible {
	color: var(--wp--preset--color--brand);
}

/* #25 — the PLO number chip is neutral/200, and its text shares a baseline
   with the copy beside it rather than sitting above it. */
.cpe-plo-num {
	background: var(--wp--preset--color--border-light);
}

.cpe-plo {
	display: flex;
	align-items: baseline;
	gap: 20px;
}

.cpe-plo-body {
	flex: 1;
}

/* #26 — the overview cards sit on neutral/100. */
.cpe-overview-box,
.cpe-overview-stats,
.cpe-stat {
	background: var(--wp--preset--color--page-background);
}

/* #27, #28 — square corners on detail-page imagery and on the structure and
   elective cards; the black copy inside those cards is medium weight. */
.cpe-prog-image,
.cpe-prog-image img,
.cpe-overview-box,
.cpe-stat,
.cpe-spec-list,
.cpe-spec-row {
	border-radius: 0;
}

.cpe-spec-row,
.cpe-spec-value {
	font-weight: 500;
}

/* #29 — an indented (course-level) row closes up against the category row
   above it instead of carrying the list's normal spacing. */
.cpe-spec-row--indent {
	margin-top: 0;
}

/* #32 — contact page: nothing rounded, the department panel runs to the top
   of its section with no white band above it, and 50px between the map and
   the block above. */
.cpe-contact-card,
.cpe-contact-hero,
.cpe-contact-hero-media,
.cpe-contact-logo,
.cpe-media-placeholder,
.cpe-contact-map,
.cpe-contact-map iframe {
	border-radius: 0;
}

.cpe-contact-hero {
	padding-top: 0;
}

.cpe-contact-map {
	margin-top: 50px;
}

@media (max-width: 782px) {
	/* #26, #39 — the grey overview cards and the elective counts stack. */
	.cpe-overview-stats,
	.cpe-prog-layout {
		flex-direction: column;
	}

	/* #32 (mobile) — details above the image stack, and the map gap is 40px. */
	.cpe-contact-hero {
		flex-direction: column;
	}

	.cpe-contact-map {
		margin-top: 40px;
	}
}

/* ============================================================
   Design review — second pass
   Issues #3 #6 #9 #13 (re-fixed after live verification)
   ============================================================ */

/* #13 — the first attempt keyed off `.cpe-social`, but the footer that
   actually renders comes from the wp_template_part row in the database, and
   that copy's social-links block carries no className. Scoping to the footer
   instead means the chip is styled by where it sits, not by a class an admin
   would have to know to re-add. Core's own colour is inside :where(), so a
   plain descendant selector already outranks it — no !important needed. */
.cpe-footer .wp-block-social-links .wp-social-link {
	background-color: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--white);
	width: 28px;
	height: 28px;
}

.cpe-footer .wp-block-social-links .wp-social-link svg {
	width: 16px;
	height: 16px;
	fill: var(--wp--preset--color--white);
}

/* #3 — core/read-more puts the className on the <a> itself, so the news,
   กิจกรรม and งานวิจัย cards matched `.cpe-detail-link` but never
   `.cpe-detail-link a`, and lost the chevron the หลักสูตร/ทุนการศึกษา cards
   (a <p> wrapping an <a>) kept. Matching the anchor in both shapes makes it
   one component again. */
a.cpe-detail-link::after {
	content: "";
	width: 16px;
	height: 16px;
	flex-shrink: 0;
	background-color: var(--wp--preset--color--muted);
	-webkit-mask: url("../icons/fi-rr-angle-small-right.svg") no-repeat center / contain;
	mask: url("../icons/fi-rr-angle-small-right.svg") no-repeat center / contain;
}

.cpe-post-card:hover a.cpe-detail-link::after {
	background-color: var(--wp--preset--color--brand);
	-webkit-mask: url("../icons/fi-rr-angle-small-right.svg") no-repeat center / contain;
	mask: url("../icons/fi-rr-angle-small-right.svg") no-repeat center / contain;
}

/* #9, #40 — `border-color: transparent` still reserved the 1px ring and let
   the page background show through it, which reads as the faint outline the
   review flagged. Painting the border the same colour as the fill removes the
   line while keeping the button exactly the same size in both states. */
.wp-block-button.cpe-btn-outline .wp-block-button__link:hover,
.cpe-facility-card .wp-block-button__link:hover,
.wp-block-button.cpe-btn-open .wp-block-button__link:hover {
	border-color: var(--wp--preset--color--brand-hover);
}

/* #6 — the auto-fill rule could never produce a fourth column: every section
   is capped at 1440px with a 160px gutter, so the row is 1120px wide no
   matter how wide the viewport is. Releasing the cap on the Home card
   sections above 1440px is what actually lets the grid grow; the gutter
   scales with it so the heading above stays aligned with the cards. */
@media (min-width: 1441px) {
	.home .cpe-section {
		max-width: none;
		padding-inline: clamp(160px, 11vw, 320px);
	}

	.home .cpe-card-grid.wp-block-post-template {
		grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
		justify-content: stretch;
	}
}

/* ============================================================
   Mobile — Figma 393px frames
   Navbar 617:2057 · overlay menu 579:2055 · footer 617:4951
   ------------------------------------------------------------
   600px is deliberate: it is exactly where core/navigation swaps
   to its hamburger (overlayMenu:"mobile"), so the header layout
   and the menu change over together instead of fighting.
   ============================================================ */

@media (max-width: 600px) {

	/* ---------- Navbar ---------- */

	/* 30px gutter / 20px rows, per the Mobile navbar frame. */
	.cpe-header { padding: 20px 30px; }

	/* #36 — the design puts the language pill before the burger; the markup
	   has the nav (which owns the burger) first. Ordering them here rather
	   than reordering the blocks keeps the header part editable as-is. */
	.cpe-header-right > .cpe-lang-switch,
	.cpe-header-right > .wp-block-navigation { order: 0; }
	.cpe-header-right > .cpe-lang-switch { order: 1; }
	.cpe-header-right > .wp-block-navigation { order: 2; }

	/* The burger is the exported Uicons glyph, not core's inline SVG. */
	.wp-block-navigation__responsive-container-open {
		width: 18px;
		height: 18px;
		padding: 0;
		background: url("../icons/fi-rr-menu-burger.svg") no-repeat center / contain;
	}

	.wp-block-navigation__responsive-container-open svg { display: none; }

	/* ---------- Overlay menu ---------- */

	.wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay) {
		background-color: var(--wp--preset--color--white);
		padding: 20px 30px;
	}

	.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-close {
		width: 20px;
		height: 20px;
		padding: 0;
		background: url("../icons/fi-rr-cross.svg") no-repeat center / contain;
	}

	.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-close svg { display: none; }

	.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content {
		padding-top: 40px;
		gap: 20px;
	}

	.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content {
		font-size: 16px;
		font-weight: 500;
		line-height: 24px;
		color: var(--wp--preset--color--primary);
	}

	/* Core hides the submenu arrow in the overlay and force-expands every
	   submenu, which flattens the menu into one long list. The design is an
	   accordion, so put the arrow back and collapse the submenus. The open
	   state is core's own aria-expanded, maintained by the navigation block's
	   interactivity — no extra script, and the admin toggles the behaviour
	   with the block's own "Open on click" setting. */
	/* Strip the desktop dropdown chrome: inside the overlay these are inline
	   sections of the menu, not floating panels. */
	.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__submenu-container {
		position: static;
		width: auto;
		max-width: none;
		margin: 0;
		padding: 0;
		border: 0;
		border-radius: 0;
		box-shadow: none;
		background: transparent;
		opacity: 1;
		visibility: visible;
	}

	/* Collapsed by default, matching the frame. core's aria-expanded cannot be
	   used as the open state here: isSubmenuOpen() ends in `|| isMenuOpen`, so
	   every submenu reports expanded the moment the overlay opens — which is
	   what rendered them all as open dropdowns. The open state is our own
	   class instead, set by assets/js/mobile-menu.js. */
	.wp-block-navigation__responsive-container.is-menu-open .has-child > .wp-block-navigation__submenu-container {
		display: none;
	}

	.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content .has-child.cpe-submenu-open > .wp-block-navigation__submenu-container {
		display: flex;
		flex-direction: column;
		gap: 20px;
		padding: 20px 0 0 20px;
	}

	/* Core gives submenu containers `gap: inherit` and its own top padding in
	   the overlay; both have to be beaten at equal specificity, and the items
	   themselves must not carry block-gap margins on top of the gap. */
	.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__submenu-container > .wp-block-navigation-item {
		margin: 0;
	}

	/* The design shows no disclosure arrow (588:4778), and core renders it as
	   a sibling of the label button, so in the overlay's column layout it
	   would stack underneath the label rather than sit beside it. */
	.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__submenu-icon {
		display: none;
	}

	/* The desktop dropdown gives these 8px/20px padding, which added 16px to
	   every sub-item's height and pushed the indent past the designed 20px. */
	.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
		display: block;
		padding: 0;
		white-space: normal;
	}

	/* ---------- Footer (Component 3) ---------- */

	.cpe-footer { padding: 30px 30px 15px; gap: 40px; }

	.cpe-footer-top { flex-direction: column; gap: 30px; }

	.cpe-footer-brand { gap: 30px; }

	.cpe-footer .cpe-brand {
		flex-direction: row;
		align-items: center;
		gap: 20px;
	}

	/* The site logo is a 73px asset; the mobile footer draws it at 43x30
	   (617:4951), and at full size it squeezed the department name from two
	   lines onto four. */
	.cpe-footer .cpe-brand .wp-block-site-logo,
	.cpe-footer .cpe-brand .custom-logo {
		width: 43px;
		height: auto;
		flex-shrink: 0;
	}

	.cpe-footer .cpe-brand-name { flex: 1; }

	/* Two link columns side by side, 60px apart — not one stacked list. */
	.cpe-footer-nav { flex-wrap: nowrap; gap: 60px; }

	.cpe-footer .wp-block-social-links .wp-social-link {
		width: 36px;
		height: 36px;
	}

	.cpe-footer .wp-block-social-links .wp-social-link svg {
		width: 20px;
		height: 20px;
	}

	.cpe-footer-address { gap: 20px; }
}

/* #19 — the grey overview boxes on ประวัติภาควิชา are left-aligned in the
   design (Figma 553:1937/553:1940); ours were centred. */
.cpe-stat-box { text-align: left; }

/* ============================================================
   Hero — mobile (Figma Carousel 972:10824, size=Mobile)
   ------------------------------------------------------------
   The responsive gutters above were written against `.cpe-hero`,
   which matches no element on the page: the padding is on
   .cpe-hero-slide. So the slide kept its desktop `0 160px 178px`
   at every width, leaving a ~73px text column at 393px. Renamed
   above; the rest of the mobile slide is specced here.
   ============================================================ */

@media (max-width: 600px) {
	/* 393x500 on mobile, not the desktop 810. */
	.cpe-hero-slider { height: 500px; }

	/* Content sits 67px off the bottom and is centred as a block. */
	.cpe-hero-slide {
		padding: 0 30px 67px;
		align-items: center;
	}

	/* Shrink-to-fit meant the block was only as wide as the eyebrow, so the
	   headline never got the full 333px column to lay out in. */
	.cpe-hero-content {
		gap: 15px;
		width: 100%;
	}

	.cpe-hero-eyebrow {
		font-size: 18px;
		line-height: 24px;
		font-weight: 600;
	}

	/* #17 — the headline has to stay on one line. The design's 32px fits its
	   333px column in Figma, but this title renders ~355px, so the "..." broke
	   onto a line of its own. Capping by viewport keeps the designed 32px
	   wherever it fits and only trims it on the narrowest screens. */
	.cpe-hero-title {
		font-size: min(32px, 7.7vw);
		line-height: 42px;
	}

	/* #17 — both hero lines are whitespace-nowrap in the design (972:10676 /
	   972:10677), so a sentence never breaks. The font-size cap above is what
	   keeps a nowrap line inside the 333px column. */
	.cpe-hero-eyebrow,
	.cpe-hero-title {
		white-space: nowrap;
	}

	/* The button row is centred under the text and the buttons take the
	   mobile size: 15px/5px padding on a 10px radius, not 20px/8px on 6px. */
	.cpe-hero-content > .cpe-hero-cta,
	.cpe-hero-content .wp-block-buttons.cpe-hero-cta {
		margin-top: 0;
		gap: 20px;
		align-self: center;
		justify-content: center;
	}

	.cpe-hero-slider .wp-block-button__link {
		padding: 5px 15px;
		border-radius: 10px;
	}
}

/* ============================================================
   วิชาเลือกในหลักสูตร — Figma 884:8499 / 884:8501
   ------------------------------------------------------------
   #39 in the review sheet asks for these rows to stack vertically
   on mobile, but the mobile frame keeps them horizontal: the row
   stays justify-between and the label wraps inside a 184px column
   with the count pinned right. Following the design.

   Stacking them also had a second effect the sheet did not ask
   for: the base rule's align-items:center then centred the count
   under the label, so "5 วิชา" and short labels looked centred.
   ============================================================ */

/* The rows are neutral/200 in the design, not white (I884:8501;884:8518). */
#electives .cpe-spec-row {
	background: var(--wp--preset--color--border-light);
}

/* 20px between rows, not the 10px the generic spec list uses. */
#electives .cpe-spec-list {
	gap: 20px;
}

@media (max-width: 782px) {
	/* Label column is a fixed 184px so it wraps exactly as designed and the
	   count keeps its own line-free column on the right. */
	#electives .cpe-spec-row > p:first-child {
		width: 184px;
		flex: 0 0 184px;
	}

	/* ค่าใช้จ่ายโดยละเอียด is the one spec list the design does stack on
	   mobile — Card context="Program Tuition and Fees" is layout="Vertical"
	   at size="Mobile" (884:7825). It stacks left-aligned, not centred, which
	   is what the blanket rule got wrong. */
	#cost .cpe-spec-row {
		flex-direction: column;
		align-items: flex-start;
		gap: 10px;
	}
}

/* โครงสร้างหลักสูตร — Figma 884:8439
   The fills are the other way round from what the theme had: the top-level
   rows are neutral/200 (884:8442), the nested วิชาแกน/วิชาเฉพาะด้าน/วิชาเลือก
   rows sit on white inside them (I884:8443;884:8471), and รวม has no fill at
   all (Card context="Program Structure of-conclude"). All three are written
   at the same #structure specificity so the modifiers still win by order. */
#structure .cpe-spec-row {
	background: var(--wp--preset--color--border-light);
}

#structure .cpe-spec-row--indent {
	background: var(--wp--preset--color--white);
}

#structure .cpe-spec-row--total {
	background: transparent;
}

/* ============================================================
   หลักสูตร listing — Figma 1164:7232 (All Programs Overview)
   ------------------------------------------------------------
   Measured from the frame: degree groups sit 50px apart, the
   degree heading is 20px above its cards, cards are 100px with
   30px between them.

   Three separate spacings were stacking between the heading and
   its cards: the group's flex `gap`, a `margin-bottom` on the
   heading, and the block-gap margin core injects on the children
   of an is-layout-flow group. That came to ~64px instead of 20.
   The same reset the home page's .cpe-degree-group already has is
   what stops the injected one.
   ============================================================ */

.cpe-curriculum-group > * { margin-block: 0; }

.cpe-curriculum-group {
	gap: 20px;
	margin-bottom: 0;
}

.cpe-curriculum-head { margin-bottom: 0; }

.cpe-curriculum-group + .cpe-curriculum-group { margin-top: 50px; }

/* Heading 4 is 24px/32 in the design (1164:7239); ours inherited a taller
   line-height, which pushed the group-to-group distance to 106px. */
.cpe-curriculum-head h2 { line-height: 32px; }

/* #40 (second half) — "ตรง icon ใช้สีและพื้นหลังแบบเดียวกับใน บริการนักศึกษา".
   Sampled from the rendered บริการนักศึกษา cards: the logo tiles there are
   primary/50 (#F2F6FB) behind a primary/700 (#4A60AC) glyph. The facility
   icons were surface-muted (#D9D9D9) behind #111. */
.cpe-service-icon {
	background-color: var(--wp--preset--color--brand-tint);
}

.cpe-service-icon--calendar {
	--cpe-icon: url("../icons/heroicon-calendar.svg");
}

.cpe-service-icon--chip {
	--cpe-icon: url("../icons/fi-rr-microchip.svg");
}

/* #32 — "พื้นหลังส่วนข้อมูลภาควิชายาวจนสุดไม่ต้องเหลือพื้นขาวด้านบน".
   The hero is a flex row with align-items:stretch, but the group is
   is-layout-flow so core puts a block-gap margin-block-start on the second
   child. In flex that margin is not collapsed — it pushed the dark card ~24px
   down and left the page showing above it. Figma 772:4655 has both halves
   550x413 starting at the same y. */
.cpe-contact-hero > * { margin-block: 0; }

/* #4 — "tag ในการ์ดข่าวสารอยู่ต่ำเกินไป". The thumb is an is-layout-flow
   group, so core gives the tag (the figure's next sibling) a block-gap
   margin-block-start. The tag is position:absolute with top:15px, and that
   margin adds to the offset, so it rendered 39px down instead of 15px. */
.cpe-post-thumb > *,
.taxonomy-category.cpe-post-tag {
	margin-block: 0;
}

/* ============================================================
   Mobile navbar — Figma 588:4779 (Default) / 588:4778 (Onclick)
   ------------------------------------------------------------
   Revises the first pass, which was built from the closed state
   only. The open state is its own layout: a white bar with the
   logo left and a 14px cross right (no language switch), then a
   white panel of 20px padding with 20px between items.
   ============================================================ */

@media (max-width: 600px) {

	/* Closed state: the logo is 51x35 here, not the 73px desktop asset. */
	.cpe-header .cpe-brand .wp-block-site-logo,
	.cpe-header .cpe-brand .custom-logo {
		width: 51px;
		height: auto;
	}

	/* ---------- Open state ---------- */

	/* The root carries no padding of its own; the bar and the panel each
	   bring their own, so they can differ (30/20 vs 20). */
	.wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay) {
		background-color: var(--wp--preset--color--white);
		padding: 0;
	}

	.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-close {
		max-width: none;
		width: 100%;
	}

	.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-dialog {
		position: relative;
		padding: 0;
		margin: 0;
	}

	/* Top bar: logo left at 30/20, matching the closed navbar's gutter. It is
	   hidden by default (below) because on desktop core leaves the responsive
	   container in normal flow, where it would render a second, full-size
	   logo in the middle of the header. */
	.wp-block-navigation__responsive-container.is-menu-open .cpe-overlay-logo {
		display: flex;
		align-items: center;
		padding: 20px 30px;
	}

	.wp-block-navigation__responsive-container.is-menu-open .cpe-overlay-logo .custom-logo {
		width: 51px;
		height: auto;
		display: block;
	}

	/* Cross is 14px in the open state (the burger is 18px), centred against
	   the 35px logo: 20 + (35 - 14) / 2 = 30px from the top. */
	.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-close {
		display: block;
		position: absolute;
		top: 30px;
		right: 30px;
		width: 14px;
		height: 14px;
		padding: 0;
		border: 0;
		background: url("../icons/fi-rr-cross.svg") no-repeat center / contain;
	}

	/* Panel: 20px padding all round, 20px between items — core's default here
	   is a 2rem+24px top padding meant to clear its own close button, which we
	   have already positioned. */
	.wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay) .wp-block-navigation__responsive-container-content {
		padding: 20px;
		gap: 20px;
	}
}

/* The overlay logo belongs to the open mobile menu only. */
.cpe-overlay-logo { display: none; }

/* =========================================================================
   Research & Innovation — Figma 925:3057
   -------------------------------------------------------------------------
   The frames on that board are wireframes: every surface is a grey from the
   #d9d9d9 / #afafaf / #f9f9f9 placeholder ramp. Those greys are stand-ins for
   depth, not a palette, so each one is read for the ROLE it plays and mapped
   onto the token the rest of the site already uses for that role — a card is
   white on the page's blue tint, a tag pill is brand-tint/brand, an emphasis
   band is brand blue. Geometry (sizes, radii, gaps) is taken from the frames
   literally.
   ====================================================================== */

/* The section heading and its 35x5 tick are two flex children, so core's
   is-layout-flow block-gap margin lands on the tick and pushes it away from
   the heading. Same collision as the curriculum listing and the contact hero. */
.cpe-section-heading > * { margin-block: 0; }

/* ---------- กลุ่มวิจัยและห้องปฏิบัติการ grid (1058:9128) ---------- */

/* Figma draws three 370px columns, which overflow the 1120px content column by
   30px; they are equal thirds of that column with the 20px gutter the rest of
   the site uses, so 360px each. Columns come from the block's own setting
   rather than being fixed here, so changing it in the editor works. */
.cpe-term-cards {
	display: grid;
	grid-template-columns: repeat(var(--cpe-term-cards-columns, 3), 1fr);
	gap: 20px;
	width: 100%;
}

.cpe-term-cards-wrap > * { margin-block: 0; }

.cpe-term-cards-wrap .cpe-pagination { margin-top: 40px; }

.cpe-term-card {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 20px;
	min-height: 180px;
	padding: 20px;
	border-radius: 15px;
	background: var(--wp--preset--color--white);
	color: var(--wp--preset--color--primary);
	text-align: center;
	text-decoration: none;
	transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.cpe-term-card:hover {
	box-shadow: 0 0 10px 1px rgba(17, 17, 17, 0.08);
	transform: translateY(-2px);
}

.cpe-term-card-logo,
.cpe-term-logo-img {
	width: 60px;
	height: 60px;
	object-fit: contain;
	flex-shrink: 0;
	border-radius: 10px;
}

.cpe-term-logo-block .cpe-term-logo-img {
	width: var(--cpe-term-logo-size, 60px);
	height: var(--cpe-term-logo-size, 60px);
}

/* A group with no logo yet still has to occupy its 60px so the card's two rows
   do not jump when one is added. */
.cpe-term-logo--empty {
	display: block;
	background: var(--wp--preset--color--brand-tint);
}

.cpe-term-card-name {
	font-size: 20px;
	line-height: 28px;
	font-weight: 600;
}

/* ---------- Tag pills (1172:10121, 1172:10159) ---------- */

/* Used three ways with one look: cpe/term-tags emits spans, core/post-terms
   emits links, and the group header wraps either. */
.cpe-tag-pills {
	display: flex;
	flex-wrap: wrap;
	gap: 20px;
	margin: 0;
}

.cpe-tag-pill,
.cpe-tag-pills > a {
	display: inline-flex;
	align-items: center;
	padding: 3px 15px;
	border-radius: 100px;
	background: var(--wp--preset--color--brand-tint);
	color: var(--wp--preset--color--brand);
	font-size: 14px;
	line-height: 20px;
	font-weight: 500;
	text-decoration: none;
}

.cpe-tag-pills > a:hover { background: var(--wp--preset--color--brand-hover); }

/* ---------- One lab: header card (1172:10116) ---------- */

.cpe-lab-header {
	display: flex;
	align-items: flex-start;
	gap: 20px;
	width: 100%;
	padding: 30px;
	border-radius: 15px;
	background: var(--wp--preset--color--white);
}

.cpe-lab-header > *,
.cpe-lab-header-body > * { margin-block: 0; }

.cpe-lab-header-body {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 20px;
	min-width: 0;
}

.cpe-lab-title {
	margin: 0;
	font-size: 32px;
	line-height: 42px;
	font-weight: 700;
}

.cpe-lab-desc {
	margin: 0;
	font-size: 16px;
	line-height: 24px;
	color: var(--wp--preset--color--primary);
}

.cpe-lab-desc p { margin: 0; }

/* ---------- Text-only research card (1172:10144) ---------- */

/* Same card as the news listing with the image removed, so it inherits the
   radius, background and body padding and only overrides what the frame
   actually changes: no fixed heights, and the tag inline above the title
   instead of floating over an image that is not there. */
.cpe-post-card--text {
	min-height: 0;
	border: 1px solid var(--wp--preset--color--white);
}

.cpe-post-card--text .cpe-post-body {
	height: auto;
	min-height: 0;
	gap: 20px;
	justify-content: flex-start;
}

.cpe-post-card--text .cpe-post-text { gap: 10px; }

.cpe-post-card--text .excerpt { -webkit-line-clamp: 2; }

/* ---------- "โดย ..." on a research item (925:2237) ---------- */

.cpe-byline {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 10px 20px;
	width: 100%;
}

.cpe-byline > * { margin-block: 0; }

/* No researcher names on the post means no byline: cpe/meta-tags renders
   nothing, and a lone "โดย" is worse than no line at all. */
.cpe-byline:not(:has(.cpe-byline-name)) { display: none; }

.cpe-byline-label {
	margin: 0;
	font-size: 16px;
	line-height: 24px;
	color: var(--wp--preset--color--muted);
}

.cpe-byline-names {
	display: flex;
	flex-wrap: wrap;
	gap: 10px 20px;
}

.cpe-byline-name {
	font-size: 16px;
	line-height: 24px;
	color: var(--wp--preset--color--primary);
}

.cpe-single-rule {
	width: 100%;
	margin: 0;
	border: 0;
	border-top: 1px solid var(--wp--preset--color--border-light);
}

/* =========================================================================
   Scholarships — Figma 1172:8119 / 1184:844
   ====================================================================== */

/* ---------- ประกาศ band (1183:769) ---------- */

/* The frame paints this band #afafaf, the same placeholder grey it uses for
   any "filled emphasis" surface. Its job is to be the one loud element on an
   otherwise white page, which is what brand blue does everywhere else here. */
.cpe-notice-stack > * { margin-block: 0; }

.cpe-notice-stack {
	display: flex;
	flex-direction: column;
	gap: 30px;
	width: 100%;
}

.cpe-notice-banner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 20px;
	width: 100%;
	padding: 20px 30px;
	border-radius: 20px;
	background: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--white);
}

.cpe-notice-banner > *,
.cpe-notice-body > * { margin-block: 0; }

.cpe-notice-body {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 20px;
	min-width: 0;
}

.cpe-notice-title {
	margin: 0;
	font-size: 32px;
	line-height: 42px;
	font-weight: 500;
}

.cpe-notice-title a {
	color: var(--wp--preset--color--white);
	text-decoration: none;
}

.cpe-notice-title a:hover { text-decoration: underline; }

.cpe-notice-desc {
	margin: 0;
	font-size: 16px;
	line-height: 24px;
	color: var(--wp--preset--color--white);
}

/* The frame leaves the date its grey #727272, which reads on a grey band and
   not on a blue one; the icon is drawn in currentColor terms via its own
   mask-less SVG, so both are lightened together here. */
.cpe-notice-banner .cpe-post-date { color: rgba(255, 255, 255, 0.85); }

.cpe-notice-banner .cpe-post-date::before {
	background-color: var(--wp--preset--color--white);
	-webkit-mask: url("../icons/heroicon-calendar.svg") no-repeat center / contain;
	mask: url("../icons/heroicon-calendar.svg") no-repeat center / contain;
	opacity: 0.85;
}

/* core/read-more puts the class on the <a> itself, so this is the button. */
a.cpe-notice-cta {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
	padding: 10px 20px;
	border-radius: 10px;
	background: var(--wp--preset--color--white);
	color: var(--wp--preset--color--primary);
	font-size: 16px;
	line-height: 24px;
	font-weight: 500;
	text-decoration: none;
}

a.cpe-notice-cta:hover { background: var(--wp--preset--color--brand-hover); }

/* ---------- ทุนการศึกษาทั้งหมด grid (1183:755) ---------- */

/* Three 360px cards across the 1120px column with a 20px gutter and a 40px
   row gap — the block's own grid layout supplies both, so the column count
   stays editable; only the responsive steps live here. */
.cpe-scholarship-grid .cpe-scholarship-card { min-height: 128px; }

@media (max-width: 1100px) {
	.cpe-scholarship-grid { grid-template-columns: repeat(2, 1fr) !important; }
}

@media (max-width: 700px) {
	.cpe-scholarship-grid { grid-template-columns: 1fr !important; }
}

/* post-title renders an <h3> here rather than the hand-written heading the
   Home page card uses; give it the same type. */
.cpe-scholarship-card .wp-block-post-title {
	margin: 0;
	font-size: 18px;
	line-height: 24px;
	font-weight: 600;
}

.cpe-scholarship-card .wp-block-post-title a { text-decoration: none; }

/* ---------- One announcement (1187:965) ---------- */

.cpe-notice-single-title {
	margin: 0;
	width: 100%;
	font-size: 24px;
	line-height: 32px;
	font-weight: 700;
	text-align: left;
}

/* 1187:8311 — a 4:5 portrait plate 563px tall, centred in the column. */
.cpe-notice-single-image {
	margin: 0;
	width: 100%;
	display: flex;
	justify-content: center;
}

.cpe-notice-single-image img {
	width: auto;
	max-width: 100%;
	max-height: 563px;
	aspect-ratio: 1080 / 1350;
	object-fit: cover;
	border-radius: 10px;
}

/* ---------- Attachment / link buttons (1188:8349) ---------- */

/* Ordinary core buttons carrying a block style, so each announcement lists as
   many files or links as it has, edited in its own body. */
.wp-block-buttons.cpe-file-links {
	display: flex;
	gap: 20px;
	width: 100%;
	margin: 0;
}

.wp-block-buttons.cpe-file-links > .wp-block-button { flex: 1 1 0; min-width: 0; }

.wp-block-button.cpe-file-link .wp-block-button__link,
.wp-block-button.cpe-url-link .wp-block-button__link {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
	width: 100%;
	padding: 15px 30px;
	border: 1px solid var(--wp--preset--color--border-light);
	border-radius: 10px;
	background: var(--wp--preset--color--white);
	color: var(--wp--preset--color--primary);
	font-size: 16px;
	line-height: 24px;
	font-weight: 400;
	text-align: left;
}

.wp-block-button.cpe-file-link .wp-block-button__link:hover,
.wp-block-button.cpe-url-link .wp-block-button__link:hover {
	background: var(--wp--preset--color--brand-tint);
	border-color: var(--wp--preset--color--brand-hover);
}

/* The leading glyph names the kind of destination (fi-rr-document /
   fi-rr-link); the trailing one is the same "opens in a new place" arrow on
   both, matching arrow-up-right-from-square in the frame. */
.wp-block-button.cpe-file-link .wp-block-button__link::before,
.wp-block-button.cpe-url-link .wp-block-button__link::before,
.wp-block-button.cpe-file-link .wp-block-button__link::after,
.wp-block-button.cpe-url-link .wp-block-button__link::after {
	content: "";
	width: 16px;
	height: 16px;
	flex-shrink: 0;
	background-color: var(--wp--preset--color--primary);
	-webkit-mask: var(--cpe-icon) no-repeat center / contain;
	mask: var(--cpe-icon) no-repeat center / contain;
}

.wp-block-button.cpe-file-link .wp-block-button__link::before {
	--cpe-icon: url("../icons/fi-rr-document.svg");
}

.wp-block-button.cpe-url-link .wp-block-button__link::before {
	--cpe-icon: url("../icons/fi-rr-link.svg");
}

.wp-block-button.cpe-file-link .wp-block-button__link::after,
.wp-block-button.cpe-url-link .wp-block-button__link::after {
	--cpe-icon: url("../icons/fi-rr-arrow-up-right-from-square.svg");
}

/* An empty pagination nav still lays out as a flex row with the listing's
   block gap above it, leaving a visible hole under a single-page listing. */
.cpe-pagination:not(:has(.page-numbers, a)) { display: none; }

/* ---------- Responsive ---------- */

@media (max-width: 1100px) {
	.cpe-term-cards { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 782px) {
	.cpe-lab-header { flex-direction: column; }
	.cpe-lab-title { font-size: 24px; line-height: 32px; }

	.cpe-notice-banner { flex-direction: column; align-items: flex-start; }
	.cpe-notice-title { font-size: 24px; line-height: 32px; }

	/* Stacked, and each still edge to edge: `flex: 1 1 0` sizes the main axis,
	   which is now the column, so without this each button shrink-wraps its
	   own label and the row of full-width cards becomes two centred pills. */
	.wp-block-buttons.cpe-file-links {
		flex-direction: column;
		align-items: stretch;
	}

	.wp-block-buttons.cpe-file-links > .wp-block-button { flex: 0 0 auto; width: 100%; }
}

@media (max-width: 700px) {
	.cpe-term-cards { grid-template-columns: 1fr; }
}

/* Core's constrained layout puts `margin-inline: auto` on every direct child of
   <main>. .cpe-page-wrap is a flex COLUMN, where auto side margins override
   `stretch` and shrink-wrap the child to its max-content width — the same trap
   already documented above for post-content. Left alone, the section headings
   float centred in the middle of the page and the announcement band and card
   grids come out narrower than the 1120px column they are measured against. */
.cpe-page-wrap > .cpe-section-heading,
.cpe-page-wrap > .cpe-notice-list,
.cpe-page-wrap > .cpe-scholarship-list,
.cpe-page-wrap > .cpe-research-list,
.cpe-page-wrap > .cpe-research-latest,
.cpe-page-wrap > .cpe-term-cards-wrap {
	width: 100%;
	max-width: 100%;
	margin-inline: 0;
}

/* Figma 1058:7919 and 1172:8137 both stack their sections 40px apart, not the
   30px the older listing pages use. */
.page-slug-research .cpe-page-wrap,
.page-slug-scholarships .cpe-page-wrap,
.tax-research_group .cpe-page-wrap { gap: 40px; }

/* Figma 1183:778 groups the title and its one-line summary 10px apart, then
   leaves 20px before the date row. Three flat siblings on one 20px gap made
   the band 23px taller than the frame. */
.cpe-notice-heading {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 10px;
	width: 100%;
}

.cpe-notice-heading > * { margin-block: 0; }

/* The --lg card's body has been asking for 224px (Figma 1058:7926) since it was
   written, and never got it: `.cpe-post-body { flex: 1 }` resolves to
   `flex: 1 1 0%`, and in a column flex container flex-basis replaces height, so
   the body collapsed to its 142px min-height and every large card came out
   446px instead of 528px. Stating the basis is what the rule meant to say. */
.cpe-post-card--lg .cpe-post-body { flex: 0 0 224px; }

/* Figma 1188:8333 keeps the glyph and its label together on the left with the
   "opens elsewhere" arrow alone on the right. space-between on a link whose
   only children are two pseudo-elements spreads all three instead, stranding
   the label in the middle, so the row is a 3-track grid. */
.wp-block-button.cpe-file-link .wp-block-button__link,
.wp-block-button.cpe-url-link .wp-block-button__link {
	display: grid;
	grid-template-columns: 16px 1fr 16px;
	align-items: center;
	gap: 10px;
}

/* Core sizes a plain separator to 100px via a three-class selector, which beat
   the width this rule already asked for. */
.cpe-single-rule.wp-block-separator:not(.is-style-dots) {
	width: 100%;
	max-width: 100%;
}

/* =========================================================================
   Dual Degree banner — Figma 1499:8678 (Landing 617:3106)
   -------------------------------------------------------------------------
   Replaces the 1062:9260 wireframe band (three programme cards and a sign-up
   panel). The banner is now one programme, DAI, over a campus photo: 1440x700,
   a navy-to-translucent-blue wash, and a 250px-blurred dark pool behind the
   text so the white type holds up over the bright buildings. Two calls to
   action: Explore (the course game) and More Information (qmul.kmutt.ac.th).

   The photo is the Group's own background image (block settings), not a CSS
   url, so it can be swapped from the editor. The wash and the dark pool are
   pseudo-elements under the content (isolation keeps their z-index local).
   ====================================================================== */

.cpe-section.cpe-dual {
	position: relative;
	isolation: isolate;
	overflow: hidden;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 40px;
	min-height: 700px;
	padding-block: 50px;
	background-color: #313872;
	background-size: cover;
	background-position: 50% 0%;
	color: var(--wp--preset--color--white);
	text-align: center;
}

.cpe-section.cpe-dual::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background:
		linear-gradient(90deg, rgba(0, 0, 0, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%),
		linear-gradient(180deg, rgb(49, 56, 114) 16.469%, rgba(44, 95, 186, 0.2) 71.437%);
	pointer-events: none;
}

/* 562x251 at (433, 262) in the 1440x700 frame: centred, a little below middle. */
.cpe-section.cpe-dual::after {
	content: "";
	position: absolute;
	left: 50%;
	top: 55%;
	width: 562px;
	max-width: 80%;
	height: 251px;
	transform: translate(-50%, -50%);
	z-index: -1;
	background: rgba(0, 0, 0, 0.8);
	filter: blur(250px);
	pointer-events: none;
}

.cpe-dual > *,
.cpe-dual-head > *,
.cpe-dual-text > * { margin-block: 0; }

/* ---------- Rules either side of the eyebrow and of the DAI pill ---------- */

/* The two 200x1 strokes from the frame, fading towards the outer end. */
.cpe-dual-eyebrow::before,
.cpe-dual-eyebrow::after,
.cpe-dual-code-row::before,
.cpe-dual-code-row::after {
	content: "";
	flex: 0 1 200px;
	height: 1px;
	background: url("../icons/dai-rule-left.svg") no-repeat center / 100% 1px;
}

.cpe-dual-eyebrow::after,
.cpe-dual-code-row::after {
	background-image: url("../icons/dai-rule-right.svg");
}

.cpe-dual-eyebrow {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 30px;
	width: 100%;
	margin: 0;
	font-size: 32px;
	line-height: 42px;
	font-weight: 700;
	color: var(--wp--preset--color--white);
}

/* ---------- Logos, name, DAI, dual-degree line (1499:8684) ---------- */

.cpe-dual-head {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 20px;
	width: 100%;
}

.cpe-dual-logos {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 30px;
}

.cpe-dual-logos > * { margin-block: 0; }

/* Two unlike marks, so each keeps its own designed box: the KMUTT tile is a
   43x62 portrait block, the Queen Mary lockup a 133x36 landscape one. */
.cpe-dual-logo { margin: 0; }
.cpe-dual-logo--kmutt img { width: 43px; height: 62px; }
.cpe-dual-logo--qmul img { width: 133px; height: 36px; }

.cpe-dual-title {
	max-width: 678px;
	margin: 0;
	font-size: 40px;
	line-height: 52px;
	font-weight: 700;
	color: var(--wp--preset--color--white);
}

.cpe-dual-code-row {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 30px;
	width: 100%;
}

.cpe-dual-code {
	margin: 0;
	padding: 3px 20px 0;
	border-radius: 100px;
	background: #5a63aa;
	font-size: 24px;
	line-height: 32px;
	font-weight: 700;
	color: var(--wp--preset--color--white);
}

.cpe-dual-text {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 15px;
	width: 100%;
}

.cpe-dual-sub {
	margin: 0;
	font-size: 24px;
	line-height: 32px;
	font-weight: 500;
	color: var(--wp--preset--color--white);
}

.cpe-dual-tagline {
	margin: 0;
	font-size: 18px;
	line-height: 24px;
	font-weight: 600;
	color: var(--wp--preset--color--white);
}

/* ---------- Explore / More Information (1499:8757) ---------- */

.wp-block-buttons.cpe-dual-actions {
	display: flex;
	justify-content: center;
	gap: 20px;
	margin: 0;
	filter: drop-shadow(0 0 5px rgba(17, 17, 17, 0.05));
}

.cpe-dual-actions .wp-block-button__link {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 10px;
	width: 400px;
	max-width: 100%;
	padding: 10px 24px;
	border-radius: 50px;
	font-size: 20px;
	line-height: 32px;
	font-weight: 600;
	transition: filter 0.2s ease, background-color 0.2s ease;
}

.cpe-dual-actions .wp-block-button__link::after {
	content: "";
	width: 24px;
	height: 24px;
	flex-shrink: 0;
	background: no-repeat center / 24px 24px;
}

.wp-block-button.cpe-dual-explore-btn .wp-block-button__link {
	background: linear-gradient(90deg, #313873 0%, #8893e8 100%);
	color: var(--wp--preset--color--white);
}

.wp-block-button.cpe-dual-explore-btn .wp-block-button__link::after {
	background-image: url("../icons/dai-explore-gamepad.svg");
}

.wp-block-button.cpe-dual-more-btn .wp-block-button__link {
	background: rgba(255, 255, 255, 0.9);
	color: #111;
}

.wp-block-button.cpe-dual-more-btn .wp-block-button__link::after {
	background-image: url("../icons/dai-more-arrow.svg");
}

.wp-block-button.cpe-dual-explore-btn .wp-block-button__link:hover,
.wp-block-button.cpe-dual-explore-btn .wp-block-button__link:focus-visible {
	color: var(--wp--preset--color--white);
	filter: brightness(1.12);
}

.wp-block-button.cpe-dual-more-btn .wp-block-button__link:hover,
.wp-block-button.cpe-dual-more-btn .wp-block-button__link:focus-visible {
	background: var(--wp--preset--color--white);
	color: #111;
}

/* ---------- Responsive ---------- */

@media (max-width: 900px) {
	.cpe-section.cpe-dual { min-height: 0; padding-block: 60px; gap: 30px; }
	.cpe-dual-eyebrow { font-size: 26px; line-height: 34px; }
	.cpe-dual-eyebrow::before,
	.cpe-dual-eyebrow::after { display: none; }
	.cpe-dual-title { font-size: 30px; line-height: 40px; }
	.cpe-dual-sub { font-size: 18px; line-height: 26px; }
	.cpe-dual-tagline { font-size: 16px; }
	.wp-block-buttons.cpe-dual-actions { flex-direction: column; align-items: center; width: 100%; }
	.wp-block-buttons.cpe-dual-actions > .wp-block-button { width: 100%; max-width: 400px; }
	.cpe-dual-actions .wp-block-button__link { width: 100%; }
}

@media (max-width: 600px) {
	.cpe-dual-eyebrow { font-size: 22px; line-height: 30px; }
	.cpe-dual-title { font-size: 26px; line-height: 34px; }
	.cpe-dual-code-row { gap: 15px; }
	.cpe-dual-actions .wp-block-button__link { font-size: 18px; }
}

/* ============================================================
   Design review, round 3
   Re-opened: #19 #24 #25 #26 #33 #40   New: #43 #44 #45 #46 #47 #48 #49 #50 #56
   ------------------------------------------------------------
   Six of these were marked fixed last round and were not. Each one had the
   same shape of mistake — a rule was added that never reached the element it
   was aimed at, so nothing about the page changed. The causes are named
   individually below because they are worth not repeating: a pseudo-element
   that does not exist, a selector one class short of the rule it had to beat,
   a flex property on a grid, and an override that changed a colour on the
   wrong half of a component.
   ============================================================ */

/* #19 — the grey boxes on ประวัติภาควิชา read left, not centred. (The pull
   quote beside them was already white and already left; the centred grey is
   .cpe-stat-box, "2531 / ปีที่ก่อตั้ง".) */
.cpe-stat-box {
	text-align: left;
}

/* ...and the label under the number was indented 24px past it, which is why
   the box still looked centred after the align was fixed. `.cpe-stat-label`
   names two different things — the icon-and-text label on a curriculum
   overview stat, and the plain caption in a history stat box — and the
   curriculum rule turns it into a flex row with a 16px icon slot and an 8px
   gap. The history box has no icon, so it was reserving space for one that is
   never drawn. */
.cpe-stat-box .cpe-stat-label {
	display: block;
}

.cpe-stat-box .cpe-stat-label::before {
	content: none;
}

/* #24 — hover is the colour change alone. Last round only added the colour;
   the original rule's `background: page-background` was never removed, so the
   grey fill the review asked to drop stayed exactly where it was. */
.cpe-prog-toc a:hover,
.cpe-prog-toc a:focus-visible {
	background: transparent;
	color: var(--wp--preset--color--brand);
}

/* #25 — last round recoloured the chip to neutral/200 but left the number
   white, so it went from white-on-blue to white-on-light-grey: invisible.
   The number is text/primary at normal weight. */
.cpe-plo-num {
	color: var(--wp--preset--color--primary);
	font-weight: 400;
}

/* #26 — "the card INSIDE the overview card is neutral/100" was applied to the
   outer box, the stats grid and the inner cards all at once, which flattened
   the whole component into one grey rectangle with nothing to see. The outer
   card goes back to white and only the inner cards carry the grey. */
.cpe-overview-box {
	background: var(--wp--preset--color--white);
}

.cpe-overview-stats {
	background: transparent;
}

.cpe-stat {
	background: var(--wp--preset--color--page-background);
	padding: 15px 20px;
}

/* ...and the four cards did not start on the same line, because this grid was
   never added to the block-gap reset: core gives every child after the first a
   24px margin-block-start, so cards 2-4 sat a row lower than card 1. */
.cpe-overview-stats > * {
	margin-block: 0;
}

/* #33 — the underline is .cpe-section-tick, a real element inside
   .cpe-section-heading. Last round set `gap: 0` on .cpe-section-head (the
   ROW that holds the heading and "ดูทั้งหมด", where the gap is horizontal)
   and coloured `.cpe-section-head::after`, which does not exist — no rule in
   this stylesheet ever creates it. Both declarations painted nothing. */
.cpe-section-heading {
	gap: 0;
}

.cpe-section-tick {
	background: var(--wp--preset--color--brand);
}

/* #40 — the hover fill and the border. The fix went onto
   `.cpe-facility-card .wp-block-button__link:hover` (0,3,0) while the rule it
   had to beat is `.wp-block-button.cpe-btn-launch .wp-block-button__link:hover`
   (0,4,0). Specificity, not order, decided it, so the button kept its
   brand-tint fill and its blue border. Corrected on the base rule itself
   rather than by stacking a third selector on top. */
.wp-block-button.cpe-btn-launch .wp-block-button__link:hover {
	background: var(--wp--preset--color--brand-hover);
	border-color: transparent;
	color: var(--wp--preset--color--brand);
}

/* #43 — #35 asked for "no white surround" on the gallery IMAGE and the fix
   made the whole card transparent, which also took away the white behind the
   caption. The card keeps its white; only the image tile is transparent. */
.cpe-gallery-card {
	background: var(--wp--preset--color--white);
}

.cpe-gallery-card:hover .cpe-gallery-card-title {
	color: var(--wp--preset--color--brand);
}

/* #44 — the badge on a single reads like the badge on the cards it came from:
   brand-tint fill, brand text, no outline. It was neutral-grey with a border
   and black text, which is a different component. */
.cpe-cat-pill {
	background: var(--wp--preset--color--brand-tint);
	border-color: transparent;
	color: var(--wp--preset--color--brand);
}

/* #45 — exchange and internship titles turn primary/700 with the card. */
.cpe-exchange-card:hover .cpe-exchange-title,
.cpe-intern-card:hover .cpe-intern-title {
	color: var(--wp--preset--color--brand);
}

/* #46 — and the whole card is the target, not just the "รายละเอียด" link. The
   overlay hangs off the link the card already has, so the card still exposes
   exactly one <a> to a screen reader and to the keyboard. */
.cpe-exchange-card,
.cpe-intern-card {
	position: relative;
}

.cpe-exchange-card .cpe-detail-link a::before,
.cpe-intern-card .cpe-detail-link a::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
}

/* #47 — the text frame sits flush with the photo above it, and the phone and
   email line up along the bottom of the row however tall the position takes.
   .cpe-staff-info has to grow for `margin-top: auto` to have space to push
   into. */
.cpe-staff-info {
	padding-inline: 0;
	margin-inline: 0;
	flex: 1;
	display: flex;
	flex-direction: column;
}

.cpe-staff-contact {
	margin-top: auto;
}

/* #48, #49 — 20px between the name block and the first section, and between
   the sections themselves (was 30). */
.cpe-staff-detail-main {
	gap: 20px;
}

/* #48 — the gap under a section heading was 44px, not the 20px asked for: the
   section's own `gap: 20px` plus the 24px margin-block-start core gives every
   flow child after the first. The gap alone carries the spacing now. */
.cpe-staff-detail-section > * {
	margin-block: 0;
}

/* #49 — and 20px between the contact rows, with each row reading downwards:
   icon, then label above value. The row is a two-column grid so the icon can
   span both text lines without wrapping the markup in another group. */
.cpe-staff-detail-meta {
	gap: 20px;
}

.cpe-staff-detail-meta-item {
	display: grid;
	grid-template-columns: 40px 1fr;
	column-gap: 15px;
	row-gap: 2px;
	align-items: center;
}

.cpe-staff-detail-meta-item::before {
	grid-row: 1 / span 2;
	grid-column: 1;
}

/* #50 — a section with no data is not rendered at all, rather than a heading
   over nothing. Keyed on the content, so it covers the เจ้าหน้าที่ the review
   names AND an อาจารย์ who simply has not filled the field in yet — neither
   needs a post-type branch or an admin toggle. */
.cpe-staff-detail-section:not(:has(.cpe-research-tag, table)) {
	display: none;
}

/* #56 — the plan header rows on the Master/Doctoral structure. `--plan` sets
   `padding: 10px 0 0` because it used to be an unboxed label; once #27 gave
   #structure rows a grey fill, that id-weighted rule painted a background
   behind a row with no horizontal padding, so the text ran into the left edge
   of its own grey bar. */
#structure .cpe-spec-row--plan {
	padding: 15px 30px;
}

/* ---------- Mobile ---------- */

@media (max-width: 782px) {
	/* #26 (mobile) — the grey cards stack. The previous attempt set
	   `flex-direction: column` on .cpe-overview-stats, which is
	   `display: grid`: flex-direction does nothing there, so the four cards
	   stayed in their four columns the whole way down to 393px. */
	.cpe-overview-stats {
		grid-template-columns: 1fr;
	}
}

/* #51, #52, #55, #57 — the PLO descriptions are lists now, and take the type
   the paragraph they replace had. cpe-obj-list already existed. */
.cpe-plo-list {
	margin: 0;
	padding-left: 35px;
	display: flex;
	flex-direction: column;
	gap: 8px;
	font-size: 16px;
	line-height: 1.6;
	color: var(--wp--preset--color--muted-dark);
}

.cpe-plo-list li { margin: 0; }

/* ============================================================
   Home hero carousel — Figma 972:9248
   ------------------------------------------------------------
   The section was already a slider component; what it lacked was slides (one
   slide means no timer, no indicators, no arrows) and these two controls.
   ============================================================ */

/* The indicators are accent/yellow/500 for the current slide and border/default
   for the rest — sampled from the frame at #ffcb47 and #e6e6e6. They were white
   at 60%/100% opacity, which on this hero's light photo wash was nearly
   invisible in both states. 30px above the bottom edge (770 + 10 of 810). */
.cpe-hero-dots {
	bottom: 30px;
}

.cpe-hero-dot {
	background: var(--wp--preset--color--border-light);
	opacity: 1;
}

.cpe-hero-dot.is-active {
	background: var(--wp--preset--color--accent-yellow-500);
	width: 31px;
}

/* fi-rr-angle-small-left / -right, 35x35, 30px from the left edge and 19px from
   the right (972:10438 / 972:10443), centred on the hero.

   The exported glyphs are fill="white", which the frame's own render shows
   almost disappearing into the 50%-white wash over the photo. They are drawn
   here in the hero's foreground colour instead — the same #111 and the same
   drop shadow the design already gives the eyebrow and the title on that wash,
   for the same reason. Geometry and glyph are the exported asset's, unchanged;
   masking rather than painting is what lets the colour come from CSS. */
.cpe-hero-arrow {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	z-index: 3;
	width: 35px;
	height: 35px;
	padding: 0;
	border: 0;
	background-color: var(--wp--preset--color--primary);
	cursor: pointer;
	filter: drop-shadow(0 0 8px rgba(17, 17, 17, 0.1));
	transition: opacity 0.2s ease;
	opacity: 0.85;
}

.cpe-hero-arrow:hover,
.cpe-hero-arrow:focus-visible {
	opacity: 1;
}

.cpe-hero-arrow--prev {
	left: 30px;
	-webkit-mask: url("../icons/fi-rr-angle-small-left.svg") no-repeat center / contain;
	mask: url("../icons/fi-rr-angle-small-left.svg") no-repeat center / contain;
}

.cpe-hero-arrow--next {
	right: 19px;
	-webkit-mask: url("../icons/fi-rr-angle-small-right.svg") no-repeat center / contain;
	mask: url("../icons/fi-rr-angle-small-right.svg") no-repeat center / contain;
}

/* On a phone the arrows would sit on top of the headline, and a swipe is the
   expected gesture there anyway, so the dots carry the navigation alone. */
@media (max-width: 600px) {
	.cpe-hero-arrow {
		display: none;
	}
}


/* ============================================================
   #41, #43 — the real icon assets
   ------------------------------------------------------------
   Every icon on the site used to be an inline SVG I had drawn by hand: a 2px
   stroke on a 24x24 grid, close to the shape but in nobody's icon set. They
   are now the exported files — Heroicons for the phone and the calendar as the
   review asks, Uicons (Figma 785:8478) for the rest.

   The glyphs are drawn through `mask`, so `background-color` carries the
   colour and one file serves every colour the site uses it in.
   ============================================================ */

/* Every masked icon reads --cpe-icon. An element that carries the base class
   but no --variant would otherwise resolve `mask` to an invalid value, which
   drops the masking entirely and leaves a solid coloured square where nothing
   used to be drawn. Declaring the fallback on :root makes it an inherited
   value, so any rule that names a real file beats it whatever the source
   order — which the variants would not do against a rule further down. */
:root {
	--cpe-icon: linear-gradient(transparent, transparent);
}

/* An icon on a coloured tile cannot be masked on the tile itself — the mask
   would clip the tile away with it — so the tile keeps its background and the
   glyph is drawn by a pseudo-element over it. Each --variant class only names
   the file, which is also what keeps the variant rules one line long. */
.cpe-service-icon,
.cpe-intern-icon,
.cpe-panel-icon {
	display: grid;
	place-items: center;
}

.cpe-service-icon::before,
.cpe-intern-icon::before,
.cpe-panel-icon::before {
	content: "";
	background-color: var(--wp--preset--color--brand);
	-webkit-mask: var(--cpe-icon) no-repeat center / contain;
	mask: var(--cpe-icon) no-repeat center / contain;
}

/* The sizes the tiles already centred their background at. */
.cpe-service-icon::before { width: 18px; height: 18px; }
.cpe-intern-icon::before { width: 20px; height: 20px; }
.cpe-panel-icon::before { width: 25px; height: 25px; }

/* The staff contact rows spend their ::before on the tile, so the glyph goes
   in ::after — placed back into the tile's own grid cell rather than after the
   text, which is what lets two pseudo-elements stack without extra markup. */
.cpe-staff-detail-meta-item::after {
	content: "";
	grid-row: 1 / span 2;
	grid-column: 1;
	place-self: center;
	width: 20px;
	height: 20px;
	background-color: var(--wp--preset--color--brand);
	-webkit-mask: var(--cpe-icon) no-repeat center / contain;
	mask: var(--cpe-icon) no-repeat center / contain;
}

/* The breadcrumb's home link carried its own inline <svg> in functions.php;
   it is the same masked square as everything else now. */
.cpe-breadcrumb .cpe-crumb-home::before {
	content: "";
	display: block;
	width: 20px;
	height: 20px;
	background-color: var(--wp--preset--color--primary);
	-webkit-mask: url("../icons/fi-rr-home.svg") no-repeat center / contain;
	mask: url("../icons/fi-rr-home.svg") no-repeat center / contain;
}

.cpe-breadcrumb .cpe-crumb-home:hover::before {
	background-color: var(--wp--preset--color--brand);
}

/* ============================================================
   Link-shaped CTAs are buttons, not paragraphs
   ------------------------------------------------------------
   "ดูกิจกรรมทั้งหมด", "ดูโครงการและทุน", "รายละเอียด" and the two document rows
   were paragraphs whose whole text happened to be a link. Adding a link to a
   paragraph in the editor makes WordPress paste the target page's *title* into
   the text — which is how "แลกเปลี่ยนต่างประเทศ" ended up in front of
   "ดูโครงการและทุน". A button keeps its URL as an attribute, so the label is
   only ever what the admin typed, and the link is set from the button's own
   control.

   The class stays where it sat on the <p> — on the row — so every rule already
   written against `.cpe-detail-link`, `.cpe-see-all`, `.cpe-doc-link` and
   `.cpe-doc-card` still describes these CTAs and none of them had to be
   rewritten. Only the button chrome has to be undone.
   ============================================================ */

/* `font` and `color` inherit rather than being restated, so the type keeps
   coming from the row exactly as it came from the <p>. */
.wp-block-buttons.cpe-detail-link .wp-block-button__link,
.wp-block-buttons.cpe-see-all .wp-block-button__link,
.wp-block-buttons.cpe-doc-link .wp-block-button__link,
.wp-block-buttons.cpe-doc-card .wp-block-button__link {
	background: none;
	border: 0;
	border-radius: 0;
	padding: 0;
	font: inherit;
	color: inherit;
	text-decoration: none;
}

/* The wrapper core puts around the link has no spacing job here. The row's own
   `gap` is left alone: on the two document rows it is the space between the
   icons and the label, not between buttons. */
.wp-block-buttons.cpe-detail-link > .wp-block-button,
.wp-block-buttons.cpe-see-all > .wp-block-button,
.wp-block-buttons.cpe-doc-link > .wp-block-button,
.wp-block-buttons.cpe-doc-card > .wp-block-button {
	margin: 0;
	max-width: 100%;
}

/* The label used to be the flex child that filled these two bars; the wrapper
   core inserts is that child now. It has to be a flex container as well as a
   flex item: the link inside is inline-flex, so as a block the wrapper kept a
   baseline's worth of descender under it and the bar came out 3px taller than
   the design. */
.wp-block-buttons.cpe-doc-link > .wp-block-button,
.wp-block-buttons.cpe-doc-card > .wp-block-button {
	flex: 1;
	display: flex;
}

/* Filling the bar means the label has to be told where to sit in it: the base
   button rule centres its content, which the <a> never did while it was only
   as wide as its text. */
.wp-block-buttons.cpe-doc-link .wp-block-button__link,
.wp-block-buttons.cpe-doc-card .wp-block-button__link {
	width: 100%;
	justify-content: flex-start;
}

/* .cpe-see-all is the one whose type sat on the <a> rather than on the <p>, so
   the row has to carry it for the reset above to hand it back. */
.wp-block-buttons.cpe-doc-link {
	line-height: 24px;
}

.wp-block-buttons.cpe-see-all {
	font-size: 16px;
	line-height: 24px;
	font-weight: 500;
	color: var(--wp--preset--color--brand);
}

.wp-block-buttons.cpe-see-all .wp-block-button__link:hover {
	color: var(--wp--preset--color--brand-dark);
}

/* The Student Life cells already take a primary/50 wash on hover and the whole
   cell is the link; the CTA inside it stayed grey through all of that. It
   turns primary/700 with the cell now, arrow included — the same hover the
   gallery, exchange and internship cards were given. */
.cpe-feature-cell:hover .cpe-detail-link,
.cpe-feature-cell:hover .cpe-detail-link .wp-block-button__link {
	color: var(--wp--preset--color--brand);
}

.cpe-feature-cell:hover .cpe-detail-link a::after {
	background-color: var(--wp--preset--color--brand);
}

/* ============================================================
   Smooth scrolling for the programme pages' table of contents
   ------------------------------------------------------------
   `scroll-behavior` only does anything on the scrolling element, so it cannot
   be scoped by nesting. Keying it off the presence of the TOC means a new
   programme page built from the same blocks gets it without an admin setting
   anything — and no other page picks it up.
   ============================================================ */
html:has(.cpe-prog-toc) {
	scroll-behavior: smooth;
}

/* Land the section clear of the top edge, on the same 30px offset the sticky
   TOC beside it uses. */
html:has(.cpe-prog-toc) .cpe-prog-section {
	scroll-margin-top: 30px;
}

/* Someone who has asked their system for less motion gets the jump back. */
@media (prefers-reduced-motion: reduce) {
	html:has(.cpe-prog-toc) {
		scroll-behavior: auto;
	}
}

/* #26 — the overview card gets its corners back. #27 had squared everything on
   the programme detail pages at once; the reviewer wants that only for the
   structure and elective rows, which stay square. */
.cpe-overview-box {
	border-radius: 15px;
}

.cpe-stat {
	border-radius: 10px;
}

/* #43 — the gallery card's image sits flush at the top, so only the bottom two
   corners are rounded; the top stays square, as #35 asked. */
.cpe-gallery-card {
	border-bottom-left-radius: 15px;
	border-bottom-right-radius: 15px;
}

/* ============================================================
   การเข้าศึกษาต่อ — Figma 1261:723
   ------------------------------------------------------------
   The listing is a grid of rounds; the detail screen is the same component as a
   ประกาศทุนการศึกษา, down to the 563px poster, so that template reuses those
   classes rather than restating them and letting the two drift.
   ============================================================ */

.cpe-admission-grid {
	width: 100%;
}

.cpe-admission-grid > * {
	margin-block: 0;
}

/* 360x140 in the frame, three to a row with a 40px gutter. The card grows past
   140px rather than clipping when a round's name or description runs long. */
.cpe-admission-card {
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	gap: 20px;
	height: 100%;
	min-height: 140px;
	padding: 20px;
	border-radius: 15px;
	background: var(--wp--preset--color--white);
}

.cpe-admission-card > *,
.cpe-admission-card-head > * {
	margin-block: 0;
}

.cpe-admission-card-head {
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.cpe-admission-title {
	margin: 0;
	font-size: 18px;
	line-height: 24px;
	font-weight: 600;
}

.cpe-admission-title a {
	color: inherit;
	text-decoration: none;
}

.cpe-admission-desc {
	margin: 0;
	font-size: 16px;
	line-height: 24px;
	color: var(--wp--preset--color--muted);
}

/* The whole card is the link, as on the หลักสูตร and ทุนการศึกษา cards. The
   overlay hangs off the title's own <a> so the card still exposes one link. */
.cpe-admission-card {
	position: relative;
}

.cpe-admission-card .cpe-admission-title a::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
}

.cpe-admission-card:hover .cpe-admission-title,
.cpe-admission-card:hover .cpe-detail-link,
.cpe-admission-card:hover .cpe-detail-link a {
	color: var(--wp--preset--color--brand);
}

.cpe-admission-card:hover a.cpe-detail-link::after,
.cpe-admission-card:hover .cpe-detail-link a::after {
	background-color: var(--wp--preset--color--brand);
}

.cpe-admission-card .cpe-detail-link {
	justify-content: flex-end;
	width: 100%;
}

@media (max-width: 1100px) {
	.cpe-admission-grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (max-width: 782px) {
	.cpe-admission-grid {
		grid-template-columns: 1fr;
	}
}

/* #16 — on mobile/tablet the Home News and Research cards line up with every
   other section. The ≤1100px rule capped each column at 320px and started it
   at the left, so on a 390px phone the card stopped 10px short of the right
   edge (24px gutter left, 34px right) and on a tablet a 60px strip was left
   empty. 1fr lets the columns fill the row the way the program, scholarship
   and FAQ cards already do. Desktop (>1100px) keeps the Figma 320px row. */
@media (max-width: 1100px) {
	.home .cpe-card-grid.wp-block-post-template {
		grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
	}
}

/* #60 — the admission card's description shows up to three lines.
   It used to stop after 16 characters: the block's excerptLength counts
   characters for Thai (no spaces between words), so the template now allows
   100 and the line count is set here instead. */
.cpe-admission-desc .wp-block-post-excerpt__excerpt {
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 3;
	overflow: hidden;
}

/* #72 — News & Events and Research cards: title up to three lines,
   description up to two. The 224px body (Figma 1058:7926) holds both:
   20 + 72 title + 10 + 48 description + 20 + 24 meta + 20 = 214px. */
.cpe-post-card--lg .wp-block-post-title {
	-webkit-line-clamp: 3;
}

.cpe-post-card--lg .excerpt {
	-webkit-line-clamp: 2;
}

/* #71 — the featured card's image runs the full height of the card. The thumb
   was a fixed 304px, so whenever the text beside it (title, description, date)
   needed more, the card grew and left a white strip under the photo. The thumb
   now stretches with the card (304px is the floor) and the image is pinned to
   it, so the photo's own proportions can't push the card taller either. */
.cpe-post-card--featured .cpe-post-thumb {
	height: auto;
	min-height: 304px;
	align-self: stretch;
}

/* Pinned at the figure, not the img: the <a> between them is itself
   positioned (it sits above the card's stretched link), so an absolute img
   would size against the inline link instead of the thumb. */
.cpe-post-card--featured .cpe-post-thumb .wp-block-post-featured-image {
	position: absolute;
	inset: 0;
}

.cpe-post-card--featured .cpe-post-thumb .wp-block-post-featured-image a {
	display: block;
	height: 100%;
}

/* #65 — on the ข่าวสารและกิจกรรม overview the gallery cards are rounded on all
   four corners (15px), like the news and event cards beside them. Scoped to
   that section: the แกลลอรี่ listing keeps the square top #35/#43 asked for. */
.cpe-gallery-preview .cpe-gallery-card {
	border-radius: 15px;
}

/* #67 — tab strip (ฝึกงาน): the strip is Secondary/100 (#F4F5F7) with black,
   normal-weight labels; the active tab is primary/700 with white,
   medium-weight text. Secondary/100 has no palette token yet, so it is
   written out here. */
.cpe-tabs {
	background: #f4f5f7;
}

.cpe-tabs .cpe-tab {
	color: var(--wp--preset--color--primary);
	font-weight: 400;
}

.cpe-tabs .cpe-tab.is-active {
	background: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--white);
	font-weight: 500;
}

/* #77 — the Home scholarship cards are all the same width. They were sized
   to their own titles (Figma 617:3147: 353/321/344px, left-aligned), so every
   card came out a different width; now three equal columns fill the row.
   Desktop only — the ≤1100px (2 columns) and ≤700px (1 column) rules above
   already use equal tracks and must keep winning there. */
@media (min-width: 1101px) {
	.cpe-card-grid:not(.wp-block-post-template) {
		grid-template-columns: repeat(3, 1fr);
	}
}

/* #66 — "หลักสูตรร่วม 2 สถาบัน" takes the building glyph instead of the
   external-link arrow: the badge names a partnership, not a link. */
.cpe-badge-joint::before {
	--cpe-icon: url("../icons/fi-rr-building.svg");
}

/* Exchange cards from posts (inc/exchange.php). The card shell is unchanged;
   what changes is that each slot is now a core post block, which wraps its
   value in a <figure> or <a> the hand-built card did not have. */
.cpe-exchange-thumb .wp-block-post-featured-image {
	margin: 0;
	width: 100%;
	height: 100%;
}

.cpe-exchange-thumb .wp-block-post-featured-image img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* The country pill is core/post-terms: the label is a category link. */
.cpe-exchange-flag {
	z-index: 2;
}

.cpe-exchange-flag a,
.cpe-exchange-title a {
	color: inherit;
	text-decoration: none;
}

/* ระยะเวลา / มีทุน are the post's tags, one pill per tag. */
.cpe-exchange-tags {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
	position: relative;
	z-index: 2;
}

.cpe-exchange-tags a {
	display: inline-flex;
	padding: 5px 20px;
	border-radius: 100px;
	background: var(--wp--preset--color--brand-tint);
	color: var(--wp--preset--color--brand);
	font-size: 14px;
	line-height: 20px;
	font-weight: 500;
	text-decoration: none;
}

.cpe-exchange-tags .wp-block-post-terms__separator {
	display: none;
}

/* Whole card clickable, hung off the title link like the news cards. */
.cpe-exchange-card .cpe-exchange-title a::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
}

.cpe-exchange-card a.cpe-detail-link {
	position: relative;
	z-index: 2;
	margin-left: auto;
}

.cpe-exchange-card:hover a.cpe-detail-link::after {
	background-color: var(--wp--preset--color--brand);
}

/* ---------- Announcement banner on the detail pages (1261:835, 1270:750) ----------
   The same band as the ทุนการศึกษา listing (.cpe-notice-banner), opened up to
   carry the full title and summary instead of a link out to this page. */
.cpe-notice-banner--single {
	display: flex;
}

.cpe-notice-banner--single .cpe-notice-title {
	color: var(--wp--preset--color--white);
}

/* 1346:763 — 15px between the heading and the period on a round, not the 20px
   the scholarship band leaves before its date. */
.cpe-admission-single .cpe-notice-body { gap: 15px; }

/* 1346:778 — "ช่วงที่เปิดรับสมัคร" over a dot and the period. */
.cpe-apply-period {
	display: flex;
	flex-direction: column;
	gap: 5px;
}

.cpe-apply-period > * { margin: 0; }

.cpe-apply-period-label {
	font-size: 14px;
	line-height: 20px;
	font-weight: 500;
	color: rgba(255, 255, 255, 0.85);
}

.cpe-apply-period-value {
	display: flex;
	align-items: center;
	gap: 10px;
	font-size: 16px;
	line-height: 24px;
	color: var(--wp--preset--color--white);
}

.cpe-apply-period-value::before {
	content: "";
	width: 10px;
	height: 10px;
	flex-shrink: 0;
	border-radius: 50%;
	background: var(--wp--preset--color--brand-pale);
}

/* ---------- Error page (1314:8607) ---------- */

.cpe-error-page {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 50px;
	min-height: 70vh;
	padding: 80px 16px;
	background: var(--wp--preset--color--bg-page);
	text-align: center;
}

.cpe-error-page > *,
.cpe-error-body > *,
.cpe-error-text > * { margin: 0; }

.cpe-error-image img {
	display: block;
	width: 200px;
	height: 200px;
}

.cpe-error-body {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 30px;
}

.cpe-error-text {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 10px;
	max-width: 786px;
}

.cpe-error-title {
	font-size: 24px;
	line-height: 32px;
	font-weight: 700;
	color: var(--wp--preset--color--brand-dark);
}

.cpe-error-desc {
	font-size: 20px;
	line-height: 32px;
	font-weight: 600;
	color: #000;
}

.cpe-error-actions { justify-content: center; }

.cpe-error-retry .wp-block-button__link {
	padding: 8px 20px;
	border-radius: 6px;
	background: var(--wp--preset--color--brand-dark);
	color: var(--wp--preset--color--white);
	font-size: 20px;
	line-height: 32px;
	font-weight: 600;
	text-decoration: none;
}

.cpe-error-retry .wp-block-button__link:hover {
	background: var(--wp--preset--color--brand);
}

/* =========================================================================
   "สำรวจหลักสูตร" on a programme card — Figma 1506:8923
   -------------------------------------------------------------------------
   An outlined brand button with a gamepad, beside the usual "รายละเอียด ›".
   The card's detail link is stretched over the whole card (#2), so this
   button has to sit above that overlay to be clickable. The wrapper itself
   must stay unpositioned: a positioned wrapper would become the overlay's
   containing block and shrink it to the button row.
   ====================================================================== */

.cpe-program-actions {
	display: flex;
	align-items: center;
	gap: 30px;
}

.cpe-program-actions > * { margin-block: 0; }

.wp-block-buttons.cpe-explore-link {
	position: relative;
	z-index: 2;
	margin: 0;
}

.cpe-explore-link .wp-block-button__link {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	padding: 7px 19px;
	border: 1px solid var(--wp--preset--color--brand);
	border-radius: 6px;
	background: transparent;
	color: var(--wp--preset--color--brand);
	font-size: 18px;
	line-height: 24px;
	font-weight: 600;
	white-space: nowrap;
}

.cpe-explore-link .wp-block-button__link::after {
	content: "";
	width: 18px;
	height: 18px;
	flex-shrink: 0;
	background: url("../icons/fi-rr-gamepad.svg") no-repeat center / 18px 18px;
}

.cpe-explore-link .wp-block-button__link:hover,
.cpe-explore-link .wp-block-button__link:focus-visible {
	background: var(--wp--preset--color--brand-tint);
	color: var(--wp--preset--color--brand);
}

@media (max-width: 600px) {
	.cpe-program-actions { width: 100%; justify-content: space-between; gap: 15px; flex-wrap: wrap; }
}

/* =========================================================================
   Floating "Play & Explore Programs" — Figma 1506:8869
   -------------------------------------------------------------------------
   180px wide, pinned to the lower right of the landing page (x1216 y698 in
   the 1440x900 first screen). The × overlaps the badge's top-right corner by
   20px. Closing it hides it for the rest of the visit (sessionStorage), so it
   comes back next time rather than never.
   ====================================================================== */

.cpe-explore-pop {
	position: fixed;
	right: 44px;
	bottom: 24px;
	z-index: 900;
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	width: 180px;
	animation: cpe-explore-pop-in 0.4s ease both;
}

.cpe-explore-pop[hidden] { display: none; }

@keyframes cpe-explore-pop-in {
	from { opacity: 0; transform: translateY(12px); }
	to { opacity: 1; transform: none; }
}

.cpe-explore-pop-close {
	position: relative;
	z-index: 1;
	display: flex;
	align-items: center;
	margin: 0 0 -20px;
	padding: 5px;
	border: 0;
	border-radius: 100px;
	background: #e6e6e6;
	cursor: pointer;
}

.cpe-explore-pop-close img { display: block; width: 18px; height: 18px; }

.cpe-explore-pop-close:hover { background: #d6d6d6; }

.cpe-explore-pop-link {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 10px;
	width: 100%;
	text-decoration: none;
}

/* The source image is a square with margin around the round badge; the frame
   shows a 120x115 window into it, offset to centre the badge. */
.cpe-explore-pop-badge {
	position: relative;
	width: 120px;
	height: 115px;
	overflow: hidden;
	transition: transform 0.2s ease;
}

.cpe-explore-pop-badge img {
	position: absolute;
	left: -7.34%;
	top: -7.91%;
	width: 110.45%;
	height: 115%;
	max-width: none;
}

.cpe-explore-pop-label {
	width: 100%;
	padding: 5px 20px;
	border-radius: 15px;
	background: #e3eaf6;
	color: #4a60ac;
	font-size: 18px;
	line-height: 24px;
	font-weight: 600;
	text-align: center;
}

.cpe-explore-pop-link:hover .cpe-explore-pop-badge,
.cpe-explore-pop-link:focus-visible .cpe-explore-pop-badge { transform: translateY(-3px); }

@media (max-width: 600px) {
	.cpe-explore-pop { right: 16px; bottom: 16px; width: 140px; }
	.cpe-explore-pop-badge { width: 92px; height: 88px; }
	.cpe-explore-pop-label { padding: 4px 12px; font-size: 15px; line-height: 20px; }
}

@media (prefers-reduced-motion: reduce) {
	.cpe-explore-pop { animation: none; }
	.cpe-explore-pop-badge { transition: none; }
}

/* ============================================================
   QA sheet 2026-10-29 — #82 #83 #84 #85 #86 #88
   ============================================================ */

/* #82 — contact page, mobile: details and photo stack. Editors have wrapped
   the dark card and the photo in a core Row (flex, nowrap), so the existing
   .cpe-contact-hero column rule never reached them: on a phone the card was a
   57px strip beside the photo. Stack whatever Row holds the hero. */
@media (max-width: 782px) {
	.is-layout-flex:has(> .cpe-contact-hero) {
		flex-direction: column;
		flex-wrap: wrap;
		align-items: stretch;
	}

	.is-layout-flex:has(> .cpe-contact-hero) > * {
		width: 100%;
		min-width: 0;
		flex-basis: auto;
		margin: 0;
	}

	.is-layout-flex:has(> .cpe-contact-hero) .cpe-contact-card,
	.is-layout-flex:has(> .cpe-contact-hero) .cpe-contact-hero-media { min-width: 0; }

	.is-layout-flex:has(> .cpe-contact-hero) > .wp-block-image img {
		display: block;
		width: 100%;
		height: auto;
	}
}

/* #83 — programme pages, mobile: 24px title, and nothing past the right edge.
   Stacked, .cpe-prog-layout kept align-items:flex-start, so the content
   column was sized to its longest line rather than the screen and ran off the
   right side; stretch gives it the same 24px margin as the left. */
@media (max-width: 782px) {
	body:has(.cpe-prog-detail) .cpe-page-title {
		font-size: 24px;
		line-height: 32px;
	}

	.cpe-prog-layout { align-items: stretch; }

	.cpe-prog-layout > *,
	.cpe-prog-content {
		width: 100%;
		min-width: 0;
	}

	.cpe-prog-content { overflow-wrap: break-word; }

	.cpe-spec-row .cpe-spec-value { white-space: normal; }
}

/* #84 — scholarship pages, mobile: the link cards stack, and a long label
   wraps onto more lines instead of being cut off. Same cause as #82: the
   links sit in a core Row that never wraps. */
@media (max-width: 782px) {
	.is-layout-flex:has(> .cpe-file-links) {
		flex-direction: column;
		flex-wrap: wrap;
		align-items: stretch;
		gap: 15px;
	}

	.is-layout-flex:has(> .cpe-file-links) > * {
		width: 100%;
		min-width: 0;
		margin: 0;
	}

	.is-layout-flex:has(> .cpe-file-links) > .wp-block-spacer { display: none; }
}

.wp-block-button.cpe-file-link .wp-block-button__link,
.wp-block-button.cpe-url-link .wp-block-button__link {
	white-space: normal;
	overflow-wrap: anywhere;
	height: auto;
}

/* #85 — gallery cards: 15px on the top two corners (overrides #35's square
   corners for the listing card only; album photo grids stay square). */
.cpe-gallery-thumb {
	border-radius: 15px 15px 0 0;
	overflow: hidden;
}

/* #86 — News & Events and Research cards. Core styles the post-title link as
   inline-block, which makes the whole title one unbreakable box, so the line
   clamp on the <h2> could never take effect: on a phone a long title ran to
   five lines and pushed the date out of the card. Inline lets it clamp. */
.cpe-post-body .wp-block-post-title a { display: inline; }

@media (max-width: 782px) {
	.cpe-post-card .cpe-post-body .wp-block-post-title { -webkit-line-clamp: 3; }
	.cpe-post-card .cpe-post-body .excerpt { -webkit-line-clamp: 2; }
}

/* #88 — Home Student Life header: the gradient carries a photo at 10%
   (Figma I617:3154;898:9647, primary 800 -> 700 -> 500). The photo is a
   pseudo-element under the text; isolation keeps its z-index local. */
.cpe-feature-head {
	position: relative;
	isolation: isolate;
	background: linear-gradient(90deg, #41508c 25%, #4a60ac 59.135%, #6889c9 100%);
}

.cpe-feature-head::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: var(--cpe-photo, url("../images/student-life-bg.jpg")) no-repeat center / cover;
	opacity: 0.1;
	border-radius: inherit;
	pointer-events: none;
}

/* Editor only: the hero slides one under another, each labelled, instead of
   stacked on top of each other as they are on the site — stacked, editors saw
   all three slides' text at once and could not tell which picture belonged to
   which slide. (The iframe's body carries .editor-styles-wrapper.) */
.editor-styles-wrapper .cpe-hero-slider {
	display: flex;
	flex-direction: column;
	gap: 24px;
	height: auto;
	overflow: visible;
	background: transparent;
	counter-reset: cpe-slide;
}

.editor-styles-wrapper .cpe-hero-slider > .cpe-hero-slide {
	position: relative;
	inset: auto;
	min-height: 560px;
	opacity: 1;
	visibility: visible;
	counter-increment: cpe-slide;
}

/* The label sits on ::before, not ::after: the editor draws its hover and
   selection outline on every block's ::after (inset 0, rounded), so a label
   there stretched over the whole slide as a black panel on hover. The 50%
   white wash that normally lives on ::before moves to an inset box-shadow,
   which paints above the background photo and below the content. */
.editor-styles-wrapper .cpe-hero-slider > .cpe-hero-slide {
	box-shadow: inset 0 0 0 100vmax rgba(249, 249, 249, 0.5);
}

.editor-styles-wrapper .cpe-hero-slider > .cpe-hero-slide::before {
	content: "สไลด์ที่ " counter(cpe-slide);
	inset: auto;
	top: 16px;
	left: 16px;
	z-index: 2;
	padding: 4px 14px;
	border-radius: 100px;
	background: #111;
	color: #fff;
	font-size: 14px;
	line-height: 20px;
	pointer-events: none;
}

/* #90 — footer social icons centred in their circles. On a phone the circle
   is enlarged to a touch-sized target but the anchor inside kept core's
   padding-box layout, so the 16px glyph sat in the top-left corner. Centre
   the glyph in whatever size the circle is. */
.cpe-footer .wp-block-social-links .wp-social-link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 0;
}

.cpe-footer .wp-block-social-links .wp-social-link a,
.cpe-footer .wp-block-social-links .wp-block-social-link-anchor {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	height: 100%;
	padding: 0;
	margin: 0;
	line-height: 0;
}

/* #91 — Home Student Life header, mobile: the heading drops from 40px to
   24px ("ชีวิตนักศึกษาที่นี่ ไม่ได้มีแค่การเรียน" / "Student Life Here Is
   More Than Just Studying"). */
@media (max-width: 782px) {
	.cpe-feature-head h3 {
		font-size: 24px;
		line-height: 32px;
	}
}

/* #93 — hero on mobile: a line that does not fit wraps instead of running
   off the screen (#17's nowrap was right for the first Thai slide, but the
   English eyebrow "New International Collaborative Programs" is wider than
   any phone), and the buttons drop to 16px. */
@media (max-width: 782px) {
	.cpe-hero-eyebrow,
	.cpe-hero-title {
		white-space: normal;
		overflow-wrap: break-word;
		max-width: 100%;
	}

	.cpe-hero-content { min-width: 0; max-width: 100%; }

	.cpe-hero-slider .wp-block-button__link {
		font-size: 16px;
		line-height: 24px;
	}
}
