/* ==========================================================================
   Lawrence Chan — personal authority site
   Design system. No external fonts, no external assets: everything inlined
   or system-provided so the site loads fast and works offline-ish.
   ========================================================================== */

:root {
  /* Colour */
  --ink:        #12161f;
  --ink-soft:   #2a3140;
  --navy:       #0e1a2b;
  --navy-deep:  #091320;
  --brass:      #b3894a;
  --brass-lit:  #d4a862;
  --paper:      #faf8f5;
  --paper-warm: #f3efe8;
  --card:       #ffffff;
  --muted:      #5c6473;
  --muted-lite: #8a91a0;
  --line:       #e6e0d8;
  --line-dark:  rgba(255, 255, 255, 0.14);
  --field-line: #cfc8be;

  /* On-dark text. Tinted from the navy hue rather than neutral grey, so text
     on the dark ground stays warm with the rest of the system. */
  --on-dark:       #e8e5df;
  --on-dark-soft:  #d3d8e0;
  --on-dark-muted: #c3c8d1;
  --on-dark-dim:   #adb5c2;
  --on-dark-faint: #9aa4b2;
  --on-dark-meta:  #97a1b0;
  --on-dark-link:  #b6bec9;
  --on-dark-base:  #cfd5de;

  /* Interaction states, previously hard-coded at each call site. */
  --brass-deep: #9d7639;
  --navy-lift:  #16283f;

  /* Status. Muted and warm rather than default browser red/green, so an error
     still belongs to this palette. */
  --error:        #b3402f;
  --error-text:   #a03526;
  --error-bg:     #fdeeeb;
  --error-line:   #e8bdb4;
  --error-strong: #8e2f22;
  --error-ring:   rgba(179, 64, 47, .13);
  --ok-bg:        #edf6ee;
  --ok-line:      #b9d9bd;
  --ok-text:      #245c2c;

  /* Editorial note block (the "fill this in" callouts). */
  --note-line: #c9b48c;
  --note-text: #7a6234;

  --focus-ring: 0 0 0 3px rgba(179, 137, 74, .18);

  /* Translucent layers. Tokenised so a future theme change cannot miss them. */
  --paper-veil:        rgba(250, 248, 245, .88);
  --paper-veil-strong: rgba(250, 248, 245, .94);
  --surface-on-dark:   rgba(255, 255, 255, .045);
  --border-on-dark:    rgba(255, 255, 255, .28);
  /* .40 alpha, not .28 — clears WCAG 1.4.11's 3:1 floor for non-text UI
     boundaries (measured 3.61–3.79:1 against the CTA band gradient). This
     token was referenced twice in this file for a full session before it was
     ever actually defined here — the previous edit verified brace-balance,
     not the computed style, and silently shipped broken. */
  --border-on-dark-strong: rgba(255, 255, 255, .40);
  --wash-dark:         rgba(0, 0, 0, .05);
  --placeholder-text:  rgba(255, 255, 255, .6);
  --placeholder-lead:  rgba(255, 255, 255, .9);
  --brass-wash-dark:   rgba(179, 137, 74, .18);
  --rule-on-dark:      rgba(255, 255, 255, .1);

  /* Pure white used as FOREGROUND on dark grounds. Deliberately separate from
     --card, which is white used as a SURFACE. Same value, different job. */
  --on-dark-strong: #ffffff;

  /* Tinted surfaces that sit on Paper: the brass-selected choice row and the
     editorial note block. */
  --brass-wash: #fdf9f2;
  --note-bg:    #fdf8ef;

  /* Portrait placeholder weave, shown only until a real photo is supplied. */
  --placeholder-a: #16273d;
  --placeholder-b: #132234;

  /* Footer baseline text — dimmer than --on-dark-faint, its own step. */
  --on-dark-base-dim: #77808d;

  /* Type scale. Six fixed steps plus the fluid display clamps below.
     Ratio ≈1.12 between neighbours — the smallest gap the eye reliably reads
     as a deliberate difference. Anything between these steps is drift. */
  --fs-xs:   .75rem;    /* labels, eyebrows, brand role, footer baseline */
  --fs-sm:   .84rem;    /* fine print, disclosure, field hints */
  --fs-md:   .94rem;    /* buttons, nav, card body, small UI text */
  --fs-base: 1.0625rem; /* running body copy */
  --fs-lg:   1.2rem;    /* callout headings, h4 */
  --fs-xl:   1.35rem;   /* pull quotes, small section headings */

  /* Type */
  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  /* Space */
  --gutter: clamp(1.25rem, 5vw, 2.5rem);
  --section: clamp(4rem, 10vw, 7.5rem);
  --maxw: 1140px;
  --measure: 68ch;

  --radius: 4px;
  --radius-lg: 10px;
  --shadow: 0 1px 2px rgba(18, 22, 31, .04), 0 8px 24px rgba(18, 22, 31, .06);
  --shadow-lg: 0 2px 4px rgba(18, 22, 31, .05), 0 18px 50px rgba(18, 22, 31, .10);
}

