/* ===== FONTS ===== */
/* DB Heavent + TF Lanna, restored to assets/02_fonts/ and activated per
   explicit request (2026-09-11, "เอาฟอนต์กลับมาจ่ะ" -> "กู้ไฟล์กลับ และเปิดใช้งานเลย")
   — these were deleted during an earlier unused-asset cleanup (dead weight at
   the time: present but never wired to any @font-face) and are now wired up.
   NOTE: font foundry/license terms for web-embedding are still NOT confirmed
   (see fontLicenseReview in manifest.json) — activated anyway per explicit
   user instruction; revisit if the design/brand team's license review comes
   back negative. Only DB Heavent is actually referenced by --font-heading/
   --font-body below (per the 2026-09-10 font-standardization pass, which
   moved body copy off TF Lanna onto DB Heavent site-wide) — TF Lanna's
   @font-face is declared for completeness/history but stays dormant (no
   network request fires for it) since nothing currently sets font-family to
   it. */
@font-face {
  font-family: "DB Heavent";
  src: url("assets/fonts/db-heavent-thin-v3-2-1.51930c3dff.woff2") format("woff2");
  font-weight: 100;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "DB Heavent";
  src: url("assets/fonts/db-heavent-thin-it-v3-2-1.65919edec6.woff2") format("woff2");
  font-weight: 100;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "DB Heavent";
  src: url("assets/fonts/db-heavent-ulli-v3-2-1.7324e7cb21.woff2") format("woff2");
  font-weight: 200;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "DB Heavent";
  src: url("assets/fonts/db-heavent-ulli-it-v3-2-1.cfe8c5ef5d.woff2") format("woff2");
  font-weight: 200;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "DB Heavent";
  src: url("assets/fonts/db-heavent-li-v3-2-1.855768f06f.woff2") format("woff2");
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "DB Heavent";
  src: url("assets/fonts/db-heavent-li-it-v3-2-1.c6c48594cd.woff2") format("woff2");
  font-weight: 300;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "DB Heavent";
  src: url("assets/fonts/db-heavent-v3-2-1.9c29ac0725.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "DB Heavent";
  src: url("assets/fonts/db-heavent-it-v3-2-1.b8c5b6890d.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "DB Heavent";
  src: url("assets/fonts/db-heavent-med-v3-2-1.82a4b51af5.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "DB Heavent";
  src: url("assets/fonts/db-heavent-med-it-v3-2-1.39f7f3f18f.woff2") format("woff2");
  font-weight: 500;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "DB Heavent";
  src: url("assets/fonts/db-heavent-bd-v3-2-1.ac5d0996d6.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "DB Heavent";
  src: url("assets/fonts/db-heavent-bd-it-v3-2-1.c8410811e7.woff2") format("woff2");
  font-weight: 700;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "DB Heavent";
  src: url("assets/fonts/db-heavent-blk-v3-2-1.44cfd6f0d3.woff2") format("woff2");
  font-weight: 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "DB Heavent";
  src: url("assets/fonts/db-heavent-blk-it-v3-2-1.e415157498.woff2") format("woff2");
  font-weight: 900;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "TF Lanna";
  src: url("assets/fonts/tf-lanna.cb543f83ed.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "TF Lanna";
  src: url("assets/fonts/tf-lanna-bol.bfd5c6231a.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* ===== RESET / BASE ===== */
/* smooth same-page anchor scrolling site-wide (navbar links, hero CTAs,
   course card anchors, etc.) — must live on <html> itself since that's the
   actual scrolling element, not something a wrapper class can scope */
html {
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

.tuxsa-landing-page,
.tuxsa-landing-page *,
.tuxsa-landing-page *::before,
.tuxsa-landing-page *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.tuxsa-landing-page {
  /* Typography baseline. Standalone this came from the browser defaults; inside a
     host app the host's own body would supply it instead. */
  font-size: 16px;
  line-height: normal;
  letter-spacing: normal;
  word-spacing: normal;
  font-style: normal;
  font-weight: 400;
  text-align: start;
  text-indent: 0;
  text-transform: none;
  -webkit-font-smoothing: auto;
  -moz-osx-font-smoothing: auto;

  --tuxsa-red: #cc3335;
  --tuxsa-red-dark: #aa1c28;
  --tuxsa-text: #1a1a1a;
  --tuxsa-gray: #4a4a4a;
  --tuxsa-bg: #fafafa;
  /* Per explicit request (2026-09-10): the whole site now uses DB Heavent
     for both headings/UI AND body copy — was DB Heavent (headings) + TF
     Lanna (body) per the original B2C Design System (Figma) split. Kept as
     two separate variables (rather than deleting --font-body and repointing
     every var(--font-body) usage to --font-heading) so the two roles stay
     independently swappable later without touching every selector again;
     they just happen to share a value now. Font files are now bundled and
     wired via @font-face above (see that block's own comment) — any element
     requesting a weight this typeface doesn't ship natively (600/800 aren't
     among its cuts) resolves to the nearest DB Heavent weight that IS
     registered (browser font-weight matching, not a fallback to the next
     font in this stack); the fallback stack itself only matters if the .ttf
     fails to load or for any character DB Heavent doesn't cover. */
  --font-heading: "DB Heavent", "Prompt", "Sarabun", "Noto Sans Thai", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-body: "DB Heavent", "Prompt", "Sarabun", "Noto Sans Thai", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-family: var(--font-body);
  color: var(--tuxsa-text);
  background: #ffffff;
}

.tuxsa-landing-page .container {
  max-width: 1280px;
  margin: 0 auto;
  /* longhand (not the `padding` shorthand) so this horizontal-gutter-only
     rule can never zero out another class's own vertical padding on an
     element that also happens to carry .container (e.g. .navbar__inner) */
  padding-left: 32px;
  padding-right: 32px;
}

/* offsets smooth-scrolled anchor targets so the sticky navbar (~79px tall
   above 900px) doesn't cover the top of the section they jump to */
.tuxsa-landing-page section[id] {
  /* --host-header is how much chrome the embedding page keeps pinned above this
     one. Unset when the bundle is opened on its own, so the fallback stands. */
  scroll-margin-top: calc(90px + var(--host-header, 0px));
}

/* ===== NAVBAR ===== */
/* An embedding page sets data-scrolled on this page's root once the reader has
   scrolled. That page keeps its own header pinned, and two bars cannot both own
   the top edge, so this one bows out and leaves it to the host. Opened on its
   own nothing sets the attribute, so the bar stays for the whole page. */
.tuxsa-landing-page[data-scrolled="true"] .navbar {
  display: none;
}

.tuxsa-landing-page .navbar {
  position: sticky;
  top: var(--host-header, 0px);
  z-index: 10;
  background: #ffffff;
  /* thin, low-opacity line under the bar (production-on-cloud .svc__divider convention:
     1px, subtle rgba) — tinted brand red at 35% instead of a flat gray border */
  box-shadow: 0 2px 10px rgba(204, 51, 53, 0.35);
}

.tuxsa-landing-page .navbar__inner {
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 16px 32px;
}

.tuxsa-landing-page .navbar__brand {
  display: flex;
  align-items: center;
  flex-shrink: 0;
}

.tuxsa-landing-page .navbar__logo {
  display: block;
  /* +30% vs the previous 32px */
  height: 42px;
  width: auto;
}

/* thin vertical rule between logo and nav links (production-on-cloud divider style) */
.tuxsa-landing-page .navbar__divider {
  display: block;
  flex-shrink: 0;
  width: 1px;
  align-self: stretch;
  margin: 6px 0;
  background: rgba(0, 0, 0, 0.12);
}

/* links + CTA grouped together, pinned to the right */
.tuxsa-landing-page .navbar__right {
  display: flex;
  align-items: center;
  gap: 32px;
  margin-left: auto;
}

.tuxsa-landing-page .navbar__links {
  display: flex;
  align-items: center;
  gap: 28px;
}

.tuxsa-landing-page .navbar__links a {
  font-family: var(--font-heading);
  /* +30% vs the original 15px */
  font-size: 20px;
  font-weight: 500;
  color: var(--tuxsa-text);
  text-decoration: none;
  white-space: nowrap;
}

.tuxsa-landing-page .navbar__links a:hover {
  color: var(--tuxsa-red);
}

/* element+class selector so this reliably overrides the later .btn rule
   (same-specificity class selectors would otherwise depend on source order) */
.tuxsa-landing-page a.navbar__cta {
  flex-shrink: 0;
  padding: 12px 28px;
  /* +20% vs the original 16px */
  font-size: 19px;
  /* one step up from thin (300) per request */
  font-weight: 400;
  /* full pill, matching the green reference */
  border-radius: 999px;
}

/* ===== HERO SECTION ===== */
.tuxsa-landing-page .hero {
  position: relative;
  background: linear-gradient(180deg, #ffffff 0%, #f4f4f4 100%);
  /* bottom cut way down so .showcase sits closer underneath — top kept
     for clearance under the sticky navbar */
  padding: 72px 0 24px;
  overflow: hidden;
}

.tuxsa-landing-page .hero__bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: right center;
  z-index: 0;
  /* Cover_BG.webp is already a near-white/pale-pink ambient gradient (mean
     RGB ~252/240/239) — no brightness filter needed here, unlike the prior
     bg photos this replaced (BG-2.webp/New-BG.webp both needed a +30% boost
     to stop reading as a dull gray). */
}

.tuxsa-landing-page .hero::after {
  /* fades the bg to white at the very bottom of the section so it blends
     into .showcase (white) below instead of cutting off sharply — sits
     above .hero__bg but below .hero__inner's text/buttons (z-index 1). */
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 60px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, #ffffff 100%);
  z-index: 0;
  pointer-events: none;
}

.tuxsa-landing-page .hero__content {
  position: relative;
}

.tuxsa-landing-page .hero__text {
  position: relative;
}

.tuxsa-landing-page .hero__text::before {
  /* soft white scrim behind the logo/title/subtitle only, to lift them off
     Cover_obj.webp's red ribbon graphic when it bleeds in from the right at
     narrower widths — scoped to this wrapper's own box so it structurally
     cannot reach .hero__actions (the buttons) below it. */
  content: "";
  position: absolute;
  inset: -20px -28px -12px -28px;
  background: linear-gradient(90deg, rgba(255, 255, 255, 0.65) 0%, rgba(255, 255, 255, 0.65) 45%, rgba(255, 255, 255, 0) 85%);
  border-radius: 20px;
  z-index: 0;
  pointer-events: none;
}

.tuxsa-landing-page .hero__logo,
.tuxsa-landing-page .hero__title,
.tuxsa-landing-page .hero__subtitle {
  position: relative;
  z-index: 1;
}

.tuxsa-landing-page .hero__path-deco {
  /* purely decorative route/path accent behind the text — now scoped to
     .hero__text's own box (inset:0, same containment trick as its ::before
     scrim) instead of the old fixed 420px height, so it's structurally
     confined to the logo/title/subtitle area and can never stretch down
     across .hero__actions (the buttons) at any breakpoint. Sits at z-index 0
     like .hero__bg (painted after it, so still above it), well below
     .hero__inner's z-index:1 content, and pointer-events:none so it never
     intercepts clicks. */
  position: absolute;
  inset: -12px -28px -8px -28px;
  z-index: 0;
  pointer-events: none;
}

.tuxsa-landing-page .hero__inner {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 48px;
}

.tuxsa-landing-page .hero__content {
  flex: 1 1 480px;
  max-width: 620px;
}

/* ===== HERO MEDIA (Cover_obj.webp) ===== */
.tuxsa-landing-page .hero__media {
  flex: 1 1 480px;
  display: flex;
  justify-content: center;
}

/* wraps .hero__obj to crop + fade its bottom edge — per explicit request
   ("ขยายภาพนี้ขึ้น 10% แล้วตัดภาพให้เฟดโชว์ถึงแค่บริเวณที่แคปมา"): the image
   itself renders 10% larger (528px vs the old 480px), but this wrapper's
   own height is pinned to what the OLD 480px-wide image used to stand at
   (539.17px) instead of growing 10% taller too — so enlarging the subjects
   doesn't also grow the hero section, it just shows a tighter crop of the
   now-bigger image, with a mask-image fade over the last ~22% of that
   window instead of a hard cut at the bottom edge. */
.tuxsa-landing-page .hero__obj-crop {
  position: relative;
  width: 100%;
  max-width: 528px;
  aspect-ratio: 528 / 539.17;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 78%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 78%, transparent 100%);
}

.tuxsa-landing-page .hero__obj {
  /* 1.webp is a single flattened cutout (graduates + dome + a geometric red
     diamond/arrow graphic, transparent bg, portrait 2182x2451) — unlike the
     old two-layer .hero__photo-fg + .hero__badge setup this replaces, it
     needs no absolute-positioned badge overlay. aspect-ratio reserves its
     real space before this loading="lazy" image loads, so it can't shove
     .hero__obj-crop's own height around after the fact — same class of bug
     as .learning-path__image (see that rule's comment); redundant with
     .hero__obj-crop's own aspect-ratio (which reserves the wrapper's space
     regardless), kept anyway since it costs nothing and adds a second line
     of defense. */
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 2182 / 2451;
}

.tuxsa-landing-page .hero__logo {
  display: block;
  /* source PNG is now cropped to its visible wordmark bounds (previously ~80%
     transparent padding), so this height alone already renders much larger
     than before at the same value — no extra multiplier needed on top. */
  height: clamp(32px, 2.5vw + 16px, 48px);
  width: auto;
  margin-bottom: 24px;
}

.tuxsa-landing-page .hero__title {
  font-family: var(--font-heading);
  /* Figma h1 token = DB Heavent Bold 36px, scaled up for hero impact.
     48px is the largest size that stays on one line within the ~564px
     content column measured across desktop widths (950px-1920px+). */
  font-size: 48px;
  font-weight: 700;
  line-height: 1.2;
  color: var(--tuxsa-red);
  margin-bottom: 16px;
  white-space: nowrap;
}

.tuxsa-landing-page .hero__subtitle {
  font-family: var(--font-heading);
  font-size: clamp(18px, 0.8vw + 14px, 26px);
  font-weight: 400;
  color: var(--tuxsa-gray);
  margin-bottom: 40px;
}

.tuxsa-landing-page .hero__actions {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
}

.tuxsa-landing-page .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* widened horizontal padding to match the +3px font bump below */
  padding: 16px 40px;
  /* aligned to the navbar CTA final spec: full pill + regular weight */
  border-radius: 999px;
  font-family: var(--font-heading);
  font-size: 20px;
  font-weight: 400;
  text-decoration: none;
  transition: background-color .2s ease, transform .15s ease;
  white-space: nowrap;
}

.tuxsa-landing-page .btn--primary {
  background: var(--tuxsa-red);
  color: #ffffff;
}

.tuxsa-landing-page .btn--primary:hover {
  background: var(--tuxsa-red-dark);
  transform: translateY(-1px);
}

/* ===== SHOWCASE SECTION (stats + intro + video) ===== */
.tuxsa-landing-page .showcase {
  position: relative;
  /* top cut down so section 2 sits closer under the hero (see .hero's
     padding-bottom above); bottom stays scaled x3 (+200%) to keep the
     wider gap before .roadmap */
  padding: 32px 0 114px;
  background: #ffffff;
  /* clip the enlarged/overflowing bg to the section instead of the
     content column, so it can bleed rightward without leaking past it */
  overflow: hidden;
}

.tuxsa-landing-page .showcase__inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
}

.tuxsa-landing-page .showcase__row {
  display: flex;
  /* wraps so .stat__note (flex-basis:100% below) can be forced onto its own
     line below .showcase__content + .showcase__media, despite now being a
     DOM child of this row (moved here so mobile/tablet's stacked column can
     show it between the stats and the video — see the HTML comment) rather
     than a sibling after it. `order` below puts it back at the very end for
     the desktop row layout. */
  flex-wrap: wrap;
  /* stretches .showcase__media (and in turn .video-card, via height:100%
     below) to exactly match .showcase__content's natural height, so the
     video's top edge lines up with the heading's top edge and its bottom
     edge lines up with the stats row's bottom edge — per the annotated
     screenshot's guide lines. Was align-items:center (video's own
     aspect-ratio-driven height merely centered against the text column,
     with no guarantee the edges would actually line up). Still applies
     correctly with .stat__note now also in this container: flex-wrap
     stretches items per-line, and the note sits alone on its own
     (flex-basis:100%-forced) line, so it doesn't affect the
     content/media stretch-matching on the line above it. */
  align-items: stretch;
  /* text column now grows up to the video with just this much gap */
  gap: 30px;
}

.tuxsa-landing-page .showcase__content {
  /* grows to fill the available space (up to the 30px gap before the
     video), instead of splitting evenly with .showcase__media. flex-basis
     explicitly 0 (not auto) since .showcase__row gained flex-wrap for
     .stat__note's benefit — with a content-based "auto" basis, the wrap
     algorithm was measuring this against its own (wide) natural content
     width instead of letting it shrink first, wrongly wrapping
     .showcase__media onto its own line and collapsing the video's
     stretched height to 0. Also needs min-width:0 — flex items default to
     min-width:auto (their own min-content size as a floor), and at ~901px
     the heading+stats' min-content width alone exceeded the space actually
     left over once .showcase__media's 480px was subtracted, so the wrap
     algorithm was still wrapping media to its own line there even with
     flex-basis:0. min-width:0 lets this shrink below that floor instead. */
  flex: 1 1 0%;
  min-width: 0;
  /* always first, both in the desktop row and the mobile/tablet column —
     see the order values on .stat__note/.showcase__media below */
  order: 1;
}

/* full-bleed across the section (matches .hero__bg's pattern), sized to
   3:4 (75%) of the section width per request */
.tuxsa-landing-page .showcase__bg {
  position: absolute;
  top: 0;
  left: 0;
  /* full-width per request ("bg ไม่เต็ม ขยับมาให้เต็ม") — was 75% (a "3:4 of
     the section width" sizing from an earlier request), leaving a visible
     plain-white gap on the right side of the section that the watermark
     pattern never reached. */
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: left center;
  z-index: 0;
}

.tuxsa-landing-page .showcase__heading {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 12px;
  margin-bottom: 28px;
}

.tuxsa-landing-page .showcase__heading-primary {
  font-family: var(--font-heading);
  font-size: 48px;
  font-weight: 800;
  color: var(--tuxsa-red);
  line-height: 1.2;
}

.tuxsa-landing-page .showcase__heading-secondary {
  font-family: var(--font-heading);
  font-size: 28px;
  font-weight: 500;
  color: #2b2b2b;
  line-height: 1.3;
}

.tuxsa-landing-page .showcase__stats {
  display: flex;
  align-items: stretch;
}

.tuxsa-landing-page .stat {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
  gap: 4px;
  flex: 1 1 0;
  padding: 4px 24px;
  text-align: left;
}

.tuxsa-landing-page .stat:first-child {
  padding-left: 0;
}

.tuxsa-landing-page .stat + .stat {
  border-left: 1px solid #e2e2e2;
}

.tuxsa-landing-page .stat__value {
  font-family: var(--font-heading);
  /* +100% per request, was 40px */
  font-size: 80px;
  font-weight: 800;
  color: var(--tuxsa-red);
  line-height: 1.1;
}

.tuxsa-landing-page .stat__label {
  /* +100% per request, was 13px */
  font-size: 26px;
  color: var(--tuxsa-gray);
}

/* hidden by default (tablet/desktop) — see the max-width:600px override
   below, which shows this to force a 3rd line on mobile only */
.tuxsa-landing-page .stat__break--mobile-only {
  display: none;
}

.tuxsa-landing-page .stat__note {
  /* footnote-sized per request ("ลดขนาด font แล้วขยับออกมาไกลๆ เหมือนหมายเหตุ")
     — was 18px (matched body copy), now matches this site's other small-print
     disclaimer (.promo-card__disclaimer, 13px) instead */
  font-size: 13px;
  /* desktop: forced onto its own line below both columns (flex-basis:100%
     on a wrapped row — see .showcase__row) and pushed to the very end via
     order, so this gap separates it from both the text column and the
     video, matching "ปรับให้อยู่ต่ำกว่าข้อความและวิดิโอ". +15% per follow-up
     request ("เลื่อนหมายเหตุลงมาอีก 15%"), was 24px. Overridden on
     mobile/tablet below, where it sits between the stats and the video
     instead. */
  margin-top: 27.6px;
  color: var(--tuxsa-gray);
  /* desktop row: full-width line of its own, after content+media — see the
     ≤900px override for the mobile/tablet order+width instead */
  order: 3;
  flex-basis: 100%;
}

.tuxsa-landing-page .showcase__media {
  /* fixed-ish basis — no longer grows in step with .showcase__content,
     which now claims the remaining space up to the 30px gap */
  flex: 0 1 480px;
  order: 2;
}

.tuxsa-landing-page .video-card {
  position: relative;
  width: 100%;
  /* height (not aspect-ratio) fills .showcase__media, which itself is
     stretched by .showcase__row's align-items:stretch to exactly match
     .showcase__content's natural height — see that rule's comment. Only
     works in the row layout; the ≤900px media query below restores a fixed
     aspect-ratio for the stacked-column layout, where there's no sibling
     to stretch against. */
  height: 100%;
  /* nudged down 10% of its own height per request ("เลื่อนวิดิโอลง 10%") —
     shifts the whole card down without changing its size, so it no longer
     sits flush with the heading/stats top+bottom edges above. */
  transform: translateY(10%);
  border-radius: 16px;
  overflow: hidden;
  background: linear-gradient(135deg, #2a2a2a, #111111);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.18);
}

.tuxsa-landing-page .video-card__player {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  border: 0;
  background: #000000;
}

/* manual play fallback: revealed via JS only if muted autoplay gets
   silently blocked by the browser's own policy (can't be forced client-side
   — a real click always satisfies autoplay policy, so this guarantees the
   video is never just stuck frozen with no way to start it) */
.tuxsa-landing-page .video-card__play-fallback {
  position: absolute;
  inset: 0;
  z-index: 3;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: rgba(0, 0, 0, 0.35);
  cursor: pointer;
}

.tuxsa-landing-page .video-card__play-fallback[hidden] {
  display: none;
}

.tuxsa-landing-page .video-card__play-fallback svg {
  width: 30px;
  height: 30px;
  margin-left: 4px;
}

.tuxsa-landing-page .video-card__play-fallback::before {
  content: "";
  position: absolute;
  width: 72px;
  height: 72px;
  border-radius: 50%;
  background: rgba(204, 51, 53, 0.9);
  z-index: -1;
  transition: background-color .2s ease, transform .2s ease;
}

.tuxsa-landing-page .video-card__play-fallback:hover::before {
  background: var(--tuxsa-red-dark);
  transform: scale(1.08);
}

.tuxsa-landing-page .video-card__mute-btn {
  position: absolute;
  right: 16px;
  bottom: 16px;
  z-index: 2;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.55);
  border: 1.5px solid rgba(255, 255, 255, 0.25);
  color: #ffffff;
  cursor: pointer;
  backdrop-filter: blur(4px);
  transition: background-color .2s ease, border-color .2s ease;
}

.tuxsa-landing-page .video-card__mute-btn:hover {
  background: rgba(0, 0, 0, 0.8);
  border-color: var(--tuxsa-red);
}

.tuxsa-landing-page .video-card__mute-btn svg {
  width: 20px;
  height: 20px;
}

.tuxsa-landing-page .video-card__mute-btn .icon-unmuted {
  display: none;
}

.tuxsa-landing-page .video-card__mute-btn.is-unmuted .icon-muted {
  display: none;
}

.tuxsa-landing-page .video-card__mute-btn.is-unmuted .icon-unmuted {
  display: block;
}

/* ===== ROADMAP SECTION (7-year timeline) ===== */
.tuxsa-landing-page .roadmap {
  padding: 114px 0 114px;
  /* ambient photo backdrop behind the white panel, with a 30% white wash
     layered on top to soften the image's red down from full intensity */
  background:
    linear-gradient(rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0.3)),
    url("assets/images/timeline-image-bg-2.75725431d3.webp") center / cover no-repeat;
}

/* plain white "backing" layer so the timeline stands out from the photo
   backdrop behind it */
.tuxsa-landing-page .roadmap__panel {
  background: #ffffff;
  border-radius: 24px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.08);
  padding: 56px 48px 72px;
}

.tuxsa-landing-page .roadmap__title {
  font-family: var(--font-heading);
  font-size: 40px;
  font-weight: 800;
  color: var(--tuxsa-red);
  text-align: center;
  line-height: 1.35;
  margin-bottom: 88px;
}

.tuxsa-landing-page .roadmap__timeline {
  position: relative;
  display: flex;
  /* stretch (not center) so every pill matches the tallest card's height,
     regardless of how many lines its own description wraps to */
  align-items: stretch;
  justify-content: space-between;
  gap: 12px;
  padding: 0 56px;
}

.tuxsa-landing-page .roadmap__track {
  position: absolute;
  left: 56px;
  right: 56px;
  top: 50%;
  height: 2px;
  /* dashed "not yet reached" segment */
  background: repeating-linear-gradient(to right, rgba(204, 51, 53, 0.3) 0 6px, transparent 6px 13px);
  transform: translateY(-50%);
  z-index: 0;
  overflow: visible;
}

/* line "draws" itself in, segment by segment, driven by JS — glowing
   solid red once "reached", vs. the dashed track underneath for what's
   still ahead */
.tuxsa-landing-page .roadmap__track-fill {
  display: block;
  height: 100%;
  width: 0;
  background: var(--tuxsa-red);
  box-shadow: 0 0 12px rgba(204, 51, 53, 0.65);
  transition: width .21s cubic-bezier(.45, 0, .2, 1);
}

/* snake connector for the tablet-portrait 3-top/2-bottom grid — hidden
   everywhere else (only switched on inside that breakpoint below) */
.tuxsa-landing-page .roadmap__track-svg {
  display: none;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  overflow: visible;
}

.tuxsa-landing-page .roadmap__track-bg-path {
  fill: none;
  stroke: rgba(204, 51, 53, 0.3);
  stroke-width: 2px;
  stroke-dasharray: 6 7;
}

.tuxsa-landing-page .roadmap__track-fill-path {
  fill: none;
  stroke: var(--tuxsa-red);
  stroke-width: 2px;
  filter: drop-shadow(0 0 6px rgba(204, 51, 53, 0.65));
  transition: stroke-dashoffset .21s cubic-bezier(.45, 0, .2, 1);
}

.tuxsa-landing-page .roadmap__item {
  position: relative;
  z-index: 1;
  display: flex;
  /* equal-width slots so all 5 pills' text always has the same room to
     wrap into, instead of sizing to content and overflowing */
  flex: 1 1 0;
  min-width: 0;
}

/* the card itself — starts hidden/shrunk and pops in one at a time on
   scroll (JS adds .is-active as the line reaches it) */
.tuxsa-landing-page .roadmap__pill {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  /* top-anchored so the icon+year and the course name's first line land
     at the same height across every card */
  justify-content: flex-start;
  width: 100%;
  min-width: 0;
  box-sizing: border-box;
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid rgba(204, 51, 53, 0.1);
  border-radius: 22px;
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.05);
  opacity: 0;
  transform: translateY(14px) scale(0.92);
  transition: opacity .45s ease, transform .45s cubic-bezier(.34, 1.56, .64, 1),
    background .35s ease, box-shadow .35s ease, border-color .35s ease;
}

.tuxsa-landing-page .roadmap__pill.is-active {
  opacity: 1;
  transform: translateY(0) scale(1);
  background: #ffffff;
  border-color: rgba(204, 51, 53, 0.18);
  box-shadow: 0 16px 34px rgba(0, 0, 0, 0.08), 0 0 32px rgba(204, 51, 53, 0.22);
}

/* icon floats outside/above the card, centered over it — sits above the
   card with roughly 60% of its own height above the top edge and the
   rest overlapping down into it */
.tuxsa-landing-page .roadmap__icon {
  position: absolute;
  left: 50%;
  top: 0;
  z-index: 2;
  opacity: 0;
  transform: translate(-50%, -60%) scale(0.7);
  transition: opacity .4s ease, transform .4s cubic-bezier(.34, 1.56, .64, 1);
  pointer-events: none;
}

.tuxsa-landing-page .roadmap__icon img {
  width: 70px;
  height: 70px;
  object-fit: contain;
  display: block;
}

.tuxsa-landing-page .roadmap__icon.is-shown {
  opacity: 1;
  transform: translate(-50%, -60%) scale(1);
}

/* the year lives in its own centered line inside the card, above the
   course name */
.tuxsa-landing-page .roadmap__dot-year {
  display: block;
  font-family: var(--font-heading);
  font-size: 32px;
  font-weight: 800;
  color: var(--tuxsa-red);
  margin-bottom: 8px;
}

.tuxsa-landing-page .roadmap__content {
  min-width: 0;
  /* top padding clears the icon's overlap into the card plus a small gap */
  padding: 34px 20px 20px;
  text-align: center;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .3s ease, transform .3s cubic-bezier(.22, 1, .36, 1);
}

.tuxsa-landing-page .roadmap__content.is-shown {
  opacity: 1;
  transform: translateY(0);
}

.tuxsa-landing-page .roadmap__desc {
  font-size: 18px;
  font-weight: 700;
  line-height: 1.3;
  color: var(--tuxsa-text);
}

.tuxsa-landing-page .roadmap__highlight {
  font-size: 16px;
  line-height: 1.3;
  color: var(--tuxsa-gray);
  margin-top: 2px;
}

/* the newest, upcoming course pops in last and stays lit up as the
   chain's focal point — a clearly visible red border, same size as the
   other cards, held once the reveal sequence lands on it */
.tuxsa-landing-page .roadmap__item--featured .roadmap__pill.is-active {
  border: 2px solid var(--tuxsa-red);
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1), 0 0 46px rgba(204, 51, 53, 0.3);
}

.tuxsa-landing-page .roadmap__item--featured .roadmap__highlight {
  color: var(--tuxsa-red);
  font-weight: 700;
}

/* ===== WHY SECTION (why TUXSA) ===== */
.tuxsa-landing-page .why {
  padding: 100px 0 120px;
  /* per request, replacing the flat white */
  background: url("assets/images/why-tuxsa-bg.0997dd7129.webp") center / cover no-repeat;
}

/* red badge backdrop behind the heading so it reads clearly against the
   photo background — rounded to echo .why__card's own 16px corners, with
   the same red glow language used on card hover */
.tuxsa-landing-page .why__title {
  display: table;
  margin: 0 auto 72px;
  font-family: var(--font-heading);
  font-size: 40px;
  font-weight: 800;
  color: #ffffff;
  text-align: center;
  background: linear-gradient(135deg, var(--tuxsa-red) 0%, var(--tuxsa-red-dark) 100%);
  padding: 18px 48px;
  border-radius: 20px;
  box-shadow: 0 14px 34px rgba(204, 51, 53, 0.28), 0 0 40px rgba(204, 51, 53, 0.18);
}

.tuxsa-landing-page .why__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 28px;
}

