/* ════════════════════════════════════════════════════════════════
   TARANG — the WEBSITE layer.
   Descends from the shipped app language (workco/src/styles/tarang.css).
   Same grammar at document scale: paper ground, ink rules carrying every
   structure, mono rubrics, square stamps, tabular figures, teal as signal only.

   LOAD ORDER: linked LAST on every page, after v9.css / chain.css /
   pricing.css / security.css, so it wins ties on equal specificity.

   The app's tg- names are reused wherever the pattern is identical, so the
   two systems read as one brand. Website-only additions are marked NEW.
   ════════════════════════════════════════════════════════════════ */

/* ── A · tokens ───────────────────────────────────────────────────
      ONE theme. Light, and only light.
      There is no "night section" and, since 2026-08-18, no dark mode
      either: Dan asked for the switch to go, so the whole `html.dark`
      token block, the toggle button and every `html.dark` override went
      with it. The page is paper from the masthead to the colophon and
      stays that way whatever the visitor's OS prefers.
      (History: 2026-08-08 this replaced alternating dark and light bands
      with one light ground plus a switch — "no more mix dark light dark
      light". The bands are still gone; only the switch has followed.)
      Every value below is the app's own (workco/src/index.css §A), so a
      visitor who opens the product recognises the room they just left.
      NOTE: the product app still HAS a dark mode. This is the marketing
      site only — do not read this comment as a change to workco/. ── */
:root{
  /* paper + ink */
  --paper:#FAF9F6;
  --paper-2:#F2F1EC;
  --hair:#E4E2DA;
  --ink:#0F1115;          /* drawn ink: rules, stamps, the primary button */
  --rule:#14181C;
  --tx:#0E1317;
  --tx-2:#29313A;
  --tx-3:#59616A;
  --tx-4:#646C74;
  --on-ink:#EDF2F0;       /* text sitting ON an ink fill, never --paper */

  /* the signal + the marks */
  --teal:#0D9488;
  --teal-deep:#115E59;
  --teal-bright:#0D9488;  /* on paper the bright variant would not hold AA */
  --teal-soft:#F0FDFA;
  --grn:#047857;
  --red:#B91C1C;
  --amb:#B45309;
  --pur:#7C3AED;
  --line-green:#06C755;

  /* shape + depth — the 28/20/14 ramp is retired */
  --r:8px;
  --r-sheet:18px;
  --shadow-sm:0 1px 2px rgba(15,17,21,.05);
  --shadow-md:0 2px 6px rgba(15,17,21,.06);
  --shadow-obj:0 22px 48px -18px rgba(15,17,21,.28);   /* device mockups ONLY */

  /* type — two families, one voice */
  --font:'Anuphan','Noto Sans TC',-apple-system,'Noto Sans Thai',sans-serif;
  --mono:'IBM Plex Mono','SF Mono','Noto Sans Thai','Noto Sans TC',monospace;
  --ease:cubic-bezier(.22,.7,.16,1);

  /* ── legacy aliases. The 21 pages still name these; they now resolve to
        Tarang values, so an untouched page repaints instead of breaking.
        --wh/--wh-2/--wh-3 meant "text on an ink section". There are no ink
        sections left, so they resolve to ordinary body text and every rule
        that used them keeps working with no edit. --ink-2/--ink-3 were the
        grounds of those sections and become paper for the same reason. ── */
  --serif:var(--font);          /* one line retires serif site-wide */
  --ink-2:var(--paper-2);
  --ink-3:var(--paper);
  --bd:var(--hair);
  --bd-ink:var(--hair);
  --wh:var(--tx);
  --wh-2:var(--tx-2);
  --wh-3:var(--tx-3);
  --onink:var(--tx);
  --onink-2:var(--tx-2);
  --onink-3:var(--tx-3);
  --r-lg:var(--r);
  --r-md:var(--r);
  --r-sm:var(--r);
  --shadow-lg:var(--shadow-md);
  --ease-io:cubic-bezier(.65,0,.35,1);
}

/* ── A2 · (removed 2026-08-18) the dark-mode token swap lived here.
      Deleted with the toggle rather than left dormant: a token block no
      selector can ever reach is a second palette that silently rots out of
      step with the one above, and the next person to touch the colours
      would have had to keep both honest for no reader. ── */

