/* ============================================================
   Zip AI shared design system — loaded LAST on every page.
   Single source of truth for: fonts (2 families), header/nav,
   vertical mobile menu, stat counters. Overrides per-page CSS.
   ============================================================ */

/* ---------- 2-font system (2026-08-13): Anuphan (display: h1-h3, buttons, th,
   stat numerals) + IBM Plex Sans Thai (everything else). Measured off
   /medical-tourism: two families, zero serif. --font-serif is the lever --
   h1/h2 below read it with !important, so --font-display alone moves nothing. --- */
:root{
  --font-display:"Anuphan",system-ui,sans-serif;
  --font-serif:"Anuphan",system-ui,sans-serif;
  --font-body:"IBM Plex Sans Thai","Sarabun",system-ui,sans-serif;
  --font-mono:"IBM Plex Sans Thai","Sarabun",system-ui,sans-serif;
}

/* ============================================================
   COLLAPSED DESIGN TOKENS — v3 (2026-08-13)
   Derived from /medical-tourism (Shane: "i really like this page the most
   of all", 13 ส.ค.) and cross-checked against the futuredesigner.io
   teardown in design/WEBSITE-REFERENCE-SPEC-2026-08-13.md.
   Where the two disagree, /medical-tourism wins — it is already in our
   palette, already Thai, already shipped, already approved.

   🔴 DECLARATION-ONLY. Every name below is NEW, so defining them here
   changes NOTHING on any page that does not reference them. A page opts
   in with `class="tok-v3"` on <body>. index.html is the pilot; the other
   28 pages are untouched until the pilot is approved.

   NOT in this set on purpose: anything that paints a .lit box. Elevation
   for .lit lives in glow3.css and only in glow3.css
   (feedback_zipai_glow_is_one_shared_file). The gold ring was RETIRED
   there on 2026-08-13 (Shane: "i like the flat clean look") and replaced
   with a hairline + this same 4-layer stack. Nothing in this file
   overrides a .lit box-shadow.
   ============================================================ */
:root{
  /* --- radius: 4 steps. MT ships 10px cards / 20px media / 999 pills.
         futuredesigner ships 4/12/16/999. MT wins on cards+media; the
         4px chip step is kept because both use a small step for labels. --- */
  --r3-chip : 6px;    /* micro-labels, ticks, inline stamps */
  --r3-card : 10px;   /* every card / panel / box  (MT .blk .pf .vs-col) */
  --r3-media: 20px;   /* photos, video frames, bands (MT .heroimg .figwide) */
  --r3-pill : 999px;  /* buttons, chips, FABs */

  /* --- shadow: ONE 4-layer stack, ink-tinted, alpha ≤ .06 per layer.
         The reference's 4-layer physics, translated for a bright ground:
         layer COUNT + tint carries the depth, never alpha (spec §6).
         Theirs peaks at α .60 — that reads as dirt on #FFFDF8. --- */
  --sh3-1: 0 1px 2px rgba(28,35,33,.045),
           0 8px 18px rgba(28,35,33,.045),
           0 26px 42px rgba(28,35,33,.035),
           0 62px 82px rgba(28,35,33,.025);
  /* raised state — same 4 layers, pushed one step, still ≤ α .06 */
  --sh3-2: 0 2px 4px rgba(28,35,33,.055),
           0 12px 26px rgba(28,35,33,.055),
           0 38px 60px rgba(28,35,33,.045),
           0 84px 104px rgba(28,35,33,.03);
  /* the ONE accent glow: LINE green CTA only. Gold stays reserved for
     the glow3 ring, per spec §6 — mint for action, gold for the ring. */
  --sh3-cta: 0 8px 26px rgba(6,199,85,.30);

  /* --- motion: one easing, two durations. Reference measured 500ms
         reveal / 150ms hover; ours ran 1150ms / 520ms. --- */
  --ease3      : cubic-bezier(.33,.9,.28,1);
  --dur3-reveal: 500ms;
  --dur3-hover : 150ms;

  /* --- rhythm: --sec-y already exists in premium.css and is already
         driving `.premium section`. This adds the missing horizontal
         half so section padding is ONE pair, not seven. --- */
  --sec-x: clamp(20px,2.4vw,32px);
}
body{font-family:var(--font-body);font-size:1.02rem;line-height:1.625;font-variant-numeric:lining-nums tabular-nums}
h1{font-family:var(--font-serif)!important;font-weight:500!important;font-variant-numeric:lining-nums tabular-nums}
h2,.h2{font-family:var(--font-serif)!important;font-weight:600!important;letter-spacing:-0.02em;font-variant-numeric:lining-nums tabular-nums}
h1{font-size:clamp(2.4rem,5.4vw,4rem);line-height:1.15;letter-spacing:-0.01em}
/* ONE h2 size, 2026-08-13. Audit found /google-maps rendering h2 at TEN
   distinct sizes from 12px to 44.8px, three of them smaller than its largest
   h3 -- visual hierarchy contradicting document structure. Value is the
   measured reference: 30px desktop / 21px mobile. Heading TAGS are unchanged;
   this is a size fix, not a structure fix.
   `.clients-wall h2` keeps its 12px eyebrow treatment on purpose -- it labels
   a logo strip, it does not open a section. */
h2,.h2{font-size:clamp(21px,2.2vw,30px);line-height:1.25}
/* h3 moved to --font-display 2026-08-13: the reference runs h3 as Anuphan 800,
   and /medical-tourism was the only page getting it (via a page-local rule).
   Both tokens are sans now, so this is a family swap, not a serif reintroduction. */
h3,h4,h5,summary,button,.logo{font-family:var(--font-display)!important;font-weight:700}