.tuxsa-landing-page .why__card {
  position: relative;
  background: #f0f0f0;
  border-radius: 16px;
  /* red-tinted shadow at rest so the cards pop off the photo background
     even before hovering — deepens further on hover */
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.06), 0 0 20px rgba(204, 51, 53, 0.16);
  padding: 56px 24px 32px;
  text-align: center;
  margin-top: 40px;
  transition: transform .25s ease, box-shadow .25s ease, background .25s ease;
}

/* hovered card flips to solid TUXSA red with white text */
.tuxsa-landing-page .why__card:hover {
  transform: translateY(-8px);
  background: var(--tuxsa-red);
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.06), 0 0 28px rgba(204, 51, 53, 0.28);
}

.tuxsa-landing-page .why__card:hover .why__card-title,
.tuxsa-landing-page .why__card:hover .why__list {
  color: #ffffff;
}

.tuxsa-landing-page .why__icon {
  position: absolute;
  top: -40px;
  left: 50%;
  transform: translateX(-50%);
  width: 80px;
  height: 80px;
  border-radius: 50%;
  background: var(--tuxsa-red);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 10px 20px rgba(204, 51, 53, 0.35);
}

.tuxsa-landing-page .why__icon img {
  width: 40px;
  height: 40px;
  /* source PNGs are black-line-art on transparent — force them white to
     match the red circle background (icons are named per the 04_Why TUXSA
     asset folder: certificate / graduation / money-saving / rocket) */
  filter: brightness(0) invert(1);
}