/* --------------------------------------------------------------------------
   Reset / base
   -------------------------------------------------------------------------- */

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

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

/* Every in-page anchor clears the sticky header, which is 72px plus breathing
   room. Without this the target section's eyebrow and heading land underneath
   it — worst on the translated pages, whose primary CTA is an in-page jump. */
[id] { scroll-margin-top: 88px; }

/* The skip link is an accessibility affordance; animating it defeats the point
   of skipping. It jumps, everything else glides. */
.skip-link:focus { scroll-behavior: auto; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-base);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

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

h1, h2, h3, h4 {
  font-family: var(--serif);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.015em;
  color: var(--ink);
  margin: 0 0 .6em;
  text-wrap: balance;
}

h1 { font-size: clamp(2.35rem, 6vw, 4rem); letter-spacing: -0.03em; }
h2 { font-size: clamp(1.85rem, 4vw, 2.75rem); letter-spacing: -0.022em; }
h3 { font-size: clamp(1.2rem, 2.2vw, 1.45rem); }

/* Sub-heading step. Exists so secondary section headings stop being written
   as inline font-size:1.4rem, which landed within ~8% of .lede and flattened
   the hierarchy. Sits a clear step above .lede (≈1.4×) and below h2. */
.h--sm { font-size: clamp(1.5rem, 3vw, 1.85rem); }
h4 { font-size: var(--fs-lg); font-family: var(--sans); font-weight: 650; letter-spacing: -0.005em; }

p { margin: 0 0 1.15em; max-width: var(--measure); text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

a { color: inherit; }

strong { font-weight: 650; }

::selection { background: var(--brass); color: var(--on-dark-strong); }

/* Focus — visible, never removed. */
:focus-visible {
  outline: 2px solid var(--brass);
  outline-offset: 3px;
  border-radius: var(--radius);
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--navy);
  color: var(--on-dark-strong);
  padding: .75rem 1.25rem;
  z-index: 200;
}
.skip-link:focus { left: 0; }

/* --------------------------------------------------------------------------
   Layout primitives
   -------------------------------------------------------------------------- */

.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.wrap--narrow { max-width: 800px; }

.section { padding-block: var(--section); }
.section--tight { padding-block: clamp(3rem, 7vw, 5rem); }

.section--dark {
  background: var(--navy);
  color: var(--on-dark);
}
.section--dark h1,
.section--dark h2,
.section--dark h3,
.section--dark h4 { color: var(--on-dark-strong); }
.section--dark p { color: var(--on-dark-muted); }

.section--warm { background: var(--paper-warm); }

.eyebrow {
  font-family: var(--sans);
  font-size: var(--fs-xs);
  font-weight: 650;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--brass);
  margin: 0 0 1.1rem;
  display: block;
}
.section--dark .eyebrow { color: var(--brass-lit); }

.lede {
  font-size: clamp(1.1rem, 2vw, 1.3rem);
  line-height: 1.55;
  color: var(--ink-soft);
}
.section--dark .lede { color: var(--on-dark-soft); }

.rule {
  border: 0;
  border-top: 1px solid var(--line);
  margin-block: clamp(2.5rem, 6vw, 4rem);
}
.section--dark .rule { border-color: var(--line-dark); }

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .55em;
  font-family: var(--sans);
  font-size: var(--fs-md);
  font-weight: 620;
  letter-spacing: .005em;
  line-height: 1;
  padding: 1.05em 1.75em;
  border-radius: var(--radius);
  border: 1px solid transparent;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .18s ease, border-color .18s ease, color .18s ease, transform .18s ease;
  min-height: 48px;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }

