/* ============================================================
   Fintellect base - reset, typography, layout primitives.
   The whole site reads in one voice: Anuphan, one type scale,
   flat colour bands, hairline rules, almost no shadow/rounding.
   ============================================================ */

@font-face {
  font-family: 'Anuphan';
  font-style: normal;
  font-weight: 100 700;
  font-display: swap;
  src: url('../fonts/anuphan-thai-var.woff2') format('woff2');
  unicode-range: U+02D7, U+0303, U+0331, U+0E01-0E5B, U+200C-200D, U+25CC;
}
@font-face {
  font-family: 'Anuphan';
  font-style: normal;
  font-weight: 100 700;
  font-display: swap;
  src: url('../fonts/anuphan-latin-var.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

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

/* The UA's [hidden] rule loses to any author `display`, so a component that
   ships `hidden` and sets display:flex renders anyway - and to a no-JS
   visitor it renders permanently. Make the attribute authoritative once,
   here, instead of per component. */
[hidden] { display: none !important; }

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

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--body-size);
  line-height: var(--body-leading);
  font-weight: 400;
  color: var(--body-color);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

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

/* ---- Browser surfaces carry the design too ---- */
::selection { background: var(--blue-300); color: var(--navy-900); }
.band-dark ::selection { background: var(--gold); color: var(--navy-900); }
:focus-visible { outline: 2px solid var(--blue-700); outline-offset: 3px; border-radius: 1px; }
.band-dark :focus-visible { outline-color: var(--gold); }

/* ---- Headings ---- */
h1, h2, h3, h4 {
  margin: 0;
  color: var(--ink);
  text-wrap: balance;
  overflow-wrap: break-word;
}

h1, .display {
  font-size: var(--display-size);
  font-weight: var(--display-weight);
  line-height: var(--display-leading);
  letter-spacing: var(--display-tracking);
}

h2 {
  font-size: var(--h2-size);
  font-weight: var(--h2-weight);
  line-height: var(--h2-leading);
  letter-spacing: var(--h2-tracking);
}

h3 {
  font-size: var(--h3-size);
  font-weight: var(--h3-weight);
  line-height: var(--h3-leading);
  letter-spacing: var(--h3-tracking);
}

/* Thai display lines need extra headroom for tone marks */
:lang(th) h1, :lang(th) .display { line-height: 1.22; }
:lang(th) h2 { line-height: 1.3; }
:lang(th) h3 { line-height: 1.45; }

p { margin: 0 0 var(--space-4); max-width: var(--measure); }
p:last-child { margin-bottom: 0; }

.lead {
  font-size: var(--lead-size);
  line-height: 1.6;
  font-weight: 400;
}

.small { font-size: var(--small-size); }

a { color: var(--blue-700); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 0.25em; text-decoration-thickness: 1px; }

hr { border: 0; border-top: 1px solid var(--hairline); margin: var(--space-12) 0; }

strong { font-weight: 600; color: var(--ink); }

/* ---- Section label (small caps line above a block) ---- */
.section-label {
  display: block;
  font-size: var(--label-size);
  font-weight: 620;
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--blue-700);
  margin-bottom: var(--space-4);
}