.tuxsa-landing-page .why__icon img[src*="money-saving"],
.tuxsa-landing-page .why__icon img[src*="graduation"] {
  /* +20% per request */
  width: 48px;
  height: 48px;
}

.tuxsa-landing-page .why__icon img[src*="certificate"] {
  /* +20% per request */
  width: 48px;
  height: 48px;
}

.tuxsa-landing-page .why__card-title {
  font-family: var(--font-heading);
  /* matches .roadmap__dot-year (section 3's ค.ศ. numbers), per request */
  font-size: 30px;
  /* one weight-step lighter than Bold(800), per request — color stays exact brand HEX */
  font-weight: 700;
  color: var(--tuxsa-red);
  line-height: 1.35;
  margin-bottom: 18px;
  transition: color .25s ease;
}

.tuxsa-landing-page .why__list {
  text-align: center;
  padding-left: 0;
  list-style: none;
  /* +10% per request, was 18px */
  font-size: 19.8px;
  line-height: 1.65;
  color: var(--tuxsa-text);
  transition: color .25s ease;
}

.tuxsa-landing-page .why__list li {
  list-style: none;
}

.tuxsa-landing-page .why__list li + li {
  margin-top: 8px;
}

/* card 1 only: its 3 manual line-breaks must never split "ได้รับ" from its
   object (ตามหลักภาษาไทย per request) — the best grammar-safe 3-way split
   still overflows the narrowest card width (320px / 1280px+ breakpoints)
   by ~3.5px on its last line. A barely-perceptible letter-spacing pullback
   (not a font-size change, so it stays visually consistent with the other
   3 cards) reclaims just enough width to keep it at 3 lines everywhere,
   matching cards 2-4, without touching a single word. */
.tuxsa-landing-page .why__list-item--dense {
  letter-spacing: -0.2px;
}

/* card 2 (graduation) only: split "เรียนออนไลน์ได้ทุกที่ ทุกเวลา" / "ตลอด 24
   ชั่วโมง" onto two lines, but ONLY on desktop (≥901px, matching this
   project's own desktop cutoff — .why__grid switches 2→4 columns there) —
   per explicit request to touch desktop alone, mobile/tablet unchanged.
   Hidden by default so mobile/tablet keep flowing this as one line same as
   before. */
.tuxsa-landing-page .why__break--desktop-only {
  display: none;
}

@media (min-width: 901px) {
  .tuxsa-landing-page .why__break--desktop-only {
    display: inline;
  }
}

/* card 4 (rocket) only: opposite of .why__break--desktop-only above — this
   break stays part of the mobile/tablet line-wrap (unchanged from before)
   but must NOT apply on desktop, where "คุณภาพ" instead flows onto the same
   line as "และผู้เชี่ยวชาญตัวจริง" per request. Shown by default, hidden
   ≥901px. */
.tuxsa-landing-page .why__break--mobile-tablet-only {
  display: inline;
}

@media (min-width: 901px) {
  .tuxsa-landing-page .why__break--mobile-tablet-only {
    display: none;
  }
}

/* root-cause fix (replaces an earlier iPad-landscape-only forced <br>):
   .why__grid switches from 2 to 4 columns at 901px, but .container doesn't
   reach its full 1280px width until the viewport does — so from 901px up
   to 1279px every card was squeezed down to ~185-255px, badly wrapping
   every line of this card's text (not just the "ตลอด 24 ชั่วโมง" line
   originally reported), regardless of touch vs. mouse input. Keep 2
   columns through that whole range so cards stay comfortably wide
   (~470-620px) — the layout only needs to go to 4 columns once .container
   is actually near its 1280px cap, where cards are ~283px and every line
   already wraps naturally without help. */
@media (min-width: 901px) and (max-width: 1279px) {
  .tuxsa-landing-page .why__grid {
    grid-template-columns: repeat(2, 1fr);
    row-gap: 56px;
  }
}

/* ===== COURSES SECTION (7 ปี 5 หลักสูตร) ===== */
.tuxsa-landing-page .courses {
  position: relative;
  padding: 100px 0 120px;
  /* light gray per request, was white — lets the red cards stand out */
  background: #f5f5f5;
  overflow: hidden;
  /* cursor position for the reveal-mask effect below, kept updated by
     scripts.js on mousemove; defaults to the section's centre */
  --mx: 50%;
  --my: 50%;
}

/* the certificate watermark image, reused here per request — hidden by
   default, revealed in a soft circle that follows the cursor as it
   moves over the section's own background */
.tuxsa-landing-page .courses__bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  -webkit-mask-image: radial-gradient(220px circle at var(--mx) var(--my), rgba(0, 0, 0, 0.9), transparent 70%);
  mask-image: radial-gradient(220px circle at var(--mx) var(--my), rgba(0, 0, 0, 0.9), transparent 70%);
  transition: opacity .25s ease;
}

.tuxsa-landing-page .courses:hover .courses__bg {
  opacity: 1;
}

.tuxsa-landing-page .courses .container {
  position: relative;
  z-index: 1;
}

.tuxsa-landing-page .courses__title {
  text-align: center;
  margin-bottom: 56px;
}

.tuxsa-landing-page .courses__title-main {
  display: block;
  font-family: var(--font-heading);
  font-size: 40px;
  font-weight: 800;
  color: var(--tuxsa-text);
  line-height: 1.35;
}

.tuxsa-landing-page .courses__title-sub {
  display: block;
  font-family: var(--font-heading);
  font-size: 32px;
  font-weight: 700;
  color: var(--tuxsa-red);
  line-height: 1.35;
}

/* expand/collapse accordion row, per ref (pinterest.com/pin/919438080196750650) —
   all 5 cards sit at equal width at rest; hovering (or focusing, for keyboard
   users) one card grows it via flex-grow while its siblings shrink, swapping
   a vertical collapsed label for the full card content */
.tuxsa-landing-page .courses__grid {
  display: flex;
  align-items: stretch;
  gap: 16px;
  /* portrait ~3:4 card ratio per reference (playing-card style), fixed at
     rest AND on hover — the row height never changes, only card width does.
     the expanded state "stretches sideways" (image tile + text panel
     side-by-side) instead of growing taller. width at rest is 230.4px
     (container 1280px, 5 columns, 16px gaps), so height = 230.4 * 4/3 */
  height: 307px;
}

.tuxsa-landing-page .course-card {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  overflow: hidden;
  /* red card / white text per request, replacing the earlier light-gray card */
  background: var(--tuxsa-red);
  border-radius: 16px;
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.06);
  cursor: pointer;
  transition: flex-grow .45s cubic-bezier(.4, 0, .2, 1), box-shadow .25s ease;
}

/* :focus-visible, NOT :focus-within — the card carries tabindex="0", so a
   plain mouse click focuses the card itself and :focus-within would keep it
   expanded after the pointer leaves; hovering a second card then puts two at
   flex-grow:4 (4+4+1+1+1 = 11 instead of 8), shrinking both to 419px, and
   since the photo tile is a fixed 307px the text panel collapses 269px -> 112px
   and gets sliced by overflow:hidden. :focus-visible only matches keyboard
   focus, so Tab still expands the card while a click no longer sticks.
   Wrapped in :is() so browsers without :has() ignore that one argument and
   keep the :hover accordion working instead of dropping the whole rule. */
.tuxsa-landing-page .course-card:is(:hover, :focus-visible, :has(:focus-visible)) {
  flex: 4 1 0;
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.06), 0 0 28px rgba(204, 51, 53, 0.28);
  outline: none;
}

.tuxsa-landing-page .course-card__collapsed-label {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* icon + name centered as one grouped block, top-to-bottom, in the card */
  justify-content: center;
  gap: 12px;
  padding: 0 16px;
  opacity: 1;
  transition: opacity .2s ease;
}

.tuxsa-landing-page .course-card__icon {
  width: 60px;
  height: 60px;
  object-fit: contain;
  /* source icons are black line art — invert to white for the red card */
  filter: brightness(0) invert(1);
}

.tuxsa-landing-page .course-card--upcoming .course-card__icon {
  /* +10% per request, was 60px */
  width: 66px;
  height: 66px;
}

.tuxsa-landing-page .course-card__name {
  text-align: center;
  font-family: var(--font-heading);
  /* +25% per request, was 18px */
  font-size: 22.5px;
  font-weight: 700;
  line-height: 1.3;
  color: #ffffff;
}

.tuxsa-landing-page .course-card:is(:hover, :focus-visible, :has(:focus-visible)) .course-card__collapsed-label {
  opacity: 0;
}

/* photo variant (per asset in assets/05_Major/<major>/, MBA cover reused as a
   placeholder for every card until dedicated images are ready) — image and
   text panel sit side-by-side (row), not stacked, so the row height never
   needs to grow: at rest the image is hidden (0 width, panel shows just the
   course-name label), on hover the image becomes a 230px square tile on the
   left and the panel (fit text + CTA) fills the remaining width on the right */
.tuxsa-landing-page .course-card--photo {
  display: flex;
  flex-direction: row;
  align-items: stretch;
}

.tuxsa-landing-page .course-card--photo .course-card__photo-wrap {
  /* hidden at rest per request — image only appears once hovered */
  position: relative;
  flex: 0 0 0px;
  min-width: 0;
  overflow: hidden;
  transition: flex-basis .45s cubic-bezier(.4, 0, .2, 1);
}

.tuxsa-landing-page .course-card--photo:is(:hover, :focus-visible, :has(:focus-visible)) .course-card__photo-wrap {
  /* matches the row's fixed 307px height, so the tile itself is square.
     Deliberately NOT grown to fit .course-card__photo-degree (below) —
     this width also sets how much space is left for the description panel
     beside it (panel = hovered-card-width minus this value), and per this
     project's own established rule (see the comment on the "@media
     (hover: none), (max-width: 900px)" block) real desktop/mouse users
     must keep the hover accordion at ANY window width ≥901px, not just
     wide ones — at 901px the hovered card is only ~379px wide, so growing
     this tile in step with taller content would leave the panel just
     ~30-70px wide there, clipping the existing .course-card__fit text too,
     not just new content. Since the tile's own width is fixed regardless
     of viewport (flex-shrink:0), .course-card__photo-degree (below) was
     placed ON this tile instead of in the width-constrained side panel,
     sidestepping the problem rather than fighting it. */
  flex-basis: 307px;
}

