/* ============================================================
   Zip AI — PREMIUM LAYER
   Ported from a measured teardown of anga.co.th (2026-08-01).
   Reference spec + gap table: ../../design/ANGA-REFERENCE-SPEC.md

   What this file is: the *physics* that make ANGA read as premium —
   wide/faint shadows, big soft radii, tall photos, generous section
   rhythm, restrained motion. Expressed in ZIP AI'S OWN PALETTE
   (bright, sky/mint) — we copy the system, never the orange.

   Load AFTER shared.css. Bump ?v= on every change or cached
   visitors keep the old stylesheet (see root CLAUDE.md).
   ============================================================ */

:root{
  /* --- shadow physics (the single biggest "cheap vs premium" tell) ---
     ANGA measured: blur 50–200px at 7–12% alpha. Ours was 8–28px at 13%:
     tight + dark = heavy. Wide + faint = expensive. */
  --sh-xs : 0 4px 18px rgba(34,48,74,.06);
  --sh-sm : 0 4px 50px rgba(34,48,74,.07);
  --sh-md : 0 4px 90px -16px rgba(34,48,74,.13);
  --sh-lg : 0 4px 100px -44px rgba(34,48,74,.19);
  --sh-xl : 0 4px 200px rgba(34,48,74,.17);
  --sh-glow: 0 4px 33px -11px rgba(62,142,247,.30), -26px -14px 93px -60px rgba(24,184,122,.35);

  /* --- radius scale (ANGA: 20/22/24/30/100px) --- */
  --r-sm:14px; --r-md:20px; --r-lg:22px; --r-xl:30px; --r-pill:100px;

  /* --- section rhythm (ANGA: py-24 / md:py-36 / lg:py-48 = 96/144/192px) --- */
  --sec-y: clamp(64px,9vw,140px);
  --sec-y-lg: clamp(88px,13vw,192px);

  /* --- container (ANGA: 1240–1350px) --- */
  --wrap-max:1320px;

  /* --- motion (ANGA: .3s ease for hover; long expressive cubic for entrance) --- */
  --ease-anga:cubic-bezier(.4,.01,.165,.99);
  --dur-hover:.3s;
}

/* ============================================================
   1. THE GROWING HIGHLIGHT
   Direct port of ANGA's `.anga-shadow-primary`: a 2px gradient
   border whose angle rotates 135deg -> 495deg over 4s, plus a
   pulsing multi-layer drop-shadow. Desktop only — on mobile it
   costs battery and the effect is invisible at that size.
   Usage: <div class="glow-card"> … </div>
   ============================================================ */
@property --angle{syntax:"<angle>";initial-value:135deg;inherits:false}

/* No background here on purpose — the host card keeps its own (several of ours
   are translucent on dark sections). We only add the ring + the glow. */
.glow-card{
  position:relative;z-index:1;border-radius:var(--r-lg);
  filter:drop-shadow(0 2px 16px rgba(62,142,247,.20))
         drop-shadow(0 -6px 26px rgba(24,184,122,.10))
         drop-shadow(0 7px 30px rgba(62,142,247,.05));
  will-change:filter;transform:translateZ(0);
}
/* A TRUE ring, not a filled rectangle behind the card.
   ANGA can get away with a filled rect because their card is opaque white; ours
   sit on dark sections at 5% opacity, where a filled rect washes the whole card.
   The mask punches out the middle so only the 2px band paints. */
.glow-card::before,
.cmp-usbg::before{
  content:"";position:absolute;inset:-2px;z-index:-1;pointer-events:none;
  border-radius:calc(var(--r-lg) + 2px);
  background:linear-gradient(var(--angle),var(--sky) 0,rgba(24,184,122,0) 50%);
  padding:2px;
  -webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);
  -webkit-mask-composite:xor;
  mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);
  mask-composite:exclude;
}
@media (min-width:1024px){
  .glow-card::before{animation:zipRotate 4s linear infinite}
  .glow-card{animation:zipGlowPulse 4s linear infinite}
}
@keyframes zipRotate{ to{--angle:495deg} }
@keyframes zipGlowPulse{
  0%,100%{filter:drop-shadow(0 2px 16px rgba(62,142,247,.20)) drop-shadow(0 -6px 26px rgba(24,184,122,.10)) drop-shadow(0 7px 30px rgba(62,142,247,.05))}
  50%    {filter:drop-shadow(0 2px 16px rgba(62,142,247,.40)) drop-shadow(0 -6px 26px rgba(24,184,122,.26)) drop-shadow(0 7px 30px rgba(62,142,247,.10))}
}
@media (prefers-reduced-motion:reduce){
  .glow-card,.glow-card::before{animation:none!important}
}