/* ---- Layout primitives ---- */
.container {
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.band { padding-block: var(--section-pad); }
.band-tint { background: var(--paper-tint); }

.band-dark {
  background: var(--navy-900);
  color: var(--on-dark-body);
}
.band-dark h1, .band-dark h2, .band-dark h3, .band-dark h4 { color: var(--on-dark); }
.band-dark strong { color: var(--on-dark); }
.band-dark .section-label { color: var(--blue-400); }
.band-dark a:not(.btn) { color: var(--blue-300); }
.band-dark hr { border-color: var(--hairline-dark); }

.band-raised { background: var(--navy-800); }

/* More space above a heading than below it */
.band h2 + p, .band h2 + .lead { margin-top: var(--space-6); }

/* ---- Hero/CTA action rows (home hero, inner-page heroes) ---- */
.hero-actions {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  margin-top: var(--space-8);
  flex-wrap: wrap;
}
@media (max-width: 480px) {
  .hero-actions { flex-direction: column; align-items: flex-start; gap: var(--space-6); }
}

/* ---- Buttons ---- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  font-family: var(--font);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.01em;
  padding: 0.95em 1.7em;
  border: 1px solid transparent;
  border-radius: 2px;
  cursor: pointer;
  text-decoration: none;
  transition: background-color var(--dur) var(--ease-out),
              color var(--dur) var(--ease-out),
              border-color var(--dur) var(--ease-out),
              transform var(--dur) var(--ease-out);
}
.btn:hover { text-decoration: none; transform: translateY(-1px); }
.btn:active { transform: translateY(0); }

/* On the navy ground the CI gold carries the primary action */
.btn-gold { background: var(--gold); color: var(--navy-900); }
.btn-gold:hover { background: #FFD83F; }

/* On light grounds the CI primary blue carries it */
.btn-primary { background: var(--blue-700); color: #fff; }
.btn-primary:hover { background: var(--navy-800); }

.btn-ghost { border-color: var(--hairline-dark); color: var(--on-dark); background: transparent; }
.btn-ghost:hover { border-color: var(--blue-300); color: var(--blue-300); }

/* ---- LINE brand mark (fintellect_line_mark) ----
   The one third-party mark in the build. #06C755 is LINE's licensed brand
   green and is deliberately outside the CI palette - do not re-tint it to
   a CI blue, and do not let the No-Gray/One-Gold rules touch it. */
.line-mark { display: inline-flex; align-items: center; color: #06C755; }
.line-mark-glyph { display: block; width: 1.35em; height: 1.35em; }
.contact-line { display: flex; align-items: center; gap: 0.55em; }
/* Standing in for a .section-label, the mark carries that row's optical weight. */
.section-label .line-mark-glyph { width: 1.75rem; height: 1.75rem; }


/* ---- Stats band: animated counters (parts/stats-band.php) ---- */
.stat-number {
  font-size: var(--stat-size);
  font-weight: 650;
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.band-dark .stat-number { color: var(--gold); }
.stat-caption { margin-top: var(--space-2); color: var(--muted); font-size: var(--small-size); }
.band-dark .stat-caption { color: var(--on-dark-muted); }

/* Stats band (parts/stats-band.php) */
.stats-lede { max-width: 52ch; }
/* A grid rather than a flex row with a huge gap: the columns stay aligned
   and the longest caption is free to wrap without shoving its neighbours. */
.stats-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-8) clamp(2rem, 5vw, 4rem);
  margin-top: var(--space-12);
  padding-top: var(--space-8);
  border-top: 1px solid var(--hairline-dark);
}
@media (max-width: 900px) {
  .stats-row { grid-template-columns: repeat(2, 1fr); gap: var(--space-8); }
}

/* ---- Accessibility helpers ---- */
.screen-reader-text {
  position: absolute;
  width: 1px; height: 1px;
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}
.skip-link {
  position: absolute; left: var(--space-4); top: -100%;
  background: var(--gold); color: var(--navy-900);
  padding: var(--space-2) var(--space-4); z-index: 100;
  font-weight: 600;
}
.skip-link:focus { top: var(--space-4); }

@media (prefers-reduced-motion: reduce) {
  /* iteration-count and scroll-behavior belong in this rule: without the
     first, an `infinite` animation runs forever at 0.01ms and strobes;
     without the second, scroll-behavior only resets on html and every
     scroll container has to repeat it. */
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}

/* ---- Site chrome (header.php renders this on every page) ---- */
.site-head { position: relative; z-index: 60; border-bottom: 1px solid var(--hairline-dark); }
.site-head-row {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  padding-block: var(--space-4);
}

/* The real logo (ลุงเบ้, 2026-08-30) is a stacked lockup: mark over
   "Fintellect" over "Consulting", 200x160. It is the whole brand signature,
   so it is used whole - the header row grows to fit it rather than the
   lockup shrinking until "Consulting" stops being readable. White on every
   navy ground; logo-blue.svg is the light-ground counterpart. */
.wordmark { display: block; text-decoration: none; }
.wordmark:hover { text-decoration: none; }
.wordmark img { height: 4.5rem; width: auto; }
@media (max-width: 900px) {
  .wordmark img { height: 3.5rem; }
}

.site-nav { display: flex; gap: var(--space-6); margin-left: auto; }
/* :not(.btn) so the gold CTA inside the mobile panel keeps its navy text -
   an unscoped .site-nav a colour rule outranks .btn-gold and made the
   mobile CTA unreadable (client feedback, 2026-08-29). */
.site-nav a:not(.btn) {
  color: var(--on-dark-body);
  font-size: var(--small-size);
  font-weight: 500;
  padding-block: var(--space-2);
  border-bottom: 2px solid transparent;
  transition: color var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out);
}
.site-nav a:not(.btn):hover { color: var(--on-dark); text-decoration: none; }
.site-nav a:not(.btn)[aria-current="page"] { color: var(--on-dark); border-bottom-color: var(--blue-300); }

.btn-head { font-size: var(--small-size); padding: 0.8em 1.4em; }

/* The desktop header row must not wrap; it absorbs width through its own
   gaps instead. See DESIGN.md, "The Header Row Rule". */
@media (min-width: 901px) {
  .site-nav a, .lang-switch a, .btn-head { white-space: nowrap; }
}
@media (max-width: 1150px) {
  .site-nav { gap: var(--space-4); }
  .btn-head { padding: 0.8em 1.1em; }
}

/* Language toggle (EN | ไทย), rendered inside the primary nav */
.lang-switch { display: flex; align-items: center; gap: var(--space-2); margin-left: var(--space-2); }
.lang-switch a {
  color: var(--on-dark-body);
  font-size: var(--small-size);
  font-weight: 500;
  padding-block: var(--space-2);
  border-bottom: 2px solid transparent;
  transition: color var(--dur) var(--ease-out);
}
.lang-switch a:hover { color: var(--on-dark); text-decoration: none; }
.lang-switch a[aria-current="true"] { color: var(--on-dark); border-bottom-color: var(--blue-300); }
.lang-switch a + a { border-left: 1px solid var(--hairline-dark); padding-left: var(--space-2); }

/* Mobile nav: the toggle discloses the nav as a full-width panel */
.nav-toggle { display: none; }
.nav-cta { display: none; } /* desktop header carries .btn-head instead */

@media (max-width: 900px) {
  .site-head-row { justify-content: space-between; flex-wrap: nowrap; gap: var(--space-4); }
  .btn-head { display: none; } /* the .nav-cta link inside the panel carries the CTA on phones */
  .nav-toggle {
    display: grid;
    place-content: center;
    width: 2.75rem; height: 2.75rem;
    margin-left: auto;
    background: transparent;
    border: 1px solid var(--hairline-dark);
    border-radius: 2px;
    cursor: pointer;
  }
  .nav-toggle-bars,
  .nav-toggle-bars::before,
  .nav-toggle-bars::after {
    content: "";
    display: block;
    width: 1.125rem; height: 2px;
    background: var(--on-dark);
    transition: transform var(--dur) var(--ease-out), opacity var(--dur) var(--ease-out);
  }
  .nav-toggle-bars { position: relative; }
  .nav-toggle-bars::before { position: absolute; top: -6px; }
  .nav-toggle-bars::after { position: absolute; top: 6px; }
  .nav-toggle[aria-expanded="true"] .nav-toggle-bars { background: transparent; }
  .nav-toggle[aria-expanded="true"] .nav-toggle-bars::before { transform: translateY(6px) rotate(45deg); }
  .nav-toggle[aria-expanded="true"] .nav-toggle-bars::after { transform: translateY(-6px) rotate(-45deg); }

  /* The panel is an overlay, not an in-flow section: it hangs off the
     header and floats over the page instead of pushing it down (client
     feedback, 2026-08-29). Tonal transparency only, no shadow, per the
     no-shadow doctrine: deep navy at 82% behind a blur where the browser
     supports one, 94% opaque where it does not. */
  .site-head .site-nav {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    display: flex;
    flex-basis: auto;
    flex-direction: column;
    gap: 0;
    margin: 0;
    padding: var(--space-2) var(--gutter) var(--space-6);
    background: color-mix(in srgb, var(--navy-900) 94%, transparent);
    border-top: 1px solid var(--hairline-dark);
    border-bottom: 1px solid var(--hairline-dark);
    opacity: 0;
    visibility: hidden;
    /* Deliberately no transform: this box is backdrop-filtered, and a moving
       filtered box cannot reuse its blur - it is re-rasterised every frame.
       The panel cross-fades; the staggered items carry the motion. */
    transition: opacity 240ms var(--ease-out),
                visibility 0s linear 240ms;
  }
  @supports (backdrop-filter: blur(1px)) {
    .site-head .site-nav {
      background: color-mix(in srgb, var(--navy-900) 82%, transparent);
      backdrop-filter: blur(16px) saturate(1.15);
    }
  }
  .site-head.nav-open .site-nav {
    opacity: 1;
    visibility: visible;
    transition-delay: 0s;
  }
  /* A dim over the page beneath, so the panel reads as "on top of" and a
     tap anywhere outside closes it (handler in main.js). */
  .site-head .nav-scrim {
    position: fixed;
    inset: 0;
    background: color-mix(in srgb, var(--navy-900) 45%, transparent);
    opacity: 0;
    visibility: hidden;
    transition: opacity 260ms var(--ease-out), visibility 0s linear 260ms;
    z-index: -1;
  }
  .site-head.nav-open .nav-scrim { opacity: 1; visibility: visible; transition-delay: 0s; }

  /* The panel hangs off the header, so a scroll would carry the menu out of
     view and leave only the fixed scrim behind. Freeze the page while it is
     open (class set in main.js). Scoped to this breakpoint deliberately: at
     desktop width there is no panel, so the lock must not survive a resize. */
  html.nav-locked, html.nav-locked body { overflow: hidden; }

  /* Items arrive after the panel, 45ms apart. */
  .site-head.nav-open .site-nav > * { animation: nav-item-in 300ms var(--ease-out) both; }
  .site-head.nav-open .site-nav > *:nth-child(1) { animation-delay: 60ms; }
  .site-head.nav-open .site-nav > *:nth-child(2) { animation-delay: 105ms; }
  .site-head.nav-open .site-nav > *:nth-child(3) { animation-delay: 150ms; }
  .site-head.nav-open .site-nav > *:nth-child(4) { animation-delay: 195ms; }
  .site-head.nav-open .site-nav > *:nth-child(5) { animation-delay: 240ms; }
  .site-head.nav-open .site-nav > *:nth-child(6) { animation-delay: 285ms; }
  .site-head.nav-open .site-nav > *:nth-child(n+7) { animation-delay: 330ms; }
  @keyframes nav-item-in {
    from { opacity: 0; transform: translateY(-0.5rem); }
    to   { opacity: 1; transform: none; }
  }

  .site-head.nav-open .site-nav .nav-cta { display: inline-flex; }
  .site-head .site-nav a:not(.nav-cta) {
    padding-block: var(--space-3);
    border-bottom: none;
    font-size: 1rem;
  }
  /* Rows read as a list: a hairline between them, none under the last link. */
  .site-head .site-nav a:not(.nav-cta) + a:not(.nav-cta) { border-top: 1px solid var(--hairline-dark); }
  .site-head .site-nav .lang-switch { margin: var(--space-3) 0 0; gap: var(--space-4); }
  .site-head .site-nav .lang-switch a { padding-block: var(--space-2); }
  .site-head .site-nav .lang-switch a[aria-current="true"] { color: var(--blue-300); }
  .site-head .site-nav a:not(.btn)[aria-current="page"] { color: var(--blue-300); }
  .site-head .site-nav .nav-cta { margin-top: var(--space-4); align-self: flex-start; }
}

/* ---- Media crops: images live in fixed frames and move inside them ---- */
.media-crop { overflow: hidden; }
.media-crop img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 700ms var(--ease-out);
}
@media (hover: hover) {
  a:hover .media-crop img,
  .media-crop:hover img { transform: scale(1.04); }
}

/* ---- Arrow links (McKinsey nudge) ---- */
.arrow-link { display: inline-flex; align-items: center; gap: 0.5em; font-weight: 600; }
.arrow-link .arrow { display: inline-block; transition: transform var(--dur) var(--ease-out); }
a:hover .arrow, a.arrow-link:hover .arrow { transform: translateX(0.35em); }

/* ---- Footer ---- */
.site-foot { border-top: 1px solid var(--hairline-dark); padding-block: var(--space-12) var(--space-6); }
.foot-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-8);
  align-items: start;
}
.foot-logo { height: 5rem; width: auto; }
.foot-tagline { margin-top: var(--space-3); font-size: var(--small-size); color: var(--on-dark-muted); }
.site-foot .site-nav { display: flex; flex-direction: column; gap: var(--space-2); margin: 0; }
.foot-contact p { margin-bottom: var(--space-2); color: var(--on-dark-muted); }
.foot-contact a { color: var(--on-dark-body); }
/* Social row (fintellect_social). Outlined circles, not the reference's
   filled blue discs: a solid fill would put a second accent colour on the
   navy ground and break the one-gold rule. */