.tuxsa-landing-page .course-card__photo {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* darkened name + degree info on the hover-revealed photo tile itself —
   .course-card__photo-wrap is 0-width (overflow:hidden) at rest, so these
   are naturally hidden along with the photo until hover grows the tile to
   307px — no separate opacity/hover rule needed. */
.tuxsa-landing-page .course-card__photo-scrim {
  position: absolute;
  inset: 0;
  /* darkens the tile photo ~70% per request, so the name reads clearly */
  background: rgba(0, 0, 0, 0.7);
  pointer-events: none;
}

.tuxsa-landing-page .course-card__photo-info {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  text-align: center;
  padding: 16px 12px;
}

.tuxsa-landing-page .course-card__photo-name {
  font-family: var(--font-heading);
  font-size: 22.5px;
  font-weight: 700;
  line-height: 1.3;
  color: #ffffff;
}

/* degree/major detail — secondary to the name above, so noticeably
   smaller; the tile is a fixed 307px square regardless of viewport width
   (see the flex-basis comment above), so this has stable room to wrap in
   at every breakpoint, unlike the width-constrained side panel */
.tuxsa-landing-page .course-card__photo-degree {
  /* +10% per request, was 13px */
  font-size: 14.3px;
  line-height: 1.35;
  color: rgba(255, 255, 255, .8);
}

.tuxsa-landing-page .course-card__photo-degree strong {
  color: #ffffff;
  font-weight: 700;
}

.tuxsa-landing-page .course-card--photo .course-card__photo-panel {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
}

.tuxsa-landing-page .course-card__photo-expanded {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 16px 20px;
  text-align: center;
  opacity: 0;
  transition: opacity .3s ease;
  pointer-events: none;
}

.tuxsa-landing-page .course-card--photo:is(:hover, :focus-visible, :has(:focus-visible)) .course-card__photo-expanded {
  opacity: 1;
  transition-delay: .15s;
  pointer-events: auto;
}

.tuxsa-landing-page .course-card--photo .course-card__cta {
  margin-top: 0;
  flex: 0 0 auto;
}

.tuxsa-landing-page .course-card__fit {
  /* 18px per request, was 14px */
  font-size: 18px;
  line-height: 1.6;
  color: rgba(255, 255, 255, .9);
  white-space: nowrap;
}

.tuxsa-landing-page .course-card__fit strong {
  display: block;
  margin-bottom: 6px;
  color: #ffffff;
  font-weight: 700;
}

.tuxsa-landing-page .course-card__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: 28px;
  padding: 10px 28px;
  border-radius: 999px;
  border: 1.5px solid #ffffff;
  background: transparent;
  color: #ffffff;
  font-family: var(--font-heading);
  font-size: 15px;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color .2s ease, color .2s ease, transform .2s ease;
}

.tuxsa-landing-page a.course-card__cta:hover {
  background: #ffffff;
  color: var(--tuxsa-red);
  /* +20% per request */
  transform: scale(1.2);
}

.tuxsa-landing-page .course-card__cta--upcoming {
  /* clickable now that it links out — was cursor:default */
  cursor: pointer;
}

.tuxsa-landing-page .course-card__badge {
  position: absolute;
  top: 16px;
  right: 16px;
  z-index: 1;
  /* "raised" white pill per reference — was a solid yellow chip.
     -20% per request off the +50% size: font-size 19.5→15.6px,
     padding 12/27→9.6/21.6px. DB Heavent (--font-heading) + red outer glow */
  background: #ffffff;
  color: var(--tuxsa-red);
  font-family: var(--font-heading);
  font-size: 15.6px;
  font-weight: 700;
  padding: 9.6px 21.6px;
  border-radius: 999px;
  box-shadow: 0 8px 18px rgba(0, 0, 0, 0.18), 0 0 20px rgba(204, 51, 53, 0.5);
  white-space: nowrap;
  /* shown only while the photo tile is collapsed. The badge sits at the
     card's top-right, which is exactly where the description panel lands
     once .course-card__photo-wrap grows and pushes it over, so the two
     would otherwise sit on top of each other. Same .45s curve as that
     tile's flex-basis, so the pill fades out as the photo opens. */
  opacity: 1;
  visibility: visible;
  transition: opacity .45s cubic-bezier(.4, 0, .2, 1), visibility 0s;
}

/* the same two selectors that grow .course-card__photo-wrap above */
.tuxsa-landing-page .course-card--photo:is(:hover, :focus-visible, :has(:focus-visible)) .course-card__badge {
  opacity: 0;
  visibility: hidden;
  transition: opacity .45s cubic-bezier(.4, 0, .2, 1), visibility 0s .45s;
}

/* ===== TEASER SECTION (Applied Economics — countdown) =====
   Background is now the photo from assets/06_Countdown/ (dark red scene,
   was a light gradient wash) — all outer text recolored white per request
   ("ตัวหนังสือเปลี่ยนเป็นขาว") since dark/red text would be unreadable
   against the dark red photo. This supersedes the earlier "TUXSA เหมือนเดิม"
   instruction (keeping that word uncolored) for the same legibility reason —
   the countdown card itself is untouched, it already has its own white
   background so its dark numbers/red accents stay legible regardless. */
.tuxsa-landing-page .teaser {
  position: relative;
  overflow: hidden;
  padding: 100px 0;
  /* flat TUXSA-red background, per request ("แบบเรียบๆ") */
  background: var(--tuxsa-red);
}

/* hidden rather than removed, so it's easy to flip back to a photo bg */
.tuxsa-landing-page .teaser__bg {
  display: none;
}

.tuxsa-landing-page .teaser .container {
  position: relative;
  z-index: 1;
}

/* white frame with a red-tinted shadow holding the content, so it reads
   as a card floating on the section's own red backdrop */
.tuxsa-landing-page .teaser__panel {
  background: #ffffff;
  border-radius: 24px;
  padding: 56px 48px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.1), 0 0 50px rgba(204, 51, 53, 0.28);
  /* everything slides in from the left together as one unit on scroll —
     scripts.js adds .is-shown via IntersectionObserver */
  opacity: 0;
  transform: translateX(-60px);
  transition: opacity .9s ease, transform .9s cubic-bezier(.22, 1, .36, 1);
}

.tuxsa-landing-page .teaser__panel.is-shown {
  opacity: 1;
  transform: translateX(0);
}

.tuxsa-landing-page .teaser__title {
  text-align: center;
  font-family: var(--font-heading);
  font-size: 40px;
  font-weight: 800;
  color: var(--tuxsa-text);
  line-height: 1.35;
  margin-bottom: 50px;
}

.tuxsa-landing-page .teaser__title span {
  display: block;
}

.tuxsa-landing-page .teaser__title-accent {
  color: var(--tuxsa-red);
}

.tuxsa-landing-page .teaser__inner {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: 40px;
}

.tuxsa-landing-page .teaser__content {
  flex: 0 1 auto;
  max-width: 480px;
}

.tuxsa-landing-page .teaser__new-program {
  background: #ffffff;
  color: var(--tuxsa-red);
  font-family: var(--font-heading);
  font-size: 15.6px;
  font-weight: 700;
  padding: 8.6px 20px;
  border-radius: 999px;
  /* red outline instead of a drop shadow */
  border: 2px solid var(--tuxsa-red);
  white-space: nowrap;
}

.tuxsa-landing-page .teaser__course-name {
  font-family: var(--font-heading);
  /* single line +30% per request: 44px → 57.2px */
  font-size: 57.2px;
  font-weight: 800;
  line-height: 1.15;
  margin-top: 17.6px;
  margin-bottom: 9.5px;
  white-space: nowrap;
  color: var(--tuxsa-red);
}

.tuxsa-landing-page .teaser__desc {
  max-width: 480px;
  font-size: 18px;
  line-height: 1.6;
  color: var(--tuxsa-gray);
  margin-bottom: 19px;
}

.tuxsa-landing-page .teaser__cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 12px 32px;
  border-radius: 999px;
  background: linear-gradient(135deg, var(--tuxsa-red) 0%, var(--tuxsa-red-dark) 100%);
  color: #ffffff;
  font-family: var(--font-heading);
  font-size: 17px;
  font-weight: 700;
  text-decoration: none;
  box-shadow: 0 8px 18px rgba(0, 0, 0, 0.12), 0 0 20px rgba(204, 51, 53, 0.35);
  transition: box-shadow .2s ease, transform .15s ease;
  /* gentle attention-grabbing pulse ("ว่ากดสิๆ") — paused on hover so the
     lift feedback below takes over cleanly */
  animation: teaserCtaPulse 1.8s ease-in-out infinite;
}

@keyframes teaserCtaPulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.05); }
}

.tuxsa-landing-page .teaser__cta:hover {
  box-shadow: 0 8px 18px rgba(0, 0, 0, 0.12), 0 0 32px rgba(204, 51, 53, 0.5);
  transform: translateY(-2px);
  animation-play-state: paused;
}

@media (prefers-reduced-motion: reduce) {
  .tuxsa-landing-page .teaser__cta {
    animation: none;
  }
}

.tuxsa-landing-page .teaser__cta-arrow {
  font-size: 18px;
}

/* decorative visual on the right — nudged further right, per request,
   since the gap to the panel's right edge was reading wider than the
   gap on the text column's left */
.tuxsa-landing-page .teaser__visual {
  flex: 0 1 auto;
  max-width: 480px;
  min-width: 0;
  transform: translateX(10%);
}

.tuxsa-landing-page .teaser__visual-img {
  display: block;
  width: 100%;
  height: auto;
  /* reserves the real space before this loading="lazy" image loads, so it
     can't shove content below it down mid-scroll — same class of bug as
     .learning-path__image (see that rule's comment) */
  aspect-ratio: 1546 / 791;
}

/* ===== STEPS SECTION (เลือกการเรียนได้ตามเป้าหมายของคุณ) =====
   Card format/font/size/style copied 1:1 from the Why TUXSA section
   (.why__card / .why__icon / .why__card-title / .why__list) per request —
   the circle badge holds the step number instead of an icon image, and
   the subtitle/divider from the previous draft were dropped since
   .why__card has no equivalent (its first list item already covers that
   line's content, so nothing is lost). */
.tuxsa-landing-page .steps {
  padding: 100px 0 120px;
  /* de-tinted + brightened version, per request ("มันติดเขียว ทำให้มันสว่าง ขาวขึ้น") */
  background: url("assets/images/goal-bg-white.37b7ada639.webp") center / cover no-repeat;
}

.tuxsa-landing-page .steps__title {
  font-family: var(--font-heading);
  font-size: 40px;
  font-weight: 800;
  color: var(--tuxsa-text);
  text-align: center;
  margin-bottom: 72px;
}

.tuxsa-landing-page .steps__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 28px;
}

/* same root-cause squeeze, same fix, as .why__grid: this base rule jumps
   2->4 columns at 901px, but .container doesn't reach its full 1280px
   width until the viewport does — so from 901px up to 1279px every card
   was squeezed down to ~185-255px. .step-card__title now shrinks to fit
   (see scripts.js's syncStepTitleSize, since it's forced to a single line —
   white-space:nowrap below), but a narrower card still means a smaller
   shared font-size for ALL four titles (they're kept uniform), so this
   still matters: keeping 2 columns through this range keeps every card
   comfortably wide, letting the titles stay closer to their 30px desktop
   size instead of shrinking further than necessary. Placed right after the
   base rule (not grouped with the other root-cause fixes further down the
   file) so it wins the cascade against it — matching this rule's own
   specificity. */
@media (min-width: 901px) and (max-width: 1279px) {
  .tuxsa-landing-page .steps__grid {
    grid-template-columns: repeat(2, 1fr);
    row-gap: 28px;
  }
}

.tuxsa-landing-page .step-card {
  position: relative;
  background: #f0f0f0;
  border-radius: 16px;
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.06);
  padding: 56px 24px 32px;
  text-align: center;
  margin-top: 40px;
  transition: transform .25s ease, box-shadow .25s ease;
  /* grid items default to min-width:auto, which refuses to shrink a track
     below its content's intrinsic minimum — since .step-card__title is
     white-space:nowrap, without this the card itself would grow past its
     1fr share (squeezing its siblings unevenly) instead of ever reporting
     overflow, defeating scripts.js's syncStepTitleSize shrink-to-fit
     measurement. Same fix as this file's other flex/grid overflow cases. */
  min-width: 0;
}

.tuxsa-landing-page .step-card:hover {
  transform: translateY(-8px);
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.06), 0 0 28px rgba(204, 51, 53, 0.28);
}

.tuxsa-landing-page .step-card__icon {
  position: absolute;
  top: -40px;
  left: 50%;
  transform: translateX(-50%);
  width: 80px;
  height: 80px;
  border-radius: 50%;
  background: var(--tuxsa-red);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 10px 20px rgba(204, 51, 53, 0.35);
}

.tuxsa-landing-page .step-card__number {
  font-family: var(--font-heading);
  font-size: 32px;
  font-weight: 800;
  color: #ffffff;
  line-height: 1;
}

.tuxsa-landing-page .step-card__title {
  font-family: var(--font-heading);
  /* 30px is the max/starting size — scripts.js's syncStepTitleSize shrinks
     this (via an inline font-size override) whenever the longest of the 4
     titles would otherwise overflow its card, and applies that same
     resulting size to all 4 titles so they always match, per request
     ("เพิ่มเรียนเพื่อ...ทำเป็น 1 บรรทัด...ให้ลดขนาด...รีเช็คให้ทุกกล่องใช้ขนาดฟอนต์
     เท่ากันเสมอ"). white-space:nowrap below forces a single line instead of
     ever wrapping — the JS is what keeps that from clipping. */
  font-size: 30px;
  font-weight: 700;
  color: var(--tuxsa-red);
  line-height: 1.35;
  margin-bottom: 8px;
  white-space: nowrap;
}

.tuxsa-landing-page .step-card__subtitle {
  font-family: var(--font-heading);
  font-size: 18px;
  color: var(--tuxsa-gray);
  margin-bottom: 20px;
}

.tuxsa-landing-page .step-card__divider {
  display: block;
  width: 64px;
  height: 1px;
  background: #cfcfcf;
  margin: 0 auto 20px;
}

.tuxsa-landing-page .step-card__list {
  text-align: left;
  padding-left: 20px;
  font-size: 18px;
  line-height: 1.65;
  color: var(--tuxsa-text);
}

.tuxsa-landing-page .step-card__list li + li {
  margin-top: 8px;
}

.tuxsa-landing-page .step-card__list small {
  display: block;
  font-size: 14px;
  color: var(--tuxsa-gray);
}

/* mobile only: this bullet's forced <br> (kept for desktop/tablet, where
   the card is wide enough to not need it) made it 2 lines here too — drop
   the break so it wraps naturally like every other bullet in this list,
   at the same font size, instead of forcing one line with smaller text
   that no longer matched its siblings */