.btn--primary {
  background: var(--brass);
  color: var(--on-dark-strong);
  border-color: var(--brass);
}
.btn--primary:hover { background: var(--brass-deep); border-color: var(--brass-deep); }

.btn--dark {
  background: var(--navy);
  color: var(--on-dark-strong);
  border-color: var(--navy);
}
.btn--dark:hover { background: var(--navy-lift); border-color: var(--navy-lift); }

.btn--ghost {
  background: transparent;
  color: var(--ink);
  border-color: var(--line);
}
.btn--ghost:hover { border-color: var(--ink); }

/* .cta-band is a dark navy gradient but isn't tagged .section--dark (it sets
   its own text colours directly), so the ghost button never picked up the
   light-on-dark variant — it rendered ink text on a navy border, on navy.
   Same override, extended to cover it. */
/* Border alpha raised from .28 to .40. At .28 the composited border measured
   2.48–2.51:1 against the band gradient — below the 3:1 WCAG 1.4.11 floor for
   non-text UI boundaries. The border is a ghost button's only shape cue, so
   fixing the label colour alone left the control still hard to locate.
   At .40 it measures 3.79:1 (dark end) and 3.61:1 (light end). */
.section--dark .btn--ghost,
.cta-band .btn--ghost {
  color: var(--on-dark-strong);
  border-color: var(--border-on-dark-strong);
}
.section--dark .btn--ghost:hover,
.cta-band .btn--ghost:hover { border-color: var(--on-dark-strong); }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: .85rem;
  margin-top: 2rem;
}

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

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--paper-veil);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid var(--line);
}

/* Touch devices: a blurred sticky header recomposites on every scroll frame,
   which is a measurable cost on the mid-range Android common across the
   Malaysia and Indonesia audience. Opaque ground, identical appearance. */
@media (hover: none) and (pointer: coarse) {
  .site-header {
    background: var(--paper);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  min-height: 72px;
}

.brand {
  text-decoration: none;
  display: flex;
  flex-direction: column;
  gap: .1rem;
  padding-block: .75rem;
}
.brand__name {
  font-family: var(--serif);
  font-size: var(--fs-lg);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.brand__role {
  font-size: var(--fs-xs);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
}

.nav { display: flex; align-items: center; gap: 2rem; }

.nav__list {
  display: flex;
  align-items: center;
  gap: 1.9rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

.nav__link {
  text-decoration: none;
  font-size: var(--fs-md);
  font-weight: 550;
  color: var(--ink-soft);
  padding-block: .4rem;
  border-bottom: 1.5px solid transparent;
  transition: color .16s ease, border-color .16s ease;
}
.nav__link:hover { color: var(--ink); }
.nav__link[aria-current="page"] {
  color: var(--ink);
  border-bottom-color: var(--brass);
}

.nav__cta { font-size: var(--fs-sm); padding: .8em 1.3em; min-height: 48px; }

/* --------------------------------------------------------------------------
   Language switcher
   Sits left of the primary CTA so the CTA stays the last, highest-weight
   thing the eye lands on. Menu right-aligns to the trigger so it never runs
   off the viewport edge near the header's right side.
   -------------------------------------------------------------------------- */

.lang-switch { position: relative; }

.lang-switch__trigger {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  height: 48px;
  padding: 0 .75rem;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--ink-soft);
  font-family: var(--sans);
  font-size: var(--fs-sm);
  font-weight: 620;
  letter-spacing: .01em;
  cursor: pointer;
  transition: border-color .15s ease, color .15s ease;
}
.lang-switch__trigger:hover { border-color: var(--ink); color: var(--ink); }
.lang-switch__icon { width: 17px; height: 17px; flex: none; }
.lang-switch__chevron { width: 13px; height: 13px; flex: none; transition: transform .15s ease; }
.lang-switch__trigger[aria-expanded="true"] .lang-switch__chevron { transform: rotate(180deg); }

.lang-switch__menu {
  position: absolute;
  top: calc(100% + .5rem);
  right: 0;
  z-index: 110;
  min-width: 172px;
  margin: 0;
  padding: .4rem;
  list-style: none;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}
.lang-switch__menu[hidden] { display: none; }

.lang-switch__item {
  display: block;
  padding: .65rem .75rem;
  border-radius: var(--radius);
  font-size: var(--fs-md);
  font-weight: 550;
  color: var(--ink-soft);
  text-decoration: none;
}
.lang-switch__item:hover { background: var(--paper-warm); color: var(--ink); }
.lang-switch__item.is-current { color: var(--brass); font-weight: 650; }

.nav-toggle {
  display: none;
  flex: none;
  background: none;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  width: 48px;
  height: 48px;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--ink);
}
.nav-toggle svg { width: 20px; height: 20px; }
.nav-toggle .icon-close { display: none; }
.nav-toggle[aria-expanded="true"] .icon-open { display: none; }
.nav-toggle[aria-expanded="true"] .icon-close { display: block; }

@media (max-width: 860px) {
  .nav-toggle { display: inline-flex; }
  .nav {
    position: absolute;
    inset: 100% 0 auto 0;
    display: none;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--paper);
    border-bottom: 1px solid var(--line);
    padding: 1rem var(--gutter) 1.75rem;
    box-shadow: var(--shadow);
  }
  .nav.is-open { display: flex; }
  .nav__list {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
  }
  .nav__link {
    display: block;
    padding: .95rem 0;
    border-bottom: 1px solid var(--line);
    font-size: var(--fs-lg);
  }
  .nav__link[aria-current="page"] { border-bottom-color: var(--line); color: var(--brass); }
  .nav__cta { margin-top: 1.25rem; width: 100%; }
  .site-header__inner { position: relative; }

  .lang-switch { margin-top: .75rem; }
  .lang-switch__trigger { width: 100%; justify-content: center; }
  .lang-switch__menu { left: 0; right: 0; min-width: 0; }
}

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