/* ============================================================
   2. COMPARISON TABLE  (ANGA's "ANGA vs They" block)
   3 columns: attribute label | US (elevated + glow) | THEM (flat, grey).
   Their column is deliberately un-styled — the contrast IS the argument.
   Mobile: collapses to stacked pairs, us-first.
   ============================================================ */
.cmp{max-width:1080px;margin:0 auto;padding:0 16px}
/* --cmp-rows MUST equal (1 header + N data rows) — do NOT count cmp-foot.
   Explicit rows are required so the lifted card's `grid-row:1/-1` resolves against
   them; with implicit rows only, `-1` collapses to row 1 and the card covers the
   header alone. cmp-foot auto-places in the next implicit row, cleanly outside
   the card's span. The card is ALSO position:absolute so it never collides with
   auto-placement (an abspos grid child is positioned against its grid area and is
   skipped by the auto-placement algorithm — without this the header cells get
   pushed down a row). */
.cmp-grid{
  display:grid;grid-template-columns:minmax(150px,1.05fr) minmax(200px,1.2fr) minmax(180px,1fr);
  grid-template-rows:repeat(var(--cmp-rows,8),auto);
  position:relative;
}
/* The elevated middle column sits behind the rows and carries the growing
   highlight (§1) — this is exactly what ANGA does with .anga-shadow-primary. */
.cmp-usbg{
  /* Both lines MUST be explicit. For an abspos grid child an `auto` grid line
     resolves to the container's padding edge (not "span 1"), so `grid-column:2`
     would stretch the card across columns 2+3. */
  position:absolute;grid-column:2 / 3;grid-row:1 / -1;
  /* FIX 2026-08-01: top was -14px which caused the card to extend 14px above
     .cmp-grid, overlapping the section subtitle. top:0 keeps the card within
     the grid boundary at the top. bottom:-14px is kept for the raised-footer
     look; cmp-foot is excluded from --cmp-rows so it sits in an implicit row. */
  top:0;bottom:-14px;left:0;right:0;
  border-radius:var(--r-lg);
  background:var(--card);box-shadow:var(--sh-md),var(--sh-glow);
  z-index:0;
}
@media (min-width:1024px){
  .cmp-usbg::before{animation:zipRotate 4s linear infinite}
}
@media (prefers-reduced-motion:reduce){
  .cmp-usbg::before{animation:none!important}
}
.cmp-head{display:contents}
.cmp-head .cmp-brand,
.cmp-head .cmp-them{
  padding:30px 20px 26px;text-align:center;font-family:var(--font-display);
  font-weight:800;font-size:clamp(20px,2.4vw,30px);position:relative;z-index:2;
}
.cmp-head .cmp-them{color:var(--muted)}
/* logo-zipai-500.png is a SQUARE mark (500x500), not a wordmark — keep it square
   and set the name in type beside it. */
.cmp-brand{display:flex;align-items:center;justify-content:center;gap:10px}
.cmp-brand img,.cmp-brand svg{height:42px;width:42px;display:block;flex:none}
/* LEGACY grid-based comparison table (.cmp-lbl/.cmp-us/.cmp-vs cells).
   index.html and ai-visibility.html now use a REAL <table> with <tr class="cmp-row">.
   `display:contents` on a <tr> deletes the row box and dumps every cell onto one line —
   that is exactly what broke both tables on 2026-08-02. Scoped to non-<tr> so the legacy
   grid markup still works and real tables are left alone. Do not un-scope this. */
.cmp-row:not(tr){display:contents}
.cmp-lbl,.cmp-us,.cmp-vs{
  padding:22px 20px;border-top:1px solid var(--line);
  font-size:15px;line-height:1.7;position:relative;z-index:2;
}
.cmp-lbl{font-weight:700;color:var(--ink);border-top-color:transparent;
  box-shadow:inset 0 1px 0 var(--line)}