/* ── B · the kill list ─────────────────────────────────────────
      The counted hardcoded signatures that read as "the old look".
      Cinematic grammar: glass, grain, aurora, pills, lift, sheen. ── */

/* film grain + aurora: the two purely cinematic overlays */
#grain,
.aurora,
.hero__scrim,
.proof__scrim,
.product__glow,
.finale__bg,
.proof__bg{ display:none !important; }

/* buttons stop glowing: a coloured halo is glass grammar, not print */
.btn,
.btn--line,
.btn--line:hover,
.btn--teal,
.btn--teal:hover,
.rgn__opt{ box-shadow:none !important; }
.btn--ghost{ background:transparent !important; }/* every 999px pill becomes a radius-8 mark */
.btn, .lang button, .nav__pill, .pcard__tag, .pcard__rec, .hero__four span, .hero__four b, .lang a{ border-radius:var(--r) !important; }

/* glass dies: no backdrop blur anywhere */
.nav__pill,
.lang,
.bcard__browserbar,
.rgn__card,
.hero__four{ -webkit-backdrop-filter:none !important; backdrop-filter:none !important; }

/* cards stop floating: flat, hairlined, square-ish */
.bcard,
.fcard,
.icard,
.pcard,
.faq__item,
.stat{
  border-radius:0 !important;
  box-shadow:none !important;
  transform:none !important;
}
.bcard::after,
.pcard::after,
.icard::after{ display:none !important; }   /* the sheen sweep */

/* hover lift is gone — an entry darkens its hairline instead */
.bcard:hover,
.fcard:hover,
.icard:hover,
.pcard:hover{ transform:none !important; box-shadow:none !important; }

/* the reveal engine loses its blur — print does not defocus */
html.js .rv{ filter:none !important; transform:translateY(14px); }
html.js .rv.is-in{
  transform:none;
  transition:opacity .6s var(--ease),transform .6s var(--ease);
  transition-delay:calc(var(--rvd,0)*70ms);
}

/* scroll progress: an ink bar with a teal tip, no glow */
#progress i{
  background:var(--rule) !important;
  box-shadow:none !important;
  border-right:3px solid var(--teal);
}

/* ── C · the rubric — mono small-caps, the app's own metrics ── */
.tg-kicker{
  font-family:var(--mono);
  font-size:10.5px;
  line-height:1.5;                 /* >=1.5: Thai ascenders must never clip */
  letter-spacing:.14em;
  text-transform:uppercase;        /* no-op on Thai/Chinese, intended */
  font-weight:600;
  color:var(--tx-3);
  display:block;
}
.tg-kicker--teal{ color:var(--teal); }
.tg-met{
  font-family:var(--mono);
  font-size:10.5px;
  line-height:1.5;
  letter-spacing:.06em;
  color:var(--tx-4);
  font-variant-numeric:tabular-nums;
  white-space:nowrap;
}
/* A rubric line that is one short label may never wrap. A rubric line that is a
   whole sentence of credentials MUST, or it runs off the side of a phone -
   which is exactly what the trust and credit lines did at 390px. */
.tg-met--wrap,
.hero__trust,
.hero__cred{ white-space:normal; }

/* ── D · the section rule — opens every content group.
      NEW at website scale: the rule DRAWS itself as the section arrives. ── */
.tg-sec{
  position:relative;
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:16px;
  padding-top:9px;
  margin-bottom:clamp(26px,3.4vw,44px);
}
.tg-sec::before{
  content:'';
  position:absolute;
  left:0; right:0; top:0;
  height:2px;
  background:var(--rule);
  transform:scaleX(0);
  transform-origin:left center;
}
.tg-sec--page::before{ height:3px; }
html.js .tg-sec.is-in::before,
html:not(.js) .tg-sec::before{
  transform:scaleX(1);
  transition:transform .7s var(--ease);
}
/* the kicker follows the rule in, a beat behind */
html.js .tg-sec .tg-kicker,
html.js .tg-sec .tg-met{ opacity:0; }
html.js .tg-sec.is-in .tg-kicker,
html.js .tg-sec.is-in .tg-met{
  opacity:1;
  transition:opacity .45s var(--ease) .18s;
}