.hero {
  background: linear-gradient(180deg, var(--paper) 0%, var(--paper-warm) 100%);
  padding-block: clamp(3.5rem, 9vw, 6.5rem) clamp(3rem, 8vw, 5.5rem);
  border-bottom: 1px solid var(--line);
}

/* THE SPLIT: copy on the left, portrait on the right, collapsing to one column
   at 900px. Two selectors, one pattern — .hero__grid and .contact__grid were
   previously declared separately with byte-identical values apart from
   align-items, which is how they drifted into looking like two different
   systems. They are one system with two alignments; anything else that needs
   this shape should join this rule rather than redeclare it. */
.hero__grid,
.contact__grid {
  display: grid;
  grid-template-columns: 1.15fr .85fr;
  gap: clamp(2rem, 6vw, 4.5rem);
}
.hero__grid    { align-items: center; }
/* start, not center: this column is a stack of copy, actions and a tick list
   that is usually taller than the portrait beside it. */
.contact__grid { align-items: start; }

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

.hero h1 { margin-bottom: .45em; }
.hero .lede { margin-bottom: 0; }

/* --------------------------------------------------------------------------
   Contact page
   One action, stated once, at a size that matches how much it matters.
   -------------------------------------------------------------------------- */

/* The split itself is declared once, with .hero__grid, under "Hero". Only the
   contact page's own deviation lives here.

   WHY apply.html IS TWO COLUMNS AND ms/ + zh/ ARE NOT. This was logged as an
   inconsistency to resolve; it isn't one. apply.html is a standalone contact
   page with no hero, so it is the only place the portrait can appear at all.
   The translated pages are single long pages whose hero already carries the
   portrait — giving their contact section a second copy of the same face
   would be the actual inconsistency. The exception is the page type, not the
   component, and it should not be extended. */
@media (max-width: 900px) {
  /* Portrait above the copy on mobile: in a trust purchase the face is the
     argument, and it should not sit below two screens of text. */
  .contact__grid .portrait { order: -1; max-width: 300px; aspect-ratio: 1 / 1; }
}

/* The single primary action on the page earns more presence than a standard
   button. Not a new variant for its own sake — this page has exactly one. */
.btn--lg {
  font-size: var(--fs-base);
  padding: 1.25em 2em;
  min-height: 58px;
}

.contact__alt {
  margin-top: 1rem;
  font-size: var(--fs-sm);
  color: var(--muted);
}
.contact__alt a {
  color: var(--ink-soft);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--line);
}
.contact__alt a:hover { text-decoration-color: var(--brass); }

/* Portrait frame — holds a real photo, or a labelled placeholder. */
.portrait {
  position: relative;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--navy);
  box-shadow: var(--shadow-lg);
}
.portrait img { width: 100%; height: 100%; object-fit: cover; }

