/*
Theme Name: KPJ Little Heroes
Theme URI: https://kpjhealth.com.my/
Author: KPJ Healthcare
Description: Campaign portal theme for KPJ Healthcare. The site root lists live campaigns; each campaign gets its own page and URL. Ships the KPJ x Spider-Man "Little Heroes, Big Courage" paediatric campaign and the KPJ Cares Junior programme page, with content edited in inc/data-*.php.
Version: 1.8.0
Requires at least: 6.0
Tested up to: 6.7
Requires PHP: 7.4
License: Proprietary
Text Domain: kpj-little-heroes
*/

/* ==========================================================================
   Fonts
   ========================================================================== */
@font-face{font-family:Flexo;font-weight:300;font-display:swap;src:url("assets/fonts/Flexo-Light.woff2") format("woff2"),url("assets/fonts/Flexo-Light.woff") format("woff")}
@font-face{font-family:Flexo;font-weight:400;font-display:swap;src:url("assets/fonts/Flexo-Regular.woff2") format("woff2"),url("assets/fonts/Flexo-Regular.woff") format("woff")}
@font-face{font-family:Flexo;font-weight:500;font-display:swap;src:url("assets/fonts/Flexo-Medium.woff2") format("woff2"),url("assets/fonts/Flexo-Medium.woff") format("woff")}
@font-face{font-family:Flexo;font-weight:600;font-display:swap;src:url("assets/fonts/Flexo-Demi.woff2") format("woff2"),url("assets/fonts/Flexo-Demi.woff") format("woff")}
@font-face{font-family:Flexo;font-weight:700;font-display:swap;src:url("assets/fonts/Flexo-Bold.woff2") format("woff2"),url("assets/fonts/Flexo-Bold.woff") format("woff")}