@media (max-width: 600px) {
  .tuxsa-landing-page .step-card__break {
    display: none;
  }
}

/* per request: keep this break wherever the phrase genuinely needs 2 lines
   (measured against the real rendered card, not just assumed) — below
   ~800px the card is too narrow to fit the whole phrase on one line, and
   without the break the browser's own wrap point lands mid-word inside
   "on-campus" (worse than the current explicit break), so it must stay
   forced there. Above 1280px the 4-column desktop layout narrows the card
   back down to the same problem (still needs the break — untouched, this
   is the "already ลงตัว" desktop look). Only 810-1279px (2-column, card
   wide enough — see the .steps__grid root-cause fix above) has genuine
   room to fit the whole phrase on a single line, so the break is dropped
   only there. 810px (not the measured ~795px crossover) leaves a safety
   margin for font-rendering differences across browsers/OS. */
@media (min-width: 810px) and (max-width: 1279px) {
  .tuxsa-landing-page .step-card__break {
    display: none;
  }
}

@media (min-width: 901px) {
  /* desktop-only: balance line breaks instead of the browser's default
     greedy wrap, which was splitting a couple of these bullets at an
     awkward point (e.g. a single orphaned word stranded on its own line) */
  .tuxsa-landing-page .step-card__list li {
    text-wrap: balance;
  }
}

/* ===== LEARNING PATH SECTION (เส้นทางมุ่งสู่ปริญญาโท) =====
   Placeholder shell only — see the HTML comment above the section for why. */
.tuxsa-landing-page .learning-path {
  padding: 100px 0 120px;
  /* per request, replacing the flat tinted wash */
  background: url("assets/images/journey-bg.872f4d6b3a.webp") center / cover no-repeat;
}

.tuxsa-landing-page .learning-path__title {
  font-family: var(--font-heading);
  font-size: 40px;
  font-weight: 800;
  color: var(--tuxsa-text);
  text-align: center;
  margin-bottom: 48px;
}

/* white "backing" layer so the artwork stands out from the section's
   tinted background — same treatment as .roadmap__panel */
.tuxsa-landing-page .learning-path__panel {
  background: #ffffff;
  border-radius: 24px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.08);
  padding: 40px;
  /* reveal-on-scroll, toggled via .is-shown by an IntersectionObserver in
     scripts.js — same fade/rise treatment as the roadmap timeline's reveal */
  opacity: 0;
  transform: translateY(32px);
  transition: opacity .6s ease, transform .6s ease;
}

.tuxsa-landing-page .learning-path__panel.is-shown {
  opacity: 1;
  transform: translateY(0);
}

.tuxsa-landing-page .learning-path__image {
  display: block;
  width: 100%;
  height: auto;
}

/* reserves each image's real space before it ever loads (both are
   loading="lazy" and this section sits well below the fold), so the layout
   doesn't jump when a several-hundred-KB image suddenly appears mid-scroll
   — most noticeable on .learning-path__image--mobile (1380x2350, a very
   tall portrait image that used to render as 0-height until loaded, then
   shove ~500-600px of content down at mobile widths, reading as the whole
   page "jumping" to this section). Without this, the exact moment it snaps
   in depends on scroll position/connection speed, so it wasn't reliably
   reproducible by eye — the fix is the same either way: give the browser
   the real ratio upfront so it never has to guess. */
.tuxsa-landing-page .learning-path__image--desktop {
  aspect-ratio: 2758 / 964;
}

.tuxsa-landing-page .learning-path__image--mobile {
  aspect-ratio: 1380 / 2350;
}

/* only one of the two artworks shows at a time — the mobile version is a
   genuinely different portrait composition, not just a reflow, so this is
   a straight display swap rather than a responsive grid/crop */
.tuxsa-landing-page .learning-path__image--mobile {
  display: none;
}

/* ===== BIRTHDAY SURPRISE SECTION (promo codes) ===== */
.tuxsa-landing-page .birthday {
  position: relative;
  overflow: hidden;
  padding: 100px 0 80px;
}

.tuxsa-landing-page .birthday__bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  z-index: 0;
}

.tuxsa-landing-page .birthday .container {
  position: relative;
  z-index: 1;
}

.tuxsa-landing-page .birthday__title {
  font-family: var(--font-heading);
  font-size: 56px;
  font-weight: 800;
  color: var(--tuxsa-red);
  text-align: center;
  letter-spacing: .02em;
}

.tuxsa-landing-page .birthday__subtitle {
  margin-top: 8px;
  font-size: 22px;
  color: var(--tuxsa-text);
  text-align: center;
  margin-bottom: 56px;
}

.tuxsa-landing-page .birthday__carousel {
  position: relative;
}

.tuxsa-landing-page .birthday__track {
  flex: 1 1 auto;
  display: flex;
  gap: 24px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  padding: 4px 4px 12px;
  scrollbar-width: none;
}

.tuxsa-landing-page .birthday__track::-webkit-scrollbar {
  display: none;
}

.tuxsa-landing-page .birthday__slide {
  flex: 0 0 calc((100% - 48px) / 3);
  min-width: 0;
  scroll-snap-align: start;
}

.tuxsa-landing-page .promo-card {
  height: 100%;
  background: #f0f0f0;
  border-radius: 24px;
  padding: 20px;
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.06);
}

.tuxsa-landing-page .promo-card__panel {
  height: 100%;
  background: #ffffff;
  border-radius: 16px;
  padding: 28px 24px;
  text-align: center;
}

.tuxsa-landing-page .promo-card__title {
  font-family: var(--font-heading);
  font-size: 37.18px;
  font-weight: 800;
  color: var(--tuxsa-red);
}

.tuxsa-landing-page .promo-card__subtitle {
  margin-top: 4px;
  font-size: 19.5px;
  color: var(--tuxsa-text);
}

.tuxsa-landing-page .promo-card__divider {
  display: block;
  width: 90%;
  height: 1px;
  background: #d5d5d5;
  margin: 20px auto 20px;
}

.tuxsa-landing-page .promo-card__codes {
  display: flex;
  flex-direction: column;
  gap: 12px;
  text-align: left;
}

/* compact "ticket" coupon — scaled-down version of the reference design to
   fit the existing narrow carousel card (per explicit choice: shrink the
   design rather than widen the cards) */
.tuxsa-landing-page .coupon {
  display: flex;
  align-items: stretch;
  background: #ffffff;
  border: 1px solid #ececec;
  border-radius: 12px;
  overflow: hidden;
}

.tuxsa-landing-page .coupon__amount {
  /* shrink-to-fit its own text instead of a fixed width, so the white
     body side gets the freed-up space (was flex: 0 0 108px) */
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 8px 12px;
  background: rgba(204, 51, 53, 0.08);
  text-align: center;
  white-space: nowrap;
}

.tuxsa-landing-page .coupon__amount-label {
  /* 200% per request off the previous 9.6px */
  font-size: 19.2px;
  font-weight: 700;
  color: var(--tuxsa-red);
}

.tuxsa-landing-page .coupon__amount-value {
  font-family: var(--font-heading);
  /* 200% per request off the previous 19.2px */
  font-size: 38.4px;
  font-weight: 800;
  color: var(--tuxsa-red);
  line-height: 1;
}

.tuxsa-landing-page .coupon__amount-currency {
  /* 200% per request off the previous 11.52px */
  font-size: 23.04px;
  margin-right: 1px;
}

.tuxsa-landing-page .coupon__body {
  flex: 1 1 auto;
  min-width: 0;
  padding: 10px 12px;
}

.tuxsa-landing-page .coupon__top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
  flex-wrap: wrap;
}

.tuxsa-landing-page .coupon__info {
  /* lets the course name actually shrink/ellipsis instead of forcing the
     flex item to grow to its full content width (the default flexbox
     min-width:auto behavior) */
  min-width: 0;
  flex: 1 1 auto;
}

.tuxsa-landing-page .coupon__course {
  /* uses --font-body (DB Heavent as of 2026-09-10; was TF Lanna, then DB Heavent originally) */
  font-family: var(--font-body);
  /* max size that keeps the longest full name ("หลักสูตร Applied Data Science")
     on one line at the narrowest layout (165px available at row layout,
     >=1345px) with a safety margin, per request ("ขยายใหญ่อีก...อยู่ใน 1 บรรทัด") */
  font-size: 18px;
  /* thin per request ("ตัวบาง"), was 800 */
  font-weight: 400;
  color: var(--tuxsa-text);
  line-height: 1.3;
  white-space: nowrap;
}

.tuxsa-landing-page .coupon__code-row {
  display: flex;
  align-items: center;
  /* no-wrap on purpose — the code value truncates below instead, so the
     copy button is structurally guaranteed to stay on the same line right
     after the code, regardless of exact font metrics */
  flex-wrap: nowrap;
  gap: 5px;
  margin-top: 4px;
  /* 200% per request off the previous 11.52px */
  font-size: 23.04px;
}

.tuxsa-landing-page .coupon__code-label {
  flex: 0 0 auto;
  color: var(--tuxsa-gray);
}

.tuxsa-landing-page .coupon__code-value {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 700;
  color: var(--tuxsa-red);
}

/* ALL coupon codes, desktop only (≥901px) — per follow-up request
   ("ปรับให้ทุกโค้ด ไม่ต้อง bold"), widened from just MBA300BD/MBA7YRS to
   every .coupon__code-value. Non-bold measures narrower, helping keep
   every code on one line within the original 3-per-row desktop layout
   (still stays red). Mobile/tablet keep the base rule's bold (700) above,
   completely untouched. */
@media (min-width: 901px) {
  .tuxsa-landing-page .coupon__code-value {
    font-weight: 400;
  }
}

.tuxsa-landing-page .coupon__copy-btn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 6px 14px;
  border: none;
  border-radius: 999px;
  background: var(--tuxsa-red);
  color: #ffffff;
  font-family: var(--font-heading);
  /* 200% per request off the previous 11.52px */
  font-size: 23.04px;
  font-weight: 700;
  cursor: pointer;
  transition: background-color .2s ease;
}

/* shrunk + moved inline after the code, per request ("ย่อปุ่มลง เอาไว้หลังโค้ด") —
   replaces the separate small copy-icon button that used to sit here. */
.tuxsa-landing-page .coupon__copy-btn--compact {
  padding: 4px 10px;
  font-size: 11px;
}

/* Enlarged (11px->13px) only at the row layout (>=1345px, where .coupon
   is side-by-side, not stacked) since narrowing .coupon__amount to fit its
   own text only freed width there — the stacked/column layout below 1345px
   has the same available row width as before (independent of the amount
   block's own width), so the button stays at its original safe size there
   to avoid truncating the longest code ("MBA7YRS") on mobile. */
@media (min-width: 1345px) {
  .tuxsa-landing-page .coupon__copy-btn--compact {
    padding: 5px 12px;
    font-size: 13px;
  }
}

.tuxsa-landing-page .coupon__copy-btn:hover {
  background: var(--tuxsa-red-dark);
}

/* toast notification for click-to-copy feedback */
.tuxsa-landing-page .toast {
  position: fixed;
  left: 50%;
  bottom: 32px;
  z-index: 200;
  transform: translate(-50%, 12px);
  padding: 12px 24px;
  border-radius: 999px;
  background: #1a1a1a;
  color: #ffffff;
  font-size: 14px;
  font-weight: 600;
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.2);
  opacity: 0;
  pointer-events: none;
  transition: opacity .25s ease, transform .25s ease;
}