.portrait__placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .6rem;
  text-align: center;
  padding: 2rem;
  background:
    repeating-linear-gradient(
      45deg,
      var(--placeholder-a), var(--placeholder-a) 14px,
      var(--placeholder-b) 14px, var(--placeholder-b) 28px
    );
  color: var(--placeholder-text);
  font-size: var(--fs-sm);
  letter-spacing: .04em;
}
.portrait__placeholder strong {
  display: block;
  color: var(--placeholder-lead);
  font-size: var(--fs-md);
  letter-spacing: .02em;
}

@media (max-width: 900px) {
  .portrait { max-width: 340px; aspect-ratio: 1 / 1; }
}

/* --------------------------------------------------------------------------
   Internationalisation
   The Latin serif stack has no CJK coverage, so Chinese would silently fall
   back to a default sans and lose all typographic intent. These append real
   CJK families and adjust the settings that only matter for CJK.
   -------------------------------------------------------------------------- */

:root[lang^="zh"] {
  --serif: "Songti SC", "Noto Serif CJK SC", "Source Han Serif SC",
           "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", serif;
  --sans: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB",
          "Noto Sans CJK SC", "Microsoft YaHei", "Segoe UI", sans-serif;
}

/* CJK glyphs are dense and full-width; they need more air between lines and
   none of the negative tracking that suits Latin display type. */
:root[lang^="zh"] body { line-height: 1.85; }
:root[lang^="zh"] h1,
:root[lang^="zh"] h2,
:root[lang^="zh"] h3 { letter-spacing: 0; line-height: 1.4; }
:root[lang^="zh"] .eyebrow { letter-spacing: .08em; }
/* Italics are not a Chinese typographic convention — they synthesise badly. */
:root[lang^="zh"] em,
:root[lang^="zh"] .testimonial blockquote p { font-style: normal; }

/* Malay runs longer than English word-for-word; prevent long compounds from
   breaking narrow layouts. */
:root[lang^="ms"] h1,
:root[lang^="ms"] h2 { overflow-wrap: break-word; }

/* --------------------------------------------------------------------------
   Trust row — compact proof inside the hero, above the fold
   -------------------------------------------------------------------------- */

.trust-row {
  display: flex;
  flex-wrap: wrap;
  gap: .55rem 1.4rem;
  list-style: none;
  margin: 2rem 0 0;
  padding: 1.25rem 0 0;
  border-top: 1px solid var(--line);
}
.trust-row li {
  position: relative;
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: .01em;
  color: var(--muted);
  padding-left: 1.1rem;
}
.trust-row li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .45em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--brass);
}

/* --------------------------------------------------------------------------
   Credential strip
   -------------------------------------------------------------------------- */

.creds {
  background: var(--navy);
  color: var(--on-dark-base);
  /* Deeper than before: the strip now carries a framing line and a closing
     line, and the old 2rem floor made those read as cramped afterthoughts. */
  padding-block: clamp(2.75rem, 6vw, 4rem);
}

/* This strip is not a --section--dark, so it doesn't inherit that rule.
   Plain --brass is too dark on navy; --brass-lit is the on-dark step. */
.creds .eyebrow { color: var(--brass-lit); }

.creds__intro {
  max-width: 60ch;
  margin: 0 0 clamp(1.75rem, 4vw, 2.5rem);
  color: var(--on-dark-soft);
}

.creds__list {
  display: grid;
  /* Explicit steps rather than auto-fit. auto-fit with a 215px floor produced
     a ragged 4 → 3 → 2 → 1 sequence, and the 3-up state left one item orphaned
     on its own row — which is most of what made the strip read as a generic
     stat grid. 2x2 is a deliberate rhythm, not a leftover. */
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(1.5rem, 4vw, 3rem);
  list-style: none;
  margin: 0;
  padding: 0;
}
@media (min-width: 34em) {
  .creds__list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 62em) {
  .creds__list { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.creds__check {
  margin: clamp(1.75rem, 4vw, 2.5rem) 0 0;
  max-width: 60ch;
  font-size: var(--fs-sm);
  color: var(--on-dark-dim);
}
.creds__check a {
  color: var(--on-dark-strong);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--border-on-dark);
}
.creds__check a:hover { text-decoration-color: var(--brass-lit); }

.creds__item { border-left: 2px solid var(--brass); padding-left: 1.1rem; }
.creds__value {
  display: block;
  font-family: var(--serif);
  font-size: var(--fs-lg);
  color: var(--on-dark-strong);
  line-height: 1.3;
  margin-bottom: .25rem;
}
.creds__label {
  display: block;
  font-size: var(--fs-xs);
  letter-spacing: .05em;
  color: var(--on-dark-meta);
}

/* --------------------------------------------------------------------------
   Cards
   -------------------------------------------------------------------------- */

.grid {
  display: grid;
  gap: clamp(1.25rem, 3vw, 2rem);
}
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); }