:root{--font:Flexo,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial,sans-serif}
html{scroll-behavior:smooth}
body{margin:0;background:#eef1f5;font-family:var(--font);color:#1e293b}
a{color:#005088;text-decoration:none}a:hover{color:#e62117}

/* How far the WordPress admin bar pushes the document down. Consumed by
   assets/css/kpj-chrome.css to offset the fixed KPJ header, and by the Junior
   page's sticky sub-nav and anchor targets. Resolves to 0 for logged-out
   visitors, who never see the bar. */
body.admin-bar .kpjlh-page{--wp-admin-offset:32px}
@media screen and (max-width:782px){body.admin-bar .kpjlh-page{--wp-admin-offset:46px}}
/* Below 600px WordPress switches #wpadminbar to position:absolute, so it scrolls
   out of the way on its own. Offsetting a fixed header against it there would
   leave a permanent 46px gap under the admin bar instead. */
@media screen and (max-width:600px){body.admin-bar .kpjlh-page{--wp-admin-offset:0px}}

/* ==========================================================================
   Keyframes
   ========================================================================== */
@keyframes heroRise{from{opacity:0;transform:translateY(34px)}to{opacity:1;transform:translateY(0)}}
@keyframes cardIn{from{opacity:0;transform:rotate(6deg) translateY(50px) scale(.94)}to{opacity:1;transform:rotate(1.5deg) translateY(0) scale(1)}}
@keyframes drawWeb{from{stroke-dashoffset:300}to{stroke-dashoffset:0}}
@keyframes swaySlow{0%,100%{transform:rotate(-2.5deg)}50%{transform:rotate(2.5deg)}}
@keyframes pulseGlow{0%,100%{box-shadow:0 10px 24px rgba(37,211,102,.35)}50%{box-shadow:0 10px 34px rgba(37,211,102,.6)}}

/* container band matching the header content alignment */
.kpj-hdr-band{width:100%;max-width:none;margin-right:auto;margin-left:auto;padding-right:.75rem;padding-left:.75rem;box-sizing:border-box}
@media(min-width:576px){.kpj-hdr-band{max-width:540px}}
@media(min-width:768px){.kpj-hdr-band{max-width:720px}}
@media(min-width:992px){.kpj-hdr-band{max-width:960px}}
@media(min-width:1200px){.kpj-hdr-band{max-width:1140px}}
@media(min-width:1400px){.kpj-hdr-band{max-width:1320px}}

/* disable hero image parallax on mobile — prevents it drifting into the partnership section on scroll */
@media(max-width:768px){.hero-media{transform:none!important}}

/* ==========================================================================
   Spidey-Senses cards: 2x5 mobile / 5x2 desktop grid
   ========================================================================== */
.spidey-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:14px}
@media(min-width:768px){.spidey-grid{grid-template-columns:repeat(5,1fr);gap:16px}}
.ss-card{position:relative;overflow:hidden;background:#fff;border:2.5px solid #001f3f;border-radius:10px;box-shadow:5px 5px 0 #001f3f;padding:22px 12px;text-align:center;color:#001f3f;display:flex;flex-direction:column;gap:12px;align-items:center;transition:border-color .25s,box-shadow .25s,transform .25s}
.ss-badge{position:relative;width:46px;height:46px;display:grid;place-items:center}
.ss-badge .ic{width:46px;height:46px;border-radius:50%;background:#e62117;color:#fff;border:2px solid #001f3f;display:grid;place-items:center;font-size:18px;z-index:1;transition:box-shadow .25s}
.corner-web{position:absolute;top:0;left:0;width:78px;height:78px;pointer-events:none;opacity:.16;z-index:0;background:no-repeat center/contain;background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40'><g fill='none' stroke='%23334155' stroke-width='1.3'><line x1='0' y1='0' x2='40' y2='0'/><line x1='0' y1='0' x2='37' y2='15'/><line x1='0' y1='0' x2='28' y2='28'/><line x1='0' y1='0' x2='15' y2='37'/><line x1='0' y1='0' x2='0' y2='40'/><path d='M12 0 Q11 6 10 5 Q6 10 0 12'/><path d='M24 0 Q21 10 17 17 Q10 21 0 24'/><path d='M36 0 Q31 14 25 25 Q14 31 0 36'/></g></svg>")}

/* ==========================================================================
   Merch grid
   ========================================================================== */
.merch-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:16px}
.merch-grid>div{grid-column:span 2}
.merch-grid>div:nth-child(4){grid-column:2 / span 2}
.merch-grid>div:nth-child(5){grid-column:4 / span 2}
@media(max-width:640px){.merch-grid{grid-template-columns:1fr}.merch-grid>div,.merch-grid>div:nth-child(4),.merch-grid>div:nth-child(5){grid-column:auto}}
.merch-tile{position:relative;box-sizing:border-box;height:176px;padding:12px;border:1px solid #dbe7f6;border-radius:14px;background:radial-gradient(120% 120% at 50% 18%,#f4f8fe 0%,#eaf1fb 55%,#dbe7f6 100%);display:flex;align-items:center;justify-content:center;overflow:hidden}
.merch-tile::before{content:"";position:absolute;inset:0;background-image:radial-gradient(circle at 88% 12%,rgba(0,31,63,.06) 0 1px,transparent 1px);background-size:14px 14px;opacity:.5;pointer-events:none}
.merch-tile img{position:relative;z-index:1}
/* width:auto/height:auto on the rules below neutralise the <img> width/height
   presentational hints, which would otherwise beat max-width/max-height and
   stretch the artwork vertically. */
.merch-badge{width:124px;height:124px;border-radius:50%;object-fit:cover;box-shadow:0 8px 18px rgba(0,31,63,.28),0 0 0 4px #fff,0 0 0 5px rgba(0,31,63,.08)}
.merch-book{max-width:88%;max-height:78%;width:auto;height:auto;border-radius:6px;box-shadow:0 12px 20px rgba(0,31,63,.26);transform:rotate(-2.2deg)}
.merch-tote{max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain;filter:drop-shadow(0 12px 16px rgba(0,31,63,.24))}
.merch-gsc-chip{position:relative;z-index:1;box-sizing:border-box;width:100%;padding:14px 12px;background:#fff;border:1px solid #dbe7f6;border-radius:12px;display:grid;place-items:center;box-shadow:0 10px 20px rgba(0,31,63,.14)}
.merch-gsc{max-width:100%;height:auto;display:block}
.merch-sticker{max-width:84%;max-height:90%;width:auto;height:auto;object-fit:contain;border-radius:8px;box-shadow:0 12px 20px rgba(0,31,63,.24)}

/* ==========================================================================
   Doctors: mobile swipe carousel
   ========================================================================== */
.doc-swipe-hint{display:none;justify-content:center;align-items:center;gap:8px;margin-top:16px;color:#94a3b8;font:700 11px var(--font);text-transform:uppercase;letter-spacing:1.5px}
.doc-cta-mobile{display:none}
.doc-swipe-hint .l{animation:swipeHintL 1.6s ease-in-out infinite}
.doc-swipe-hint .r{animation:swipeHintR 1.6s ease-in-out infinite}
@keyframes swipeHintL{0%,100%{transform:translateX(0);opacity:.5}50%{transform:translateX(-4px);opacity:1}}
@keyframes swipeHintR{0%,100%{transform:translateX(0);opacity:.5}50%{transform:translateX(4px);opacity:1}}
@media(prefers-reduced-motion:reduce){.doc-swipe-hint .l,.doc-swipe-hint .r{animation:none}}
@media(max-width:640px){#docGrid{display:flex!important;gap:12px!important;overflow-x:auto;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;padding-inline:7.5%;scrollbar-width:none}#docGrid::-webkit-scrollbar{display:none}#docGrid>[data-doc-card]{flex:0 0 85%;scroll-snap-align:center}.doc-swipe-hint{display:flex}.doc-cta-desktop{display:none}.doc-cta-mobile{display:block}}

/* Cards hidden by the region filter / 8-card cap */
[data-doc-card][hidden]{display:none!important}

/* ==========================================================================
   Poster coverflow (Partnership)
   ========================================================================== */
.pf-stage{position:relative;width:min(100%,300px);height:400px;perspective:1500px;margin:0 auto}
.pf-card{position:absolute;top:50%;left:50%;width:190px;border-radius:16px;overflow:hidden;box-shadow:0 30px 60px rgba(0,0,0,.6),0 0 0 1px rgba(255,255,255,.14);transition:transform .6s cubic-bezier(.3,0,.15,1),opacity .6s,filter .6s;will-change:transform;background:#0a0e1a;cursor:pointer}
/* height:auto is required — the width/height attributes on the <img> are
   presentational hints, and without this the height hint wins over aspect-ratio
   and the card renders at the file's own ratio instead of 2:3. */
.pf-card>img{display:block;width:100%;height:auto;aspect-ratio:2/3;object-fit:cover}
.pf-dots{display:flex;gap:8px;justify-content:center}
.pf-dots button{width:8px;height:8px;padding:0;border:none;border-radius:50%;background:rgba(255,255,255,.28);cursor:pointer;transition:all .3s}
.pf-dots button.on{background:#e62117;width:22px;border-radius:4px}

/* ==========================================================================
   Packages crossfade
   ========================================================================== */
.pkg-xf{position:relative}
.pkg-slide{position:absolute;inset:0;opacity:0;transition:opacity 1.1s ease}
.pkg-slide.on{opacity:1}
.pkg-slide img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.pkg-grad{position:absolute;inset:0;background:linear-gradient(180deg,rgba(0,20,40,0) 55%,rgba(0,20,40,.86) 100%)}
.pkg-name{position:absolute;left:16px;right:16px;bottom:13px;color:#fff;font:700 15px var(--font);z-index:2}
@media(prefers-reduced-motion:reduce){.pkg-slide{transition:none}}

/* ==========================================================================
   Hover states
   Ported from the `style-hover` attributes the original dc runtime synthesised
   into inline rules. Keep these in sync with the markup classes.
   ========================================================================== */
.ss-card:hover{transform:translateY(-3px)}
.kpjlh-doc-card:hover{box-shadow:0 16px 32px rgba(0,31,63,.1);transform:translateY(-3px)}
.kpjlh-wa:hover{background:#20BA5A;color:#fff}
.kpjlh-wa-lift:hover{background:#20BA5A;color:#fff;transform:translateY(-2px)}
.kpjlh-outline-btn:hover{background:#005088;color:#fff}
.kpjlh-red-btn:hover{background:#c81a10;color:#fff;transform:translateY(-2px)}
.kpjlh-foyer-row:hover{box-shadow:0 8px 20px rgba(0,31,63,.08)}
.kpjlh-faq-toggle:hover{background:#f8fafc}

/* FAQ answer panel — the original mounted/unmounted it; here it is toggled. */
.kpjlh-faq-answer{display:none;padding:14px 20px 16px;font-size:13px;line-height:1.65;color:#475569;border-top:1px solid #f1f5f9}
.kpjlh-faq-item.is-open .kpjlh-faq-answer{display:block}
.kpjlh-faq-item.is-open .kpjlh-faq-chevron{transform:rotate(180deg)}
.kpjlh-faq-chevron{font-size:12px;color:#94a3b8;transition:transform .25s}

/* Region tabs — active state replaces the runtime's computed style object */
.kpjlh-tab{border:1px solid #e2e8f0;cursor:pointer;padding:9px 18px;border-radius:99px;font:700 11px var(--font);text-transform:uppercase;letter-spacing:1px;transition:all .2s;background:#fff;color:#475569}
.kpjlh-tab.is-active{background:#e62117;color:#fff;border-color:#e62117;box-shadow:0 6px 14px rgba(230,33,23,.3)}

/* Foyer groups — only the selected region's venues are shown */
.kpjlh-foyer-group[hidden],.kpjlh-foyer-empty[hidden]{display:none!important}

/* ==========================================================================
   Portal home (site root) — the campaign index
   ========================================================================== */
/* --kpj-bg-grey from kpj-chrome.js, the standard KPJ page background. */
.kpjlh-portal{background:#f3f5f7;min-height:60vh;display:flex;align-items:center;padding:clamp(48px,9vw,110px) clamp(16px,4vw,48px)}
.kpjlh-portal-inner{max-width:960px;margin:0 auto;width:100%;text-align:center;display:flex;flex-direction:column;gap:16px;align-items:center}
.kpjlh-portal-eyebrow{display:inline-flex;align-items:center;gap:8px;background:rgba(230,33,23,.1);color:#c81a10;font:700 11px var(--font);letter-spacing:1.5px;padding:7px 14px;border-radius:99px;text-transform:uppercase}
.kpjlh-portal-title{margin:0;font:800 clamp(30px,4.4vw,52px)/1.08 var(--font);color:#001f3f;letter-spacing:-1px}
.kpjlh-portal-lede{margin:0;max-width:560px;color:#475569;font-size:clamp(14px,1.5vw,17px);line-height:1.65;text-wrap:pretty}
.kpjlh-portal-empty{margin:24px 0 0;color:#94a3b8;font-size:14px}

.kpjlh-portal-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr));gap:18px;width:100%;margin-top:22px}
.kpjlh-portal-card{display:flex;flex-direction:column;text-align:left;background:#fff;border:1px solid #e2e8f0;border-radius:18px;overflow:hidden;transition:transform .25s,box-shadow .25s,border-color .25s}
.kpjlh-portal-card:hover{border-color:#cbd5e1;transform:translateY(-3px);box-shadow:0 16px 32px rgba(0,31,63,.1)}
.kpjlh-portal-thumb{display:block;line-height:0}
.kpjlh-portal-thumb img{display:block;width:100%;height:auto;aspect-ratio:16/9;object-fit:cover}
.kpjlh-portal-card-body{display:flex;flex-direction:column;gap:8px;padding:20px}
.kpjlh-portal-card-title{font:700 17px var(--font);color:#001f3f}
.kpjlh-portal-card-desc{font-size:13px;line-height:1.6;color:#64748b}
.kpjlh-portal-card-cta{margin-top:4px;font:700 12px var(--font);color:#e62117;text-transform:uppercase;letter-spacing:1px;display:inline-flex;align-items:center;gap:7px}
.kpjlh-portal-card:hover .kpjlh-portal-card-cta{color:#005088}

.kpjlh-portal-foot{margin:28px 0 0;font-size:13px;color:#475569}
.kpjlh-portal-foot a{color:#005088;border-bottom:1px solid rgba(0,80,136,.35);padding-bottom:1px}
.kpjlh-portal-foot a:hover{color:#e62117;border-bottom-color:#e62117}
.kpjlh-portal-foot i{font-size:10px;margin-left:3px}

@media(prefers-reduced-motion:reduce){.kpjlh-portal-card{transition:none}.kpjlh-portal-card:hover{transform:none}}

/* ==========================================================================
   Cross-link to the KPJ Cares Junior page.

   The mirror of the .jr-lh-tab that page carries back here, deliberately
   identical in geometry and structure — motif, vertical label, arrow — so the
   two read as a pair. Each tab wears the destination campaign's colour: that
   one is Spider-Man red with a web motif, this one is Junior teal with a star.

   #0f6e6b is the Junior teal-ink, not the brand teal #32b6b2: white on the
   brand teal is 2.48:1, which an 11px label cannot use. This is 6.06:1, and
   #147f7b on hover is 4.83:1 — both a shade better than the red tab they
   mirror (5.82:1 / 4.57:1).

   z-index 70 is deliberate and matches its counterpart: the chrome header is
   9999 and the bottom nav 3, so this sits above page content but can never
   cover the KPJ chrome.
   ========================================================================== */
/* right:-4px + 4px extra right padding bleed the element itself past the screen
   edge, so the extreme edge pixels — the natural place to click or tap an
   edge-flush target — always land on the anchor. Hover changes colour only:
   an earlier hover slide moved the tab out from under a cursor parked at the
   edge and swallowed the first click, so nothing moves on hover any more. */
.kpjlh-cj-tab{position:fixed;right:-4px;top:50%;translate:0 -50%;z-index:70;
  display:flex;flex-direction:column;align-items:center;gap:8px;
  padding:15px 11px 15px 7px;border-radius:10px 0 0 10px;
  background:#0f6e6b;color:#fff;
  box-shadow:-3px 0 14px rgba(0,31,63,.26);
  transition:background .2s ease;
  /* Clips the sheen to the rounded shape; the focus ring uses a negative offset
     so it is drawn inside and survives the clip. */
  overflow:hidden}
.kpjlh-cj-tab:hover{background:#147f7b;color:#fff}
.kpjlh-cj-tab:focus-visible{outline:3px solid #fff;outline-offset:-6px}

/* Plain white on the teal fill, matching the red tab it mirrors. The logo's own
   letter colours cannot sit directly on the teal — they measure 1.96–3.31:1
   there — which is why an earlier revision put the label on a white plate; the
   plate is gone, so the wordmark is white (6.06:1 at rest, 4.83:1 on hover). */
.kpjlh-cj-tab-label{writing-mode:vertical-rl;transform:rotate(180deg);
  font:700 11px var(--font);letter-spacing:1px;text-transform:uppercase;white-space:nowrap;
  display:inline-flex;align-items:center;gap:4px}
.kpjlh-cj-tab-junior i{font-style:normal}
/* Real inline SVGs, not <use> shadow trees, so document CSS reaches them and
   currentColor tracks the hover state. */
.kpjlh-cj-tab-star{width:15px;height:15px;flex:none;fill:currentColor;opacity:.85}
.kpjlh-cj-tab-arrow{width:13px;height:13px;flex:none;fill:none;stroke:currentColor;
  stroke-width:2;stroke-linecap:round;stroke-linejoin:round}

/* A light band passes down the face. Three passes, then it settles. At rest the
   band parks below the visible area, so it shows nothing at all when animation
   is off. */
.kpjlh-cj-tab::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,transparent 40%,rgba(255,255,255,.5) 50%,transparent 60%);
  background-size:100% 300%;background-position:0 130%;
  animation:kpjlhCjSheen 4.5s ease-in-out 3}
@keyframes kpjlhCjSheen{0%,70%{background-position:0 130%}100%{background-position:0 -30%}}

/* Narrower on small screens, where it shares the edge with the chrome's fixed
   bottom nav — the same treatment .jr-lh-tab uses on its own page. At 25px the
   strip only grazes the trailing edge of the widest lines; the 48px logo tab
   this replaced covered whole words, which is why it had to become a floating
   badge instead. */
@media(max-width:730px){
  .kpjlh-cj-tab{padding:13px 9px 13px 5px;gap:6px}
  .kpjlh-cj-tab-arrow{display:none}
}
/* The universal selector does not match pseudo-elements, so a blanket
   *{animation:none} would leave this running for anyone who asked it not to. */
@media(prefers-reduced-motion:reduce){
  .kpjlh-cj-tab{transition:none}
  .kpjlh-cj-tab::after{animation:none}
}