.foot-social {
  list-style: none;
  display: flex;
  gap: var(--space-3);
  margin: var(--space-6) 0 0;
  padding: 0;
}
.foot-social a {
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  border: 1px solid var(--hairline-dark);
  border-radius: 50%;
  color: var(--on-dark-body);
  transition: color var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out);
}
.foot-social a:hover { color: var(--gold); border-color: var(--gold); text-decoration: none; }
.foot-social svg { width: 1.05rem; height: 1.05rem; }

.foot-legal { margin-top: var(--space-12); padding-top: var(--space-4); border-top: 1px solid var(--hairline-dark); }
.foot-legal p { color: var(--on-dark-muted); }
.foot-disclaimer { margin-top: var(--space-4); border-top: 1px solid var(--hairline-dark); }
.foot-disclaimer summary {
  padding-block: var(--space-4);
  color: var(--on-dark-body);
  cursor: pointer;
  font-weight: 600;
}
.foot-disclaimer summary:hover { color: var(--blue-300); }
.foot-disclaimer-copy { padding-bottom: var(--space-4); max-width: var(--measure); }
.foot-disclaimer-copy p { font-size: var(--body-size); line-height: var(--body-leading); }

/* Footer nav: plain links, no current-page underline */
.site-foot .site-nav a { border-bottom: none; padding-block: 0; font-size: var(--small-size); }