/* ── E · NEW text animation: the teleprinter.
      A mono rubric resolves in steps, like a line typed onto a ledger.
      Kickers and stamps only — never body copy. ── */
html.js .tg-tele{ clip-path:inset(0 100% 0 0); }
html.js .tg-tele.is-in{
  clip-path:inset(0 0 0 0);
  transition:clip-path .62s steps(14,end) .1s;
}

/* ── F · ruled row — the default container. No box. ── */
.tg-row{
  display:flex;
  align-items:center;
  gap:12px;
  padding:13px 0;
  border-bottom:1px solid var(--hair);
  min-width:0;
}
.tg-row:last-child{ border-bottom:0; }
.tg-row--edge{ box-shadow:inset 3px 0 0 var(--tg-edge,var(--teal)); padding-left:12px; }

/* ── G · stamp — a MARK OF RECORD. Square, bordered, mono. Never tappable. ── */
.tg-stamp{
  display:inline-flex;
  align-items:center;
  gap:5px;
  font-family:var(--mono);
  font-size:10px;
  font-weight:700;
  letter-spacing:.06em;
  text-transform:uppercase;
  line-height:1.35;                /* NOT 1 — Thai vowels sit above the line */
  padding:3px 7px;
  border:1.5px solid var(--ink);
  color:var(--ink);
  background:transparent;
  border-radius:0;
  white-space:nowrap;
  flex:none;
}
.tg-stamp--teal { border-color:var(--teal); color:var(--teal-deep); background:var(--teal-soft); }
.tg-stamp--grn  { border-color:var(--grn);  color:var(--grn);  background:#ECFDF5; }
.tg-stamp--red  { border-color:var(--red);  color:var(--red);  background:#FEF2F2; }
.tg-stamp--amb  { border-color:var(--amb);  color:var(--amb);  background:#FFFBEB; }
.tg-stamp--ghost{ border-color:var(--hair); color:var(--tx-3); background:transparent; }
.tg-stamp--fill { background:var(--ink); color:var(--onink); border-color:var(--ink); }
.tg-stamp--lg   { font-size:11.5px; padding:5px 10px; }
.tg-stamp svg{ width:12px; height:12px; flex:none; }

/* ── H · choice chip — TAPPABLE. Radius 8, deliberately NOT a stamp. ── */
.tg-choice{
  display:inline-flex;
  align-items:center;
  gap:6px;
  font-family:var(--mono);
  font-size:11px;
  font-weight:600;
  letter-spacing:.04em;
  line-height:1.4;
  padding:6px 11px;
  border:1.5px solid var(--hair);
  border-radius:var(--r);
  color:var(--tx-3);
  background:transparent;
  cursor:pointer;
  transition:color .2s,border-color .2s,box-shadow .2s;
}
.tg-choice:hover{ color:var(--tx); border-color:var(--tx-3); }
.tg-choice.on,
.tg-choice[aria-pressed='true'],
.tg-choice[aria-selected='true']{
  border-color:var(--ink);
  color:var(--ink);
  box-shadow:inset 0 0 0 1px var(--ink);
}

/* ── I · the figure — a number set like it matters. ── */
.tg-fig{
  font-family:var(--font);
  font-size:34px;
  font-weight:700;
  letter-spacing:-.04em;
  line-height:1.05;
  font-variant-numeric:tabular-nums;
  color:var(--ink);
}
.tg-fig--sm{ font-size:22px; }
.tg-fig--lg{ font-size:clamp(38px,4.4vw,60px); }
.tg-fig--xl{ font-size:clamp(52px,6.6vw,104px); letter-spacing:-.05em; }
.tg-fig .tg-cur{
  font-family:var(--mono);
  font-size:.36em;
  font-weight:600;
  letter-spacing:0;
  color:var(--tx-3);
  vertical-align:26%;
  margin-right:3px;
}
.tg-fig .tg-suf{
  font-family:var(--mono);
  font-size:.3em;
  font-weight:600;
  letter-spacing:.06em;
  color:var(--tx-3);
  vertical-align:26%;
  margin-left:4px;
}
.tg-fig em{ font-style:normal; color:var(--teal); }

/* ── J · time + digits — the raw material, one voice everywhere. ── */
.tg-time{
  font-family:var(--mono);
  font-size:11px;
  letter-spacing:.02em;
  color:var(--tx-3);
  font-variant-numeric:tabular-nums;
  white-space:nowrap;
}
.tg-num{ font-variant-numeric:tabular-nums; }

/* ── K · NEW · the masthead — the website's page-opener. ── */
.tg-mast{ position:relative; }
.tg-mast__rubric{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:18px;
  flex-wrap:wrap;
  padding-top:11px;
  border-top:3px solid var(--rule);
}
.tg-mast__h{
  font-family:var(--font);
  font-weight:700;
  font-size:clamp(46px,9.5vw,118px);
  line-height:.98;
  letter-spacing:-.045em;
  color:var(--tx);
  margin:clamp(26px,4vw,52px) 0 0;
}
.tg-mast__h em{ font-style:normal; color:var(--teal); }
/* masked line-rise: each line is a clipping window, the line rises out of it */
.tg-mast__h .tg-l{ display:block; overflow:hidden; }
.tg-mast__h .tg-l > span{ display:block; }
html.js .tg-mast__h .tg-l > span{ transform:translateY(108%); }
html.js .is-lit .tg-mast__h .tg-l > span{
  transform:translateY(0);
  transition:transform .95s var(--ease);
  transition-delay:calc(var(--ld,0)*110ms);
}

/* ── L · NEW · ruled column grid — the bento/plan/footer replacement.
      Cells split by hairlines. No boxes, ever. ── */
.tg-cols{
  display:grid;
  gap:0;
  border-top:1.5px solid var(--rule);
}
.tg-cols > *{
  padding:20px 22px;
  border-bottom:1px solid var(--hair);
  border-right:1px solid var(--hair);
  min-width:0;
}
.tg-cols > *:last-child{ border-right:0; }
.tg-cols--2{ grid-template-columns:repeat(2,1fr); }
.tg-cols--3{ grid-template-columns:repeat(3,1fr); }
.tg-cols--4{ grid-template-columns:repeat(4,1fr); }
.tg-cols--5{ grid-template-columns:repeat(5,1fr); }
.tg-cols__n{
  font-family:var(--mono);
  font-size:10.5px;
  font-weight:600;
  letter-spacing:.14em;
  color:var(--tx-4);
  display:block;
  margin-bottom:12px;
  font-variant-numeric:tabular-nums;
}
@media (max-width:860px){
  .tg-cols--3,.tg-cols--4,.tg-cols--5{ grid-template-columns:repeat(2,1fr); }
  .tg-cols > *{ padding:16px 15px; }
  .tg-cols--3 > *:nth-child(2n),
  .tg-cols--4 > *:nth-child(2n),
  .tg-cols--5 > *:nth-child(2n){ border-right:0; }
}
@media (max-width:520px){
  .tg-cols--2,.tg-cols--3,.tg-cols--4,.tg-cols--5{ grid-template-columns:1fr; }
  .tg-cols > *{ border-right:0 !important; }
}

/* ── M · NEW · the plate — every image is a printed figure. ── */
.tg-plate{
  position:relative;
  border:1px solid var(--hair);
  background:var(--paper-2);
  border-radius:0;
  overflow:hidden;
}
.tg-plate > img,
.tg-plate > video{ display:block; width:100%; height:auto; border-radius:0; }
.tg-plate__cap{
  display:flex;
  align-items:center;
  gap:10px;
  padding:9px 12px;
  border-top:1px solid var(--hair);
  background:var(--paper);
  font-family:var(--mono);
  font-size:10.5px;
  line-height:1.5;
  letter-spacing:.06em;
  color:var(--tx-3);
}
.tg-plate__cap .tg-stamp{ font-size:9px; padding:2px 6px; }

/* ── N · the page is paper, end to end ────────────────────────────
      The five sections that were painted dark (hero, product, proof,
      finale, heritage) plus the footer are now paper like everything
      else. They each carry ~36 references to the old "on ink" tokens,
      so rather than rewrite those rules one at a time the tokens are
      remapped for the whole document in §A. This block only has to
      undo the GROUNDS and the handful of hardcoded values.
      .tg-band--ink is deliberately kept as an inert alias: it is still
      written in the markup of pages not yet converted, and it must not
      re-introduce a dark band there. ── */
.tg-band--ink{ background:var(--paper); color:var(--tx); }

.hero,
.product,
.proof,
.finale,
.heritage,
.footer{ background:var(--paper); color:var(--tx); }
.proof,
.heritage{ background:var(--paper-2); }   /* a quieter paper, never a dark band */

/* the 13 hardcoded light-on-dark values that no token could reach */
.footer__grid > *,
.footer__bottom,
.nav__panel,
.hero__live-sep{ border-color:var(--hair); }
.hero__live-sep{ background:var(--hair); }
.nav__links a:hover,
.nav__links a.is-active{ box-shadow:inset 0 -2px 0 var(--teal); }.lang button, .lang a{ border-color:var(--hair); color:var(--tx-3); }.lang button:hover, .lang a:hover{ color:var(--tx); border-color:var(--tx-3); }.lang button.is-on, .lang a.is-on{ color:var(--ink); border-color:var(--ink); box-shadow:inset 0 0 0 1px var(--ink); }
.nav__ham i{ background:var(--tx); }
.nav__logo{ color:var(--tx); }
.nav__logo b{ color:var(--teal); }
.hero__scrollcue i{ background:var(--hair); }
.btn--ghost{ color:var(--tx) !important; border-color:var(--tx-3) !important; }
.btn--ink{ background:var(--ink); color:var(--on-ink); }
.tg-stamp--fill{ background:var(--ink); color:var(--on-ink); }

/* a hairline grid ground, drawn in CSS — the retired glass artwork's stand-in.
   It reads on paper as faint graph paper, which is the right register here. */
.tg-grid-ground{
  position:absolute; inset:0; pointer-events:none;
  background-image:
    linear-gradient(to right,var(--hair) 1px,transparent 1px),
    linear-gradient(to bottom,var(--hair) 1px,transparent 1px);
  background-size:clamp(52px,6vw,88px) clamp(52px,6vw,88px);
  opacity:.34;                      /* graph paper, not a visible grid */
  -webkit-mask-image:radial-gradient(120% 80% at 50% 42%,#000 25%,transparent 74%);
  mask-image:radial-gradient(120% 80% at 50% 42%,#000 25%,transparent 74%);
}

/* ── N2 · (removed 2026-08-18) the theme switch stood here, between the
      language picker and the join button. Its markup, its script and its
      icons went in the same pass — see §A2. ── */

/* ── O · NEW · the ghost numeral — print register behind a section. ── */
.tg-ghost-no{
  position:absolute;
  font-family:var(--mono);
  font-weight:700;
  font-size:clamp(150px,26vw,380px);
  line-height:.8;
  letter-spacing:-.04em;
  color:transparent;
  -webkit-text-stroke:1.5px var(--hair);
  pointer-events:none;
  user-select:none;
  z-index:0;
}

/* ── P · the rail — timeline spine. ── */
.tg-rail{ position:relative; padding-left:34px; }
.tg-rail::before{
  content:'';
  position:absolute;
  left:16px; top:4px; bottom:4px;
  width:2px;
  background:var(--rule);
}
.tg-rail > *{ position:relative; }
.tg-node{
  position:absolute;
  left:-22.5px;
  top:4px;
  width:11px; height:11px;
  background:var(--paper);
  border:2px solid var(--rule);
  border-radius:50%;
  box-sizing:border-box;
}
.tg-node--done{ background:var(--grn); border-color:var(--grn); }
.tg-node--live{ background:var(--teal); border-color:var(--teal); box-shadow:0 0 0 4px var(--teal-soft); }
.tg-node--hollow{ border-color:var(--hair); }

/* ── Q · the seal — the ONE ambient live signal, straight from the app. ── */
.tg-seal{
  display:inline-block;
  width:10px; height:10px;
  border-radius:2px;
  background:transparent;
  border:1.5px solid var(--tx-4);
  box-sizing:border-box;
  flex:none;
}
.tg-seal--in{
  background:#22C55E; border-color:#22C55E;
  animation:tg-seal-pulse 2s ease-in-out infinite;
}
@keyframes tg-seal-pulse{
  0%,100%{ box-shadow:0 0 0 0 rgba(34,197,94,.30); }
  50%    { box-shadow:0 0 0 5px rgba(34,197,94,0); }
}

/* ── R · buttons — flat, radius 8, one press state. ── */
.tg-btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:9px;
  font-family:var(--font);
  font-weight:600;
  font-size:15px;
  line-height:1.4;
  padding:14px 24px;
  border-radius:var(--r);
  border:1.5px solid transparent;
  background:var(--ink);
  color:var(--paper);
  cursor:pointer;
  white-space:nowrap;
  transition:transform .12s var(--ease),background .2s,border-color .2s,color .2s;
}
.tg-btn:active{ transform:translateY(1px); }
.tg-btn svg{ width:18px; height:18px; flex:none; }
.tg-btn--line{ background:var(--line-green); color:#fff; border-color:var(--line-green); }
.tg-btn--line:hover{ background:#05B64E; border-color:#05B64E; }
.tg-btn--teal{ background:var(--teal); color:#fff; border-color:var(--teal); }
.tg-btn--teal:hover{ background:var(--teal-deep); border-color:var(--teal-deep); }
.tg-btn--ghost{
  background:transparent;
  color:var(--tx);
  border-color:var(--tx-3);
}
.tg-btn--ghost:hover{ border-color:var(--ink); color:var(--ink); }
.tg-btn--lg{ padding:17px 30px; font-size:16.5px; }
.tg-btn--sm{ padding:9px 16px; font-size:13.5px; }
.tg-band--ink .tg-btn{ background:var(--dk-rule); color:var(--dk-paper); }
.tg-band--ink .tg-btn--line{ background:var(--line-green); color:#fff; }
.tg-band--ink .tg-btn--ghost{ background:transparent; color:var(--onink); border-color:rgba(237,242,240,.34); }
.tg-band--ink .tg-btn--ghost:hover{ border-color:var(--onink); }

/* ── S · display type — the site's headline voice. ── */
.tg-h{
  font-family:var(--font);
  font-weight:700;
  letter-spacing:-.04em;
  line-height:1.02;
  color:var(--tx);
  font-size:clamp(30px,4.6vw,58px);
}
.tg-h--xl{ font-size:clamp(38px,6.6vw,86px); letter-spacing:-.045em; }
.tg-h--sm{ font-size:clamp(22px,2.6vw,32px); letter-spacing:-.03em; line-height:1.12; }
.tg-h em{ font-style:normal; color:var(--teal); }

/* ── T · SCRIPT SAFETY.
      Tarang's display metrics are tight. Thai tone marks and upper vowels,
      and Chinese at negative tracking, WILL clip at Latin settings —
      and a headless screenshot at the wrong size hides it.
      These floors are not optional. ── */
body[data-lang="th"] .tg-mast__h,
body[data-lang="zh"] .tg-mast__h{ line-height:1.25; letter-spacing:-.025em; }
body[data-lang="th"] .tg-h,
body[data-lang="zh"] .tg-h{ line-height:1.28; letter-spacing:-.02em; }
body[data-lang="th"] .tg-h--sm,
body[data-lang="zh"] .tg-h--sm{ line-height:1.35; }
body[data-lang="th"] .tg-fig,
body[data-lang="zh"] .tg-fig{ line-height:1.18; }
body[data-lang="zh"] .tg-kicker,
body[data-lang="zh"] .tg-stamp{ letter-spacing:.06em; }
/* the masked line-rise needs headroom or the mask clips the tone marks */
body[data-lang="th"] .tg-mast__h .tg-l,
body[data-lang="zh"] .tg-mast__h .tg-l{ padding-bottom:.06em; }

/* ── U · reduced motion = the printed page.
      Everything already in position, rules pre-drawn, nothing waiting. ── */
@media (prefers-reduced-motion:reduce){
  html.js .rv,
  html.js .rv.is-in{ opacity:1 !important; transform:none !important; filter:none !important; transition:none !important; }
  .tg-sec::before,
  .kicker::before{ transform:scaleX(1) !important; transition:none !important; }
  html.js .tg-sec .tg-kicker,
  html.js .tg-sec .tg-met{ opacity:1 !important; transition:none !important; }
  html.js .tg-tele,
  html.js .tg-tele.is-in{ clip-path:none !important; transition:none !important; }
  html.js .tg-mast__h .tg-l > span{ transform:none !important; transition:none !important; }
  .tg-seal--in{ animation:none !important; }
  .tg-btn{ transition:none !important; }
}

/* ── V · the typewriter, site-wide ────────────────────────────────
   Dan asked for text motion "all over the website". Rather than tag every
   kicker with .tg-tele by hand across 21 pages, the section rubric carries
   the reveal itself: the label resolves in steps as its rule draws, so the
   rule and the words arrive together like a printing head crossing the page.

   Verified before shipping, because one agent reported the observer "stops
   firing after the third section": with REAL wheel events at human cadence
   every rule fires from the observer - 16/16 index, 11/11 chain, 7/7 story,
   11/11 pricing - all well inside the safety net. What that report actually
   caught was `scroll-behavior:smooth` swallowing a tight programmatic
   scrollTo loop in its own test, not a defect on the page. */
   A clip-path on .kicker also clips its ::before, which IS the section rule.
   So this reveal is SMOOTH, not stepped: at steps(15) a 2px rule 1200px wide
   appears in visible chunks instead of drawing. The stepped typewriter stays
   where it belongs - on `.tg-tele`, the masthead rubrics, which carry no rule. */
html.js .kicker{
  clip-path:inset(0 100% 0 0);
}
html.js .kicker.is-in{
  clip-path:inset(0 0 0 0);
  transition:clip-path .72s var(--ease) .06s;
}

@media (prefers-reduced-motion:reduce){
  html.js .kicker,
  html.js .kicker.is-in{ clip-path:none !important; transition:none !important; }
}

/* ── U · touch targets ────────────────────────────────────────────────
   Apple asks for 44x44. The header chrome and the footer index are drawn
   small ON PURPOSE - they are furniture, not content - so grow the HIT area
   with a pseudo-element and leave the drawing alone. Nothing moves; a thumb
   just stops missing. Growing the boxes instead would push the nav past a
   320px screen, which is why they were small in the first place.

   The heights are measured, not chosen. An expanded target that OVERLAPS its
   neighbour makes mis-taps worse, so each one stops at the midpoint of the
   real gap: nav controls have the whole page below them (44 is free), footer
   links sit 21px apart (40 is the largest that cannot overlap), and the
   sideways growth is +2px, exactly half the 4px gap between ไทย / EN / 中.
   Re-measure before raising any number here. */
@media (pointer:coarse){.lang button, .nav__logo, .nav__ham, .bill__opt, .footer__grid li a, .pcard__more a, .pcard__second a, .art__crumb a, .lang a{ position:relative; }
  /* nav + billing toggle: nothing above or below, so take the full 44.
     FIXED 2026-08-18 — the tail of this comment had lost its opening `/*` and
     was sitting INSIDE the selector list below as `so take the full 44 */`.
     One invalid selector voids the whole list, so Chrome was dropping this
     entire rule and the language picker, logo, hamburger and billing toggle
     have had NO 44px touch target on phones since it was introduced. Proved
     with a headless-Chrome cssRules count (2 rules parsed, not 3) before
     touching it, not inferred from reading. */
  .lang button::before, .nav__logo::before, .nav__ham::before, .bill__opt::before,
  .lang a::before{
    content:''; position:absolute; top:50%; left:-2px; right:-2px;
    height:44px; transform:translateY(-50%);
  }
  /* stacked links: 19px tall, 21px apart, so 40 meets the neighbour exactly */
  .footer__grid li a::before,.pcard__more a::before,.pcard__second a::before{
    content:''; position:absolute; top:50%; left:0; right:0;
    height:40px; transform:translateY(-50%);
  }
  /* the article breadcrumb is the worst target on the site: an inline link only
     14px tall, and a thumb only actually caught 6px of it. 15px of clear space
     above and 30px below, so 34 is the most it can take without overlapping. */
  .art__crumb a::before{
    content:''; position:absolute; top:50%; left:0; right:0;
    height:34px; transform:translateY(-50%);
  }
}

/* ── Thai must never inherit the mono label treatment ──────────────────────
   Two things go wrong when a Thai string lands in the small uppercase labels:

   1. IBM Plex Mono contains no Thai glyphs at all, so the browser silently
      substitutes another face. The type we designed is not the type served.
   2. The letter-spacing that flatters Latin capitals is actively harmful in
      Thai. Thai stacks vowel and tone marks above and below the consonant they
      belong to, so spacing the letters apart slides each consonant away from
      its own marks - and Thai puts no spaces between words, so extra
      letter-spacing removes the main cue a reader uses to find where one word
      ends and the next begins.

   HOW THIS IS TARGETED, and why the first attempt was wrong: I hand-listed the
   classes I thought carried Thai labels and it fixed 20 of 30 checks. Measuring
   instead of guessing found 269 real cases across ~20 different parents. Almost
   all of them are the language span itself INHERITING mono from whatever wraps
   it, so styling the span is what actually covers the site. The parent classes
   are kept below for the pages where Thai is not wrapped in a span.

   Not touched deliberately: price figures. The baht sign is U+0E3F and sits
   inside the Thai Unicode block, so a naive check counts every price as Thai
   text. The mono figures are a deliberate part of the design and stay.

   Verified by computed font on every page, in all three languages, not by eye. */
body[data-lang="th"] .th,
body[data-lang="th"] .kicker,
body[data-lang="th"] .tg-kicker,
body[data-lang="th"] .tg-met,
body[data-lang="th"] .shero__chip,
body[data-lang="th"] .hero__eyebrow,
body[data-lang="th"] .hero__live,
body[data-lang="th"] .hero__trust,
body[data-lang="th"] .hero__cred,
body[data-lang="th"] .footer__grid h4,
body[data-lang="th"] .footer__tag,
body[data-lang="th"] .footer__bottom,
body[data-lang="th"] .tg-plate__cap,
body[data-lang="th"] .fl-entry__rub,
body[data-lang="th"] .fl-entry__read,
body[data-lang="th"] .loc__n,
body[data-lang="th"] .loc__pm,
body[data-lang="th"] .prow__wk,
body[data-lang="th"] .cplan__name,
body[data-lang="th"] .cplan__where,
body[data-lang="th"] .cplan__xh,
body[data-lang="th"] .cplan__chips li,
body[data-lang="th"] .co-step__k,
body[data-lang="th"] .co-row__v,
body[data-lang="th"] .co-total__l,
body[data-lang="th"] .co-cycle__save,
body[data-lang="th"] .co-rail__soon,
body[data-lang="th"] .swap__lab,
body[data-lang="th"] .figstrap,
body[data-lang="th"] .fig-line__cap,
body[data-lang="th"] .tag,
body[data-lang="th"] .open__q,
body[data-lang="th"] .cmp__plan,
body[data-lang="th"] .pcard__tag,
body[data-lang="th"] .pcard__rec,
body[data-lang="th"] .art__crumb,
body[data-lang="th"] figcaption,
body[data-lang="th"] label,
/* the last stragglers, each found by tracing ancestry rather than by guessing
   again: stamps in comparison tables, the schedule-demo day letters, the proof
   stats, and the "per location / month" suffixes that sit inside a price but
   are words, not figures. The figures themselves stay mono on purpose. */
body[data-lang="th"] .tg-stamp,
body[data-lang="th"] .cond,
body[data-lang="th"] .stat .mono,
body[data-lang="th"] .pc__per,
body[data-lang="th"] .cplan__num i,
body[data-lang="th"] .cplan__row,
body[data-lang="th"] .cplan__xv,
body[data-lang="th"] .pcard__price .mono,
body[data-lang="th"] .cmp__rectag,
body[data-lang="th"] .cmp__pp,
body[data-lang="th"] .oa__fee,
/* these four re-declare the mono face on a bare child, so the parent rule alone
   does not reach them */
body[data-lang="th"] .oa__fee span,
body[data-lang="th"] .cplan__row span,
body[data-lang="th"] .cplan__xv b,
body[data-lang="th"] .tg-suf {
  font-family: var(--font);   /* the site body stack, defined in v9.css */
  letter-spacing: 0;
  text-transform: none;
}

/* The language switcher is a set of links now, not buttons, so that a crawler
   can follow it into the other two language trees. Links bring an underline and
   an inherited colour that a <button> never had, and both have to be turned off
   for it to look like the control it replaced. */
.lang a{ text-decoration:none; line-height:normal; }
.lang a:hover{ text-decoration:none; }