.tuxsa-landing-page .toast.is-visible {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* back-to-top button: hidden until the visitor scrolls down (toggled via JS) */
.tuxsa-landing-page .back-to-top {
  position: fixed;
  right: 32px;
  /* the embedding SkillLane page pins its own floating "ค้นหาคอร์สด้วย AI"
     pill to this same corner (~64px tall, ~24px off the bottom); at the old
     32px this button landed right on top of it, so sit clear above it */
  bottom: 108px;
  z-index: 150;
  width: 56px;
  height: 56px;
  border: none;
  border-radius: 50%;
  /* TUXSA brand red per request ("HEX ของแบรนด์ tuxsa"), was an eyeballed
     teal-green approximation with no real brand hex behind it */
  background: var(--tuxsa-red);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity .25s ease, transform .25s ease, visibility .25s, background-color .2s ease;
}

.tuxsa-landing-page .back-to-top.is-visible {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.tuxsa-landing-page .back-to-top:hover {
  background: var(--tuxsa-red-dark);
}

.tuxsa-landing-page .back-to-top svg {
  width: 22px;
  height: 22px;
}

.tuxsa-landing-page .promo-card__panel--cta {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.tuxsa-landing-page .promo-card__line {
  margin-top: 20px;
  font-size: 20.8px;
  color: var(--tuxsa-text);
}

.tuxsa-landing-page .promo-card__badge {
  margin-top: 20px;
  padding: 10px 20px;
  border: 2px solid var(--tuxsa-red);
  border-radius: 10px;
  font-size: 20.8px;
  font-weight: 700;
  color: var(--tuxsa-red);
}

.tuxsa-landing-page .promo-card__big {
  margin-top: 8px;
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.tuxsa-landing-page .promo-card__big-prefix,
.tuxsa-landing-page .promo-card__big-suffix {
  font-size: 19.5px;
  color: var(--tuxsa-text);
}

/* keep "สูงสุดกว่า" on one line at any width/orientation — as a shrinkable
   flex item next to the big number, letting it wrap internally orphaned
   its last word ("กว่า") onto its own line the moment the row got tight
   (e.g. landscape phones, which are wide enough to skip the portrait-only
   narrow-card rules below but still too narrow for the desktop 3-up row) */
.tuxsa-landing-page .promo-card__big-prefix {
  white-space: nowrap;
}

.tuxsa-landing-page .promo-card__big-number {
  font-family: var(--font-heading);
  font-size: 57.2px;
  font-weight: 800;
  color: var(--tuxsa-red);
  line-height: 1;
}

.tuxsa-landing-page .promo-card__line--small {
  margin-top: 12px;
  font-size: 18.2px;
  color: var(--tuxsa-gray);
}

.tuxsa-landing-page .promo-card__packages {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 20px;
}

.tuxsa-landing-page .promo-card__package {
  width: 100%;
  border: 1.5px solid #d5d5d5;
  border-radius: 12px;
  padding: 14px 18px;
  /* centered on every version, desktop included — matches the "Full
     Package" box below, which has been centered everywhere since it lost
     its side-by-side photo */
  text-align: center;
}

/* the gift-card photo is a separate element now (sibling of this box, not
   its child — see .promo-card__package-image below), so the "Full Package"
   condition text stands alone here and is centered like the photo above it */
.tuxsa-landing-page .promo-card__package-text {
  text-align: center;
}

.tuxsa-landing-page .promo-card__package-name {
  font-size: 16.5px;
  font-weight: 700;
  color: var(--tuxsa-text);
  white-space: nowrap;
}

.tuxsa-landing-page .promo-card__package-gift {
  margin-top: 4px;
  font-size: 15px;
  color: var(--tuxsa-text);
}

.tuxsa-landing-page .promo-card__package-value {
  color: var(--tuxsa-red);
  font-weight: 700;
  /* keep "มูลค่า X บาท*" together — wraps as one unit instead of
     splitting mid-phrase onto the next line */
  white-space: nowrap;
}

/* sits below the "Full Package" box (a plain sibling in the flex-column
   .promo-card__packages, not packed inside that box's bordered frame) so
   the free gift reads as its own stand-out visual instead of competing
   with the condition text for space inside the same box. Sized up from
   the old inline 99px now that it has the whole card's width to itself. */
.tuxsa-landing-page .promo-card__package-image {
  align-self: center;
  width: 160px;
  height: auto;
  border-radius: 8px;
  margin-top: 4px;
  /* reserves the real space before this loading="lazy" image loads — same
     class of bug as .learning-path__image (see that rule's comment) */
  aspect-ratio: 760 / 569;
}

.tuxsa-landing-page .promo-card__disclaimer {
  margin-top: 16px;
  font-size: 13px;
  color: var(--tuxsa-red);
}

.tuxsa-landing-page .promo-card__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: 24px;
  padding: 12px 28px;
  border-radius: 999px;
  background: var(--tuxsa-red);
  color: #ffffff;
  font-family: var(--font-heading);
  font-size: 16px;
  font-weight: 700;
  text-decoration: none;
  transition: background-color .2s ease;
}

.tuxsa-landing-page .promo-card__cta:hover {
  background: var(--tuxsa-red-dark);
}

/* ===== CERTIFICATE CHECK ===== */
.tuxsa-landing-page .cert-check {
  position: relative;
  padding: 100px 0 120px;
  background: #ffffff;
  overflow: hidden;
}

.tuxsa-landing-page .cert-check__bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  z-index: 0;
}

.tuxsa-landing-page .cert-check__inner {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  /* -25% then another -20% per request, was 64px -> 48px -> now this */
  gap: 38.4px;
}

.tuxsa-landing-page .cert-check__visual {
  position: relative;
  /* widened from 58% so the certificate image renders ~25% larger than
     before, per request ("ขยายภาพให้ใหญ่ขึ้น 25%") */
  flex: 1 1 72.5%;
  min-width: 0;
}

.tuxsa-landing-page .cert-check__image {
  display: block;
  width: 100%;
  height: auto;
  /* reserves the real space before this loading="lazy" image loads — same
     class of bug as .learning-path__image (see that rule's comment) */
  aspect-ratio: 961 / 636;
}

.tuxsa-landing-page .cert-check__content {
  flex: 1 1 27.5%;
  /* NOT min-width:0 — this column must never shrink below the CTA
     button's own min-width (220px), otherwise it overflows at narrow
     row-layout widths just above the 900px stacking breakpoint */
  text-align: center;
}

.tuxsa-landing-page .cert-check__title {
  font-family: var(--font-heading);
  font-size: 34px;
  font-weight: 800;
  line-height: 1.35;
  color: var(--tuxsa-text);
  margin-bottom: 32px;
}

.tuxsa-landing-page .cert-check__cta {
  min-width: 220px;
}

/* ===== FAQ ===== */
.tuxsa-landing-page .faq {
  padding: 100px 0 120px;
  /* reverted to white per request ("ใช้ BG สีขาว แบบใน ref") — was briefly
     the same light-red wash as .roadmap (rgba(204, 51, 53, 0.12)) */
  background: #ffffff;
}

.tuxsa-landing-page .faq__title {
  font-family: var(--font-heading);
  font-size: 40px;
  font-weight: 800;
  color: var(--tuxsa-text);
  text-align: center;
  margin-bottom: 56px;
}

.tuxsa-landing-page .faq__list {
  max-width: 980px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* each item is its own positioning context for its answer panel, which is
   absolutely positioned (not inline) — opening/closing an answer never
   pushes other questions around or changes .faq's own height, per request
   ("ไม่อยากให้ขนาด section มันยืดๆ หดๆ") */
.tuxsa-landing-page .faq__item {
  position: relative;
}

.tuxsa-landing-page .faq__question {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 22px 28px;
  border: none;
  border-radius: 16px;
  background: #eeeeee;
  cursor: pointer;
  text-align: left;
  font-family: var(--font-body);
  font-size: 21.6px;
  color: var(--tuxsa-text);
  transition: background-color .2s ease;
}

.tuxsa-landing-page .faq__question:hover {
  background: #e4e4e4;
}

.tuxsa-landing-page .faq__icon {
  flex: 0 0 auto;
  width: 16px;
  height: 10px;
  fill: #9a9a9a;
  transition: transform .2s ease;
}

.tuxsa-landing-page .faq__item.is-open .faq__icon {
  transform: rotate(180deg);
}

/* collapsed by default: zero height, invisible, no pointer events —
   expands via max-height rather than height:auto so the transition
   can animate without knowing the answer's real content height */
.tuxsa-landing-page .faq__answer {
  position: absolute;
  left: 0;
  right: 0;
  z-index: 5;
  background: #ffffff;
  border: 1px solid #ececec;
  border-radius: 16px;
  box-shadow: 0 16px 32px rgba(0, 0, 0, 0.14);
  padding: 0 28px;
  max-height: 0;
  opacity: 0;
  visibility: hidden;
  overflow: hidden;
  pointer-events: none;
  transition: max-height .3s ease, opacity .2s ease, padding .3s ease;
}

.tuxsa-landing-page .faq__item--below .faq__answer {
  top: calc(100% + 10px);
}

.tuxsa-landing-page .faq__item--above .faq__answer {
  bottom: calc(100% + 10px);
}

.tuxsa-landing-page .faq__item.is-open .faq__answer {
  /* was 400px, then 600px — after switching body copy to 18px/DB Heavent
     (2026-09-10), the certification-status answer (longest, 2
     paragraph-length list items) measured 624px at 320px width (the
     narrowest point tested), which now clipped at 600px. Raised to 700px
     for a comfortable margin; every shorter existing answer just reaches
     its own real height sooner within the same .3s transition, no visible
     difference for those. */
  max-height: 700px;
  opacity: 1;
  visibility: visible;
  padding: 22px 28px;
  pointer-events: auto;
}

.tuxsa-landing-page .faq__answer p {
  font-family: var(--font-body);
  /* body-copy standard: 18px regular, per request (was 21.6px to match .faq__question) */
  font-size: 18px;
  line-height: 1.6;
  color: var(--tuxsa-red);
}

.tuxsa-landing-page .faq__answer p + p,
.tuxsa-landing-page .faq__answer p + .faq__answer-list,
.tuxsa-landing-page .faq__answer-list + p {
  margin-top: 12px;
}

.tuxsa-landing-page .faq__answer-list {
  list-style: disc;
  padding-left: 20px;
}

.tuxsa-landing-page .faq__answer-list li {
  font-family: var(--font-body);
  /* body-copy standard: 18px regular, per request (was 21.6px to match .faq__question) */
  font-size: 18px;
  line-height: 1.6;
  color: var(--tuxsa-red);
}

.tuxsa-landing-page .faq__answer-list li + li {
  margin-top: 4px;
}

.tuxsa-landing-page .faq__highlight {
  font-weight: 700;
  text-decoration: underline;
  color: var(--tuxsa-text);
}

/* ===== RESPONSIVE ===== */
@media (hover: none), (max-width: 900px) {
  /* hover-to-expand only makes sense with a mouse — drop the accordion
     and show every card's content at once (static grid) on any touch
     device (hover: none), regardless of its width, so a landscape iPad
     (1194/1366 CSS px — wider than a width-only cutoff would ever catch)
     doesn't need a tap-to-reveal interaction it can't cleanly clear.
     Real desktop/laptop mouse users keep the hover accordion at any
     window width (was previously also dropped below 1400px, which caught
     ordinary laptop resolutions like 1366×768 that do have a real mouse —
     narrow-window phones still get the same static treatment via the
     width fallback here). */
  .tuxsa-landing-page .courses__grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 24px;
    height: auto;
  }

  .tuxsa-landing-page .course-card {
    flex: none;
    cursor: default;
  }

  .tuxsa-landing-page .course-card:hover,
  .tuxsa-landing-page .course-card:focus-within {
    flex: none;
  }

  .tuxsa-landing-page .course-card__collapsed-label {
    display: none;
  }

  .tuxsa-landing-page .course-card__expanded {
    position: static;
    opacity: 1;
    pointer-events: auto;
  }

  /* touch/narrow fallback for the photo variant: the desktop side-by-side
     (row) layout gets too cramped in a ~291px-wide static card, so stack
     image-on-top/text-below instead — same "always expanded" treatment as
     the other cards above, skipping the hover animation entirely.
     height is now auto (was a fixed 420px) so the description text + CTA
     button below the photo always have room to fully show instead of
     getting clipped by the card's overflow:hidden when they didn't fit in
     the leftover space under a fixed-height photo. The grid's default
     align-items:stretch still equalizes every card's height within its
     own row, same as before. */
  .tuxsa-landing-page .course-card--photo {
    flex-direction: column;
    height: auto;
  }

  .tuxsa-landing-page .course-card--photo .course-card__photo-wrap {
    /* fixed aspect ratio instead of flex-basis:% (which needs a definite
       parent height to resolve against, and the card's height is auto now) */
    flex: none;
    aspect-ratio: 3 / 2;
  }

  /* the desktop accordion's hover rule (flex-basis: 307px, a row-layout
     WIDTH meant to expand the photo on hover) is more specific than the
     override above, so it still fired here on tap — snapping the photo
     from its resting aspect-ratio height to a fixed 307px and back, which
     is exactly the "bounce" on tapping the photo. Re-assert the same
     aspect-ratio sizing for the hover/focus-within state too so nothing
     changes size on tap. */
  .tuxsa-landing-page .course-card--photo:hover .course-card__photo-wrap,
  .tuxsa-landing-page .course-card--photo:focus-within .course-card__photo-wrap {
    flex-basis: auto;
  }

  .tuxsa-landing-page .course-card--photo .course-card__photo-panel {
    flex: 1 1 auto;
    overflow: visible;
    /* wasn't a flex container, so its child (.course-card__photo-expanded)
       sized to its own content instead of stretching to fill the panel's
       full (equalized) height — a card with a shorter description ended
       up with a shorter photo-expanded box than one with a longer
       description, even though the outer cards were the same height,
       throwing off the space-between button-bottom alignment above */
    display: flex;
    flex-direction: column;
  }

  .tuxsa-landing-page .course-card__photo-expanded {
    position: static;
    opacity: 1;
    pointer-events: auto;
    padding: 20px;
    /* align-items:stretch (the panel's flex default) only covers the
       CROSS axis of a column flex container, i.e. width — filling the
       actual (vertical) main axis needs an explicit flex-grow so this
       box reaches all the way down to the panel's real bottom instead of
       stopping at its own content height */
    flex: 1 1 auto;
    /* was justify-content:center (from the base rule) — centering the
       fit-text+button as one block meant a card with a longer 4-line
       description pushed its button lower than a card with a shorter
       3-line one, even though every card in the row is the same height.
       space-between pins the button to the panel's bottom edge instead,
       regardless of how many lines the description above it takes. */
    justify-content: space-between;
  }

  .tuxsa-landing-page .course-card__fit {
    white-space: normal;
  }

  .tuxsa-landing-page .course-card__badge {
    /* .course-card__photo-wrap has no collapsed state at this breakpoint —
       it is permanently expanded (aspect-ratio 3/2, flex:none) — so by the
       same rule as the desktop hover above, the badge never shows here.
       This replaces a top:12px nudge that existed to keep the pill from
       being clipped by .course-card's overflow:hidden; nothing is painted
       now, so there is nothing left to clip. */
    opacity: 0;
    visibility: hidden;
  }
}

/* tablet landscape (touch, wide enough for 3 columns — portrait tablets
   are ≤900px and use the 2-column grid instead, which already centers its
   own single leftover card via .course-card--upcoming below): 5 cards in
   3 columns leaves the last row with just 2, pinned to the left with a
   big empty gap on the right. Use a 6-column virtual grid so that last
   pair can be centered as a group instead. */
@media (hover: none) and (min-width: 901px) {
  .tuxsa-landing-page .courses__grid {
    grid-template-columns: repeat(6, 1fr);
  }

  .tuxsa-landing-page .course-card:nth-child(1) { grid-column: 1 / 3; }
  .tuxsa-landing-page .course-card:nth-child(2) { grid-column: 3 / 5; }
  .tuxsa-landing-page .course-card:nth-child(3) { grid-column: 5 / 7; }
  .tuxsa-landing-page .course-card:nth-child(4) { grid-column: 2 / 4; }
  .tuxsa-landing-page .course-card:nth-child(5) { grid-column: 4 / 6; }
}

/* stack amount block above body instead of side-by-side — below the
   container's own 1280px max-width (i.e. viewport <1344px, where .container
   still scales 1:1 with the viewport instead of being pinned at 1280px)
   every row-layout width tested came out equally razor-thin (~0.3px to
   spare, regardless of exactly how narrow) because the slide width itself
   keeps shrinking right along with the viewport. Once the container plateaus
   at 1280px the slide width stops shrinking and gets genuinely comfortable
   — so the breakpoint is set at that plateau, not at whatever pixel
   happened to still pass the overflow check. */
@media (max-width: 1344px) {
  .tuxsa-landing-page .coupon {
    flex-direction: column;
  }

  .tuxsa-landing-page .coupon__amount {
    flex-direction: row;
    justify-content: center;
    gap: 8px;
  }
}

@media (max-width: 900px) {
  .tuxsa-landing-page .birthday__slide {
    flex-basis: calc((100% - 24px) / 2);
  }

  .tuxsa-landing-page .cert-check__inner {
    flex-direction: column;
    gap: 48px;
  }

  .tuxsa-landing-page .cert-check__visual {
    flex-basis: auto;
    width: 100%;
    max-width: 460px;
  }

  .tuxsa-landing-page .cert-check__content {
    flex-basis: auto;
    width: 100%;
  }

  .tuxsa-landing-page .courses__grid {
    grid-template-columns: repeat(2, 1fr);
    row-gap: 56px;
  }

  /* 5 cards in a 2-column grid leaves the last one alone on its own row,
     pinned to the left edge with a big empty gap beside it — span the full
     row and center it at a single column's width instead */
  .tuxsa-landing-page .course-card--upcoming {
    grid-column: 1 / -1;
    justify-self: center;
    width: calc((100% - 24px) / 2);
  }

  .tuxsa-landing-page .why__grid {
    grid-template-columns: repeat(2, 1fr);
    row-gap: 56px;
  }

  /* swap to the dedicated portrait artwork instead of squeezing the
     landscape one down — was illegibly small on tablet widths too, not
     just phones, since this used to only kick in below 600px */
  .tuxsa-landing-page .learning-path__image--desktop {
    display: none;
  }

  .tuxsa-landing-page .learning-path__image--mobile {
    display: block;
  }

  .tuxsa-landing-page .steps__grid {
    grid-template-columns: repeat(2, 1fr);
    row-gap: 28px;
  }

  /* horizontal alternating timeline doesn't fit a narrow screen —
     switch to a vertical timeline: dot + content side by side, stacked */
  .tuxsa-landing-page .roadmap {
    padding: 78px 0 80px;
  }

  .tuxsa-landing-page .roadmap__panel {
    padding: 40px 24px 56px;
    border-radius: 16px;
  }

  .tuxsa-landing-page .roadmap__title {
    font-size: 28px;
    margin-bottom: 48px;
  }

  .tuxsa-landing-page .roadmap__timeline {
    flex-direction: column;
    align-items: stretch;
    gap: 16px;
    padding: 0;
  }

  .tuxsa-landing-page .roadmap__track {
    display: none;
  }

  .tuxsa-landing-page .roadmap__item {
    display: block;
  }

  .tuxsa-landing-page .roadmap__pill {
    width: 100%;
    border-radius: 18px;
  }

  .tuxsa-landing-page .roadmap__desc,
  .tuxsa-landing-page .roadmap__highlight {
    white-space: normal;
  }

  .tuxsa-landing-page .roadmap__item--featured .roadmap__pill.is-active {
    transform: translateY(0) scale(1);
  }
}

/* tablet portrait only — phones (≤600px) keep the single-column stack
   above; this covers the full tablet-portrait range (601-1112px — plain
   iPad through iPad Pro 12.9" portrait's 1024px, portrait orientation),
   arranged as 3 cards top row + 2 cards bottom row (centered), linked by
   one continuous snake connector (drawn by scripts.js) */
@media (min-width: 601px) and (max-width: 1112px) and (orientation: portrait) {
  .tuxsa-landing-page .roadmap__timeline {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    /* dense: without it, the row-2 auto-placement cursor advances past
       column 4 (item 6's slot) and never backtracks to fill the free
       columns 2-3 for item 7, so item 7 got shoved into a phantom 3rd
       row instead of sharing row 2 — dense makes it backfill that gap */
    grid-auto-flow: dense;
    /* base rule's align-items:center (written for the flex/row desktop
       layout) also applies to grid — left as center, each card would only
       size to its own content and float in the middle of its row instead
       of matching its row-mates' height, breaking the equal-bottom-per-row
       requirement */
    align-items: stretch;
    column-gap: 16px;
    row-gap: 40px;
  }

  .tuxsa-landing-page .roadmap__item {
    display: block;
  }

  /* .roadmap__track and .roadmap__track-svg are the timeline's first two
     children, so the 5 .roadmap__item cards start at nth-child(3) */
  .tuxsa-landing-page .roadmap__item:nth-child(3) { grid-column: 1 / 3; }
  .tuxsa-landing-page .roadmap__item:nth-child(4) { grid-column: 3 / 5; }
  .tuxsa-landing-page .roadmap__item:nth-child(5) { grid-column: 5 / 7; }
  /* swapped so the snake runs in order (top row left-to-right, then a
     short drop to the nearest bottom card, then right-to-left back across
     the bottom row) instead of criss-crossing the middle */
  .tuxsa-landing-page .roadmap__item:nth-child(6) { grid-column: 4 / 6; }
  .tuxsa-landing-page .roadmap__item:nth-child(7) { grid-column: 2 / 4; }

  .tuxsa-landing-page .roadmap__pill {
    /* narrowed 20% per request so the snake line shows in the gap on
       either side, instead of being hidden right behind the card edge */
    width: 80%;
    margin: 0 auto;
    height: 100%;
    border-radius: 18px;
  }

  .tuxsa-landing-page .roadmap__desc,
  .tuxsa-landing-page .roadmap__highlight {
    white-space: normal;
  }

  .tuxsa-landing-page .roadmap__item--featured .roadmap__pill.is-active {
    transform: translateY(0) scale(1);
  }

  /* straight-line track doesn't apply to a bent path — swap for the SVG */
  .tuxsa-landing-page .roadmap__track {
    display: none;
  }

  .tuxsa-landing-page .roadmap__track-svg {
    display: block;
  }

  /* dashed "not yet reached" line removed per request — only the solid
     running line stays */
  .tuxsa-landing-page .roadmap__track-bg-path {
    display: none;
  }
}

@media (max-width: 900px) {
  .tuxsa-landing-page .showcase__inner {
    text-align: center;
  }

  .tuxsa-landing-page .showcase__row {
    flex-direction: column;
    /* the base rule's flex-wrap:wrap exists only for the desktop row-wrap
       trick that pushes .stat__note onto its own full-width line below
       content+media (see .showcase__row's own comment) — in column
       direction, "wrap" means wrap into new COLUMNS instead, and this
       row/inner has no definite height to wrap against, so
       .showcase__media was ending up pushed into a phantom second column
       with 0 height (video invisible — "วิดิโอของ section สถิติ มันหายไปไหน").
       Not an issue before .stat__note moved into this flex container. */
    flex-wrap: nowrap;
  }

  /* mobile/tablet order: stats, then the note, then the video — note moved
     up above the video here per request ("หมายเหตุ ของเวอชั่นมือถือ และไอแพด
     ให้ย้ายขึ้นไปอยู่บนวิดิโอ"), overriding the desktop order (content, media,
     note) set on the base rules above. flex-basis:100% (a row-wrap trick,
     meaningless once stacked to a column) is reset back to auto, and the
     desktop-only bottom margin is dropped in favor of the plain gap this
     column already uses between its stacked children. */
  .tuxsa-landing-page .stat__note {
    order: 2;
    flex-basis: auto;
    margin-top: 0;
  }

  /* once stacked to a column, .showcase__row's align-items:stretch only
     stretches WIDTH (the cross-axis, pre-column-flip it was height) — the
     base rule's .video-card { height:100% } has nothing meaningful to
     resolve against here (its stretched ancestor chain has no definite
     height in column mode), so it would collapse to 0. Restore a fixed
     aspect-ratio instead, same as the row layout used before this section's
     edge-matching rework. Set on .showcase__media (the flex ITEM), not
     .video-card (a grandchild two levels down) — with .stat__note now
     also living in .showcase__row (see the HTML comment), a flex-item's
     own height-via-aspect-ratio wasn't reliably propagating up to size
     .showcase__media's auto height in this column layout, leaving it at
     0 and the video invisible ("วิดิโอของ section สถิติ มันหายไปไหน") even
     though .video-card itself still computed a correct height. Aspect-ratio
     directly on the flex item sizes it from its own (already-resolved)
     width with no extra hop, sidestepping that. */
  .tuxsa-landing-page .video-card {
    height: 100%;
  }

  /* same row-basis-read-as-height bug as .hero__content/.hero__media —
     480px is a row-layout WIDTH value, but once .showcase__row stacks to
     a column here it's read as a reserved HEIGHT instead. The actual
     video-card (16:10 aspect ratio) renders shorter than that at this
     width, leaving ~50px of dead space below it before the section's own
     padding-bottom even starts, on top of the next section's padding —
     compounding into a much bigger gap than every other section transition */
  .tuxsa-landing-page .showcase__media {
    flex: none;
    order: 3;
    aspect-ratio: 16 / 10;
    /* .video-card's transform: translateY(10%) (base rule) shifts the video
       down visually WITHOUT growing this box's own reserved height, so the
       video's real bottom edge lands 10% of its own height below where this
       box ends — silently eating into (and here, exceeding) .showcase's
       bottom padding and leaving no visible gap before .roadmap
       ("เว้นช่องไฟด้วย"). Percentage margins resolve against the CONTAINING
       BLOCK'S WIDTH (a CSS quirk, for both axes), which — thanks to this same
       aspect-ratio — is exactly proportional to this box's own height, so
       6.25% (10% of the 16:10 ratio's height-to-width factor) reserves
       precisely the pushed-down amount at any width in this stacked layout. */
    margin-bottom: 6.25%;
  }

  /* centered grid per request — text-align above doesn't reach these
     since they're flex rows of their own (heading/stats), each needing
     its own justify-content to actually center as a block */
  .tuxsa-landing-page .showcase__heading {
    justify-content: center;
    text-align: center;
  }

  .tuxsa-landing-page .showcase__stats {
    justify-content: center;
  }

  .tuxsa-landing-page .stat {
    /* text-align doesn't reach flex children — .stat is itself a flex
       column (value stacked above label), so it needs align-items to
       actually center them instead of hugging the left edge */
    align-items: center;
    text-align: center;
  }

  .tuxsa-landing-page .navbar__links {
    display: none;
  }

  .tuxsa-landing-page .navbar__inner {
    padding: 14px 32px;
  }

  .tuxsa-landing-page .hero__inner {
    flex-direction: column;
    /* base rule's space-between spaces children along the main axis, which
       is now vertical */
    justify-content: flex-start;
    text-align: center;
  }

  .tuxsa-landing-page .hero__content {
    /* 480px flex-basis reads as a min-HEIGHT once the row becomes a column
       — reset it so the text block doesn't reserve tall empty space */
    flex: none;
    max-width: 100%;
  }

  .tuxsa-landing-page .hero__logo {
    margin: 0 auto 28px;
  }

  .tuxsa-landing-page .hero__actions {
    justify-content: center;
  }

  /* .hero__media's flex-basis (480px, a row-layout WIDTH) reads as a
     min-HEIGHT once .hero__inner stacks to a column here — reset it so
     Cover_obj.webp doesn't reserve a tall empty gap above itself. It's a
     normal in-flow block below the buttons now (not an absolutely
     positioned full-bleed layer like the bg), so the section's height
     just grows to fit it naturally — no extra bottom padding needed. */
  .tuxsa-landing-page .hero__media {
    flex: none;
    margin-top: 32px;
  }

  .tuxsa-landing-page .hero__title {
    font-size: 30px;
    white-space: normal;
  }

  .tuxsa-landing-page .hero__subtitle {
    font-size: 18px;
  }
}

/* tablet portrait only (601-1112px, portrait) — phones (≤600px) keep the
   sizes above; scale up text/logo/buttons per request */
@media (min-width: 601px) and (max-width: 1112px) and (orientation: portrait) {
  .tuxsa-landing-page .hero__logo {
    /* +30% of the base clamp(32px, 2.5vw + 16px, 48px) */
    height: clamp(42px, 3.25vw + 21px, 62px);
  }

  .tuxsa-landing-page .hero__title {
    /* +30% of this breakpoint's 30px, then +20% more per request = 47px */
    font-size: 47px;
  }

  .tuxsa-landing-page .hero__subtitle {
    /* +30% of this breakpoint's 18px, then +30% more per request = 30px */
    font-size: 30px;
  }

  .tuxsa-landing-page .hero__actions .btn {
    /* +20% of the base 20px / 16px 40px */
    font-size: 24px;
    padding: 19px 48px;
  }

  /* nudges Cover_obj up a bit closer to the buttons at this breakpoint —
     margin (not transform) so it actually closes the reserved space
     instead of just visually shifting while leaving a gap behind */
  .tuxsa-landing-page .hero__media {
    margin-top: -32px;
  }

  /* section vertical padding was wildly inconsistent at this breakpoint —
     roadmap used 78/80px while most others used 100/120px (and birthday's
     bottom and teaser's top/bottom were their own one-off numbers too),
     so the gap between one pair of sections could be 40px+ narrower or
     wider than the next. Standardize every section here to the same
     top/bottom padding so every transition reads as the same rhythm. */
  .tuxsa-landing-page .roadmap,
  .tuxsa-landing-page .why,
  .tuxsa-landing-page .courses,
  .tuxsa-landing-page .teaser,
  .tuxsa-landing-page .steps,
  .tuxsa-landing-page .learning-path,
  .tuxsa-landing-page .birthday,
  .tuxsa-landing-page .cert-check,
  .tuxsa-landing-page .faq {
    padding-top: 80px;
    padding-bottom: 80px;
  }

  /* .roadmap__panel (the white card) has its own 40px padding-top wrapping
     the title, on top of .roadmap's own 80px above — the only section
     with an inner wrapper like that, so it was landing at 120px total
     instead of everyone else's 80px. Give back exactly what the panel
     adds so the two combined still land on 80px, without touching the
     panel's own internal spacing (its title shouldn't touch the card's
     top edge). */
  .tuxsa-landing-page .roadmap {
    padding-top: 40px;
  }

  /* .showcase wasn't part of the standardized list above (its own top
     padding is separately tuned against the hero photo above it). Its
     bottom padding sits on .showcase's own WHITE background, immediately
     followed by .roadmap's 40px top padding on a PINK background — so
     unlike every other (same-colored) transition, this one visibly splits
     into two bands, and 80px white next to 40px pink read as unbalanced
     even though the combined total matched the site's rhythm. Matching it
     to roadmap's 40px instead reads as one even transition. */
  .tuxsa-landing-page .showcase {
    padding-bottom: 40px;
  }

}

/* touch has no real ":hover" — tapping a card fires the CTA's hover
   scale(1.2) (and the card's own hover glow), and it stays "stuck" on or
   toggles unpredictably since there's no mouse to move away and clear it,
   reading as a jarring flash/bounce instead of an intentional effect, and
   making that one card's button look mismatched against its row-mates.
   (hover: none) targets any touch device directly, at any width/orientation
   — a fixed width+orientation range would miss e.g. landscape tablets.
   Desktop mouse users (hover: hover) keep the animation untouched. */
@media (hover: none) {
  /* fully neutralized (not just the transform) — a tap can leave :hover
     "stuck" on until the next tap elsewhere, so even the background/color
     flip alone would read as the button randomly changing state. Tapping
     should just follow the link with no visual change at all. */
  .tuxsa-landing-page a.course-card__cta:hover {
    background: transparent;
    color: #ffffff;
    transform: none;
  }

  .tuxsa-landing-page .course-card:hover,
  .tuxsa-landing-page .course-card:focus-within {
    box-shadow: 0 10px 24px rgba(0, 0, 0, 0.06);
  }
}

@media (max-width: 600px) {
  /* navbar only actually shrinks to ~34px at this breakpoint (not the
     general 900px content breakpoint — it stays ~75px from 601-900px,
     which the base rule's 90px margin already clears) */
  .tuxsa-landing-page section[id] {
    scroll-margin-top: calc(50px + var(--host-header, 0px));
  }

  .tuxsa-landing-page .faq {
    padding: 64px 0 72px;
  }

  .tuxsa-landing-page .faq__title {
    font-size: 28px;
    margin-bottom: 32px;
  }

  .tuxsa-landing-page .faq__question {
    padding: 16px 18px;
    font-size: 18px;
  }

  .tuxsa-landing-page .faq__item.is-open .faq__answer {
    padding: 16px 18px;
  }

  .tuxsa-landing-page .cert-check {
    padding: 64px 0 72px;
  }

  .tuxsa-landing-page .cert-check__title {
    font-size: 26px;
    margin-bottom: 24px;
  }

  .tuxsa-landing-page .birthday {
    padding: 64px 0 56px;
  }

  .tuxsa-landing-page .birthday__title {
    font-size: 34px;
  }

  .tuxsa-landing-page .birthday__subtitle {
    font-size: 18px;
    margin-bottom: 32px;
  }

  /* one slide per view + peek of the next; swipe + dots for navigation */
  .tuxsa-landing-page .birthday__slide {
    flex-basis: 88%;
  }

  .tuxsa-landing-page .learning-path {
    padding: 64px 0 72px;
  }

  .tuxsa-landing-page .learning-path__title {
    font-size: 26px;
    margin-bottom: 32px;
  }

  .tuxsa-landing-page .learning-path__panel {
    padding: 24px 16px;
    border-radius: 16px;
  }

  .tuxsa-landing-page .teaser {
    padding: 64px 0;
  }

  .tuxsa-landing-page .teaser__panel {
    padding: 40px 24px;
    border-radius: 16px;
  }

  .tuxsa-landing-page .teaser__inner {
    flex-direction: column;
    gap: 40px;
  }

  .tuxsa-landing-page .teaser__title {
    font-size: 26px;
    margin-bottom: 40px;
  }

  .tuxsa-landing-page .teaser__course-name {
    font-size: 28px;
  }

  .tuxsa-landing-page .why {
    padding: 64px 0 72px;
  }

  .tuxsa-landing-page .why__title {
    font-size: 26px;
    margin-bottom: 56px;
    padding: 14px 28px;
    border-radius: 16px;
  }

  .tuxsa-landing-page .why__grid {
    grid-template-columns: 1fr;
    row-gap: 48px;
  }

  .tuxsa-landing-page .steps {
    padding: 64px 0 72px;
  }

  .tuxsa-landing-page .steps__title {
    font-size: 26px;
    margin-bottom: 40px;
  }

  .tuxsa-landing-page .steps__grid {
    grid-template-columns: 1fr;
    row-gap: 40px;
  }

  .tuxsa-landing-page .courses {
    padding: 64px 0 72px;
  }

  .tuxsa-landing-page .courses__title-main {
    font-size: 26px;
  }

  .tuxsa-landing-page .courses__title-sub {
    font-size: 21px;
  }

  .tuxsa-landing-page .courses__grid {
    grid-template-columns: 1fr;
    row-gap: 48px;
  }

  /* single column here (no leftover-card centering needed like the
     2-column tablet layout above) — undo that rule's half-width/centering
     so this card spans full width just like the other 4 */
  .tuxsa-landing-page .course-card--upcoming {
    justify-self: stretch;
    width: auto;
  }

  .tuxsa-landing-page .navbar__inner {
    padding: 12px 20px;
  }

  .tuxsa-landing-page .navbar__logo {
    height: 31px;
  }

  .tuxsa-landing-page a.navbar__cta {
    padding: 8px 16px;
    font-size: 15px;
  }

  .tuxsa-landing-page .hero {
    padding: 48px 0 24px;
  }

  .tuxsa-landing-page .container {
    padding-left: 20px;
    padding-right: 20px;
  }

  .tuxsa-landing-page .hero__logo {
    height: 32px;
    margin: 0 auto 20px;
  }

  .tuxsa-landing-page .hero__title {
    font-size: 24px;
  }

  .tuxsa-landing-page .hero__subtitle {
    font-size: 16px;
    margin-bottom: 28px;
  }

  .tuxsa-landing-page .hero__actions .btn {
    width: 100%;
    padding: 14px 24px;
  }

  .tuxsa-landing-page .hero__actions {
    flex-direction: column;
  }

  .tuxsa-landing-page .showcase {
    /* moved up further per request, was 24px */
    padding: 8px 0 66px;
  }

  .tuxsa-landing-page .showcase__heading-primary {
    font-size: 24px;
  }

  .tuxsa-landing-page .showcase__heading-secondary {
    font-size: 17px;
  }

  .tuxsa-landing-page .stat {
    padding: 4px 12px;
  }

  /* centered now, so give every stat equal padding instead of stripping
     the first one's (that stripping was for the old left-aligned row) */
  .tuxsa-landing-page .stat:first-child {
    padding-left: 12px;
  }

  .tuxsa-landing-page .stat__value {
    /* +100% per request, was 26px */
    font-size: 52px;
  }

  .tuxsa-landing-page .stat__label {
    /* +100% per request, was 11px */
    font-size: 22px;
  }

  /* mobile only ("เฉพาะมือถือ ตรงนี้ ตัดบรรทัดเป็น เรียนจบ / ครบทุกวิชา / ภายใน 1.5
     ปี*") — splits the 81% stat's label onto 3 lines at this specific break
     point instead of letting it wrap naturally (which split "ครบทุก" /
     "วิชา" mid-phrase). Hidden by default (see base rule below) so
     tablet/desktop keep flowing "เรียนจบครบทุกวิชา" as one line, unchanged. */
  .tuxsa-landing-page .stat__break--mobile-only {
    display: inline;
  }
}

/* iPhone 14 Pro Max specifically (430px CSS width in DevTools' device
   toolbar) — per request, further reduced to 16px in a same-day follow-up
   ("ลดลงอีกเหลือ 16px"; was 18px, originally "เฉพาะ iphon14 pro max ลดลงเหลือ
   18 px"), scoped narrowly so it doesn't also shrink .stat__label on other
   ≤600px phones (which stay at the 22px rule above). */
@media (min-width: 428px) and (max-width: 430px) {
  .tuxsa-landing-page .stat__label {
    font-size: 16px;
  }
}

/* tablet + mobile portrait only (scripts.js moves .teaser__visual to sit
   right before .teaser__cta inside .teaser__content in this same range) */
@media (max-width: 1112px) and (orientation: portrait) {
  /* everything centered as one grid instead of left-aligned */
  .tuxsa-landing-page .teaser__content {
    text-align: center;
  }

  /* the desktop-only rightward nudge (tuned for the two-column layout's
     own right-edge gap) doesn't apply once the image is centered and
     stacked here — reset it so the image sits dead-center like everything
     else instead of drifting right */
  .tuxsa-landing-page .teaser__visual {
    transform: none;
    margin: 0 auto;
  }

  .tuxsa-landing-page .teaser__cta {
    /* the image and button were landing right on top of each other
       (~0px gap) once JS moved the image to sit just above the button —
       establish a real gap, then +20% per request */
    margin-top: 29px;
    /* +20% per request, was 12px 32px / 17px */
    padding: 14px 38px;
    font-size: 20px;
  }
}

/* Birthday carousel: "next" arrow button + 3-dot indicator, hidden by
   default (desktop already shows/scrolls the 3 slides without needing
   either) and switched on only for tablet/mobile portrait below, matching
   the auto-advance feature (scripts.js) they support. */
.tuxsa-landing-page .birthday__next {
  display: none;
}

.tuxsa-landing-page .birthday__dots {
  display: none;
}

@media (max-width: 1112px) and (orientation: portrait) {
  .tuxsa-landing-page .birthday__next {
    display: flex;
    align-items: center;
    justify-content: center;
    position: absolute;
    top: 45%;
    right: 8px;
    transform: translateY(-50%);
    width: 44px;
    height: 44px;
    padding: 0;
    border: none;
    border-radius: 999px;
    background: var(--tuxsa-red);
    color: #ffffff;
    box-shadow: 0 8px 18px rgba(0, 0, 0, 0.18), 0 0 20px rgba(204, 51, 53, 0.5);
    cursor: pointer;
    z-index: 2;
    /* "เด้งๆ" — the same gentle attention-grabbing pulse used on the
       teaser CTA, so it's obvious the carousel can be pushed further */
    animation: birthdayNextPulse 1.8s ease-in-out infinite;
  }

  .tuxsa-landing-page .birthday__next svg {
    width: 22px;
    height: 22px;
  }

  @keyframes birthdayNextPulse {
    0%, 100% { transform: translateY(-50%) scale(1); }
    50% { transform: translateY(-50%) scale(1.12); }
  }

  @media (prefers-reduced-motion: reduce) {
    .tuxsa-landing-page .birthday__next {
      animation: none;
    }
  }

  .tuxsa-landing-page .birthday__dots {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 10px;
    margin-top: 20px;
  }

  .tuxsa-landing-page .birthday__dot {
    width: 9px;
    height: 9px;
    padding: 0;
    border: none;
    border-radius: 999px;
    background: rgba(204, 51, 53, 0.25);
    cursor: pointer;
    transition: background-color .2s ease, width .2s ease;
  }

  .tuxsa-landing-page .birthday__dot.is-active {
    width: 24px;
    background: var(--tuxsa-red);
  }

  /* was wrapping to 2 lines at the narrow card width here */
  .tuxsa-landing-page .promo-card__title {
    font-size: 22px;
    white-space: nowrap;
  }
}

/* tablet portrait only (601-1112): 2 slides are visible at once, so the
   middle dot never reads as its own distinct "page" — keep just start/end
   here like before. Mobile below re-shows it since there only 1 slide is
   visible per view, making all 3 real stops. */
@media (min-width: 601px) and (max-width: 1112px) and (orientation: portrait) {
  .tuxsa-landing-page .birthday__dot:nth-child(2) {
    display: none;
  }
}

/* mobile only: the "next" arrow was absolutely centered over the card
   (top: 45%) and landed right on top of the gift-card image on the 3rd
   coupon's "Full Package" box. Nudge it up slightly to the seam between
   that coupon's "Compre Prep" and "Full Package" boxes instead — clear of
   both the image and (checked against every other coupon row) the code/
   copy-button text on the other two slides. Stays back on its original
   absolute overlay spot, just retargeted. */
@media (max-width: 600px) {
  .tuxsa-landing-page .birthday__next {
    top: 49%;
    width: 31px;
    height: 31px;
  }

  .tuxsa-landing-page .birthday__next svg {
    width: 15px;
    height: 15px;
  }
}

/* small phones (iPhone SE and similar ≤375px-wide screens): the package
   title's white-space:nowrap (fine everywhere wider) actually overflows
   the box here — e.g. "Compre Prep Package (12 หรือ 18 วิชา)" renders at
   ~189px in a box only ~112px wide. Let it wrap instead of spilling past
   the box edge. */
@media (max-width: 375px) {
  .tuxsa-landing-page .promo-card__package-name {
    white-space: normal;
  }

  /* same overflow pattern on the birthday coupon rows: nowrap text sized
     for wider phones spills past its box here with no wrap/ellipsis to
     catch it — "โค้ดทุนการศึกษา 300 บาท" (169px) vs a 151px title, and
     "หลักสูตร Applied Data Science" (158px) vs a 125px course-name slot.
     Shrink just enough to clear the narrowest real content at this width. */
  .tuxsa-landing-page .promo-card__title {
    font-size: 19px;
  }

  .tuxsa-landing-page .coupon__course {
    font-size: 14px;
  }

  /* the actual discount code ("MBA300BD" etc.) was ellipsis-truncated down
     to a single letter here — "Code" label + pill button together already
     took ~92px of this row's ~125px, leaving no room for an 8-character
     code at the 23px size used everywhere wider. Shrink the label+code
     (row) and the button together so the full code is legible instead of
     hidden behind "…" */
  .tuxsa-landing-page .coupon__code-row {
    font-size: 11px;
  }

  .tuxsa-landing-page .coupon__copy-btn--compact {
    padding: 3px 8px;
    font-size: 10px;
  }
}

/* ===== NAVBAR HIDDEN ===== */
/* The bar is hidden outright rather than just made invisible: .navbar__inner
   is the only thing inside <header class="navbar">, so collapsing the header
   too removes the sticky strip (and its shadow) from the flow and lets the
   hero — and everything under it — move up into the space it used to hold. */
.tuxsa-landing-page .navbar__inner {
  display: none;
}

.tuxsa-landing-page .navbar {
  display: none;
}

/* the ~90px offset existed only to keep the sticky bar from covering the top
   of a jumped-to section; with no bar, only the host's own chrome (if any)
   needs clearing, plus a small breathing gap */
.tuxsa-landing-page section[id] {
  scroll-margin-top: calc(24px + var(--host-header, 0px));
}

/* the hero's 72px top padding was clearance under that sticky bar (48px in
   the narrow breakpoint) — with the bar gone it is just an empty band above
   the logo and above the cover art, so the hero starts flush at the top edge */
.tuxsa-landing-page .hero {
  padding-top: 0;
}

/* ...except on tablet/phone, where the embedding SkillLane page keeps its own
   compact header pinned over this one. Flush to the top there puts the TUXSA
   logo underneath that header, so give the hero back enough clearance — plus
   --host-header if the host declares extra pinned chrome on top of it. */
@media (max-width: 900px), (max-width: 1112px) and (orientation: portrait) {
  .tuxsa-landing-page .hero {
    padding-top: calc(72px + var(--host-header, 0px));
  }
}