@media (max-width: 900px) {
  .foot-grid { grid-template-columns: 1fr; }
}


/* ---- Financial Health Check and contact close ---- */
.health-check-band { background: var(--gold); color: var(--navy-900); }
.health-check-band .section-label { color: var(--navy-900); }
.health-check-grid {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 4fr);
  gap: clamp(2rem, 5vw, 5rem);
  align-items: center;
}
.health-check-copy h2 { max-width: 24ch; }
.health-check-copy .lead { margin-top: var(--space-6); }
.btn-health { margin-top: var(--space-6); background: var(--navy-900); color: #fff; }
.btn-health:hover { background: var(--navy-800); }
.health-check-closing { margin-top: var(--space-4); font-size: var(--small-size); color: var(--navy-800); }
.health-check-band .contact-qr figcaption { color: var(--navy-800); }

.contact-grid {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 4fr);
  gap: clamp(2rem, 5vw, 5rem);
  align-items: center;
}
.contact-actions { display: flex; gap: var(--space-4); margin-top: var(--space-8); flex-wrap: wrap; }
.contact-list { list-style: none; padding: 0; margin: var(--space-8) 0 0; }
.contact-list li { margin-top: var(--space-2); }
.contact-list a { color: var(--on-dark-body); }
.contact-list a:hover { color: var(--blue-300); }
.contact-qr { margin: 0; justify-self: end; text-align: center; }
.qr-card { background: #fff; padding: var(--space-4); display: inline-block; }
.qr-card img { width: 13rem; height: auto; }
/* The caption must never set the figure's width. .contact-qr is a grid item
   sized to fit-content, so a long caption (her CTA sentence runs ~750px at
   max-content) would stretch the figure to the whole track and drag the
   centred QR card away from the edge it hugs. Cap it to the card. */
.contact-qr figcaption {
  margin-top: var(--space-3);
  font-size: var(--small-size);
  color: var(--on-dark-muted);
  max-width: 15rem;
  margin-inline: auto;
}

@media (max-width: 900px) {
  .contact-grid, .health-check-grid { grid-template-columns: 1fr; }
  .contact-qr { justify-self: start; }
}

/* ============================================================
   Motion. One grammar, sitewide: content rises 28px and fades
   in as it enters the viewport, staggered inside a .reveal-group
   (in-viewport elements fire on load, which is the entrance).
   Counters count up. Visible by default; .js opts in.
   ============================================================ */

html.js .reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 700ms var(--ease-out), transform 700ms var(--ease-out);
  transition-delay: var(--d, 0ms);
}
html.js .reveal.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html.js .reveal { opacity: 1; transform: none; transition: none; }
  .media-crop img { transition: none; }
}