.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(1.6rem, 3vw, 2.1rem);
  box-shadow: var(--shadow);
}
.card h3 { margin-bottom: .5rem; }
.card p { color: var(--muted); font-size: var(--fs-md); }

.section--dark .card {
  background: var(--surface-on-dark);
  border-color: var(--line-dark);
  box-shadow: none;
}
.section--dark .card p { color: var(--on-dark-dim); }

.card__num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--paper-warm);
  color: var(--brass);
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: .02em;
  margin-bottom: 1.1rem;
}
.section--dark .card__num { background: var(--brass-wash-dark); color: var(--brass-lit); }

/* Numbered step list */
.steps { counter-reset: step; list-style: none; margin: 0; padding: 0; }
.steps > li {
  counter-increment: step;
  position: relative;
  padding-left: 3.6rem;
  padding-bottom: 2.4rem;
}
.steps > li::before {
  content: counter(step, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: -0.15em;
  font-family: var(--serif);
  font-size: var(--fs-xl);
  color: var(--brass);
}
.steps > li::after {
  content: "";
  position: absolute;
  left: 1.05rem;
  top: 2.1rem;
  bottom: .35rem;
  width: 1px;
  background: var(--line);
}
.steps > li:last-child { padding-bottom: 0; }
.steps > li:last-child::after { display: none; }
.steps h3 { margin-bottom: .35rem; }
.steps p { color: var(--muted); }
.section--dark .steps > li::after { background: var(--line-dark); }
.section--dark .steps p { color: var(--on-dark-dim); }

/* Plain checklist */
.ticks { list-style: none; margin: 0; padding: 0; }
.ticks li {
  position: relative;
  padding-left: 1.85rem;
  margin-bottom: .85rem;
  color: var(--ink-soft);
}
.ticks li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .55em;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  border: 2px solid var(--brass);
}
.section--dark .ticks li { color: var(--on-dark-muted); }

/* --------------------------------------------------------------------------
   Pull quote
   -------------------------------------------------------------------------- */

.quote {
  border-left: 3px solid var(--brass);
  padding-left: clamp(1.25rem, 3vw, 2rem);
  margin: 0;
}
.quote p {
  font-family: var(--serif);
  font-size: clamp(1.3rem, 2.6vw, 1.75rem);
  line-height: 1.4;
  color: var(--ink);
  margin-bottom: .9rem;
}
.section--dark .quote p { color: var(--on-dark-strong); }
.quote footer {
  font-size: var(--fs-sm);
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
}
.section--dark .quote footer { color: var(--brass-lit); }

/* Testimonial slots */
.testimonial {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(1.6rem, 3vw, 2.1rem);
}
.testimonial blockquote { margin: 0 0 1.25rem; }
.testimonial blockquote p {
  font-size: var(--fs-base);
  color: var(--ink-soft);
  font-style: italic;
}
.testimonial__by {
  font-size: var(--fs-sm);
  font-weight: 620;
  color: var(--ink);
}
.testimonial__meta { font-size: var(--fs-sm); color: var(--muted-lite); }


/* --------------------------------------------------------------------------
   Consent note
   No form exists on the site — see main.js's header comment for why. This
   class survived the removal: it's plain informational text used on the
   contact sections (apply.html, /ms/, /zh/) to state how a message is
   handled, not a form-validation state.
   -------------------------------------------------------------------------- */

.consent-note {
  font-size: var(--fs-sm);
  line-height: 1.6;
  color: var(--muted);
  margin: 0 0 1.25rem;
  max-width: none;
}

/* --------------------------------------------------------------------------
   Video introduction
   -------------------------------------------------------------------------- */