/* ---------- checkmark chip (replaces ✅ emoji) ---------- */
.tick{display:inline-flex;align-items:center;justify-content:center;width:1.15em;height:1.15em;margin-right:.35em;border-radius:50%;background:var(--mint,#147a5c);color:#fff;font-size:.78em;font-weight:800;vertical-align:-.15em}

/* ---------- header (identical on all 11 pages) ---------- */
header{position:sticky!important;top:0;z-index:100;background:rgba(250,246,238,.92);backdrop-filter:blur(12px);border-bottom:1px solid var(--line,#ddd5c4)}
header .nav{display:flex;align-items:center;justify-content:space-between;gap:10px;min-height:60px;height:auto;flex-wrap:nowrap;padding:0 20px;max-width:1320px;margin:0 auto}
.nav-burger{display:none;flex-direction:column;justify-content:center;gap:5px;width:44px;height:44px;padding:10px;background:none;border:1.5px solid var(--line,#ddd5c4);border-radius:10px;cursor:pointer}
.nav-burger span{display:block;height:2px;border-radius:2px;background:var(--ink,#1c2321);transition:transform .25s ease,opacity .25s ease}
header.nav-open .nav-burger span:nth-child(1){transform:translateY(7px) rotate(45deg)}
header.nav-open .nav-burger span:nth-child(2){opacity:0}
header.nav-open .nav-burger span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}

/* desktop nav */
@media (min-width:1201px){
  .nav-burger{display:none!important}
  .logo{flex-shrink:0}
  .nav-pages{display:flex!important;flex-wrap:wrap;flex:1;min-width:0;margin:0 10px;gap:clamp(4px,0.65vw,10px);justify-content:flex-end;position:static;flex-direction:row;overflow:visible}
  .nav-pages a{font-size:clamp(10.5px,0.9vw,12.5px);font-weight:700;white-space:nowrap;line-height:2;text-decoration:none;color:var(--ink,#1c2321);opacity:1;border:0;background:none;padding:0}
  .nav-pages a:hover{opacity:1}
  .nav-pages a.active{color:var(--sky,#0e6b5c);font-weight:800;opacity:1}
  /* .nav-more = vertical spoke links. Hidden on desktop so the visible nav stays at
     11 (HEADER-SPEC rule 2, wrap/CRO cap). Visible ≤1200px because the hamburger
     hides them behind a tap, where extra entries cost nothing. */
  .nav-pages a.nav-more{display:none!important}
}

/* mobile/tablet: hamburger + VERTICAL stacked menu (Shane's requirement — never horizontal scroll) */
/* btn-line.sm stays visible alongside burger — logo(84px)+burger(44px)+btn-line(123px)+gaps=271px < 335px at 375px */
@media (max-width:1200px){
  header{position:sticky!important}
  .nav-burger{display:flex}
  .nav-pages{display:none!important}
  header.nav-open .nav-pages{
    display:flex!important;flex-direction:column;align-items:stretch;
    position:absolute;left:0;right:0;top:100%;margin:0;padding:6px 16px 14px;gap:0;
    background:rgba(250,246,238,.98);backdrop-filter:blur(12px);
    border-bottom:1px solid var(--line,#ddd5c4);box-shadow:0 18px 40px rgba(28,35,33,.12);
    max-height:calc(100vh - 62px);overflow-y:auto;overflow-x:hidden;order:0;width:auto
  }
  header.nav-open .nav-pages a{
    display:block;width:100%;font-size:17px;font-weight:600;line-height:1.4;
    color:var(--ink,#1c2321);text-decoration:none;opacity:1;
    background:none;border:0;border-bottom:1px solid var(--line,#ddd5c4);
    border-radius:0;padding:14px 4px;white-space:normal
  }
  header.nav-open .nav-pages a:last-child{border-bottom:0}
  header.nav-open .nav-pages a.active{color:var(--sky,#0e6b5c);font-weight:800}
}

/* ---------- stat counters: real numbers live in the HTML (crawlers see them);
   JS zeroes then animates only when scripting runs ---------- */
.cu{font-variant-numeric:tabular-nums}

/* ---------- AEO extraction sentence (hero) ---------- */
.aeo{margin:10px 0 4px;padding:10px 16px;border-left:3px solid var(--sky,#0e6b5c);color:var(--muted,#5c6660);font-size:15.5px;line-height:1.7;max-width:560px}

/* mobile: CTA must land above the fold — tighten hero, move AEO quote below the button */
@media (max-width:860px){
  .hero h1{font-size:31px;line-height:1.3;margin-bottom:8px}
  .hero p.lead{font-size:15.5px!important;line-height:1.6;margin-bottom:10px}
  .aeo{display:none}
  .hero .trust{margin-top:12px}
}

/* ---------- phone CTA (co-equal with LINE, Thai pattern) ---------- */
.btn-call{display:inline-flex;flex-direction:column;align-items:center;gap:2px;margin-left:12px;padding:13px 22px;border:1.5px solid var(--line,#ddd5c4);border-radius:999px;background:var(--card,#fffdf8);color:var(--ink,#1c2321);text-decoration:none;font-weight:700;font-size:16.5px;line-height:1.2}
.btn-call small{font-weight:500;font-size:11.5px;color:var(--muted,#5c6660)}
.btn-call:hover{border-color:var(--sky,#0e6b5c)}
@media (max-width:860px){.btn-call{margin-left:0;margin-top:10px;width:100%;justify-content:center}}

/* FIX 3 — CTA glow (2026-07-26) */
.btn-line:not(.sm){box-shadow:0 8px 26px rgba(6,199,85,.30)}
.btn-line:not(.sm):hover{box-shadow:0 14px 36px rgba(6,199,85,.45)}

/* ============================================================
   HORMOZI OFFER STACK (2026-07-21) + MDCC PROOF CARD SYSTEM
   ============================================================ */

/* ---------- Price-tag hanging badges (rounded label, nose-left) ---------- */
/* <span class="ptag ptag-red ptag-big"><span class="ptag-string"></span><span class="ptag-body"><span class="ptag-hole"></span>text</span></span> */





/* red = final/discount/free prices */


/* emerald kept for non-price contexts only */


/* amber kept for legacy — do not use on new cards */


/* bigger size for CTAs */





/* label lines inside a tag */



/* ---------- Value anchor chips (per line-item) ---------- */
/* HTML: <span class="val-chip">ปกติ <s>฿3,500</s></span> — ONLY number inside <s> */
.val-chip{display:inline-flex;align-items:center;background:#eef3fc;color:#1a56db;border:1px solid #b8cdf0;border-radius:5px;font-size:11.5px;font-family:'Sarabun',system-ui,sans-serif;font-weight:600;padding:2px 8px;white-space:nowrap;flex-shrink:0}
.val-chip s{text-decoration:line-through;color:#1a56db}

/* ---------- val-badge: flat emerald free-value pill (s183 — replaces red ptag on the free-audit anchor) ---------- */
/* HTML: <span class="val-badge"><b>ฟรี</b><span class="vb-val">มูลค่า ฿2,500</span></span> */
.val-badge{display:inline-flex;align-items:baseline;gap:9px;background:#e9f6f0;color:#0D8A5A;border:2px solid rgba(13,138,90,.45);border-radius:999px;font-family:'Sarabun',system-ui,sans-serif;font-weight:800;font-size:18px;padding:6px 20px 8px;white-space:nowrap;vertical-align:middle;line-height:1.4}
.val-badge b{font-size:22px;font-weight:900;color:#0D8A5A}
.val-badge .vb-val{font-size:16px;font-weight:800;opacity:.95}
@media(max-width:520px){.val-badge{font-size:15px;padding:4px 15px 6px}.val-badge b{font-size:18px}.val-badge .vb-val{font-size:13.5px}}

/* ---------- inc-val: flex row, chip/tag right-aligned ---------- */
.inc.inc-val{flex-wrap:wrap;align-items:flex-start;gap:8px 12px}
.inc.inc-val .inc-text{flex:1 1 0;min-width:0}
.inc.inc-val>.val-chip{flex:0 0 auto;align-self:center}
/* ptag-string hidden globally — no height override needed */
@media(max-width:500px){
  .inc.inc-val .inc-text{flex:1 1 calc(100% - 36px);min-width:calc(100% - 36px)}
  .inc.inc-val>.val-chip{flex:0 0 auto;margin-left:auto;margin-top:3px}
}

/* ---------- val-chip: ensure space between label and strikethrough number ---------- */
.val-chip s{margin-left:2px}

/* ---------- Inline free pill (no string, no tilt) for inline callout text ---------- */



/* ---------- Total anchor row (blue anchor → red big price) ---------- */
/* HTML: รวมมูลค่ากว่า <s>฿11,000</s> <span class="val-arrow">→</span> ptag-red ptag-big */

.val-arrow{color:var(--muted,#5c6660);font-size:18px;font-weight:700;flex-shrink:0}
.val-strike{font-size:15px;font-weight:700;text-decoration:line-through;color:#1a56db}
/* Larger final price tag in total rows */



/* Footnote under CTA (payment terms) */
.sku-terms{font-size:12px;color:var(--muted,#5c6660);margin:8px 0 0;text-align:center;line-height:1.65;opacity:.9}

/* ---------- Capacity / scarcity note below CTA ---------- */
.cap-note{background:var(--sun-soft,#FFF9E8);border:1.5px dashed rgba(255,184,37,.6);border-radius:14px;padding:12px 18px;font-size:14.5px;margin:16px auto 0;max-width:520px;font-weight:600;text-align:center}

/* ---------- Savings badge (corner ribbon on .skubox) ---------- */
.skubox{position:relative}
.save-badge{position:absolute;top:-1.5px;right:-1.5px;background:#d92b2b;color:#fff;font-family:'Sarabun',system-ui,sans-serif;font-weight:800;font-size:12px;padding:7px 16px 7px 20px;border-radius:0 var(--radius,22px) 0 14px;line-height:1.4;text-align:center;box-shadow:-2px 2px 10px rgba(217,43,43,.35);z-index:2;white-space:nowrap}

/* ---------- Inline SVG icon normalization — sitewide bicon class ---------- */
/* Overrides any per-page <style> definition (shared.css loads last) */
.bicon{height:1em;width:1em;vertical-align:-0.125em;display:inline-block;flex-shrink:0;margin-right:.25em}

/* ---------- แพ็กคุ้ม chip for homepage service cards ---------- */
.pak-kum{display:inline-flex;align-items:center;background:#d92b2b;color:#fff;font-family:'Sarabun',system-ui,sans-serif;font-weight:700;font-size:11px;padding:2px 8px;border-radius:4px;vertical-align:middle;margin-left:6px;line-height:1.4}

/* ---------- MDCC-style proof card — sitewide stats component ---------- */
/* Outer wrapper: one ivory card */
.mdcc-card{background:var(--card,#fffdf8);border:1.5px solid var(--line,#ddd5c4);border-radius:var(--radius,22px);box-shadow:var(--shadow,0 12px 40px rgba(28,35,33,.08));padding:24px 26px;text-align:left;margin:20px auto 0;max-width:720px}
/* Header row */
.mdcc-card__header{display:flex;justify-content:space-between;align-items:baseline;flex-wrap:wrap;gap:6px;margin-bottom:14px}
.mdcc-card__title{font-family:var(--font-display,'Sarabun'),system-ui,sans-serif;font-size:17px;font-weight:700;color:var(--ink,#1c2321)}
.mdcc-card__note{font-size:11.5px;color:var(--muted,#5c6660);font-family:var(--font-mono,monospace)}
/* Tiles grid */
.mdcc-card__tiles{display:grid;gap:10px}
.mdcc-tiles-3{grid-template-columns:repeat(3,1fr)}
.mdcc-tiles-4{grid-template-columns:repeat(4,1fr)}
.mdcc-tiles-5{grid-template-columns:repeat(3,1fr)} /* 3+2, no orphan */
.mdcc-tiles-6{grid-template-columns:repeat(3,1fr)} /* 3×2 desktop */
/* Individual tiles */
.mdcc-tile{border-radius:12px;padding:14px 14px;background:var(--mint-soft,#e2ede4)}
.mdcc-tile .mdcc-num{font-family:var(--font-display,'Sarabun'),system-ui,sans-serif;font-weight:800;font-size:26px;line-height:1.15;margin-top:4px;color:var(--ink,#1c2321)}
.mdcc-tile .mdcc-lbl{font-family:var(--font-display,'Sarabun'),system-ui,sans-serif;font-size:12.5px;color:var(--muted,#5c6660);font-weight:500;line-height:1.4}
.mdcc-tile--hero{background:#0D8A5A!important}
.mdcc-tile--hero .mdcc-num{color:#fff}
.mdcc-tile--hero .mdcc-lbl{color:rgba(255,255,255,.85)}
/* Footnote */
.mdcc-card__foot{font-size:13px;color:var(--muted,#5c6660);margin-top:14px;line-height:1.65}
/* Responsive */
@media(max-width:640px){
  .mdcc-tiles-4{grid-template-columns:repeat(2,1fr)}
  .mdcc-tiles-3{grid-template-columns:repeat(3,1fr)}
}
@media(max-width:480px){
  .mdcc-tiles-6{grid-template-columns:repeat(2,1fr)}
  .mdcc-tiles-5{grid-template-columns:repeat(2,1fr)}
  .mdcc-tiles-3{grid-template-columns:repeat(2,1fr)}
  .mdcc-tile .mdcc-num{font-size:22px}
  
  
  /* Stack total row: anchor centred, tag centred below */
  
  .val-arrow{display:none}
  
}

/* ============================================================
   CLIENT WALL — compact proof strip, sits just below the hero
   ============================================================ */
.clients-wall{background:var(--bg,#fffdf8);border-top:1px solid var(--line,#ddd5c4);border-bottom:1px solid var(--line,#ddd5c4);padding:18px 0 22px}
@media(min-width:1024px){.clients-wall{padding:22px 0 26px}}
.clients-wall .shead{margin-bottom:10px;text-align:center}
@media(min-width:1024px){.clients-wall .shead{margin-bottom:12px}}
.clients-wall h2,.clients-wall .h2{font-size:12px!important;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--muted,#5D6B84)!important;font-family:"Sarabun",system-ui,sans-serif!important;margin-bottom:0}
.clients-logo-grid{
  display:grid;
  grid-template-columns:repeat(8,1fr);
  gap:12px;
  max-width:1180px;
  margin:0 auto;
  padding:0 20px
}
@media(max-width:1023px){.clients-logo-grid{grid-template-columns:repeat(4,1fr);gap:10px}}
@media(max-width:639px){.clients-logo-grid{grid-template-columns:repeat(3,1fr);gap:8px}}
/* FIX 2026-08-04 (CRO audit): source logos are square (120x120, see img
   width/height attrs) but this rule forced a 4/3 landscape box — object-fit:contain
   then letterboxed the square logo, shrinking it well below intended render size
   (measured 120x120 source rendering 68x38). Square box + min-size matches the
   actual source aspect and keeps a legible floor. Mirrors the same fix already
   applied to .marquee-track .client-logo-cell below. */
.client-logo-cell{
  display:flex;align-items:center;justify-content:center;
  aspect-ratio:1/1;
  min-width:64px;
  min-height:64px;
  background:#fff;
  border:1px solid var(--line,#ddd5c4);
  border-radius:10px;
  overflow:hidden;
  padding:10px
}
.client-logo-cell img{
  width:100%;height:100%;
  max-width:100%;max-height:100%;
  object-fit:contain;
  display:block
}

/* ============================================================
   BALANCE SYSTEM — Sky Clinic layout (2026-07-25)
   Scoped to body:not(.lp-page) so ads LPs keep their own
   narrow containers and conversion-optimised spacing.
   ============================================================ */

/* Container: 1280px on content pages */
body:not(.lp-page) .wrap{max-width:1280px}

/* Section rhythm: 56px mobile / 108px desktop */
body:not(.lp-page) section{padding:56px 0}
@media(min-width:1024px){body:not(.lp-page) section{padding:108px 0}}

/* Hero override — tighter padding so the hero resolves in ≤130vh.
   Specificity body:not(.lp-page) .hero = (0,2,1) beats section rule (0,1,2) */
/* vertical-only: shorthand padding here nuked page-level horizontal centering (line-oa) */
body:not(.lp-page) .hero{padding-top:28px;padding-bottom:16px}
@media(min-width:1024px){body:not(.lp-page) .hero{padding-top:44px;padding-bottom:36px}}

/* Section header block: consistent bottom gap */
body:not(.lp-page) .shead{margin-bottom:48px;text-align:center}
@media(min-width:1024px){body:not(.lp-page) .shead{margin-bottom:64px}}

/* Centred intro prose cap */
body:not(.lp-page) .shead .sub{max-width:58ch;margin-left:auto;margin-right:auto}
body:not(.lp-page) .sub{max-width:64ch;margin-left:auto;margin-right:auto}

/* Helper classes (opt-in per section) */
.prose-cap{max-width:62ch}
.prose-center{max-width:62ch;margin-left:auto;margin-right:auto;text-align:center}

/* 2-col asymmetric (0.85 text / 1.15 visual) */
.col-2-asym{display:grid;gap:32px;align-items:center}
@media(min-width:768px){
  .col-2-asym{grid-template-columns:0.85fr 1.15fr;gap:clamp(40px,5vw,88px)}
  .col-2-asym.flip{grid-template-columns:1.15fr 0.85fr}
}

/* Equal-height card grid: enforce uniform rows */
.grid-cards{
  display:grid;
  gap:20px;
  align-items:stretch
}
.grid-cards > *{height:100%}

/* ============================================================
   HERO VIDEO LAYER
   Aspect-ratio + border-radius overrides live in index.html
   inline <style> so they can share the breathe @keyframes.
   ============================================================ */
.hero-video{
  position:absolute;
  top:0;left:0;right:0;
  width:100%;
  object-fit:cover;
  opacity:0;
  transition:opacity 600ms ease;
  z-index:1;
  pointer-events:none
}
.hero-video.v-ready{opacity:1}
/* chat sits above video (same stacking context, later in DOM → higher stack) */
.chat{z-index:2}
@media(prefers-reduced-motion:reduce){.hero-video{display:none!important}}

/* ============================================================
   FIX A — CLIENT WALL MARQUEE  (two counter-moving rows)
   JS in motion.js restructures .clients-logo-grid into this.
   prefers-reduced-motion: leave as static grid (JS skips init).
   ============================================================ */

/* Compact strip overrides — beat body:not(.lp-page) section specificity */
.clients-wall{border-radius:0!important;box-shadow:none!important;margin-bottom:0!important;padding:18px 0 22px!important}
@media(min-width:1024px){.clients-wall{padding:22px 0 26px!important}}
.clients-wall .shead{margin-bottom:10px!important}
@media(min-width:1024px){.clients-wall .shead{margin-bottom:12px!important}}

.marquee-outer{
  overflow:hidden;
  position:relative;
  padding:4px 0;
}
/* Fade masks — left/right edges */
.marquee-outer::before,
.marquee-outer::after{
  content:'';
  position:absolute;
  top:0;bottom:0;
  width:clamp(30px,5vw,72px);
  z-index:2;
  pointer-events:none;
}
.marquee-outer::before{
  left:0;
  background:linear-gradient(to right,var(--card,#fffdf8),transparent);
}
.marquee-outer::after{
  right:0;
  background:linear-gradient(to left,var(--card,#fffdf8),transparent);
}
.marquee-track{
  display:flex;
  gap:12px;
  width:max-content;
  margin-bottom:12px;
}
.marquee-track:last-child{margin-bottom:0}
/* Row 1: slides left; Row 2: slides right */
.marquee-track--fwd{animation:logo-fwd 34s linear infinite}
.marquee-track--rev{animation:logo-rev 55s linear infinite}
@keyframes logo-fwd{
  from{transform:translateX(0)}
  to{transform:translateX(-50%)}
}
@keyframes logo-rev{
  from{transform:translateX(-50%)}
  to{transform:translateX(0)}
}
/* Pause on hover — pointer devices only. On touch, :hover sticks after a tap
   and the marquee freezes for the rest of the visit. */
@media (hover:hover) and (pointer:fine){
  .clients-wall:hover .marquee-track{animation-play-state:paused}
}
/* Consistent cell sizing inside marquee tracks.
   FIX 2026-08-04 (CRO audit): source logos are square (120x120, see
   img width/height attrs) but this rule forced a 3/2 landscape box —
   object-fit:contain then letterboxed the square logo top/bottom,
   shrinking it well below its intended render size. Square box +
   min-size matches the actual source aspect and keeps a legible floor. */
.marquee-track .client-logo-cell{
  flex:none;
  width:clamp(90px,11vw,128px);
  height:auto;
  aspect-ratio:1/1;
  min-width:64px;
  min-height:64px;
}
/* reduced-motion: no animation (JS won't init so grid stays; this is belt-and-suspenders) */
@media(prefers-reduced-motion:reduce){
  .marquee-track--fwd,.marquee-track--rev{animation:none!important}
  .marquee-outer{overflow:visible}
  .marquee-outer::before,.marquee-outer::after{display:none}
}

/* ============================================================
   GAP-1 — Prose measure for bare <p> in content containers
   The existing .sub rule only covers .sub elements.
   These target multi-line body <p> that run full container width.
   ============================================================ */
body:not(.lp-page) .answer-block>p,
body:not(.lp-page) .sc-body>p,
body:not(.lp-page) .phase-item p,
body:not(.lp-page) .reason>p,
body:not(.lp-page) .val>p,
body:not(.lp-page) .card>p,
body:not(.lp-page) section>.wrap>p,
body:not(.lp-page) .feat-item>p{max-width:65ch;margin-left:auto;margin-right:auto}
/* Named prose classes */
body:not(.lp-page) .photo-cap,
body:not(.lp-page) .case-cap,
body:not(.lp-page) .case-src,
body:not(.lp-page) .hero-promise,
body:not(.lp-page) .zp-proofcap,
body:not(.lp-page) .mdcc-card__foot{max-width:65ch;margin-left:auto;margin-right:auto}

/* ============================================================
   FIX B — MDCC proof tiles: stack to 1 col below 900px
   + prevent number+unit line-breaks (฿81/ราย must stay intact)
   ============================================================ */
@media(max-width:900px){
  .mdcc-tiles-3{grid-template-columns:1fr}
}
.mdcc-tile .mdcc-num{white-space:nowrap;line-height:1.5}
.mdcc-tile .mdcc-lbl{line-height:1.6}

/* ============================================================
   P3 — Section tonal staircase + card elevation (2026-07-25)
   Applied to body:not(.lp-page) content pages only.
   ============================================================ */

/* Tonal section helpers — opt-in per section */
.sec-tint{background:#eff4f1}
.sec-white{background:#fff}

/* Elevated card system — wide low-opacity halo (Anga reference 0 4px 50px 0 rgba(0,0,0,.07)) */
body:not(.lp-page) .svc{
  border:1.5px solid var(--line,#ddd5c4);
  box-shadow:0 8px 48px 0px rgba(28,35,33,.08)
}
body:not(.lp-page) .step{
  box-shadow:0 8px 44px 0px rgba(28,35,33,.07)
}
body:not(.lp-page) .stat{
  box-shadow:0 8px 44px 0px rgba(28,35,33,.07)
}
body:not(.lp-page) .mdcc-card{
  box-shadow:0 8px 56px 0px rgba(28,35,33,.08);
  border:2px solid var(--line,#ddd5c4)
}
body:not(.lp-page) .faq details{
  box-shadow:0 4px 32px 0px rgba(28,35,33,.07);
  border:1.5px solid var(--line,#ddd5c4)
}
body:not(.lp-page) .tcard{
  box-shadow:0 8px 44px 0px rgba(28,35,33,.07);
  border:1.5px solid var(--line,#ddd5c4)
}

/* Dark full-bleed bands ---------------------------------------- */
.sec-dark{
  background:linear-gradient(160deg,#1c2e28 0%,#0e1e1a 100%);
  color:#f0f5f2;
  position:relative
}
.sec-dark h2,.sec-dark .h2,.sec-dark h3{color:#f0f5f2}
.sec-dark .sub{color:rgba(240,245,242,.78)}
.sec-dark .case-cap,.sec-dark .case-src{color:rgba(240,245,242,.6)}
.sec-dark .case-cap a,.sec-dark .case-src a{color:#7fcca0}

.sec-dark .win{color:#7fcca0}
.sec-dark .warn{color:#f0947a}

/* Stats tiles on dark bg */
.sec-dark .mdcc-tile{
  background:rgba(255,255,255,.08);
  border:1.5px solid rgba(255,255,255,.15)
}
.sec-dark .mdcc-tile--hero{background:#0D8A5A!important;border-color:rgba(13,138,90,.6)!important}
.sec-dark .mdcc-tile .mdcc-num{color:#f0f5f2}
.sec-dark .mdcc-tile .mdcc-lbl{color:rgba(240,245,242,.72)}
.sec-dark .mdcc-tile--hero .mdcc-num,.sec-dark .mdcc-tile--hero .mdcc-lbl{color:#fff}

.sec-dark .mdcc-card{
  background:rgba(255,255,255,.05);
  border:1.5px solid rgba(255,255,255,.12);
  box-shadow:none
}
.sec-dark .mdcc-card__title{color:#f0f5f2}
.sec-dark .mdcc-card__note{color:rgba(240,245,242,.6)}

.sec-dark .proof-card{
  background:rgba(255,255,255,.07);
  border:1.5px solid rgba(255,255,255,.14)
}
.sec-dark .proof-card blockquote{color:#f0f5f2}
.sec-dark .proof-card p{color:rgba(240,245,242,.78)}
.sec-dark .stamp{background:rgba(13,138,90,.25);border-color:rgba(13,138,90,.5);color:#7fcca0}

/* Closing dark CTA band — darker + green radial glow */
.sec-dark-final{
  background:#0c1f1a;
  position:relative;
  overflow:hidden
}
.sec-dark-final::before{
  content:'';
  position:absolute;
  inset:0;
  background:radial-gradient(ellipse 80% 80% at 50% 50%,rgba(20,122,92,.22),transparent);
  pointer-events:none
}
.sec-dark-final .wrap{position:relative;z-index:1}
.sec-dark-final .h2,.sec-dark-final h2{color:#f0f5f2}
.sec-dark-final .sub{color:rgba(240,245,242,.78)}
.sec-dark-final .final-band{
  background:transparent;
  border:1.5px solid rgba(255,255,255,.1);
  border-radius:24px
}
.sec-dark-final .cap-note{background:rgba(255,255,255,.08);border-color:rgba(255,255,255,.18);color:rgba(240,245,242,.85)}


/* ── Founder portraits ──────────────────────────────────────────────
   Applies to EVERY page including the ads landing pages: the tint/rhythm
   system is scoped to body:not(.lp-page), and portraits were inheriting
   their raw 700x938 attributes there, rendering as ~1:4 slivers.
   shared.css loads last, so this is the authoritative rule.            */
.tcard img, .team img{
  width:100%;
  aspect-ratio:4/5;
  height:auto;
  object-fit:cover;
  object-position:center 20%;
  display:block;
}
.team{align-items:start}

/* ============================================================
   MEGA-MENU NAV (2026-07-28)
   3 grouped dropdowns: บริการ / สำหรับธุรกิจ / เรียนรู้
   NO body:not(.lp-page) scoping — applies equally to all pages.
   Desktop: hover + focus-within opens panel.
   Mobile: JS .open class toggles accordion under hamburger.
   ============================================================ */

/* nav-home: direct หน้าแรก link (shares nav-pages a style on desktop) */
.nav-home{text-decoration:none;color:var(--ink,#1c2321);font-weight:700;white-space:nowrap}
.nav-home.active{color:var(--sky,#0e6b5c)}

/* nav-group wrapper */
.nav-group{position:relative}

/* nav-label: dropdown trigger button */
.nav-label{
  display:inline-flex;align-items:center;gap:4px;
  background:none;border:0;cursor:pointer;
  font-family:var(--font-body,"IBM Plex Sans Thai"),sans-serif;
  font-weight:700;color:var(--ink,#1c2321);
  padding:4px 0;white-space:nowrap;
  line-height:2;font-size:clamp(10.5px,0.9vw,12.5px)
}
.nav-label:hover{color:var(--sky,#0e6b5c)}
.nav-group.has-active .nav-label{color:var(--sky,#0e6b5c);font-weight:800}

/* chevron */
.nav-chev{transition:transform .2s ease;flex-shrink:0}
.nav-group:hover .nav-chev,
.nav-group:focus-within .nav-chev,
.nav-group.open .nav-chev{transform:rotate(180deg)}

/* panel — hidden by default */
.nav-panel{
  display:none;
  position:absolute;top:100%;margin-top:8px;left:50%;transform:translateX(-50%);
  background:var(--bg,#fffdf8);
  border:1.5px solid var(--line,#ddd5c4);
  border-radius:16px;
  box-shadow:0 20px 60px rgba(28,35,33,.14);
  padding:18px 20px;
  min-width:min(460px,90vw);
  z-index:500;
  grid-template-columns:1fr 1fr;
  column-gap:18px
}

/* Desktop: show on hover, focus-within, or JS .open */
@media(min-width:1201px){
  .nav-group:hover .nav-panel,
  .nav-group:focus-within .nav-panel,
  .nav-group.open .nav-panel{display:grid}
}
/* invisible bridge across the 8px gap so mouse path never kills the panel */
.nav-panel::before{
  content:'';position:absolute;top:-10px;left:0;right:0;height:12px;background:transparent
}
/* group extends into the gap so :hover never drops */
@media(min-width:1201px){ .nav-group{padding-bottom:8px} }

/* column header inside panel */
.nav-col-hd{
  display:block;
  font-size:10px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;
  color:var(--muted,#5c6660);
  padding-bottom:6px;margin-bottom:6px;
  border-bottom:1px solid var(--line,#ddd5c4)
}

/* panel links — override existing .nav-pages a rule (same specificity, later in file = wins) */
.nav-panel a{
  display:flex!important;align-items:flex-start;gap:9px;
  padding:8px 7px!important;border-radius:9px;
  text-decoration:none;
  color:var(--ink,#1c2321)!important;
  font-size:13.5px!important;
  font-weight:400!important;
  white-space:normal!important;
  line-height:1.35!important;
  opacity:1!important;
  border:0!important;
  background:none!important;
  transition:background .14s;
  margin-bottom:2px
}
.nav-panel a:hover{background:rgba(14,107,92,.06)!important}
.nav-panel a.active,
.nav-panel a:focus-visible{background:rgba(14,107,92,.09)!important;color:var(--sky,#0e6b5c)!important;outline:none}
.nav-panel a:focus-visible{outline:2px solid var(--sky,#0e6b5c);outline-offset:2px}
.nav-panel a b{display:block;font-size:13px;font-weight:700;line-height:1.3;color:inherit}
.nav-panel a small{display:block;font-size:11px;color:var(--muted,#5c6660);line-height:1.4;margin-top:1px}
.nav-ico{flex-shrink:0;margin-top:2px}

/* ---- Mobile (≤1200px): accordion inside open hamburger ---- */
@media(max-width:1200px){
  .nav-group{
    display:flex;flex-direction:column;align-items:stretch;
    width:100%
  }
  .nav-label{
    display:flex!important;width:100%;
    font-size:17px!important;font-weight:600!important;
    padding:14px 4px!important;line-height:1.4!important;
    color:var(--ink,#1c2321)!important;
    border-bottom:1px solid var(--line,#ddd5c4);
    border-radius:0!important;
    justify-content:space-between
  }
  .nav-panel{
    display:none!important;
    position:static!important;transform:none!important;left:auto!important;
    background:transparent!important;
    border:0!important;box-shadow:none!important;border-radius:0!important;
    padding:0 0 0 12px!important;
    min-width:auto!important;z-index:auto!important;
    grid-template-columns:1fr!important;column-gap:0!important
  }
  .nav-group.open .nav-panel{display:grid!important}
  .nav-col-hd{display:none!important}
  .nav-panel a{
    padding:12px 4px!important;
    border-bottom:1px solid var(--line,#ddd5c4);
    border-radius:0!important;font-size:15px!important;gap:10px
  }
  .nav-panel a:last-child{border-bottom:0!important}
  .nav-panel a small{font-size:12px!important}
  /* nav-home inside open hamburger */
  .nav-home{
    display:block;width:100%;
    font-size:17px;font-weight:600;line-height:1.4;
    color:var(--ink,#1c2321);text-decoration:none;
    border-bottom:1px solid var(--line,#ddd5c4);
    padding:14px 4px
  }
  .nav-home.active{color:var(--sky,#0e6b5c);font-weight:800}
}

/* legacy nav-more — belt-and-suspenders (should be removed from HTML) */
.nav-pages a.nav-more{display:none!important}

/* v=20260731b additions */
.sec-sage{background:#e5ede7}
.sec-warm{background:#f5f0e8}
.btn-line.sm{min-height:44px!important}

/* ============================================================
   HERO-SPEC.md fold kit — v=20260809a
   Promoted out of website.html / google-maps.html inline <style>
   so the lp-page landing pages get the SAME fold as the control.
   Deliberately NOT scoped body:not(.lp-page) — the 5 pages that
   need this most all carry .lp-page (s116 scoping trap).
   Purely additive: no existing rule is modified or removed.
   ============================================================ */
.hero-price{display:inline-block;margin:14px 0 2px;padding:7px 16px;
  border:1.5px solid var(--line);border-radius:999px;background:var(--card);
  font-weight:700;font-size:15px;color:var(--ink,#0A0A0A);letter-spacing:.01em}
.hero-price .hp-sep{opacity:.45;margin:0 8px;font-weight:400}
@media(max-width:520px){.hero-price{font-size:13.5px;padding:6px 13px}}

.hero-promise{font-family:var(--font-display);font-size:15px;
  color:var(--muted);margin-top:12px;font-weight:600}

/* full-width primary CTA wrapper — spec §3, must land <= 500px */
.hero-cta{margin:22px 0 4px}

/* ---- premium restraint: Majd-reference spacing, in our BRIGHT palette ----
   Reference measured 2026-08-09 at 375px: 90-100px section padding,
   900px measure, one typeface, -2.1px tracking on the display size.
   We take the spacing + tracking ONLY. Its #000 canvas is rejected
   (locked: bright, skyclinic is the visual ref). */
.lp-page h1{letter-spacing:-.02em}
.lp-page h2{letter-spacing:-.015em;margin-top:1.15em}
@media(min-width:760px){
  .lp-page article>h2{margin-top:88px}
  .lp-page .vband{margin:72px auto}
}

/* vertical/section imagery band — carries the img/premium/*.webp squares */
.vband{margin:34px auto;max-width:900px;border-radius:20px;overflow:hidden;
  box-shadow:var(--shadow)}
.vband img{width:100%;display:block;aspect-ratio:1/1;object-fit:cover}
@media(min-width:760px){.vband img{aspect-ratio:16/9}}

/* ============================================================
   §6 ATTENTION-BUDGET FOLD — accordions past 2160px (2026-08-09)
   Applied by js/motion.js at runtime. Served HTML is unchanged,
   so AI crawlers still read every passage unwrapped.
   ============================================================ */
.sec-fold{border-top:1px solid var(--line);margin:0}
.sec-fold+.sec-fold{margin-top:0}
.sec-fold__sum{list-style:none;cursor:pointer;display:flex;align-items:center;
  justify-content:space-between;gap:16px;padding:26px 2px;position:relative}
.sec-fold__sum::-webkit-details-marker{display:none}
.sec-fold__sum h2{margin:0!important;font-size:clamp(19px,3.2vw,26px);letter-spacing:-.015em}
.sec-fold__sum::after{content:"";flex:none;width:12px;height:12px;
  border-right:2.5px solid var(--muted);border-bottom:2.5px solid var(--muted);
  transform:rotate(45deg) translateY(-3px);
  transition:transform .42s cubic-bezier(.33,.9,.28,1)}
.sec-fold[open] .sec-fold__sum::after{transform:rotate(225deg) translateY(-3px)}
.sec-fold__sum:hover h2{color:var(--sky)}
.sec-fold__body{padding-bottom:30px;animation:secFoldIn .5s cubic-bezier(.33,.9,.28,1)}
@keyframes secFoldIn{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){
  .sec-fold__body{animation:none}
  .sec-fold__sum::after{transition:none}
}

/* ============================================================
   RESTORED VISIBLE FAQ — 2026-08-09
   47 questions across 13 pages existed only in JSON-LD. Styling
   follows webdesign-balance-rules: every max-width carries
   margin-inline:auto (the #1 new-page bug), block centered but
   TEXT LEFT-ALIGNED (centering Thai body copy kills readability),
   and no kicker/eyebrow label above the heading.
   ============================================================ */
.faq-restore{padding:56px 20px 8px}
.faq-restore__inner{max-width:900px;margin-inline:auto}
.faq-restore__inner>h2{text-align:center;margin:0 0 26px}
.faq-restore .faq-item{max-width:900px;margin-inline:auto;margin-bottom:14px;
  background:var(--card,#fff);border:1.5px solid var(--line,#E8ECF4);
  border-radius:16px;padding:22px 26px;text-align:left;
  box-shadow:0 4px 20px rgba(34,48,74,.05)}
.faq-restore .faq-item h3{margin:0 0 8px;font-size:18px;line-height:1.45}
.faq-restore .faq-item p{margin:0;color:var(--muted,#5D6B84);font-size:16.5px;line-height:1.75}
@media(max-width:520px){
  .faq-restore{padding:40px 16px 4px}
  .faq-restore .faq-item{padding:18px 18px;border-radius:14px}
  .faq-restore .faq-item h3{font-size:17px}
}

/* Wide-source band: break-wide.webp is natively 1600x679 (2.36:1). Forcing it into the
   default 1:1 mobile box cropped ~58% of its width. Give wide sources a wide box. */
.vband--wide img{aspect-ratio:2.36/1}
@media(min-width:760px){.vband--wide img{aspect-ratio:2.36/1}}

/* ============================================================
   SHARED COMPONENT: us/them COMPARISON BOX  (.cmpbox)  — 2026-08-13
   Promoted out of medical-tourism.html at Shane's request ("i like ...
   the comparison box"). It shipped there as a one-off page-local block;
   this is the reusable version. The page-local copy on
   /medical-tourism is intentionally left in place until the pilot is
   approved — deleting it is rollout scope, not pilot scope.

   ⚠️ STANDING CONTENT RULE, not a style note: the right-hand column
   describes the COMMON MARKET OFFER in generic terms and NEVER names,
   quotes, or characterises a specific competitor. This is a claim rule
   and ops/claim_audit.py is the gate.

   Flat build (post gold-ring retirement): the "us" column is elevated by
   a hairline + the 4-layer low-alpha stack, never by a coloured halo.

   Markup:
     <section class="cmpbox">
       <h2>ทำไมต้อง <span>Zip AI</span></h2>
       <div class="cmpwrap"><div class="cmpgrid">
         <div class="cmp-hd cmp-lbl"></div>
         <div class="cmp-hd cmp-us first">Zip AI</div>
         <div class="cmp-hd cmp-them">ทั่วไปในตลาด</div>
         <div class="cmp-lbl">…row label…</div>
         <div class="cmp-us"><span class="cmp-tick">✓</span>…</div>
         <div class="cmp-them"><span class="cmp-dash">—</span>…</div>
         …repeat rows; put `last` on the final .cmp-us…
       </div></div>
       <p class="cmp-note">…</p>
     </section>
   ============================================================ */
.cmpbox{position:relative;overflow:hidden;margin:56px calc(-50vw + 50%);
  width:100vw;max-width:100vw;padding:56px 0 64px;background:var(--alt,#F4F5F4)}
.cmpbox h2{max-width:900px;margin:0 auto 34px;padding:0 20px;text-align:center;
  font-size:clamp(23px,4vw,38px)}
.cmpbox h2 span{color:var(--accent,#0D8A5A)}
.cmpwrap{max-width:1040px;margin:0 auto;padding:0 14px;position:relative}
.cmpgrid{display:grid;grid-template-columns:1.15fr 1fr 1fr;align-items:stretch}
/* #E2E7E2 (not var(--line)) is the row rule /medical-tourism actually paints —
   pinned so the component's hairline is the same on every page. */
.cmpgrid>div{border-bottom:1px solid #E2E7E2;
  display:flex;flex-direction:column;justify-content:center}
/* 🔴 CELL PADDING LIVES ON THE CELL-CLASS LAYER, NOT ON `.cmpgrid>div` — 2026-08-17.
   It used to be declared on `.cmpgrid>div` (0,1,1) here and again inside the 560px
   block below. Real browsers resolved that correctly (0,1,1 beats premium.css's
   `.cmp-lbl,.cmp-us,.cmp-vs` at 0,1,0), but it left the ONE property in this
   component declared at a lower layer than every other property, and it read as a
   genuine conflict: two stylesheets declaring padding for the same cells, with only
   a single type-selector between them. ops/shane_check.py SC18 reported it as a
   silent override on 10 elements at 390px.
   Fixed by moving padding onto the same `.cmpgrid <cell-class>` layer (0,2,0) as the
   font, colour and border declarations below — which is exactly what this block's
   header comment says every cell property must do. Values are UNCHANGED (16px 12px
   desktop / 12px 7px at 560), so nothing moves on any page including the anchor;
   premium.css's legacy 22px 20px is now out-ranked by a full class instead of a tag.
   Verified by DOM query on all 25 pages: every `.cmpgrid` child carries one of these
   four cell classes, so no cell loses its padding. */
.cmpgrid .cmp-lbl,.cmpgrid .cmp-us,.cmpgrid .cmp-them,.cmpgrid .cmp-vs{padding:16px 12px}
/* 🔴 EVERY CELL SELECTOR BELOW IS SCOPED UNDER .cmpgrid ON PURPOSE — do not
   "simplify" them back to bare `.cmp-us` / `.cmp-lbl` / `.cmp-tick`.

   premium.css ships a SEPARATE, older comparison layout on the very same class
   names (see premium.css §"LEGACY grid-based comparison table", used by the real
   <table> on index.html + ai-visibility.html). premium.css loads AFTER shared.css,
   so at equal specificity its `.cmp-lbl,.cmp-us,.cmp-vs` rules win and silently
   repaint this component. Measured on /medical-tourism 390px before this fix:
   premium's mobile `.cmp-us{margin:6px 12px}` inset the white column 24px inside
   its own grid track — 94.73px of cell in a 118.73px column — and its
   `border-radius:var(--r-sm)` put a stray 14px radius on MIDDLE cells. The bare
   selectors also lost text-align:center and the #fff background to it below 760px.
   /medical-tourism only looked right because its page-local <style> happened to
   re-declare enough of them; no other page had that rescue.

   Scoping to `.cmpgrid` (0,2,0) puts this component above premium's (0,1,0)
   legacy rules permanently, which is what makes it safe to reuse site-wide.
   The tick needs `.cmpgrid .cmp-us .cmp-tick` (0,3,0) to clear premium's
   `.cmp-us .cmp-tick` (0,2,0).

   Source order inside this block is load-bearing: .cmp-hd must come BEFORE
   .cmp-lbl/.cmp-us/.cmp-them so the column classes keep winning the font
   declarations, exactly as they do today. */
.cmpgrid .cmp-hd{font-family:var(--font-display);font-weight:800;text-align:center;
  padding:20px 12px!important;border-bottom:1px solid #E2E7E2;
  font-size:clamp(16px,2.4vw,21px)}
.cmpgrid .cmp-lbl{font-family:var(--font-display);font-weight:800;
  font-size:clamp(15px,2.1vw,17.5px);color:var(--ink,#0A0A0A);
  /* pinned literal — premium.css paints this inset with var(--line), which the s183 green palette
     changed on some pages; anchor /medical-tourism renders #E6E9EE, so pin it here (SC19) */
  box-shadow:inset 0 1px 0 #E6E9EE}
.cmpgrid .cmp-us{background:#fff;text-align:center;font-size:clamp(14.5px,2vw,17px);
  font-weight:700;color:var(--ink,#0A0A0A);line-height:1.6;
  border-left:2px solid rgba(13,138,90,.45);border-right:2px solid rgba(13,138,90,.45)}
.cmpgrid .cmp-us.first{border-top:2px solid rgba(13,138,90,.45);
  border-radius:12px 12px 0 0;
  box-shadow:0 -4px 34px rgba(13,138,90,.16)}
.cmpgrid .cmp-us.last{border-bottom:2px solid rgba(13,138,90,.45);
  border-radius:0 0 12px 12px;
  box-shadow:0 22px 38px -18px rgba(13,138,90,.34)}
.cmpgrid .cmp-hd.cmp-us{color:var(--accent,#0D8A5A);letter-spacing:.01em}
.cmpgrid .cmp-them{text-align:center;font-size:clamp(13.5px,1.9vw,15.5px);
  font-weight:600;color:#8A94A3;line-height:1.6}
/* 22px / mint / weight 900 is what /medical-tourism actually renders today —
   those values come from premium.css winning over the old bare .cmp-tick rule.
   Pinned here as literals so the tick is identical on pages whose --mint differs
   (google-maps runs a warm palette where --mint is #147a5c, not #18B87A). */
.cmpgrid .cmp-us .cmp-tick{display:block;width:22px;height:22px;margin:0 auto 10px;
  border-radius:50%;background:#18B87A;color:#fff;
  font-size:13px;font-weight:900;line-height:22px;text-align:center;
  box-shadow:0 3px 12px rgba(13,138,90,.34)}
.cmpgrid .cmp-dash{color:#B7BFC9;font-size:19px}
/* .cmp-note is deliberately left at (0,1,0): on every type-v2 page
   `body.type-v2 :is(article,section) p` (type.css, 0,2,2) legitimately wins and
   renders the note as 19px/600 body copy. Raising this selector would silently
   restyle the note on /medical-tourism. */
.cmp-note{max-width:1040px;margin:18px auto 0;padding:0 20px;
  font-size:14.5px;font-weight:600;color:var(--muted,#5F6B7A);text-align:center}
/* Un-pick premium.css's legacy mobile block from THIS component. Without these
   the white column detaches from its grid track (see the 24px inset above). */
@media(max-width:760px){
  .cmpgrid .cmp-us{margin:0;border-radius:0;text-align:center;background:#fff}
  .cmpgrid .cmp-us.first{border-radius:12px 12px 0 0}
  .cmpgrid .cmp-us.last{border-radius:0 0 12px 12px}
  .cmpgrid .cmp-us .cmp-tick{display:block;margin:0 auto 8px;vertical-align:baseline}
  .cmpgrid .cmp-lbl{border-top:0;box-shadow:none}
}
@media(max-width:560px){
  /* same cell-class layer as the desktop value above — see the SC18 note there */
  .cmpgrid .cmp-lbl,.cmpgrid .cmp-us,.cmpgrid .cmp-them,.cmpgrid .cmp-vs{padding:12px 7px}
  .cmpwrap{padding:0 8px}
}

/* ============================================================
   SHARED COMPONENT: FULL-BLEED PHOTO  (.figbig)  — 2026-08-13
   Promoted out of medical-tourism.html. Shane: "the big photos and
   vision". This is the floor for editorial imagery, not the ceiling.
   max-height caps the image so a tall source can never push the fold.
   Flat: no radius, no shadow, no border — the photo is the element.
     <figure class="figbig"><img …><figcaption>…</figcaption></figure>
   ============================================================ */
.figbig{position:relative;width:100vw;max-width:100vw;
  margin-left:calc(-50vw + 50%);margin-top:44px;margin-bottom:44px;overflow:hidden}
.figbig img{width:100%;display:block;object-fit:cover;max-height:80vh}
.figbig figcaption{max-width:900px;margin:14px auto 0;padding:0 20px;
  font-size:14.5px;color:var(--muted,#5F6B7A);text-align:center}
@media(min-width:1100px){.figbig{margin-top:56px;margin-bottom:56px}
  .figbig img{max-height:82vh}}

/* ============================================================
   SHARED COMPONENT: HERO VISUAL  (.hviz)  — 2026-08-15
   The "first three seconds" kit. Three inline-SVG visuals that say
   what we do before a visitor reads a word:
     .hviz--ai-search        prompt bar + engine marks + AI answer
     .hviz--ads-vs-organic   rented attention vs compounding work
     .hviz--before-after-pin Maps listing unmanaged vs managed
   Canonical markup lives in HERO-SPEC.md §7 — copy it verbatim.

   🔴 WHY INLINE SVG, NOT <symbol> + <use>, AND NOT AN IMAGE:
   - SVG <text> is real crawlable text; a JPG poster is invisible to
     AI engines. Citation is priority #1 on this site.
   - <use> puts the art in a shadow tree that THIS stylesheet cannot
     reach, which would make the shared styling + the mandatory
     prefers-reduced-motion switch below impossible. Light DOM only.
   - ~3 KB of markup, no extra request, no render-blocking weight.

   🔴 NO box-shadow here. Elevation/glow is glow3.css's alone
      (feedback_zipai_glow_is_one_shared_file). Add `lit` if a page
      wants the shared card treatment.
   🔴 UNSCOPED on purpose: /google-maps carries `lp-page`, which the
      `body:not(.lp-page)` trap (s116) would have skipped.
   CLS: every svg carries an explicit viewBox (360x300) and the
   aspect-ratio below reserves the box before paint.
   ============================================================ */
.hviz{max-width:500px;margin:22px auto 0;padding:0;width:100%}
.hviz--pair{max-width:760px;margin-inline:auto}
.hviz svg{display:block;width:100%;height:auto;aspect-ratio:6/5}
.hviz-grid{display:grid;gap:14px;grid-template-columns:1fr}
@media(min-width:640px){.hviz-grid{grid-template-columns:1fr 1fr;gap:16px}}
.hviz-cap{max-width:44em;margin:11px auto 0;font-size:13.5px;line-height:1.55;
  color:var(--muted,#5F6B7A);text-align:center}
@media(min-width:1100px){.hviz{margin-top:28px}}

/* ---- motion: OFF by default, opt-in only when the visitor allows it ---- */
@keyframes hviz-draw{to{stroke-dashoffset:0}}
@keyframes hviz-pulse{0%,100%{opacity:0}45%{opacity:.5}}
@media (prefers-reduced-motion:no-preference){
  .hviz-ln{stroke-dasharray:100;stroke-dashoffset:100;
    animation:hviz-draw 1500ms var(--ease3,cubic-bezier(.33,.9,.28,1)) 180ms forwards}
  .hviz-ln-2{animation-delay:420ms}
  .hviz-pulse{animation:hviz-pulse 3.4s var(--ease3,cubic-bezier(.33,.9,.28,1)) infinite}
}

/* ============================================================================
   MOBILE BOTTOM CTA — one deliberate full-width sticky bar   (2026-08-15)
   ----------------------------------------------------------------------------
   Shane, photographing zipai.in.th on a real iPhone: the green LINE pill sat
   floating at the bottom-LEFT and "doesn't look nice on mobile — fix it, all
   the pages".

   MEASURED CAUSE (Playwright, 375x812, all 25 landing pages):
   the site grew THREE competing bottom-CTA systems, wired differently on
   every page —
     .zp-sticky   10 pages   cream bar + full-width green pill   correct shape
     .sticky-cta  10 pages   cream bar + full-width green pill   correct shape
     .line-fab / .fb-fab     round 56-68px FABs                  desktop shape
   ...and nothing reconciled them:
     · 7 pages rendered a bar AND the round FABs at the same time
       (website.html rendered all three; measured overlap 60x60px).
     · 3 pages (about, medical-tourism, privacy) had no bar at all, only
       the round FAB.
     · privacy.html's page-local `.line-fab{position:relative}` (added with
       the fab-tip patch) knocked the FAB out of the fixed layer entirely, so
       it landed in normal flow at x=-16 — THE stray bottom-left pill in the
       photo.
     · 8 pages left 0px clearance under the last line of content, so the bar
       covered it (check.html measured -252px).

   RULE FROM HERE: on phones exactly ONE bar — flush, full-width, safe-area
   aware — and no round FAB. Desktop is untouched and keeps the round FAB.

   WHY !important: every page carries its own inline <style> block (and
   about.html an inline style="" attribute on the anchor itself) that loads
   after this file and would otherwise win on document order. Normalising 25
   pages of page-local CSS from one shared file is the whole point.

   WHY :has(): it is the only way to say "this page already has a bar, so the
   FAB is redundant" without editing 25 files. Chosen so the no-:has()
   fallback is exactly today's behaviour — the rules simply drop and nothing
   regresses.

   Glow is NOT touched here — no box-shadow is declared in this block.
   Gold ring / bloom remain owned solely by css/glow3.css.
   ============================================================================ */
/* -- 0. ALL widths: the floating button must stay in the fixed layer.
      privacy.html's fab-tip patch shipped a page-local `.line-fab{position:relative}`.
      There is no .fab-tip element in the markup, so it anchored nothing — it just
      dropped the button out of the fixed layer, where it landed in normal flow at
      the end of <body>. Measured x=-16 at 375 and x=-22 at 1440: THE stray
      bottom-left pill in Shane's photo. `position:fixed` already establishes the
      containing block an absolutely-positioned .fab-tip would need. -- */
.line-fab{position:fixed!important}

@media (max-width:860px){

  /* -- 1. both bar systems: flush to the viewport edge, safe-area aware -- */
  .zp-sticky,
  .sticky-cta{
    position:fixed!important; left:0!important; right:0!important;
    bottom:0!important; top:auto!important; width:auto!important;
    box-sizing:border-box!important; z-index:140!important;
    padding:10px 14px calc(10px + env(safe-area-inset-bottom))!important;
  }
  .zp-sticky>a,
  .sticky-cta .btn-line{
    width:100%!important; box-sizing:border-box!important;
    display:flex!important; align-items:center!important; justify-content:center!important;
  }

  /* -- 2. a bar exists -> the round FABs are redundant on a phone -- */
  body:has(.zp-sticky) .line-fab,  body:has(.zp-sticky) .fb-fab,
  body:has(.sticky-cta) .line-fab, body:has(.sticky-cta) .fb-fab{
    display:none!important;
  }

  /* -- 3. no bar markup on the page (about, ai-agency-thailand, chatbot,
        clinic, medical-tourism, nail-salon, privacy, restaurant, services)
        -> the .line-fab BECOMES the bar: full-bleed, flush, edge to edge.
        Icon-only, because this is a layout fix and no copy may be added.

        🔴 Do NOT reinstate the cream-strip-behind-a-pill version. It was
        built as `.line-fab::before{z-index:-1}` and rendered PALE: inside the
        stacking context that `position:fixed` + `z-index` creates, a negative
        z-index pseudo paints AFTER the element's own background, so the cream
        strip covered the green button instead of sitting behind it. `body::after`
        is not available as an alternative host — it is already the fixed noise
        overlay on 11 pages. The bar owns its own box; that is why this works. -- */
  body:not(:has(.zp-sticky)):not(:has(.sticky-cta)) .line-fab{
    position:fixed!important; left:0!important; right:0!important;
    bottom:0!important; top:auto!important;
    width:auto!important; height:auto!important; min-height:60px!important;
    border-radius:0!important; box-sizing:border-box!important;
    display:flex!important; align-items:center!important; justify-content:center!important;
    padding:14px 20px calc(14px + env(safe-area-inset-bottom))!important;
    z-index:140!important; transform:none!important; animation:none!important;
  }
  /* the FB button stacks ABOVE the bar, never beside it */
  body:not(:has(.zp-sticky)):not(:has(.sticky-cta)) .fb-fab{
    position:fixed!important; right:14px!important; left:auto!important;
    bottom:calc(76px + env(safe-area-inset-bottom))!important; top:auto!important;
    width:48px!important; height:48px!important; z-index:139!important;
  }

  /* -- 4. the bar must never cover the last line of content.
        Normalises the ad-hoc per-page values (0 / 28 / 60 / 76 / 90 / 120px)
        to one clearance taller than the tallest measured bar (87px). -- */
  footer{padding-bottom:calc(104px + env(safe-area-inset-bottom))!important}
  body:not(:has(footer)){padding-bottom:calc(104px + env(safe-area-inset-bottom))!important}
}

/* ============================================================
   SHARED COMPONENT: us/them TWO-COLUMN COMPARE  (.vs)  — 2026-08-16
   Shane, s163: "please all compare boxes make like 2nd photo of medical
   page" — i.e. the /medical-tourism .cmpbox look (elevated WHITE card for
   our side, muted flat card for the other side) applied to every compare
   block on the site, not just that one table.

   .vs is the OTHER compare shape: a two-card row (.vs-col.bad / .vs-col.good)
   used 15x across google-maps (7), line-oa-guide (4), pin-google-maps (2),
   geo-aeo (1) and medical-tourism (1). It had drifted into FIVE different
   page-local skins — good side variously #F4F5F4, var(--mint-soft),
   var(--card) or var(--alt); bad side variously #fff, var(--card),
   var(--sun-soft) amber or #FFF6F5 pink; radius 10px or 16px; border 1px or
   1.5px. This is the one skin, matched to .cmp-us / .cmp-them.

   🔴 CONTAINER ONLY — background, border, radius. Nothing here touches a
   single word, and nothing here sets a heading colour: .vs-col.bad carries a
   red/rose h3 on most pages because it names the CUSTOMER'S PROBLEM (สาเหตุ),
   not a competitor. That diagnostic colour is meaning, not decoration.

   🔴 NO box-shadow, deliberately. .vs-col carries .lit on most pages and
   glow3.css owns every ring/bloom on a .lit box
   (feedback_zipai_glow_is_one_shared_file). A box-shadow here would outrank
   glow3's `.lit` (0,1,0) and delete the ring. Elevation is carried by the
   white/grey value split instead.

   Specificity: `body.premium .vs .vs-col.good` = (0,4,1). It has to clear
   geo-aeo's page-local `body.premium .vs-col.good` (0,3,1). Every one of the
   25 pages carries body.premium, verified 2026-08-16.
   /medical-tourism is EXCLUDED by design — its page-local rules use
   !important, so this cannot reach it and that page stays byte-identical.
   ============================================================ */
/* 🔴 border-COLOR only — never the `border` shorthand, and never a width.
   /medical-tourism pins `.vs-col.bad/.good{background:…!important;
   border-color:…!important}` page-locally. A shorthand here still lands its
   WIDTH there (their !important covers colour, not width), which measured as
   1px -> 2px and moved every .vs card on that page by 2px. Setting colour and
   background only means their !important absorbs this rule completely and
   /medical-tourism is untouched, while every page that never fought the
   cascade picks up the shared skin at its own existing border width. */
body.premium .vs .vs-col{border-radius:10px}
body.premium .vs .vs-col.good{background:#fff;border-color:rgba(13,138,90,.45)}
body.premium .vs .vs-col.bad{background:#F4F5F4;border-color:#E2E7E2}

/* ── GEOMETRY + PADDING + TYPE, added 2026-08-17 ────────────────────────────
   Shane, s163: "make this bigger · every comparison box need same style every
   page use medical page as anchor". The skin above already unified colour and
   radius; the BOXES were still five different sizes. Measured before this rule
   at 1440 / 390 (ops-style render, working tree):

     page              padding            h3          li           p
     medical (ANCHOR)  22px 24px 28px     24px/800    18.5px/600   —
     google-maps       22 24 28 / 20 18 24  24/800    18.5/600     19/600
     case-mdcc         22px 24px 28px     24/800      18.5/600     —
     pin-google-maps   22px 24px 28px     24/800      18.5/600     19/600
     line-oa-guide     22px 24px 28px     22 / 19     17/600       16.5px/500
     geo-aeo           26px 24px          20/800      16/600       —

   Every number below is a MEASURED /medical-tourism value, not an invented one:
   h3 24px/800/1.45 and li 18.5px/600/1.8 are what the anchor's own `.vs-col`
   renders (they come from css/type.css winning over that page's local 22px/17px
   declarations — the page-local numbers there are already dead). `p` 19px/600/
   1.85 is the anchor's body-prose value. So this rule makes line-oa-guide and
   geo-aeo read exactly like the anchor instead of one and two steps smaller.

   🔴 PADDING IS THE ONE PLACE WE GO BEYOND THE ANCHOR, AND WHY.
   30px 32px is not new either — it is the anchor's own generous prose-box
   padding (css/type.css `.blk/.answer-box/.faq-item/.cta-box/.warn`). Shane
   called a box that ALREADY matched the anchor's `.vs-col` (google-maps, 22px
   24px 28px, identical) too small and too tight, so "bigger" has to mean the
   anchor's box family rather than its table-cell family. The anchor itself is
   pixel-locked by SC16 and cannot follow, which is why every rule here is
   prefixed with an explicit exclusion of that page:

       html:not(:has(link[rel="canonical"][href$="/medical-tourism"]))

   The canonical link is the exact, self-documenting identity of the page — not
   a body class (the anchor shares `lp-page premium type-v2` with 9 others) and
   not a content marker (`.mt-stats` also exists on /services). Specificity of
   the prefix is (0,2,2): `:not()` and `:has()` each take their most specific
   argument, `link[rel][href]` = (0,2,1), plus the `html` type. With ` .vs
   .vs-col li` that reaches (0,4,3), which clears line-oa-guide's page-local
   `body.type-v2 :is(article,section) .vs-col li` (0,3,3) and geo-aeo's
   `body.premium .vs-col` (0,3,1) — the two pages that were fighting the kit.

   🔴 NO box-shadow and NO heading colour here, for the same reasons as the skin
   above: glow3.css owns every ring on a `.lit` box, and `.vs-col.bad h3` is red
   because it names the CUSTOMER'S problem — that is meaning, not decoration.
   🔴 NO border-width either. Setting it moved every card on the anchor by 2px
   once already (see the note above); there is no divergence to fix anyway —
   all six pages compute a 1px used width.

   The `max-width:min(860px,100vw - 40px)` is a GUTTER FIX, not a resize. At
   390px /google-maps rendered `.vs` at the full 390 with its cards flush to
   both screen edges, because its `.vs` sits in an unpadded <section> while the
   anchor's sits in a 20px-padded <article> (measured 350 vs 390). Clamping
   against 100vw only bites when the row would otherwise reach the edge, so the
   pages that already have a padded parent are unchanged and every page lands on
   the same 20px gutter. Same technique, and same rationale, as `.see-row`.
   ─────────────────────────────────────────────────────────────────────────── */
html:not(:has(link[rel="canonical"][href$="/medical-tourism"])) .vs{
  display:grid;grid-template-columns:1fr;gap:14px;
  margin:22px auto;max-width:min(860px,100vw - 40px)}
@media(min-width:720px){
  html:not(:has(link[rel="canonical"][href$="/medical-tourism"])) .vs{
    grid-template-columns:1fr 1fr}
}
html:not(:has(link[rel="canonical"][href$="/medical-tourism"])) .vs .vs-col{
  padding:30px 32px;border-radius:10px}
html:not(:has(link[rel="canonical"][href$="/medical-tourism"])) .vs .vs-col h3{
  margin:0 0 12px;font-size:24px;font-weight:800;line-height:1.45}
html:not(:has(link[rel="canonical"][href$="/medical-tourism"])) .vs .vs-col>ul,
html:not(:has(link[rel="canonical"][href$="/medical-tourism"])) .vs .vs-col>ol{
  margin:0}
html:not(:has(link[rel="canonical"][href$="/medical-tourism"])) .vs .vs-col li{
  font-size:18.5px;font-weight:600;line-height:1.8;color:#2F3A49;margin-bottom:12px}
html:not(:has(link[rel="canonical"][href$="/medical-tourism"])) .vs .vs-col p{
  font-size:19px;font-weight:600;line-height:1.85;color:#0A0A0A;margin-bottom:20px}
html:not(:has(link[rel="canonical"][href$="/medical-tourism"])) .vs .vs-col li:last-child,
html:not(:has(link[rel="canonical"][href$="/medical-tourism"])) .vs .vs-col p:last-child{
  margin-bottom:0}

/* ============================================================
   SHARED COMPONENT: ALTERNATING FIGURE ROW  (.see-row)  — 2026-08-16
   Shane, s163: "i like the style of photo graphic left and right but we need
   to show things that informative."

   Geometry is transcribed from design/FUNNEL-REFERENCE-SPEC.md §3 (measured
   2026-08-16 off funnel.in.th/seo at 1440x900 and 390x844 — re-measure before
   reuse after 2026-09-15). Copy the SYSTEM, never the brand: their grid,
   shadow physics and cadence, none of their colour or voice.

   MARKUP IS NOT SHIPPED BY THIS FILE — no page uses these classes yet. This
   is the kit a later wave writes against:

     <div class="see-row">                     <!-- add .see-row--flip to
       <div class="see-txt">                        force figure-left -->
         <span class="see-num">01</span>
         <h3>…</h3><p>…</p>
       </div>
       <a class="see-fig" href="/img/x.webp" target="_blank" rel="noopener">
         <img src="/img/x.webp" alt="…" width="1160" height="652"
              loading="lazy" decoding="async">
         <span class="see-hint">กดดูภาพเต็ม ↗</span>
       </a>
     </div>

   🔴 Do NOT normalise the image aspect ratio and do NOT set one here. In the
   reference every figure keeps the natural crop of whatever was screenshotted
   (measured 1.78 / 1.56 / 1.40 / 0.89 / 1.73 / 1.60 / 1.94 / 1.21). Forcing a
   uniform ratio is what makes a proof screenshot look like stock art.
   ✅ .lit ON .see-fig IS CORRECT AND IS NOW SHIPPED (16 ส.ค., Shane: "use boxes
   lighting as ref"). This comment previously said the opposite; that was wrong.
   Measured live on all four index.html proof figures: glow3's
   `body .lit:not(.glow-card)` is specificity (0,3,0) and outranks both .see-fig
   and .dv-fig (0,1,0), so it REPLACES this component's shadow rather than
   stacking on it. Exactly one shadow system paints — the feared double-shadow
   does not occur. Verified: ring rgba(255,184,37,.62) 1.6px + 44px bloom.
   🔴 The rule that still holds: glow is owned SOLELY by css/glow3.css. Apply it
   by adding the `lit` CLASS. Never declare a box-shadow on .lit anywhere else
   (memory `feedback_zipai_glow_is_one_shared_file`).
   ============================================================ */
/* 🔴 The gutter is a max-width against 100vw, NOT padding — this is deliberate.
   .see-row lands in three different parents across the pages that use it:
   `.see-rows` with padding 0 20px (index, services, case-mdcc), `.see-rows`
   with padding 0 (google-maps), `.wrap` 0 20px and `.see-sect` 56px 0
   (line-oa). Measured at 390px: the padded parents give a correct 350px row at
   left:20, the unpadded ones give a 390px row at left:0 — text and figures
   flush against both screen edges.
   Adding `padding-inline:20px` here would fix the flush rows but DOUBLE the
   gutter on the four that are already padded (350px -> 310px content). Because
   `100vw` resolves against the viewport rather than the parent box, the clamp
   below only ever bites when the row would otherwise reach the screen edge, so
   every page converges on the same 20px gutter and none of them regress.
   20px is our site's own gutter (spec §2 says 28px for the reference; the
   coordinator's instruction is to match ours where they conflict).
   Safe against the classic 100vw trap: it is used to clamp DOWN and already
   subtracts 40px, so a ~15px scrollbar still leaves gutter, never overflow. */
.see-row{display:grid;grid-template-columns:495px 581px;gap:48px;
  padding:44px 0;align-items:center;
  max-width:min(1124px,100vw - 40px);margin:0 auto}
/* figure right on odd rows, left on even — the reference alternates every row.
   .see-row--flip forces the swap when the markup order can't be alternated. */
.see-row:nth-of-type(even),
.see-row--flip{grid-template-columns:581px 495px}
.see-row:nth-of-type(even) .see-txt,
.see-row--flip .see-txt{order:2}
.see-row:nth-of-type(even) .see-fig,
.see-row--flip .see-fig{order:1}
.see-num{display:block;font-family:var(--font-display);font-weight:800;
  font-size:15px;letter-spacing:.08em;color:var(--accent,#0D8A5A);margin-bottom:10px}
.see-txt h3{margin:0 0 12px;font-size:clamp(21px,2.6vw,26px);font-weight:800;line-height:1.4}
.see-txt p{margin:0}
/* the WRAPPER owns radius + shadow; the <img> has neither (spec §3) */
.see-fig{position:relative;display:block;background:#fff;border-radius:22px;
  border:1px solid transparent;overflow:hidden;
  box-shadow:0 4px 10px rgba(0,0,0,.04),0 16px 40px rgba(0,0,0,.08);
  transition:transform .18s ease,border-color .18s ease}
.see-fig:hover{transform:translateY(-2px);border-color:var(--accent,#0D8A5A)}
.see-fig img{width:100%;height:auto;display:block;border-radius:0}
.see-hint{position:absolute;right:12px;bottom:12px;padding:6px 11px;
  border-radius:999px;background:rgba(10,10,10,.72);color:#fff;
  font-size:12.5px;font-weight:700;opacity:0;transition:opacity .18s ease;
  pointer-events:none}
.see-fig:hover .see-hint{opacity:1}
@media(prefers-reduced-motion:reduce){
  .see-fig{transition:none}
  .see-fig:hover{transform:none}
}
/* --- composition: a dataviz component inside the figure frame ---------------
   A raster screenshot IS the proof, so it must bleed to the frame edge — that
   is why .see-fig ships padding:0. An inline-SVG/DOM chart (css/dataviz.css
   `.dv`) is drawn to its own box instead, so with zero padding its title,
   bars and `.dv-src` stamp sit flush against the card edge. Measured on
   index.html: `.see-fig.dv` computed padding 0px.

   `.dv-fig` is excluded on purpose — it is dataviz.css's wrapper for a RASTER
   inside a .dv figure (index.html `.see-fig.dv.dv-fig` > `.dv-fig-inner` >
   probe-*.png). Padding that one would re-introduce the very inset the frame
   is supposed to avoid for screenshots.

   24px 22px / 18px 15px are services.html's already-shipped page-local values,
   reused so the two never disagree. services.html keeps winning them locally
   (page <style> beats shared.css at equal specificity), so this rule changes
   nothing there — it only reaches the frames that currently have none.
   Radius and shadow are untouched: the frame stays 22px / 16px mobile with
   the measured two-layer shadow.

   🔴 `:has(>.dv-fig)` is an EXCLUSION, not an oversight. `.dv-fig` is
   dataviz.css's raster wrapper and it paints its OWN radius-22 + shadow frame.
   When it is the direct child, the outer `.see-fig` is deliberately reduced to
   a frameless pass-through so the two frames don't stack — google-maps.html
   line 1314 does exactly that with an inline
   `background:none;box-shadow:none;border:0;border-radius:0;overflow:visible`.
   Padding a wrapper that is not drawing a frame just pushes the `.dv-src`
   stamp 22px out of line with the frame the reader can actually see, so those
   are left at 0 and the screenshot keeps bleeding to the real frame edge.
   Verified by A/B: that element computes border-radius 0 / overflow visible
   with these rules removed, i.e. the frameless state is the page's intent. */
.see-fig.dv:not(.dv-fig):not(:has(>.dv-fig)),
.see-fig:not(.dv):has(>.dv:not(.dv-fig)){padding:24px 22px}
@media(max-width:1180px){
  .see-fig.dv:not(.dv-fig):not(:has(>.dv-fig)),
  .see-fig:not(.dv):has(>.dv:not(.dv-fig)){padding:18px 15px}
}

/* ============================================================
   .sr-only — screen-reader-only text  — 2026-08-16
   🔴 This class was used in the markup but defined in NO stylesheet
   (shared / premium / motion / glow3 / type / dataviz / v2 / website-v2) and
   in no page-local <style>. With no rule at all it is inert, so the heading
   rendered as ordinary visible copy: services.html's
   <h2 class="sr-only">รายการบริการทั้งหมด</h2> measured 1440x41 at left:0
   (390x28 at mobile) with checkVisibility() === true.

   Standard clip-rect pattern, not display:none — the text must stay in the
   accessibility tree for screen readers and keep its heading semantics.
   white-space:nowrap stops a 1px box from forcing a scroll-height blowout.
   ============================================================ */
.sr-only,.visually-hidden{
  position:absolute!important;width:1px;height:1px;margin:-1px;padding:0;
  border:0;overflow:hidden;white-space:nowrap;
  clip:rect(0 0 0 0);clip-path:inset(50%)}
/* keep skip-links usable: reveal on keyboard focus */
.sr-only-focusable:focus,.sr-only-focusable:focus-within{
  position:static!important;width:auto;height:auto;margin:0;
  overflow:visible;white-space:normal;clip:auto;clip-path:none}
/* single column, text always ABOVE the figure regardless of desktop side */
@media(max-width:1180px){
  .see-row,
  .see-row:nth-of-type(even),
  .see-row--flip{grid-template-columns:1fr;gap:22px;padding:34px 0;
    max-width:min(860px,100vw - 40px)}
  .see-row:nth-of-type(even) .see-txt,.see-row--flip .see-txt{order:1}
  .see-row:nth-of-type(even) .see-fig,.see-row--flip .see-fig{order:2}
  .see-fig{border-radius:16px}
}

/* ============================================================
   REAL BRAND MARK  (.cmp-brand img, .zip-mark)  — 2026-08-16
   Shane, s163: "also put in real zipai logo !"

   What was rendering: index.html and ai-visibility.html both put the FULL
   logo lock-up (img/logo-zipai-500.png — gradient tile + "Zip AI" wordmark +
   "AI Visibility" tagline) into a 32-42px box beside a large text "Zip AI".
   At that size the wordmark and tagline collapse into illegible mush and
   duplicate the text sitting next to them. Screenshotted at DPR 2 to confirm.

   What ships instead: the real mark ALONE — white bolt on the brand gradient.
   The bolt path is not hand-drawn. It was traced off the actual asset
   (img/logo-zipai-mark-gradient-500.png, opaque-alpha scan, bolt band y=31-362,
   7 vertices) and re-rendered at 139x331 native coordinates; silhouette diff
   against the source crop is 1.24% — edge antialiasing only. Gradient stops
   #3E8EF7 -> #18B87A are sampled from the asset's own corners.

   Inline SVG data URI on purpose: no extra request, crisp at any DPR, and the
   existing width/height rules still size it, so CLS stays 0.
   `content:url()` swaps the replaced image without touching page markup —
   the [src*=] attribute selector (0,2,1) clears the page-local
   `.cmp-brand img` (0,1,1) rules in index.html and premium.css.
   ============================================================ */
.cmp-brand img[src*="logo-zipai"],
.zip-mark{
  content:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cdefs%3E%3ClinearGradient id='zb' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%233E8EF7'/%3E%3Cstop offset='1' stop-color='%2318B87A'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='100' height='100' rx='18' fill='url(%23zb)'/%3E%3Cg transform='translate(37 19) scale(.1873)'%3E%3Cpath fill='%23fff' d='M74 0H129L73 143H139L23 331 57 193 0 192Z'/%3E%3C/g%3E%3C/svg%3E");
}
/* standalone utility for page agents: <span class="zip-mark"></span> */
.zip-mark{display:inline-block;width:32px;height:32px;vertical-align:middle;flex:none}

/* ── Google Maps FAB — added 2026-08-18 ──────────────────────────────────────
   Third button in the floating rail. Desktop order top->bottom: Maps, FB, LINE.
   .fb-fab sits at bottom:102px and .line-fab at bottom:18-22px on every page,
   so Maps takes the next slot up. Defined HERE ONLY — do not copy it into a
   page's <style>, which is how .fb-fab ended up duplicated in 15 files.
   Hidden on mobile like .fb-fab: below 860px the LINE button owns the rail
   (it becomes the full-width sticky bar). */
.maps-fab{position:fixed;right:22px;bottom:186px;z-index:120;
  display:inline-flex;align-items:center;justify-content:center;
  width:68px;height:68px;border-radius:50%;background:#fff;
  border:1.5px solid var(--line);text-decoration:none;
  box-shadow:0 10px 30px rgba(34,48,74,.18);
  transition:transform .18s ease,box-shadow .18s ease}
.maps-fab:hover{transform:scale(1.08);box-shadow:0 14px 38px rgba(34,48,74,.26)}
.maps-fab:active{transform:scale(.95)}
@media(max-width:860px){.maps-fab{display:none}}
/* Pages with no FB/LINE fab rail (blog, 404, card): the Maps button takes the
   bottom slot instead of the third one up. */
.maps-fab.solo{bottom:22px}

/* ── .fb-fab base rule — moved into the shared layer 2026-08-18 ──────────────
   The base rule lived ONLY in 15 pages' local <style>. Six pages (ai-agency-
   thailand, chatbot, clinic, nail-salon, restaurant, services) received the
   FB markup today and had no rule anywhere, which renders the button as a
   ~38x30px inline stub buried in page flow — the s142 defect, verbatim.
   Values copied from index.html:392 so pages carrying a local copy are
   byte-identical and nothing moves. */
.fb-fab{position:fixed;right:22px;bottom:102px;z-index:120;display:inline-flex;
  align-items:center;justify-content:center;width:68px;height:68px;border-radius:50%;
  background:#0866FF;color:#fff;text-decoration:none;
  box-shadow:0 10px 30px rgba(8,102,255,.45);
  transition:transform .18s ease,box-shadow .18s ease}
.fb-fab:hover{transform:scale(1.08);background:#0653cc;box-shadow:0 14px 38px rgba(8,102,255,.55)}
.fb-fab:active{transform:scale(.95)}
/* Specificity note: 15 pages carry a page-local .fb-fab{display:inline-flex} (0,1,0)
   that loads AFTER this file, so a bare .fb-fab hide here loses at 390px — SC18
   caught exactly that on about.html. `body .fb-fab` is (0,1,1) and wins on every
   page regardless of order, without !important. */
@media(max-width:860px){body .fb-fab{display:none}}

/* ── MOBILE RAIL — all three buttons stay visible on a phone (Shane, 2026-08-18) ──
   Supersedes the "a bar exists -> the round FABs are redundant on a phone" rule
   above: he wants LINE, Facebook and Maps reachable while scrolling on mobile,
   not just on desktop. Geometry follows the two layouts already in this file:
     · no bar markup  -> .line-fab IS the full-width bar (min-height 60px),
                         .fb-fab sits at 76px, so Maps takes 132px.
     · bar markup     -> the sticky bar measures up to 87px, so FB goes to 94px
                         and Maps to 150px, both clear of it.
   48px matches the .fb-fab mobile size already set above. z-index 139 keeps both
   under the bar's 140, so the bar always wins a collision. */
@media(max-width:860px){
  body .maps-fab{
    display:inline-flex!important; right:14px!important; left:auto!important;
    width:48px!important; height:48px!important; z-index:139!important;}
  body:not(:has(.zp-sticky)):not(:has(.sticky-cta)) .maps-fab{
    bottom:calc(132px + env(safe-area-inset-bottom))!important;}
  body:has(.zp-sticky) .maps-fab, body:has(.sticky-cta) .maps-fab{
    bottom:calc(150px + env(safe-area-inset-bottom))!important;}
  body:has(.zp-sticky) .fb-fab, body:has(.sticky-cta) .fb-fab{
    display:inline-flex!important; position:fixed!important;
    right:14px!important; left:auto!important;
    bottom:calc(94px + env(safe-area-inset-bottom))!important; top:auto!important;
    width:48px!important; height:48px!important; z-index:139!important;}
}

/* ── FAB RAIL — one size for all three (Shane, 2026-08-18) ──────────────────
   They were built at different times and drifted: Maps 68px button / 30px glyph,
   Facebook 68/28, LINE 60-68/38. Same rail, same target size, same optical
   weight. 68px desktop and 56px mobile both clear the 44px minimum tap target
   the mobile audit measures. The LINE bar on phones is untouched — on pages with
   no sticky bar it still becomes the full-width bar, so it is excluded by the
   same :not() selectors used above. */
.maps-fab, .fb-fab, .line-fab{width:68px!important; height:68px!important}
.maps-fab svg, .fb-fab svg, .line-fab svg{width:36px!important; height:36px!important}
@media(max-width:860px){
  body .maps-fab, body .fb-fab{width:56px!important; height:56px!important}
  body .maps-fab svg, body .fb-fab svg{width:30px!important; height:30px!important}
  /* re-stack for the larger buttons: bar pages (bar <=87px) and non-bar pages */
  body:not(:has(.zp-sticky)):not(:has(.sticky-cta)) .fb-fab{
    bottom:calc(76px + env(safe-area-inset-bottom))!important;}
  body:not(:has(.zp-sticky)):not(:has(.sticky-cta)) .maps-fab{
    bottom:calc(142px + env(safe-area-inset-bottom))!important;}
  body:has(.zp-sticky) .fb-fab, body:has(.sticky-cta) .fb-fab{
    bottom:calc(96px + env(safe-area-inset-bottom))!important;}
  body:has(.zp-sticky) .maps-fab, body:has(.sticky-cta) .maps-fab{
    bottom:calc(162px + env(safe-area-inset-bottom))!important;}
  /* the LINE bar keeps its own full-width geometry — never resized here */
  body:not(:has(.zp-sticky)):not(:has(.sticky-cta)) .line-fab{
    width:auto!important; height:auto!important;}
}


/* ── GBP pin proof: always centred, whatever the host page's figure does ─────── */
/* 🔴 DESCENDANT, not `> ` (2026-08-24). These were direct-child selectors, which
   silently stopped matching the moment the img gained ANY wrapper — index.html's
   panel is now inside a `.lit` box, and a webp `<picture>` wrap would have done the
   same thing. The rule's own promise is "always centred, whatever the host page's
   figure does"; a `>` combinator cannot keep that promise. Nothing else changed —
   descendant matches every case `>` matched, plus the wrapped ones. */
/* `width:auto` is load-bearing, not tidying. When the host figure is a `.figbig` it
   carries `width:100vw` + `margin-left:calc(-50vw + 50%)`; the auto margins below
   cancel the bleed but max-width cannot cancel a 100vw WIDTH once the viewport is
   under 820px. Measured on a 390px phone before this line existed: the figure sat
   390px wide at x=20, hanging 20px off the right edge (invisible only because
   .figbig clips). reviews.html measured identical before and after. */
figure:has(img[src*="zipai-gbp-panel"]),
figure:has(img[src*="zipai-gbp-map"]){
  width:auto;max-width:820px;margin-left:auto!important;margin-right:auto!important;text-align:center}
img[src*="zipai-gbp-panel"], img[src*="zipai-gbp-map"]{
  display:block;margin-left:auto!important;margin-right:auto!important}
figure:has(img[src*="zipai-gbp-panel"]) figcaption,
figure:has(img[src*="zipai-gbp-map"]) figcaption{text-align:center}

/* ── Comparison box logo: bigger and clearer on every page (Shane, 2026-08-18) ──
   30px read small next to the 21px header type; 36px matches the wordmark weight. */
/* ── Comparison box: the REAL Zip AI logo in the "us" column header ──────────
   (SC07 "put in real zipai logo"). Same asset every other page already ships,
   sized to the header row so it cannot shift the grid. */
/* Specificity: glow3.css carries `.premium img:not(.nav-ico):not([class*="ico"]):not(svg)`
   at (0,3,2) and loads AFTER this file, so a bare `.cmp-logo-img` (0,1,0) loses its
   height to that rule's `height:auto` — SC18 measured it on 11 rows at 390px.
   (0,2,1) was still short: glow3 is (0,3,2). `body.premium .cmpbox .cmpgrid img.cmp-logo-img`
   is (0,4,2) and wins outright. The logo is SQUARE, so `height:auto` resolved to the
   same 24px and made a manual check look correct — the gate reads the winning
   DECLARATION, not the resulting pixel, which is why it caught this and I did not. */
body.premium .cmpbox .cmpgrid img.cmp-logo-img, body .cmpbox img.cmp-logo-img{
  height:36px;width:36px;border-radius:8px;vertical-align:middle;
  display:inline-block;margin-right:8px}
@media(max-width:560px){
  body.premium .cmpbox .cmpgrid img.cmp-logo-img, body .cmpbox img.cmp-logo-img{
    height:28px;width:28px;margin-right:6px}}

/* ── RAIL VISIBILITY — Facebook on every page at mobile, same size as the rest ──
   Measured 2026-08-18: `@media(max-width:860px){body .fb-fab{display:none}}` was
   only reversed by `body:has(.zp-sticky)/.sticky-cta .fb-fab`, so every page WITHOUT
   a sticky bar (medical-tourism, services, ai-agency-thailand, restaurant,
   nail-salon, clinic) showed 2 of 3 buttons on a phone. Maps had an unconditional
   un-hide; Facebook did not. Also: the sticky-bar branch pinned .fb-fab to 48px at
   (0,2,1), beating the 56px one-size rule at (0,1,1) — both are equalised here. */
@media(max-width:860px){
  body .fb-fab{display:inline-flex!important;position:fixed!important;
    right:14px!important;left:auto!important;top:auto!important;
    width:56px!important;height:56px!important;z-index:139!important}
  body .maps-fab{width:56px!important;height:56px!important}
  body .fb-fab svg, body .maps-fab svg{width:30px!important;height:30px!important}
  /* the older no-bar branch pins 48px at (0,3,1) and beats `body .fb-fab` (0,1,1);
     restate the size here at the same weight so all three stay 56px. */
  body:not(:has(.zp-sticky)):not(:has(.sticky-cta)) .fb-fab{
    width:56px!important;height:56px!important;
    bottom:calc(76px + env(safe-area-inset-bottom))!important}
  body:has(.zp-sticky) .fb-fab, body:has(.sticky-cta) .fb-fab{
    bottom:calc(96px + env(safe-area-inset-bottom))!important}
}
/* the stray comparison logo that sits in an <h2>, outside .cmpgrid, never matched
   the (0,4,2) selector below and kept glow3's height:auto. */
body.premium .cmpbox h2 img.cmp-logo-img{height:40px!important;width:40px!important}

/* ============================================================
   s171 (2026-08-20) DESKTOP HEADER ENLARGEMENT — Shane order:
   "bigger, balance all equally, highlights like anga, full screen tab".
   NOTE (review-corrected): shared.css loads FIRST on every page —
   premium/motion/glow3/type load after it and win ties. This block wins
   its contests on SPECIFICITY (verified per-selector in the 2026-08-20
   code review), not on load order. Desktop-only (≥1201px); the ≤1200px
   hamburger build is untouched. Fixes measured defects: 11.5px links ·
   flex-end huddle · 1280px cap · mixed link/button boxes (23px vs 31px
   baseline misalignment).
   ============================================================ */
@media (min-width:1201px){
  /* full-bleed bar — outranks body:not(.lp-page) .wrap's 1280px cap */
  header .nav,
  body:not(.lp-page) header .wrap.nav{
    max-width:none;
    padding:0 clamp(28px,3.2vw,56px);
    min-height:78px;
    gap:clamp(16px,2vw,36px)
  }
  /* links spread evenly across the freed middle; nowrap so a future 6th
     item overflows visibly instead of silently stacking a second row */
  header .nav-pages{
    flex:1;
    flex-wrap:nowrap;
    justify-content:space-evenly;
    align-items:center;
    gap:clamp(14px,1.6vw,34px);
    margin:0 clamp(10px,1.6vw,30px)
  }
  /* ONE type scale + ONE box for plain links and dropdown buttons alike.
     font-family needs !important to beat line ~90's
     `button{font-family:var(--font-display)!important}` on .nav-label —
     without it the 3 dropdown buttons render Anuphan next to Plex links. */
  header .nav-pages>a,
  header .nav-pages .nav-label{
    position:relative;
    display:inline-flex;align-items:center;gap:6px;
    font-family:var(--font-body,"IBM Plex Sans Thai"),sans-serif!important;
    font-size:clamp(15px,1.15vw,17.5px);
    font-weight:700;line-height:1;
    padding:12px 2px
  }
  /* services.html pill bar: premium.css .svc-tabs{top:62px} was tuned to
     the old 60px header; at 78px it slid ~17px underneath. (0,2,0) beats
     premium's (0,1,0) regardless of premium loading later. */
  body.lp-page .svc-tabs{top:80px}
  /* anga-style grow-underline highlight (same device as .hl-grow) */
  header .nav-pages>a::after,
  header .nav-pages .nav-label::after{
    content:'';position:absolute;left:0;right:0;bottom:4px;height:3px;
    border-radius:99px;background:var(--sky,#0e6b5c);
    transform:scaleX(0);transform-origin:left center;
    transition:transform .22s ease
  }
  header .nav-pages>a:hover::after,
  header .nav-pages>a.active::after,
  header .nav-pages .nav-group:hover .nav-label::after,
  header .nav-pages .nav-group.has-active .nav-label::after{transform:scaleX(1)}
  header .nav-chev{width:14px;height:14px}
  /* Shane s171 follow-up: the line-672 .nav-group{padding-bottom:8px} hover bridge
     lifted the 3 dropdown labels ~4px above the 2 plain links. Killing it is safe:
     in production premium.css sets .nav-panel{margin-top:-2px} (panel overlaps the
     group — no gap exists) plus a hover-gated .nav-group::after 16px bridge, so the
     old padding only ever extended hover area, never bridged anything (review-verified). */
  header .nav-pages .nav-group{padding-bottom:0;display:flex;align-items:center}
}

/* ============================================================
   s172 (2026-08-22) NAV-DRIFT FIX part 2 — Shane: "some pages the
   nav position moves". Root cause: per-page body{overflow-x:hidden}
   + html{overflow-x:clip} stops overflow propagation to the viewport,
   so body becomes its own scroll container; on any page whose content
   overflows body height by ≥1px (e.g. reviews.html, +11px) the body
   grows an INNER 15px scrollbar → header/nav render 15px narrower
   than on pages that scroll at the viewport (index). overflow-x:clip
   clips identically but can never create a scroll container, so every
   page scrolls at the html scrollport and nav geometry is identical.
   body gets overflow-x:CLIP (not hidden, not visible): clip masks the same
   latent horizontal overflow that hidden did (gate 0e measured 2760px-wide
   content on google-maps desktop, a 752px sticky CTA on mobile — plain
   visible un-masks them and fails H-SCROLL/OVERWIDE), but clip never
   creates a scroll container, so body cannot become the scroller and the
   viewport/html scrolls normally with the header pinned.
   !important: must beat per-page inline body{overflow-x:hidden} and
   body.premium{overflow-x:hidden}. (Part 1 = multi-BOM quirks-mode
   fix in the HTML files themselves, same session.) */
html body{overflow-x:clip!important;overflow-y:visible!important}
/* s172 part 3 — logo block pinned site-wide. Per-page inline CSS disagrees
   (.logo 20px/800 vs 21px/700; .logo small 10px vs 12px on google-maps; mono
   vs body face). A wider logo shifts every space-evenly nav link right —
   google-maps measured +17px vs index. Values = index.html (the SC16 anchor). */
header .logo{font-family:var(--font-display)!important;font-weight:800!important;font-size:21px!important;
  text-decoration:none;color:var(--ink);line-height:1.15}
header .logo b{color:var(--sky)}
header .logo small{display:block;font-family:var(--font-mono)!important;font-weight:400!important;
  font-size:10px!important;color:var(--muted);letter-spacing:.08em;margin-top:-3px}

/* ---------- s175 (2026-08-24, Shane): balance wrapped bullet lines ----------
   The #entry-pin bullet 'ต่อ 1 ธุรกิจ' wrapped as a lone dangling fragment on
   mobile. .inc is display:flex, so the content span is a block container and
   text-wrap:balance applies; browsers without support ignore it (no-op). */
.inc>span:last-child{text-wrap:balance}

/* ---------- s176 (2026-08-25, Shane ruling): sitewide Thai orphan words ----------
   ~454 spots where a lone Thai word dangles on the last line (s175 visual sweep).
   Inherited from body so it reaches every prose block; element-level declarations
   (`.inc>span:last-child{text-wrap:balance}` above) still win where set. Chrome 117+
   only; other engines ignore (no-op). */
body{text-wrap:pretty}

/* s183 balance pass: shared CTA focus ring + hint (audit rows 6, 22) */
.btn-line:focus-visible{outline:3px solid var(--ink,#0A0A0A);outline-offset:3px}
.hint{display:block;margin-top:12px;color:var(--muted,#5B6660);font-size:14.5px}
.guarantee{font-family:var(--font-display);font-size:14px;font-weight:600;color:var(--muted,#5B6660);margin-top:14px}