.cmp-us{text-align:center;color:var(--ink)}
.cmp-vs{text-align:center;color:var(--muted)}
/* TYPE CONFORMED TO THE ANCHOR — 2026-08-17. Shane: "every comparison box need
   same style every page use medical page as anchor". This legacy <table> layout
   is the only comparison construct on the site that is NOT the shared `.cmpgrid`
   (DOM-verified: /ai-visibility is its sole user — 6 `.cmp-vs` cells; index.html
   has zero). Its cells were all one flat 15px, while the anchor's `.cmpgrid`
   renders a three-step hierarchy. These are the anchor's MEASURED values:
   `.cmp-lbl` 17.5px/800 · `.cmp-us` 17px/700 · `.cmp-vs`(=`.cmp-them`) 15.5px/600.
   Padding is deliberately left at this block's own 22px 20px — the anchor's
   equivalent is 16px 12px and dropping to it would make a box Shane asked to be
   BIGGER smaller. Markup and layout are untouched: this is a type pass.
   🔴 KEPT AT BARE (0,1,0) ON PURPOSE — do not add `:not()`, `:is()` or any
   qualifier to raise these. shared.css declares the same properties at
   `.cmpgrid <cell-class>` (0,2,0); a (0,2,0) selector here would TIE it and win
   on source order (premium loads after shared), which flattens the anchor's
   responsive `clamp(15px,2.1vw,17.5px)` to a fixed 17.5px and moves
   /medical-tourism at 390px. Tried, measured, reverted. At (0,1,0) these rules
   are invisible to every `.cmpgrid` page and reach only the legacy table.
   Verified 0 changed pixels on the anchor (SC16). */
.cmp-lbl{font-size:17.5px;font-weight:800}
.cmp-us{font-size:17px;font-weight:700}
.cmp-vs{font-size:15.5px;font-weight:600}
.cmp-us .cmp-tick{
  display:block;width:22px;height:22px;margin:0 auto 10px;border-radius:50%;
  background:var(--mint);color:#fff;font-size:13px;font-weight:900;
  line-height:22px;text-align:center;
}
/* FIX 2026-08-01: position:relative + z-index:2 ensures the footer text renders
   above the absolutely-positioned .cmp-usbg card (z-index:0). Without this,
   static in-flow elements paint at step 3 while z-index:0 positioned elements
   paint at step 6, so the white card covered the footer text. */
.cmp-foot{grid-column:1 / -1;padding:20px 6px 0;font-size:13.5px;color:var(--muted);text-align:center;
  position:relative;z-index:2;}

@media (max-width:760px){
  .cmp-grid{grid-template-columns:1fr}
  .cmp-usbg{display:none}
  .cmp-head{display:none}
  /* 2026-09-05 (GAN iteration-002): scoped to the LEGACY .cmp-grid table.
     Unscoped, these five rules also matched the shared .cmpgrid component and
     out-ranked shared.css inside its own mobile block - the exact collision
     shared.css:916-934 documents, and a live SC18 failure once ai-visibility
     was converted from .cmp-grid to .cmpgrid. */
  .cmp-grid .cmp-lbl{border-top:2px solid var(--line);box-shadow:none;padding-bottom:6px;font-size:16px}
  .cmp-grid .cmp-us,.cmp-grid .cmp-vs{border-top:0;text-align:left;padding:6px 20px}
  .cmp-grid .cmp-us{background:var(--mint-soft);border-radius:var(--r-sm);margin:6px 12px;padding:14px 16px}
  .cmp-grid .cmp-us .cmp-tick{display:inline-block;margin:0 8px 0 0;vertical-align:-4px}
  .cmp-grid .cmp-vs::before{content:"เอเจนซี่ทั่วไป: ";font-weight:700;color:var(--ink)}
}

/* ============================================================
   3. BIG PHOTOGRAPHY
   ANGA's real numbers: hero image full-bleed at min-height 720px;
   body images shipped 1000x1000 (square) alternating L/R with the
   copy; case covers 340x140 at radius 10px; logos grayscale ->
   colour on hover at scale 1.2.
   Our failure mode was capped, small, decorative images.
   ============================================================ */
/* height mirrors min-height so height:100% on the child <img> resolves correctly on iOS Safari.
   Without explicit height, height:100% computes to auto (aspect-ratio intrinsic) on iOS,
   making the image cover only ~40% of the container. min-height still acts as the floor. */
.p-hero{position:relative;min-height:clamp(420px,52vw,720px);height:clamp(420px,52vw,720px);overflow:hidden;isolation:isolate}
/* height:100%!important beats glow3.css's .premium img{height:auto} (specificity 0,3,2 > 0,1,1).
   Without !important the glow3 catch-all wins, making the image render at its intrinsic aspect-ratio
   height (~40% of the container) and leaving a grey band below it on iOS and desktop. */