.video-frame {
  position: relative;
  aspect-ratio: 16 / 9;
  margin-top: 2rem;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--navy);
  box-shadow: var(--shadow-lg);
}
.video-frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* --------------------------------------------------------------------------
   Photo strip (event / stage shots)
   -------------------------------------------------------------------------- */

.photo-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: clamp(1rem, 2.5vw, 1.5rem);
}
.photo-strip__item {
  margin: 0;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--paper-warm);
  box-shadow: var(--shadow);
}
.photo-strip__item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .5s ease;
}
.photo-strip__item:hover img { transform: scale(1.03); }

/* --------------------------------------------------------------------------
   Post cards (curated LinkedIn links)
   -------------------------------------------------------------------------- */

.post-card {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  transition: border-color .18s ease, transform .18s ease, box-shadow .18s ease;
}
.post-card:hover {
  border-color: var(--brass);
  transform: translateY(-2px);
  box-shadow: var(--shadow-lg);
}
.post-card__date {
  font-size: var(--fs-xs);
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--muted-lite);
  font-weight: 600;
  margin-bottom: .75rem;
}
.post-card h3 { font-size: var(--fs-lg); margin-bottom: .5rem; }
.post-card p { flex: 1; }
.post-card__cue {
  margin-top: 1.25rem;
  font-size: var(--fs-sm);
  font-weight: 620;
  color: var(--brass);
}

/* --------------------------------------------------------------------------
   Quick contact strip (apply page)
   -------------------------------------------------------------------------- */

.quick-contact {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1.25rem;
  margin-top: 2.25rem;
  padding: 1.5rem;
  background: var(--paper-warm);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}
.quick-contact p { color: var(--muted); max-width: 46ch; }

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

.site-footer {
  background: var(--navy-deep);
  color: var(--on-dark-faint);
  padding-block: clamp(3rem, 6vw, 4rem) 2rem;
  font-size: var(--fs-md);
}

.site-footer__grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  gap: clamp(2rem, 5vw, 3.5rem);
  margin-bottom: 3rem;
}
@media (max-width: 760px) {
  .site-footer__grid { grid-template-columns: 1fr; gap: 2.25rem; }
}

.site-footer h3 {
  color: var(--on-dark-strong);
  font-size: var(--fs-xs);
  letter-spacing: .12em;
  text-transform: uppercase;
  margin-bottom: 1rem;
  font-weight: 650;
}

.site-footer p { color: var(--on-dark-faint); font-size: var(--fs-md); }

.footer-list { list-style: none; margin: 0; padding: 0; }
.footer-list li { margin-bottom: .15rem; }
.footer-list a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.footer-list a {
  color: var(--on-dark-link);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color .15s ease, border-color .15s ease;
}
.footer-list a:hover { color: var(--on-dark-strong); border-bottom-color: var(--brass); }

/* Compliance disclosure, folded into the footer as quiet fine print rather
   than a standalone band with its own background and section padding. It
   still carries every required word — nothing here is a content change,
   only where it sits and how loudly it's set. The required "Independent
   LifeWave Brand Partner" phrase stays independently prominent in the
   header brand block on every page, which is what Policy 9.1/9.18 actually
   requires; this paragraph is the general disclosure, not that anchor. */
.site-footer__legal {
  border-top: 1px solid var(--rule-on-dark);
  padding-top: 1.5rem;
  margin-bottom: 1.25rem;
}
.site-footer__legal p {
  font-size: var(--fs-sm);
  line-height: 1.6;
  color: var(--on-dark-base-dim);
  /* No max-width: this sits beside the full-width footer grid above it, and
     a 78ch cap (left over from when this text had its own section) made it
     stop well short of that width instead of lining up with it. */
}
.site-footer__legal p + p { margin-top: .75rem; }
.site-footer__legal strong { color: var(--on-dark-faint); }

.site-footer__base {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 1rem;
  font-size: var(--fs-sm);
  color: var(--on-dark-base-dim);
}

.footer-brand {
  font-family: var(--serif);
  font-size: var(--fs-xl);
  color: var(--on-dark-strong);
  margin-bottom: .35rem;
}
.footer-role {
  font-size: var(--fs-xs);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--brass-lit);
  font-weight: 600;
  margin-bottom: 1.1rem;
}

/* --------------------------------------------------------------------------
   CTA band
   -------------------------------------------------------------------------- */