/* ============================================================
   Moving bands and the article carousel (client round 2, 2026-08-29)
   ============================================================ */

/* ---- Marquee: one mechanism, two bands ----
   The run is printed twice inside a max-content track and the track travels
   exactly -50%, so the seam IS the loop point and no JS is involved. Two
   invariants ride on that: each run's trailing padding must equal its
   internal gap (or the rhythm breaks at the seam), and the duplicate run is
   aria-hidden (or a screen reader hears the list twice).
   A band sets only what differs: --marquee-dur and --marquee-gap. */
.marquee { overflow: hidden; }
.marquee-track {
  display: flex;
  width: max-content;
  animation: marquee-drift var(--marquee-dur, 60s) linear infinite;
}
.marquee:hover .marquee-track,
.marquee:focus-within .marquee-track { animation-play-state: paused; }
.marquee-run {
  display: flex;
  align-items: center;
  gap: var(--marquee-gap);
  margin: 0;
  padding: 0 var(--marquee-gap) 0 0;
  list-style: none;
}
.marquee-item { flex: none; }
@keyframes marquee-drift {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
/* The global reduced-motion rule already stops the animation dead (it sets
   iteration-count to 1). All that is left is component-local: let the row
   be scrolled by hand, drop the edge mask, and hide the duplicate run so
   the list is not simply printed twice. */
@media (prefers-reduced-motion: reduce) {
  .marquee { overflow-x: auto; -webkit-mask-image: none; mask-image: none; }
  .marquee-run[aria-hidden="true"] { display: none; }
}

/* ---- Headline ticker (parts/headline-ticker.php) ----
   A slim newswire under the hero: a pinned label on the container's left
   axis, the titles drifting past on the right. */
.ticker-band {
  --marquee-dur: 55s;
  --marquee-gap: clamp(2rem, 4vw, 3.5rem);
  display: flex;
  align-items: stretch;
  background: var(--paper-tint);
  border-bottom: 1px solid var(--hairline);
  /* --band-inset, not --gutter: the label has to land on the same left axis
     as every heading on the page (The Left Axis Rule). */
  padding-inline: var(--band-inset) var(--gutter);
  overflow: hidden;
}
.ticker-label {
  flex: none;
  display: flex;
  align-items: center;
  margin: 0 var(--space-6) 0 0;
  padding-right: var(--space-6);
  border-right: 1px solid var(--hairline);
  white-space: nowrap;
}
.ticker-viewport { flex: 1 1 auto; min-width: 0; }
.ticker-run { padding-block: var(--space-4); }
.ticker-item {
  display: flex;
  align-items: center;
  gap: var(--marquee-gap);
}
/* A 4px square, not a bullet: nothing on a light ground here is round. */
.ticker-item::after {
  content: "";
  width: 4px; height: 4px;
  background: var(--blue-400);
}
.ticker-item a {
  color: var(--ink);
  font-size: var(--small-size);
  font-weight: 500;
  white-space: nowrap;
  text-decoration: none;
}
.ticker-item a:hover { color: var(--blue-700); text-decoration: none; }

@media (max-width: 640px) {
  .ticker-label { display: none; } /* the strip is self-evident at phone width */
}

/* ---- Reference-client logo marquee (parts/logo-marquee.php) ----
   Black and white, small, drifting slowly - the client's brief verbatim. */
.band-narrow { padding-block: clamp(2.5rem, 2rem + 2vw, 4rem); }
.logo-band .section-label { margin-bottom: clamp(2rem, 1.5rem + 1.5vw, 3rem); }
.logo-marquee {
  --marquee-dur: 90s;  /* "วิ่งช้า" - slow */
  --marquee-gap: clamp(2.5rem, 5vw, 4.5rem);
  /* the run fades out rather than clipping at a hard edge */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 5rem, #000 calc(100% - 5rem), transparent);
  mask-image: linear-gradient(90deg, transparent, #000 5rem, #000 calc(100% - 5rem), transparent);
}
.logo-item img {
  display: block;
  height: 2.5rem;
  width: auto;
  opacity: 0.6;
  transition: opacity var(--dur) var(--ease-out);
}
.logo-item img:hover { opacity: 1; }

/* ---- Article carousel (parts/post-carousel.php) ---- */
.carousel-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-8);
  margin-bottom: var(--space-12);
}
.carousel-head h2 { max-width: 22ch; }
.carousel-nav { display: flex; gap: var(--space-2); flex: none; }
.carousel-btn {
  width: 3rem; height: 3rem;
  display: grid; place-content: center;
  background: transparent;
  border: 1px solid var(--hairline);
  border-radius: 2px;
  color: var(--blue-700);
  font-size: 1.125rem;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease-out),
              border-color var(--dur) var(--ease-out),
              color var(--dur) var(--ease-out);
}
.carousel-btn:hover { background: var(--blue-700); border-color: var(--blue-700); color: var(--paper); }
.carousel-btn[disabled] { opacity: 0.35; cursor: default; }
.carousel-btn[disabled]:hover { background: transparent; border-color: var(--hairline); color: var(--blue-700); }