.p-hero>img{position:absolute;inset:0;width:100%;height:100%!important;object-fit:cover;object-position:top center;z-index:-2}
.p-hero::after{content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(180deg,rgba(10,20,35,.52) 0%,rgba(10,20,35,.28) 45%,rgba(10,20,35,.60) 100%)}
.p-hero .p-hero-in{position:relative;max-width:var(--wrap-max);margin:0 auto;padding:clamp(56px,9vw,120px) 20px;color:#fff}
.p-hero h1{color:#fff;text-shadow:0 4px 4px rgba(0,0,0,.25);letter-spacing:-.025em}

/* alternating square-image content blocks */
.p-split{max-width:var(--wrap-max);margin:0 auto;padding:var(--sec-y) 20px;
  display:grid;grid-template-columns:1fr 1fr;gap:clamp(28px,5vw,72px);align-items:center}
/* Alternation is an EXPLICIT class, not :nth-of-type — nth-of-type counts by tag
   across the whole page, so it flips unpredictably depending on how many other
   <section>s precede these. */
.p-split--rev .p-split-media{order:-1}
/* The ratio MUST live on the container, not the <img>.
   An HTML height attribute (e.g. height="1200") is a presentational hint that
   wins over `aspect-ratio` on the image itself — that is why these rendered
   546x1128 instead of square, dwarfing the copy beside them. */
.p-split-media{border-radius:var(--r-xl);overflow:hidden;box-shadow:var(--sh-lg);
  aspect-ratio:4/3;background:var(--card)}
.p-split-media img{display:block;width:100%;height:100%;object-fit:cover;
  transition:transform .5s var(--ease-anga)}
.p-split-media:hover img{transform:scale(1.05)}

/* Screenshots are evidence — never crop them. `contain` + padding shows the whole
   frame; `cover` would slice the top off a Maps profile or a probe result. */
.p-split-media--shot{background:var(--sky-soft);padding:18px}
.p-split-media--shot img{object-fit:contain;border-radius:10px}
.p-split-media--shot:hover img{transform:none}

/* Copy beside a big image needs its own box or it reads as a caption. */
.p-split-copy{background:var(--card);border-radius:var(--r-lg);padding:clamp(22px,3vw,34px);
  box-shadow:var(--sh-sm)}
.p-split-copy h3{margin-bottom:14px}
.p-split-copy p{font-size:clamp(15.5px,1.4vw,17px);line-height:1.8;color:var(--muted)}
.p-split h2,.p-split h3{font-size:clamp(26px,3.4vw,34px);margin-bottom:18px;line-height:1.25}
@media (max-width:820px){
  /* image always ABOVE the copy on mobile, regardless of desktop side */
  .p-split{grid-template-columns:1fr;padding:calc(var(--sec-y) * .72) 20px}
  .p-split--rev .p-split-media{order:-1}
}

/* full-bleed dark break section (ANGA: bg image + py-48) */
.p-break{position:relative;padding:var(--sec-y-lg) 20px;text-align:center;color:#fff;overflow:hidden;isolation:isolate}
/* same !important fix as .p-hero>img — same glow3 catch-all would otherwise win */
.p-break>img{position:absolute;inset:0;width:100%;height:100%!important;object-fit:cover;z-index:-2}
.p-break::after{content:"";position:absolute;inset:0;background:rgba(12,22,38,.66);z-index:-1}
.p-break h2{color:#fff;font-size:clamp(28px,4.4vw,50px);margin-bottom:26px}

/* logo strip: grayscale -> colour + grow on hover */
.p-logos img{
  height:40px;width:auto;filter:grayscale(1);opacity:.72;
  transition:transform var(--dur-hover) ease,filter var(--dur-hover) ease,opacity var(--dur-hover) ease;
}
.p-logos img:hover{filter:grayscale(0);opacity:1;transform:scale(1.2)}

/* ============================================================
   4. CARD + SECTION UPGRADES (applies to what we already ship)
   Deliberately scoped to .premium so nothing changes until a page
   opts in — this file is safe to deploy before it is adopted.
   ============================================================ */
.premium .card,.premium .mdcc-card,.premium .answer-block,.premium .entity-card{
  border-radius:var(--r-lg);box-shadow:var(--sh-sm)
}
.premium .mdcc-card{box-shadow:var(--sh-md)}
.premium section{padding-block:var(--sec-y)}
.premium .sec-title{text-align:center;font-size:clamp(28px,4vw,50px);line-height:1.2;margin-bottom:clamp(28px,4vw,52px)}

/* Entrance motion — duration shortened from motion.css's 1.15s to 1s.
   🔴 Do NOT re-declare opacity/transform here. motion.css owns those states and
   reveals via `.reveal.is-visible`. An earlier version of this file used
   `.reveal.in`, which meant `.premium` would have pinned every revealed element
   at opacity:0 forever — a blank site on all 24 pages. Duration only.
   NOTE: transition-timing-function is intentionally NOT overridden here.
   ease-anga (cubic-bezier(.4,.01,.165,.99)) kept opacity near-zero for the first
   700ms of a 1s transition, making reveals appear broken at any real scroll speed.
   ease-luxe from motion.css reaches 0.9 at ~430ms — premium feel, no invisible gap. */
.premium .reveal,
.premium .reveal-lg,
.premium .reveal-left,
.premium .reveal-right,
.premium .reveal-scale{
  transition-duration:1s!important;
}

/* ============================================================
   5. NAV DROPDOWN — keep it open while the mouse crosses the gap
   .nav-panel sits at top:calc(100% + 8px). That 8px of dead space
   drops :hover the moment you move toward the menu, so it vanishes.
   An invisible bridge spans the gap and keeps hover alive.
   ============================================================ */
.nav-group::after{
  content:"";position:absolute;left:-12px;right:-12px;top:100%;height:16px;
  display:none;
}
.nav-group:hover::after{display:block}
/* Widen the forgiving area around the whole group, and give the panel itself a
   generous invisible collar so a slightly-off mouse path doesn't close it. */
.nav-panel{margin-top:-2px;padding-top:calc(var(--np-pad,14px))!important}

/* ============================================================
   6. BOXES EVERYWHERE + the ring on all of them (Shane, 2026-08-01)
   Ring only — the ROTATION stays on the primary cards. 20+ elements
   each running their own 4s gradient animation is real jank on a
   mid-range Android, which is most of the Thai SMB audience.
   ============================================================ */
.boxed{
  position:relative;z-index:1;background:var(--card);
  border-radius:var(--r-lg);padding:clamp(20px,2.6vw,30px);
  box-shadow:var(--sh-sm);
}
.boxed::before{
  content:"";position:absolute;inset:-2px;z-index:-1;pointer-events:none;
  border-radius:calc(var(--r-lg) + 2px);
  background:linear-gradient(135deg,var(--sky) 0,rgba(24,184,122,0) 55%);
  padding:2px;
  -webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);
  -webkit-mask-composite:xor;
  mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);
  mask-composite:exclude;
  opacity:.85;
}
/* on hover the ring comes alive — the effect people notice, without 20 loops */
@media (min-width:1024px) and (prefers-reduced-motion:no-preference){
  .boxed:hover::before{animation:zipRotate 4s linear infinite;opacity:1}
}

/* ============================================================
   7. DEMO VIDEO — it was rendering 677px wide inside a 1265px page
   ============================================================ */
.demo-video{max-width:min(1080px,94vw)!important;margin-inline:auto}
.demo-video__wrap,.demo-video video,.demo-video__vid{width:100%!important;height:auto!important}
.demo-video__cap{font-size:clamp(15px,1.5vw,17px);line-height:1.7}
/* CLS 2026-08-11 — reserve the player's box BEFORE the mp4 header arrives.
   `height:auto` above means an empty <video> lays out at the UA default 300x150 and then
   jumps to its real height when metadata lands. chatgpt-demo.mp4 is 1280x690, so pin the
   ratio here and `height:auto` resolves from it at first layout instead. The <video> also
   carries width/height attributes for the same reason — belt and braces, because the
   `!important` width above overrides the UA's attr-derived ratio on its own. */
.demo-video__wrap,.demo-video__vid{aspect-ratio:1280/690}

/* ============================================================
   8. ANSWER BLOCKS — keep the AEO structure, drop the cheap badge
   Shane, 2026-08-01: "this part really look cheap … ANGA don't have
   any!!! but we need to do as structure seo geo aeo and ads".
   Both true. The AEO value is that the block answers the question
   FIRST in plain extractable prose — that is what ChatGPT/Perplexity/
   AI Overview lift. The little outlined pill contributes NOTHING to
   that: no schema, no heading, not a landmark. It is pure decoration
   and it is the part that reads cheap. So: pill goes, block stays.
   Do NOT "restore the label for SEO" — it never had any.
   ============================================================ */
.ab-label{
  /* stays in the DOM for screen readers and for anyone diffing the markup,
     but no longer paints the outlined chip */
  border:0!important;background:none!important;padding:0!important;
  color:var(--muted)!important;font-size:12px!important;letter-spacing:.10em!important;
  /* opacity:.62 REMOVED 2026-08-30 (s187). It composited --muted #5D6B84 to #9BA3B3
     on white = 2.54:1 at 12px — WCAG AA needs 4.5, so this chip was the WORST
     contrast on the site, worse than the #0D8A5A the same sweep was fixing.
     Measured alternatives: .80 -> 3.54, .85 -> 3.93, .90 -> 4.34, none clear it.
     Full opacity -> 5.38:1 PASS. The "pill goes, block stays" decision above is
     untouched: border/background/padding are still killed, only the fade is gone. */
  text-transform:uppercase;margin-bottom:10px!important;
}
/* the block itself becomes a proper premium card instead of a tinted strip.
   .answer-box: older class used on services + blog pages. Pages with their own
   inline .answer-box CSS (google-maps.html, etc.) keep their gradient — the
   inline <style> loads after shared CSS so their rule wins on those pages.
   On blog pages with no inline override, this provides the card background. */
.answer-block,
.answer-box{
  background:var(--card);border-radius:var(--r-lg);
  padding:clamp(22px,3vw,36px);box-shadow:var(--sh-sm);
  border-left:0!important;
}
.answer-block>p,
.answer-box>p{font-size:clamp(16px,1.5vw,17.5px);line-height:1.85}
/* CONFORMED TO THE ANCHOR — 2026-08-17. Shane: "every comparison box need same style
   every page use medical page as anchor". /medical-tourism's answer box renders
   border-radius 18px and font-weight 600; every other page rendered 22px / 400,
   because `var(--r-lg)` differs per page and nothing set the weight. Both values below
   are MEASURED off the anchor, not chosen.
   Specificity is `body.premium` (0,2,0) on purpose: the bare `.answer-box{border-radius:
   var(--radius)}` that ~14 pages declare in their own <style> block loads AFTER this
   file and would otherwise keep winning at (0,1,0). On the anchor itself both properties
   resolve to the SAME numbers it already computes (its --radius IS 18px and it declares
   font-weight:600 page-locally), so this is a no-op there — verified 0 changed pixels,
   desktop and mobile (SC16).
   🔴 `border-left:0!important` above is deliberately LEFT ALONE. The anchor renders a 1px
   left border because its page-local `border:1px solid var(--line)!important` outranks it,
   so SC19 reports a 24-row divergence. Closing it means deleting an explicit site-wide
   !important decision on ~20 pages, which is a Shane call, not a conformance sweep. */
body.premium .answer-block,
body.premium .answer-box{border-radius:18px;font-weight:600}

/* ============================================================
   9. SERVICES INDEX (/services) — ANGA /services/ structure
   Sticky pill tab bar + horizontal sliding card rail + arrows.
   ============================================================ */
.svc-hero{padding:clamp(44px,6vw,88px) 20px clamp(20px,3vw,34px);text-align:center}
.svc-h1{font-size:clamp(30px,5vw,56px);line-height:1.18;letter-spacing:-.025em;margin:0 auto 16px;max-width:16ch}
.svc-accent{color:var(--sky)}
.svc-sub{max-width:60ch;margin:0 auto;color:var(--muted);font-size:clamp(16px,1.6vw,18px);line-height:1.75}

/* pill tab bar — sticky under the header, like ANGA's */
.svc-tabs{position:sticky;top:62px;z-index:40;display:flex;justify-content:center;
  padding:14px 16px;background:linear-gradient(180deg,var(--bg) 62%,rgba(255,253,248,0))}
.svc-tabs-in{display:flex;gap:6px;padding:6px;border-radius:var(--r-pill);
  background:var(--card);box-shadow:var(--sh-sm);max-width:100%;overflow-x:auto;
  scrollbar-width:none}
.svc-tabs-in::-webkit-scrollbar{display:none}
.svc-tab{flex:none;border:0;cursor:pointer;white-space:nowrap;text-decoration:none;
  font-family:var(--font-body);font-size:14.5px;font-weight:700;color:var(--ink);
  background:none;padding:11px 20px;border-radius:var(--r-pill);
  transition:background var(--dur-hover) ease,color var(--dur-hover) ease}
.svc-tab:hover{background:var(--sky-soft)}
.svc-tab.is-on{background:var(--ink);color:#fff}

/* the rail */
.svc-rail-sec{padding:clamp(22px,3vw,40px) 0 clamp(34px,5vw,64px)}
.svc-rail-wrap{overflow:hidden}
.svc-rail{display:flex;gap:20px;overflow-x:auto;scroll-snap-type:x mandatory;
  padding:14px max(20px,calc((100vw - var(--wrap-max))/2)) 22px;
  scrollbar-width:none;-webkit-overflow-scrolling:touch}
.svc-rail::-webkit-scrollbar{display:none}
.svc-card{flex:0 0 clamp(260px,26vw,330px);scroll-snap-align:start;
  display:flex;flex-direction:column;padding:0!important;overflow:hidden}
.svc-media{aspect-ratio:16/10;overflow:hidden;background:var(--sky-soft)}
.svc-media img{width:100%;height:100%;object-fit:cover;display:block;
  transition:transform .5s var(--ease-anga)}
.svc-card:hover .svc-media img{transform:scale(1.05)}
.svc-title{font-size:19px;line-height:1.35;margin:18px 20px 8px;
  display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
.svc-price{font-family:var(--font-body);font-size:13px;font-weight:800;color:var(--mint);
  background:var(--mint-soft);border-radius:var(--r-pill);padding:3px 10px}
.svc-desc{margin:0 20px 18px;font-size:14.5px;line-height:1.75;color:var(--muted);flex:1}
.svc-cta{display:inline-flex;align-items:center;gap:7px;margin:0 20px 20px;
  align-self:flex-start;text-decoration:none;font-weight:800;font-size:14.5px;
  color:#fff;background:var(--sky);border-radius:var(--r-pill);padding:10px 18px;
  transition:transform var(--dur-hover) ease,background var(--dur-hover) ease}
.svc-cta:hover{transform:translateX(3px);background:var(--ink)}

.svc-nav{display:flex;justify-content:center;gap:12px;margin-top:6px}
.svc-arrow{width:46px;height:46px;border-radius:50%;cursor:pointer;
  border:1.5px solid var(--line);background:var(--card);color:var(--ink);
  font-size:24px;line-height:1;display:grid;place-items:center;
  box-shadow:var(--sh-xs);transition:all var(--dur-hover) ease}
.svc-arrow:hover{background:var(--ink);color:#fff;border-color:var(--ink)}

.svc-cta-band{text-align:center;padding:clamp(44px,6vw,88px) 20px;background:var(--sky-soft)}
.svc-cta-band h2{font-size:clamp(24px,3.4vw,40px);margin-bottom:12px}
.svc-cta-band p{max-width:56ch;margin:0 auto 24px;color:var(--muted);font-size:17px;line-height:1.75}

@media (max-width:900px){ .svc-tabs{top:58px} .svc-nav{display:none} }

/* ============================================================
   10. BOXED + GLOW-CARD COMBINED (v20260801g)
   When both classes appear on the same element, the ring should
   rotate like .glow-card. Without this override, .boxed::before
   hard-codes 135deg and the zipRotate animation changes --angle
   but the gradient ignores it.
   Usage: <div class="boxed glow-card">
   ============================================================ */
.boxed.glow-card::before{
  background:linear-gradient(var(--angle),var(--sky) 0,rgba(24,184,122,0) 50%);
  opacity:1;
}
@media(min-width:1024px){
  .boxed.glow-card::before{animation:zipRotate 4s linear infinite}
}
@media(prefers-reduced-motion:reduce){
  .boxed.glow-card,.boxed.glow-card::before{animation:none!important}
}

/* ============================================================
   11. TIER 2 — WARM AMBER GLOW SYSTEM (v20260801h)

   COLOUR SYSTEM — two tiers, two temperatures:

   TIER 1 — Zip AI's own boxes: rotating sky/mint ring (§1/§10)
     • Animated via zipRotate + zipGlowPulse on desktop
     • Targets: primary .skubox, .proof-card, .mdcc-card,
       demo-video containers, comparison "us" column
     • Max 1–2 animated rings per page (mobile perf ceiling)
     • Classes: .glow-card  /  .boxed.glow-card

   TIER 2 — every other card/panel: warm amber static
     • rgba(255,184,37) — earthy, warm, opposite temperature
       to Tier 1 → visual hierarchy reads at a glance
     • Implementation: outset box-shadow (3 layers) — never
       clipped by overflow:hidden (safe on .svc-card, .faq)
     • No animation, no will-change; hover brightens only
     • .glow-t2 utility class for per-page custom elements
     • CSS auto-targets common card types under .premium
       via :not(.glow-card) guard — elements promoted to
       Tier 1 are automatically excluded from Tier 2

   BOX-SHADOW FORMULA (3 layers):
     0 0 0 1.5px  rgba(255,184,37,.14)  crisp amber edge
     0 6px 32px   rgba(255,184,37,.07)  warm diffuse halo
     0 4px 50px   rgba(34,48,74,.07)    base premium depth
   ============================================================ */

/* ── Tier 2 box-shadow: owned by glow3.css (alpha raised to perceptual floor) ── */

/* ── Re-colour .boxed standalone ring to amber ───────────────
   §6 hardcodes sky/mint gradient. Any .boxed NOT also .glow-card
   gets the amber ring. Specificity 0,2,1 wins over §6 0,1,1.
   §6 hover still adds animation:zipRotate (changes --angle) but
   our gradient is fixed at 135deg so spin has no visible effect;
   only opacity strengthens on hover, which is the intent.       */
/* De-golded 2026-08-13 (ring retired — Shane: "i like the flat clean look").
   This painted the amber gradient ring on .boxed cards; it is the second of two
   page-visible gold sources that outlived the glow3.css retirement, and it is on
   /google-maps (.skubox, .step). Flattened to a hairline in the shared ink. */
.boxed:not(.glow-card)::before {
  background: rgba(10,10,10,.07);
  opacity: 1;
}
@media (min-width:1024px) and (prefers-reduced-motion:no-preference) {
  .boxed:not(.glow-card):hover::before {
    opacity: .90;
  }
}

/* ── !important override for bg-sage/bg-warm per-page rules ──
   google-maps.html has .sect.bg-sage .skubox{box-shadow:…!important}
   at spec 0,3,0. This block uses spec 0,4,0 + !important to restore
   the amber glow on any .glow-t2 element inside those tinted sections.
   Same approach covers any future page with the same inline pattern.  */
.sect.bg-sage .glow-t2:not(.glow-card),
.sect.bg-sage .step:not(.glow-card),
.sect.bg-warm .glow-t2:not(.glow-card) {
  /* RE-GOLDED 2026-08-13 (second pass) — must track glow3.css §2 exactly.
     This was the LAST de-golded remnant after the ring was restored: 29 of 30
     pages went gold and /google-maps kept 5 flat boxes, because this !important
     block at spec (0,4,0) silently outranks the shared file. Caught by ship.py
     ASSERT6 on the live deploy, not by reading CSS. */
  box-shadow:
    0 0 0 1.5px rgba(255,184,37,.22),
    0 1px 2px rgba(28,35,33,.04),
    0 8px 18px rgba(28,35,33,.035),
    0 26px 42px rgba(28,35,33,.022) !important;
}
/* the bloom needs the same !important treatment or these boxes never grow */
.sect.bg-sage .glow-t2.is-lit:not(.glow-card),
.sect.bg-sage .step.is-lit:not(.glow-card),
.sect.bg-warm .glow-t2.is-lit:not(.glow-card) {
  box-shadow:
    0 0 0 1.6px rgba(255,184,37,.62),
    0 10px 44px rgba(255,184,37,.34),
    0 8px 18px rgba(28,35,33,.035),
    0 26px 42px rgba(28,35,33,.022) !important;
}
@media (min-width:1024px) and (prefers-reduced-motion:no-preference) {
  .sect.bg-sage .glow-t2:not(.glow-card):hover,
  .sect.bg-sage .step:not(.glow-card):hover,
  .sect.bg-warm .glow-t2:not(.glow-card):hover {
    /* hover peak, tracks glow3.css §3 */
    box-shadow:
    0 0 0 2px rgba(255,184,37,.80),
    0 10px 44px rgba(255,184,37,.34),
    0 12px 26px rgba(28,35,33,.05),
    0 38px 60px rgba(28,35,33,.035) !important;
  }
}

/* ============================================================
   12. TIER 2 — AMBER BREATHING PULSE (v20260801i)
   The amber ring on non-Zip-AI boxes was static. Adding a slow
   grow/breathe via filter:drop-shadow — GPU-compositable, zero
   layout cost. Does NOT animate box-shadow (non-composited).
   Period 6s, low amplitude. Desktop + prefers-reduced-motion:no-preference only.
   Excludes .boxed (has ::before z-index:-1 that breaks under filter stacking context).
   Tier 1 (.glow-card) already has zipGlowPulse — excluded here.
   ============================================================ */
@keyframes zipAmberBreathe {
  0%,100% { filter: drop-shadow(0 4px 14px rgba(255,184,37,.00)) }
  50%     { filter: drop-shadow(0 6px 24px rgba(255,184,37,.13)) }
}
@media (min-width:1024px) and (prefers-reduced-motion:no-preference) {
  .premium .stat-tile:not(.glow-card):not(.boxed),
  .premium .mech-card:not(.glow-card):not(.boxed),
  .premium .step:not(.glow-card):not(.boxed),
  .premium .tcard:not(.glow-card):not(.boxed),
  .premium .svc:not(.glow-card):not(.boxed),
  .premium .svc-card:not(.glow-card):not(.boxed),
  .premium .answer-block:not(.glow-card):not(.boxed),
  .premium .stat:not(.glow-card):not(.boxed),
  .premium .ba-card:not(.glow-card):not(.boxed),
  .premium .p-split-copy:not(.glow-card):not(.boxed),
  .premium .stepcard:not(.glow-card):not(.boxed),
  .premium .price-card:not(.glow-card):not(.boxed),
  .premium .ctabox:not(.glow-card):not(.boxed),
  .premium .qcard:not(.glow-card):not(.boxed),
  .glow-t2:not(.glow-card):not(.boxed) {
    animation: zipAmberBreathe 6s ease-in-out infinite;
    will-change: filter;
    transform: translateZ(0);
  }
}