.cta-band {
  background: linear-gradient(135deg, var(--navy) 0%, var(--navy-lift) 100%);
  color: var(--on-dark-strong);
  padding-block: clamp(3.5rem, 8vw, 5.5rem);
  text-align: center;
}
.cta-band h2 { color: var(--on-dark-strong); }
.cta-band p {
  color: var(--on-dark-muted);
  margin-inline: auto;
  max-width: 58ch;
}
.cta-band .btn-row { justify-content: center; }

/* --------------------------------------------------------------------------
   Prose blocks (about page)
   -------------------------------------------------------------------------- */

.prose h2 { margin-top: 2.75rem; }
.prose h2:first-child { margin-top: 0; }
.prose h3 { margin-top: 2rem; }
.prose > p { color: var(--ink-soft); }
.prose ul { padding-left: 1.15rem; color: var(--ink-soft); max-width: var(--measure); }
.prose li { margin-bottom: .6rem; }

/* Reveal-on-scroll.
   Content is hidden ONLY once JS has confirmed it can reveal it again:
   the .reveal-ready class is set inside the IntersectionObserver branch,
   never at script start. If JS is off, errors, or IO is unsupported, every
   block stays visible. A marketing page must never be able to render blank. */
.reveal-ready .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .6s ease, transform .6s ease;
}
.reveal-ready .reveal.is-visible { opacity: 1; transform: none; }

@media print {
  .site-header, .cta-band, .nav-toggle, .btn { display: none !important; }
  body { background: var(--on-dark-strong); }
}


/* --------------------------------------------------------------------------
   Sticky mobile contact bar
   The desktop header keeps a visible CTA at all times; below the nav collapse
   the same affordance disappears into the hamburger. This restores it in the
   thumb zone. Absent from apply.html/thanks.html, where a single-action
   contact page is already the whole screen's focus.

   .is-suppressed (main.js): hidden for as long as the hero's own CTA row is
   also on screen. Without this the bar restated the exact same two buttons
   the reader could already see on load — the loud move, on the one screen
   meant to prove the site's restraint.
   -------------------------------------------------------------------------- */

.mobile-cta { display: none; }

@media (max-width: 860px) {
  .mobile-cta {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 90;
    display: flex;
    gap: .6rem;
    padding: .7rem var(--gutter) calc(.7rem + env(safe-area-inset-bottom));
    background: var(--paper-veil-strong);
    backdrop-filter: saturate(180%) blur(12px);
    -webkit-backdrop-filter: saturate(180%) blur(12px);
    border-top: 1px solid var(--line);
    transition: transform .2s ease;
  }
  .mobile-cta.is-suppressed { transform: translateY(100%); }
  .mobile-cta .btn { flex: 1; min-height: 50px; }
  /* Clear the bar so the footer's last line is never trapped behind it. */
  .site-footer { padding-bottom: 6rem; }
}

/* A blurred fixed bar is the same recomposite cost as the header; drop it on
   touch, matching the header rule above. */
@media (hover: none) and (pointer: coarse) {
  .mobile-cta { background: var(--paper); backdrop-filter: none; -webkit-backdrop-filter: none; }
}

@media print { .mobile-cta { display: none !important; } }


/* --------------------------------------------------------------------------
   The refusal
   Four undertakings, set as a ruled schedule rather than a bulleted list.
   The hairline above each clause is the device: it reads as a document you
   are meant to hold someone to, which is what the copy actually is.
   Deliberately unlike the credentials strip (left rules, large serif values)
   and the CTA band (centred, gradient, buttons), so the most distinctive idea
   on the page stops wearing its most generic container.
   -------------------------------------------------------------------------- */

.section--refusal h2 { font-size: clamp(2.1rem, 4.6vw, 3.1rem); }

.section--refusal .ticks li {
  padding-left: 0;
  padding-top: 1.15rem;
  margin-bottom: 1.15rem;
  border-top: 1px solid var(--border-on-dark-strong);
}
.section--refusal .ticks li:last-child { margin-bottom: 0; }

/* The round bullet is the generic marker this section is escaping. */
.section--refusal .ticks li::before { content: none; }

/* The refusal leads; the reasoning follows in the body colour. */
.section--refusal .ticks strong {
  display: block;
  margin-bottom: .3rem;
  font-family: var(--serif);
  font-size: var(--fs-lg);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--on-dark-strong);
}