.carousel {
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
  /* Without this the snap ignores the track's leading padding: the first
     card is pulled flush to the viewport edge, off the container's left
     axis, and the scroller never rests at 0. */
  scroll-padding-inline-start: var(--band-inset);
}
.carousel::-webkit-scrollbar { display: none; }
.carousel-track {
  display: flex;
  gap: clamp(1.5rem, 2.5vw, 2rem);
  margin: 0;
  list-style: none;
  /* First card lands on the container's left axis; the rest bleed off the
     right edge, so the track reads as continuing past the viewport. */
  padding: 0 var(--gutter) 0 var(--band-inset);
}
.carousel-item {
  flex: 0 0 clamp(16.5rem, 28vw, 21rem);
  scroll-snap-align: start;
  display: flex;
}
.post-card {
  display: flex;
  flex-direction: column;
  width: 100%;
  background: var(--paper);
  border: 1px solid var(--hairline);
  color: inherit;
  text-decoration: none;
  transition: background-color var(--dur) var(--ease-out),
              border-color var(--dur) var(--ease-out);
}
.post-card:hover { text-decoration: none; }
.post-card-media { aspect-ratio: 3 / 2; }
.post-card-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  flex: 1 1 auto;
  padding: var(--space-6);
}
.post-card-title { transition: color var(--dur) var(--ease-out); }
.post-card-excerpt { margin: 0; color: var(--body-color); font-size: var(--small-size); }
.post-card .arrow-link {
  margin-top: auto;
  padding-top: var(--space-2);
  font-size: var(--small-size);
}

/* ---- The card flood (a signature the client asked for by name) ----
   Hovering a card floods it to deep navy and turns the arrow gold. It is
   shared by the service cards on the home page and the post cards in the
   carousel; keeping one copy is what stops the two bands drifting into two
   card personalities. */
.service-card:hover,
.post-card:hover { background: var(--navy-900); border-color: var(--navy-900); }
.service-card:hover h3,
.post-card:hover .post-card-title { color: var(--on-dark); }
.service-card:hover p,
.post-card:hover .post-card-excerpt,
.post-card:hover .post-date { color: var(--on-dark-body); }
.service-card:hover .arrow-link,
.post-card:hover .arrow-link { color: var(--gold); }

/* .post-date is a sitewide component now (the Insights list AND the home
   carousel), so it cannot live in pages.css - that sheet does not load on
   the front page. */
.post-date { color: var(--muted); }

@media (max-width: 640px) {
  .carousel-head { flex-direction: column; align-items: flex-start; }
  .carousel-item { flex-basis: min(78vw, 20rem); }
}
