/* ================================================================
   JOHN PAUL COLLEGE INTERNATIONAL — SHARED SITE STYLESHEET
   ================================================================
   One stylesheet, loaded once, shared by every page (home.html,
   psp.html, and any future page) plus the navigation and footer
   partials. This replaces having each page carry its own full copy
   of the same ~1,400 lines of CSS — that duplication was the main
   cause of page bloat and slow loads.

   DEPLOYMENT (SharePoint on-premises):
   Upload this file to the site's Style Library or Site Assets
   library, then reference it from the master page (or from each
   page, until the master page is wired up) with:
     <link rel="stylesheet" href="/sites/YOURSITE/SiteAssets/css/jpic-shared.css">
   Update the href to match wherever it actually lands.

   WHAT LIVES HERE vs WHAT STAYS PER-PAGE:
   - Brand tokens, base typography, buttons, icons, and every
     reusable km- and y- prefixed component (hero shell, why-cards,
     journey pathway, stats, campus, stories, safe, accordion,
     contact, video modal, final CTA) — all shared, defined below.
   - Navigation rail (.jpicnav-*) and footer (.jpic-footer/.jf-*)
     — shared, defined once below.
   - Anything page-specific (e.g. home's "30 years" hero watermark,
     or psp's .psp-* section styles) stays in that page's own
     <style> block, since it's used nowhere else.
   ================================================================ */

/* === BEGIN self-hosted fonts (generated by tools/build-local-fonts.py) === */
/* Downloaded from Google Fonts, SIL Open Font License.
   Self-hosted so there is no third-party request: @import cost a chained
   round trip, and fonts.googleapis.com is blocked in mainland China, which
   stalled every /Zh-Hans/ and /Zh-Hant/ page.
   Re-run tools/build-local-fonts.py to change weights or scripts. */
@font-face{font-family:'Noto Sans Thai';font-style:normal;font-weight:300 800;font-display:swap;src:url('../font/google/noto-sans-thai-thai.woff2?v=1f5a1736') format('woff2');unicode-range:U+02D7, U+0303, U+0331, U+0E01-0E5B, U+200C-200D, U+25CC;}
@font-face{font-family:'Raleway';font-style:italic;font-weight:300 800;font-display:swap;src:url('../font/google/raleway-vietnamese-italic.woff2?v=80de52ae') format('woff2');unicode-range:U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}
@font-face{font-family:'Raleway';font-style:italic;font-weight:300 800;font-display:swap;src:url('../font/google/raleway-latin-ext-italic.woff2?v=263c505d') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'Raleway';font-style:italic;font-weight:300 800;font-display:swap;src:url('../font/google/raleway-latin-italic.woff2?v=8c08eb8b') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'Raleway';font-style:normal;font-weight:300 800;font-display:swap;src:url('../font/google/raleway-vietnamese.woff2?v=49d1df38') format('woff2');unicode-range:U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}
@font-face{font-family:'Raleway';font-style:normal;font-weight:300 800;font-display:swap;src:url('../font/google/raleway-latin-ext.woff2?v=2d603982') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'Raleway';font-style:normal;font-weight:300 800;font-display:swap;src:url('../font/google/raleway-latin.woff2?v=b1bef1f0') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'Roboto';font-style:normal;font-weight:300 700;font-display:swap;src:url('../font/google/roboto-vietnamese.woff2?v=0b60bbe0') format('woff2');unicode-range:U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}
@font-face{font-family:'Roboto';font-style:normal;font-weight:300 700;font-display:swap;src:url('../font/google/roboto-latin-ext.woff2?v=cedb374b') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'Roboto';font-style:normal;font-weight:300 700;font-display:swap;src:url('../font/google/roboto-latin.woff2?v=1404ca34') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
/* === END self-hosted fonts === */

:root{
  /* ---- Brand colour tokens (single source of truth) ---- */
  --jpic-blue:#004990; --jpic-blue-dark:#003366; --jpic-blue-light:#3a7cc6;
  --jpic-red:#ED1B2E; --jpic-gold:#4980C1; --jpic-gold-dark:#4980C1;
  --jpic-burgundy:#880D27; --jpic-burgundy-dark:#6b0a1f; --jpic-burgundy-lite:#b23a52;
  --jpic-soft:#fbf1f3;
  --white:#ffffff; --off-white:#f5f7fa;
  --grey-100:#edf0f5; --grey-200:#dce1e8; --grey-500:#6b7a8d;
  --grey-600:#4f5b6b; --grey-700:#3a4553; --grey-900:#1a2230;

  /* ---- Type tokens ---- */
  --km-display:'Raleway',sans-serif; --km-body:'Roboto',sans-serif;
}

/* ---- SharePoint chrome suppression (safe on every page) ---- */

/* Remove the browser-default 8px body margin so the full-bleed hero sits flush
   to the viewport edges (SharePoint already resets this; this keeps standalone
   previews and any un-reset context consistent, and makes the hero+quick-nav
   fill exactly one screen). */
html,body{margin:0;}


/* ================================================================
   PAGE COMPONENT LIBRARY — shared across home.html, psp.html, etc.
   ================================================================ */
  
  /* ---------- ICONS (SVG jp-icon, sized via width/height) ---------- */
.jp-icon{width:22px;height:22px;flex-shrink:0;display:inline-block;vertical-align:middle;}
.jp-icon-sm{width:16px;height:16px;}



  /* ---------- ICON-FONT SIZE SCALE (icon-font glyphs, sized via font-size) ----------
     Apply directly to the <i class="icon-..."> element — e.g.
     <i class="icon-default-heart icon-med"></i> — instead of writing a
     new CSS rule every time an icon needs a size. !important is
     intentional: several pages have a blanket `[class^="icon-"]{font-size:1em}`
     rule (inherit size from a sized wrapper div) that is more specific
     than a single class and would otherwise silently win. These utility
     classes are meant to always be the definitive size when used. */
.icon-x-small{font-size:20px !important;line-height:1;}
.icon-small{font-size:25px !important;line-height:1;}
.icon-med{font-size:35px !important;line-height:1;}
.icon-large{font-size:45px !important;line-height:1;}
.icon-x-large{font-size:55px !important;line-height:1;}
.icon-xx-large{font-size:65px !important;line-height:1;}

/****** SUPPORT TEXT ****/






/* ============================================================
   TEXT SHINE  —  animated metallic-gradient headline effect
   ------------------------------------------------------------
   A bright band sweeps slowly across a gradient that is clipped
   to the text. First built for the PSP hero ("A Confident Start").
   Wrap the words you want to shine in a span (or apply to a
   heading) and add .jp-shine plus one colour variant:

     <span class="jp-shine">A Confident Start</span>
     <span class="jp-shine jp-shine-blue">Study in Australia</span>

   • Designed for DARK / photo backgrounds. On LIGHT backgrounds
     use the deeper -royal / -ember variants (readable on white).
   • Colours are driven by --jp-shine-1..6 custom props, so you can
     recolour inline without a new class if you ever need to.
   • Speed via .jp-shine-slow / .jp-shine-fast; freeze with
     .jp-shine-still. Honours prefers-reduced-motion automatically.
   • Pair with your own font-size/weight (it only paints the fill).
   ============================================================ */
.jp-shine{
  /* default = brand GOLD on dark */
  --jp-shine-1:#4980C1;                    /* deep edge     */
  --jp-shine-2:#4980C1;                    /* warm mid      */
  --jp-shine-3:#ffffff;                    /* hot highlight */
  --jp-shine-4:#4980C1;
  --jp-shine-5:var(--jpic-gold,#4980C1);
  --jp-shine-6:var(--jpic-gold-dark,#4980C1);
  --jp-shine-glow:rgba(0,0,0,.42);         /* legibility halo on photos */
  --jp-shine-speed:6.5s;
  background:linear-gradient(100deg,
    var(--jp-shine-1) 0%, var(--jp-shine-2) 22%, var(--jp-shine-3) 35%,
    var(--jp-shine-4) 48%, var(--jp-shine-5) 68%, var(--jp-shine-6) 100%);
  background-size:220% 100%;
  -webkit-background-clip:text; background-clip:text;
  -webkit-text-fill-color:transparent; color:transparent;
  text-shadow:none;                        /* text-shadow can't render on clipped text */
  filter:drop-shadow(0 3px 16px var(--jp-shine-glow));
  background-position:38% 0;   /* (was jpShineSweep … infinite: build-m1.js – now only on hover, below) */
}
@media (hover:hover) and (prefers-reduced-motion:no-preference){
  :hover > .jp-shine:not(.jp-shine-still), .jp-shine:not(.jp-shine-still):hover{
    animation:jpShineHover var(--jp-shine-speed) ease-in-out 1 both;
  }
}
@keyframes jpShineHover{
  0%{background-position:38% 0;}
  35%{background-position:118% 0;}
  75%{background-position:-18% 0;}
  100%{background-position:38% 0;}
}
@keyframes jpShineSweep{
  0%,100%{background-position:118% 0;}
  50%    {background-position:-18% 0;}
}

/* ---- Colour variants (for DARK / photo backgrounds) ---- */







/* ---- Colour variants tuned for LIGHT backgrounds (readable on white) ---- */



/* ---- Motion helpers ---- */


.jp-shine-still{animation:none; background-position:38% 0;}

@media (prefers-reduced-motion:reduce){
  .jp-shine{animation:none; background-position:38% 0;}
}

small { font-family: var(--km-body,'Roboto',sans-serif); }  /* was 'Lato' - never imported */

.uppercase {text-transform: uppercase !important;}





















.small-print {	font-size: 70%;}







/*JPIC*/
























  /* ---------- HERO ---------- */
/* Hero height = one screenful minus the quick-nav bar, so on load the hero +
   the sticky quick-nav together fill exactly one viewport and the nav's bottom
   edge rests on the bottom of the screen. dvh (with a vh fallback) makes iOS
   Safari measure the *visible* viewport, not the larger toolbar-hidden one.
   --qn-h is the bar height (64 desktop / 58 mobile); +1 covers its border. */
.km-hero{position:relative;
  min-height:calc(100vh - var(--qn-h) - 1px);
  min-height:calc(100dvh - var(--qn-h) - 1px);
  display:flex;align-items:center;overflow:hidden;
  background:var(--jpic-blue-dark);}
/* On <1024px the fixed mobile top bar (60px) also sits in the viewport, so
   subtract it too, keeping the nav's bottom on the screen edge. */
@media (max-width:1023px){
  .km-hero{
    min-height:calc(100vh - 60px - var(--qn-h) - 1px);
    min-height:calc(100dvh - 60px - var(--qn-h) - 1px);}
}
.km-hero-media{position:absolute;inset:0;z-index:0;overflow:hidden;}
.km-hero-img{width:100%;height:100%;object-fit:cover;animation:kmKenBurns 22s ease-in-out infinite alternate;}
@keyframes kmKenBurns{from{transform:scale(1);}to{transform:scale(1.12);}}
.km-hero-overlay{position:absolute;inset:0;z-index:1;
  background:
    linear-gradient(0deg, rgba(8,14,26,.94) 0%, rgba(8,14,26,.62) 30%, rgba(8,14,26,.14) 58%, rgba(8,14,26,0) 72%),
    linear-gradient(110deg, rgba(110,27,43,.4) 0%, rgba(0,73,144,.32) 50%, rgba(0,73,144,.05) 100%);}
.km-hero-inner{position:relative;z-index:2;max-width:1200px;margin:0 auto;padding:150px 32px 90px;width:100%;}
/* On short viewports (landscape tablets/phones, short desktop windows) the
   hero's tall vertical padding pushed the sticky quick-nav past the fold and
   clipped it. Trim the padding there so the quick-nav clears under the hero. */
@media (max-height:900px){
  .km-hero-inner{padding-top:104px;padding-bottom:56px;}
}
@media (max-height:740px){
  .km-hero-inner{padding-top:88px;padding-bottom:44px;}
}
.km-hero-title{font-family:var(--km-display);font-weight:800;color:#fff;
  font-size:clamp(34px,5.4vw,64px);line-height:1.08;margin:0 0 16px;max-width:820px;
  letter-spacing:-.01em;text-shadow:0 2px 20px rgba(0,0,0,.5),0 1px 4px rgba(0,0,0,.4);}
.km-hero-tagline{font-family:var(--km-display);font-weight:700;font-style:italic;color:var(--jpic-gold);
  font-size:clamp(18px,2.4vw,26px);margin:0 0 16px;}
.km-hero-pathway{color:rgba(255,255,255,.92);font-size:clamp(14px,1.5vw,18px);font-weight:500;margin:0 0 28px;}

.km-hero-pillars li:not(:first-child)::before{content:'';display:inline-block;width:1px;height:14px;
  background:rgba(255,255,255,.4);margin-right:10px;vertical-align:middle;}
.km-hero-buttons{display:flex;flex-wrap:wrap;gap:14px;}

/* ================================================================
   ALUMNI / FEATURE STORY HERO — shared "look & feel"
   Opt-in components used by the alumni-*.html story pages. Add
   `km-hero-story` to the <section class="km-hero"> to get the refined
   scrim, toned line-draw and lifted secondary CTA; use .km-hero-back,
   .km-hero-meta (+ flag/sep) and .km-hero-lede inside .km-hero-copy.
   ================================================================ */






/* unified kicker — replaces the old pill + flag-chip + loose-text tagline */





/* story-hero polish: cleaner left scrim, subtle line-draw + visible icon, lifted CTA */





/* !important for the same reason as .km-btn-outline-light:hover below — see the note there. */



  .km-page {
    font-family: var(--km-body);
    color: var(--grey-700);
    line-height: 1.6;
    box-sizing: border-box;
    -webkit-font-smoothing: antialiased;
  }
  .km-page * {
    box-sizing: border-box;
  }
  .km-inner {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 32px;
  }
  .km-center {
    text-align: center;
    margin-bottom: 48px;
  }
  .km-label {
    display: inline-block;
    font-family: var(--km-display);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 3px;
    text-transform: uppercase;
    color: var(--jpic-blue);
    margin-bottom: 16px;
    padding-left: 36px;
    position: relative;
  }
  .km-label::before {
    content: "";
    position: absolute;
    left: 0;
    top: 50%;
    width: 24px;
    height: 2px;
    background: var(--jpic-gold);
    transform: translateY(-50%);
  }
  
  .km-center .km-label {
    padding-left: 0;
  }
  .km-center .km-label::before {
    left: 50%;
    transform: translate(-50%, -50%);
    top: -12px;
  }
  .km-h2 {
    font-family: var(--km-display);
    font-weight: 800;
    font-size: clamp(28px, 3.2vw, 40px);
    line-height: 1.18;
    color: var(--jpic-blue);
    margin: 0 0 18px;
  }
  .km-h2-sm {
    font-size: clamp(24px, 2.4vw, 30px);
  }
  .km-lead {
    font-size: 16px;
    line-height: 1.75;
    color: var(--grey-700);
    margin: 0 0 28px;
  }
  /* NOTE: the bare `a:visited` that used to sit in this list was REMOVED on
     2026-08-22. With `color: inherit` applied to it, every visited link on the site
     took the body text colour and lost its underline — so a link a reader had
     already followed became almost invisible, and its appearance changed depending
     on browsing history. The component selectors below genuinely do want to inherit
     (they are whole-card and whole-step links, where the <a> must not restyle the
     text inside it); a global `a:visited` never did. */
  

  /* ═══════════════════════ LINKS — NO UNDERLINES ═══════════════════════
     Adam, 2026-08-22: no link on this site carries an underline.

     THE BASELINE BELOW IS THE HALF THAT PAGE STYLES COULD NOT FIX. There was no
     bare element rule for `a` in this stylesheet at all, so any link that no rule
     happened to style fell through to the browser's own default — underlined, and
     #0000EE blue. That was most links on the site, and it is why underlines kept
     reappearing in places nobody had styled. tools/fix-link-underlines.py swept the
     295 explicit underline declarations out of 163 page-scoped blocks (originals in
     .claude/backups/link-underlines-2026-08-22/); this rule removes the default that
     was sitting underneath all of them.

     `a` alone is enough for every state (:link/:visited/:hover/:active), because any
     author rule beats the UA stylesheet. Do NOT extend this to `a:hover` — that
     raises specificity to (0,1,1) and would then out-rank the single-class rules
     below, killing their hover affordance. */
  a {
    text-decoration: none;
  }

  /* KEYBOARD FOCUS IS NOT DECORATION. Underlines are gone, so focus has to be
     carried by something still visible: a gold ring. This is the global floor —
     components with their own focus style simply override it.
     THIS RULE IS LOAD-BEARING. The sweep also removed 12 page-scoped rules that used
     an underline as their focus indicator (all on <a>, in years7-10.html across six
     locales). Deleting a focus indicator without a replacement is an accessibility
     regression, so this ring is what makes that safe. If it is ever removed, those
     12 rules have to come back, or keyboard users get no focus indication at all. */
  a:focus-visible {
    outline: 3px solid var(--jpic-gold);
    outline-offset: 3px;
    border-radius: 3px;
  }

  /* .jp-link — THE PROSE LINK. Use this for a link inside a sentence, where the
     reader has to be able to tell it is a link at all.

     It does the job an underline used to do, without one:
       · navy + 700 at rest, so it differs from body copy by WEIGHT as well as
         colour. That matters for WCAG 1.4.1 (Use of Color) — colour alone is not a
         sufficient cue, and with underlines gone, weight is what carries it.
       · on hover, a gold marker-pen wash sweeps in behind the bottom of the text.
         Gold as a BACKGROUND is fine (the design-system rule is that --jpic-gold is
         1.65:1 on white and so fails AA as TYPE, never as a graphic), and navy type
         over gold is comfortably readable.
     background-size is animated rather than a ::after bar because a background
     wraps correctly across line breaks, which an absolutely positioned bar does not. */
  
  
  /* On a dark ground the type goes white and the wash stays gold. */
  
  
  

  /* Buttons */
  .km-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-family: var(--km-display);
    font-weight: 700;
    font-size: 14px;
    letter-spacing: 0.4px;
    padding: 14px 30px;
    border-radius: 6px;
    text-decoration: none;
    transition:
      transform 0.2s,
      box-shadow 0.2s,
      background 0.2s,
      color 0.2s;
    cursor: pointer;
    border: 2px solid transparent;
    /* border-box + max-width — pages that stretch a CTA with width:100% were getting
       the 30px side padding and 2px border added on top of the track (content-box),
       so a full-width button sat ~64px wider than its container and scrolled the page
       sideways on phones. Both together keep any button inside its column. */
    box-sizing: border-box;
    max-width: 100%;
  }
  .km-btn span[aria-hidden="true"] {
    display: inline-block;
    transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
  }
  .km-btn:hover span[aria-hidden="true"] {
    transform: translateX(5px);
  }
  @media (prefers-reduced-motion: reduce) {
    .km-btn span[aria-hidden="true"] {
      transition: none;
    }
  }
  .km-btn-gold {
    background: var(--jpic-gold);
    color: var(--jpic-blue);
    box-shadow: 0 4px 16px rgba(73,128,193, 0.35);
  }
  .km-btn-gold:hover {
    background: var(--jpic-gold-dark);
    transform: translateY(-2px);
    box-shadow: 0 8px 24px rgba(73,128,193, 0.45);
  }
  
  
  .km-btn-outline {
    background: rgba(255, 255, 255, 0.06);
    color: #fff !important;
    border-color: rgba(255, 255, 255, 0.7);
  }
  .km-btn-outline:hover {
    background: #fff;
    color: var(--jpic-blue) !important;
  }
  
  /* !important is REQUIRED here, not sloppiness. The base rule above sets
     `color:#fff !important` (it has to, to beat the legacy global `a{color}` the
     SharePoint master page used to inject), and that !important also beat THIS
     hover rule — so the button filled solid white while the label stayed white
     and the text vanished on hover. Reported on Welcome/korea.html 2026-08-21;
     the bug was live on all 193 pages that use .km-btn-outline-light.
     If the base rule ever loses its !important, drop it from here too. */
  
  
  

  /* ---------- WHY ---------- */
  .km-why {
    padding: 90px 0;
    background: var(--white);
  }
  
  .km-why-image {
    position: relative;
  }
  .km-why-image img {
    width: 100%;
    border-radius: 12px;
    object-fit: cover;
    /* Bias the crop toward the top: these are people photos and faces sit
       in the upper third, so a centred crop (esp. of a portrait source in a
       landscape box on mobile) decapitates the subjects. */
    object-position: center 20%;
    aspect-ratio: 4/5;
    box-shadow: 0 20px 50px rgba(0, 51, 102, 0.18);
  }
  /* Floating achievement badge overlaid on the why-image photo — e.g.
     "30+ Years of Excellence". Additive/optional: only appears where a
     page's markup includes it (currently home.html). */
  
  
  
  
  

  
  /* Modifier: lays the same cards out 4-across full width — used when the
     cards sit below the why-grid rather than squeezed into its narrower
     content column (currently home.html only). */
  
  
  /*****HOVER****/
  
  
  
  
  
  

  /* ---------- WHY ACHIEVEMENT BAND ----------
     The proof-point numbers (years, nationalities, ATAR, pathway support)
     live inside the Why section as one rounded highlight band, rather
     than as a separate full-bleed dark section further down the page —
     ties the value proposition and the achievement stats into a single
     "why + proof" block (home.html only; .km-stats elsewhere is untouched). */
  
  
  
  .km-why-stat:not(:last-child)::after {
    content: "";
    position: absolute;
    right: -12px;
    top: 8%;
    height: 84%;
    width: 1px;
    background: linear-gradient(var(--jpic-gold), transparent);
  }
  
  
  
  
  
  

  /* ---------- JOURNEY ---------- */
  .km-journey {
    padding: 90px 0;
    background: var(--off-white);
  }
  

  /* Branch layout: two optional entry tracks -> shared spine */
  
  
  
  
  
  
  
  

  /* Convergence connector */
  
  
  
  
  

  /* Shared destination spine */
  
  
  

  /* Destination steps (Secondary School, University) get a gold gradient
     icon to mark them visually as "the goal" — everything on the left
     (entry tracks) reads blue, the shared spine on the right reads gold. */
  
  

  /* Optional step styling — lighter tone + dashed ring signals "this step
     can be skipped if the student already meets the entry requirement". */
  
  

  
  
  
  
  
  
  
  
  

  /* ---------- STATS ---------- */
  
  /* minmax(0,1fr) — a bare 1fr is minmax(auto,1fr), so a track can never shrink
     below the min-content width of its stat. Long word-stats ("Vice Captain",
     "Dux of the College") then push the whole grid past the viewport and the page
     scrolls sideways on phones. minmax(0,…) lets the track shrink and the text wrap. */
  
  
  .km-stat:not(:last-child)::after {
    content: "";
    position: absolute;
    right: 0;
    top: 18%;
    height: 64%;
    width: 1px;
    background: linear-gradient(var(--jpic-gold), transparent);
  }
  
  
  
  
  

  /* ---------- CAMPUS ---------- */
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  

  /* ---------- SUCCESS STORIES ---------- */
  .km-stories {
    padding: 90px 0;
    background: var(--off-white);
  }
  .km-stories .km-h2 {
    /*color: #fff;*/
  }
  .km-stories .km-label {
    color: var(--jpic-gold);
  }
  
  
  
  
  
  
  
  
  
  
  
  
  
  

  /* ============================================================
     GLOBAL VIDEO CUE — one shared "this is a video, tap to play"
     language reused across every page (home Success Stories,
     campus tour, HSP student-story thumbnails, homestay
     testimonial avatars, and any future video). Self-contained:
     it draws its own play triangle and pulsing gold ring in pure
     CSS, so it needs NO icon font or SVG sprite and renders
     identically everywhere.

     USAGE
       <a class="jp-video" data-vimeo="123456">
         <img ...>
         <span class="jp-videobadge">Watch video</span>   <!-- optional, larger media -->
         <span class="jp-videocue" aria-hidden="true"></span>
       </a>
     Put .jp-video on the clickable trigger (the [data-vimeo] /
     link element); drop a .jp-videocue inside it. Size modifiers:
     .jp-videocue-lg (hero/tour), default (story cards),
     .jp-videocue-sm (small avatars/thumbnails).
     ============================================================ */
  
  

  
  /* Play triangle — pure CSS, brand gold */
  
  /* Pulsing gold ring draws the eye to the control */
  
  @keyframes jpVideoCuePulse {
    0% { opacity: 0.9; transform: scale(1); }
    70% { opacity: 0; transform: scale(1.6); }
    100% { opacity: 0; transform: scale(1.6); }
  }
  
  
  

  
  

  /* "Watch video" badge — the at-a-glance signal on larger media */
  
  

  
  

  /* ---------- HERO BACKGROUND VIDEO (.jp-herovid) ----------
     Layers a silent, looping film over the hero photo.

     The existing .km-hero-img STAYS PUT and is doing two jobs: it is the
     LCP element and it is the poster. So a visitor who never receives the
     video — reduced motion, small screen, Save-Data, slow link, or a
     browser that refuses autoplay — sees exactly the hero they see today.
     That is the whole design: the video is an enhancement, never a
     dependency, and it costs nothing to the people who don't get it.

     Markup — ONE empty div inside .km-hero-media, AFTER the <img>:
       <div class="jp-herovid"
            data-hv-1080="/Video/Foo-1080.mp4"
            data-hv-720="/Video/Foo-720.mp4" aria-hidden="true"></div>
     js/jpic-herovideo.js injects the <video> only when it is safe to, and
     only after window.load, so the film never competes with the hero image
     for bandwidth. Absolute URLs are used as-is; root-relative paths are
     resolved against window.JPIC_MEDIA_BASE when that is set, which is the
     one-line switch to Azure Storage / a CDN.

     The existing .km-hero-overlay IS the scrim — headline contrast is
     unchanged. Do NOT add a second overlay on top of the video. */
  
  
  
  /* Once the film is up it completely covers the photo, so the photo's slow
     Ken Burns push is just wasted compositing — and on a still frame behind
     moving video it can read as a wobble. Stop it. */
  
  

  /* ---------- LIFE GALLERY ----------
     Uniform 3-col editorial card grid (same visual language as the
     Success Stories cards above: photo + gradient overlay + tag + title
     + one-line caption). Replaces the old 6-cell bento grid with mixed
     spans and single-word captions, which read as busy/flat rather than
     inviting. */
  
  
  
  
  
  
  
  
  
  
  

  /* ---------- SAFE ----------
     Asymmetric photo + feature-list layout (same pattern language as
     .km-why-grid) instead of a lone 6-card icon grid — a real photo plus
     a floating stat badge gives the section a human anchor point rather
     than reading as six identical boxes filling space. */
  
  
  
  
  
  
  
  
  
  
  
  
  
  

  /*-------------ACCOMMODATION------------*/
  /* ====================== SECTION SHELL ====================== */
  
  
  
  

  /* ====================== TWO PATHWAYS ====================== */
  

  /* Each card: a photo on the OUTER edge and a content panel that overlaps
   it with an angled edge. ATAR = photo left, IB = photo right. */
  
  
  

  /* Photo sits behind, pinned to the outer edge */
  
  
  

  /* Content panel overlaps the photo with an angled cut */
  
  
  
  
  
  
  
  
  
  
  
  
  

  /* ---------- INFO (FAQ + TEAM) ---------- */
  .km-info {
    padding: 90px 0;
    background: var(--white);
  }
  .km-info-grid {
    display: grid;
    grid-template-columns: 1.05fr 0.95fr;
    gap: 56px;
    align-items: start;
  }
  .km-accordion {
    margin-top: 8px;
  }
  .km-acc-item {
    border-bottom: 1px solid var(--grey-200);
  }
  .km-acc-item summary {
    cursor: pointer;
    list-style: none;
    padding: 18px 36px 18px 0;
    position: relative;
    font-family: var(--km-display);
    font-weight: 600;
    font-size: 15px;
    color: var(--grey-900);
  }
  .km-acc-item summary::-webkit-details-marker {
    display: none;
  }
  .km-acc-item summary::after {
    content: "+";
    content: "+" / "";
    position: absolute;
    right: 4px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--jpic-red);
    font-size: 22px;
    font-weight: 400;
    transition: transform 0.25s;
  }
  .km-acc-item[open] summary::after {
    content: "–";
    content: "–" / "";
  }
  .km-acc-body {
    padding: 0 0 18px;
  }
  .km-acc-body p {
    font-size: 14px;
    color: var(--grey-500);
    margin: 0;
    line-height: 1.7;
  }

  
  
  
  
  
  
  
  
  /* Hover mirrors the primary gold CTA (.km-btn-gold) rather than an
     off-brand red — navy pill lifts into brand gold with a navy glyph. */
  
  
  
  
  
  
  /* Contact rows are actionable (enquiry popup / tel:) — keep them white on
     the navy panel and let them warm to brand gold on hover. */
  
  
  
  
  
  

  /* ---------- FINAL CTA ---------- */
  .km-cta {
    position: relative;
    padding: 80px 0;
    overflow: hidden;
    background: linear-gradient(
      135deg,
      var(--jpic-blue-dark) 0%,
      var(--jpic-blue) 55%,
      var(--jpic-blue-light) 100%
    );
  }
  .km-cta-bg {
    position: absolute;
    inset: 0;
    background: radial-gradient(
      ellipse at 75% 50%,
      rgba(73,128,193, 0.12) 0%,
      transparent 60%
    );
  }
  .km-cta-inner {
    position: relative;
    z-index: 1;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 40px;
    flex-wrap: wrap;
  }
  .km-cta-crest {
    font-size: 34px;
    color: var(--jpic-gold);
    margin-bottom: 10px;
  }
  .km-cta-text h2 {
    font-family: var(--km-display);
    font-weight: 800;
    color: #fff;
    font-size: clamp(26px, 3vw, 38px);
    margin: 0 0 8px;
    line-height: 1.15;
  }
  .km-cta-text p {
    color: rgba(255, 255, 255, 0.82);
    font-size: 16px;
    margin: 0;
  }
  .km-cta-buttons {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
  }

  /* ====================== FINAL CTA ====================== */
  .y-final-cta {
    background: linear-gradient(
      135deg,
      var(--jpic-blue-dark) 0%,
      var(--jpic-blue) 70%
    );
    color: #fff;
    padding: 46px 28px;
  }
  
  
  
  
  
  

  /* ---------- VIDEO LIGHTBOX (Vimeo popup) ---------- */
  .km-modal {
    position: fixed;
    inset: 0;
    z-index: 2147483000;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 24px;
  }
  .km-modal.is-open {
    display: flex;
  }
  
  
  
  
  
  
  

  /* ---------- RESPONSIVE ---------- */
@media(max-width:991px){
  
  /* Gentler crop on mobile than 16/10: a portrait source keeps heads-to-waist
     (paired with object-position:center 20% above), landscape sources still fit. */
  .km-why-image img{aspect-ratio:4/3;max-height:460px;}
  
  .km-info-grid{grid-template-columns:1fr;gap:48px;}
  /* Journey: stack the two entry tracks above the shared destination */
  
  
  
  
  /* See the minmax(0,1fr) note on .km-stats-grid above — the 2-up mobile grid needs
     it too, and the roomy 28px desktop side padding leaves too little room for a
     word-stat to wrap into once two tracks share a 375px screen. */
  
  
  
  
  
  
  
  
  
  
}

@media(max-width:600px){
  .km-inner{padding:0 20px;}
  
  
  
  
  
  /* Journey: stack each track's steps vertically, arrows point down */
  
  
  
  
  
  
  
  
  .km-hero-buttons .km-btn,.km-cta-buttons .km-btn{width:100%;justify-content:center;}
}

/* ================================================================
   NAVIGATION RAIL — .jpicnav-*
   ================================================================ */
.jpicnav{
  --mist:#F4F2F4; --ink:#1A1A1A; --soft-ink:#44444A; --line:#D9D9DE;
  /* Was 'Inter' - a third typeface loaded site-wide for the nav rail alone
     (~47 KB latin, ~140 KB on /Vi/). DESIGN-SYSTEM.md only tokenises Raleway
     and Roboto, so the rail now uses the body token like everything else. */
  --jpn-body:var(--km-body,'Roboto',sans-serif);
  --jpn-rail-w:76px; --jpn-rail-w-open:250px; --jpn-flyout-w:355px;
  --jpn-ease:cubic-bezier(.4,0,.2,1);
  font-family:var(--jpn-body);
}
.jpicnav *{box-sizing:border-box;}
.jpicnav a{text-decoration:none;}
.jpicnav button{font-family:inherit;cursor:pointer;background:none;border:0;}
.jpicnav :focus-visible{outline:2px solid var(--jpic-gold);outline-offset:2px;border-radius:4px;}

/* ================= DESKTOP / TABLET RAIL ================= */
.jpicnav-rail{
  position:fixed;top:0;left:0;height:100vh;width:var(--jpn-rail-w);
  background:var(--jpic-blue);color:#fff;z-index:1000;
  display:flex;flex-direction:column;
  transition:width .22s var(--jpn-ease);
  box-shadow:2px 0 18px rgba(0,20,50,.18);
}
.jpicnav-rail.is-expanded{width:var(--jpn-rail-w-open);}

/* ---- Scrollable menu body ----
   The rail is a fixed 100vh column, so on a short window (a 1280x700 laptop, or
   any browser carrying a lot of chrome) the menu is taller than the rail. It
   used to be silently CLIPPED — the lists shrank and their own overflow:hidden
   cut the last items off with no way to reach them. The lists now keep their
   natural height (flex:0 0 auto below) and this wrapper scrolls instead, which
   also lets keyboard focus scroll a clipped item into view for free.
   The wrapper — not the rail — is the scroll container on purpose: the collapse
   toggle sits at right:-16px, deliberately overhanging the rail edge, and an
   overflow on the rail would slice it in half. The logo lockup and the toggle
   therefore stay pinned above the scrolling menu. */
.jpicnav-rail-scroll{
  flex:1 1 auto;min-height:0;display:flex;flex-direction:column;
  overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;
  scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.32) transparent;
}
.jpicnav-rail-scroll::-webkit-scrollbar{width:6px;}
.jpicnav-rail-scroll::-webkit-scrollbar-track{background:transparent;}
.jpicnav-rail-scroll::-webkit-scrollbar-thumb{background:rgba(255,255,255,.3);border-radius:3px;}
.jpicnav-rail-scroll::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.5);}

.jpicnav-rail-brand{position:relative;display:flex;flex-direction:column;align-items:center;
  justify-content:center;gap:10px;flex:0 0 auto;padding:50px 0px 50px 0px;}
.jpicnav-rail.is-expanded .jpicnav-rail-brand{flex-direction:row;flex-wrap:wrap;column-gap:14px;row-gap:6px;}
.jpicnav-rail-logo{display:flex;flex-direction:column;align-items:center;}
.jpicnav-mark-compact{width:48px;height:48px;object-fit:contain;flex:0 0 auto;}
.jpicnav-mark-full{display:none;height:84px;width:auto;max-width:100%;object-fit:contain;}
.jpicnav-rail.is-expanded .jpicnav-mark-compact{display:none;}
.jpicnav-rail.is-expanded .jpicnav-mark-full{display:block;}





.jpicnav-rail-brand .jpicnav-toggle{
  position:absolute;top:50%;right:-16px;transform:translateY(-50%);
  width:32px;height:32px;border-radius:50%;background-color:var(--jpic-blue);
  color:var(--jpic-gold);display:flex;align-items:center;justify-content:center;
  box-shadow:0 2px 8px rgba(0,20,50,.35);border:2px solid var(--jpic-gold);
  transition:transform .22s var(--jpn-ease);
}
.jpicnav-rail.is-expanded .jpicnav-toggle{transform:translateY(-50%) rotate(180deg);}
.jpicnav-toggle .jpicnav-icon{font-size:16px;line-height:1;}

.jpicnav-rail-list{list-style:none;margin:0;padding:50px 8px 8px 8px;display:flex;flex-direction:column;gap:2px;
  overflow:hidden;flex:0 0 auto;}
.jpicnav-rail-list-utility{margin-top:auto;padding-bottom:18px;}
.jpicnav-rail-divider{height:1px;background:rgba(255,255,255,.18);flex:0 0 auto;}
.jpicnav-rail-divider-top{margin:0 16px;}


.jpicnav-rail-item{
  display:flex;align-items:center;gap:16px;width:100%;min-height:48px;padding:12px 14px;
  border-radius:10px;color:rgba(255,255,255,.92);font-size:14px;font-weight:600;
  white-space:nowrap;position:relative;overflow:hidden;
  transition:background .28s var(--jpn-ease),color .2s,padding-left .28s var(--jpn-ease);
}
.jpicnav-rail-item .jpicnav-icon{display:inline-block;font-size:20px;line-height:1;flex:0 0 auto;width:22px;text-align:center;
  transition:transform .28s var(--jpn-ease),color .2s;}
/* Labels are timed against the width move rather than alongside it: on the way
   OUT they leave first, so no text is left being squeezed by a narrowing rail;
   on the way IN they wait for the rail to have made room, then fade up. Two
   rules, because the base declaration is the closing target and the .is-expanded
   one is the opening target — that is what makes the timing direction-aware. */
.jpicnav-rail-item .jpicnav-label{opacity:0;transition:opacity .12s var(--jpn-ease);overflow:hidden;}
.jpicnav-rail.is-expanded .jpicnav-rail-item .jpicnav-label{opacity:1;transition:opacity .16s var(--jpn-ease) .12s;}
/* Premium hover: soft gradient wash, icon lifts to gold, content nudges right,
   and a gold accent line grows in from the middle — a quieter preview of the
   full accent bar used for the active/expanded state below. */
.jpicnav-rail-item::after{
  content:'';position:absolute;left:0;top:50%;width:3px;height:0;
  border-radius:0 3px 3px 0;background:var(--jpic-gold);
  transform:translateY(-50%);
  transition:height .28s var(--jpn-ease);
}
.jpicnav-rail-item:hover,.jpicnav-rail-item:focus-visible{
  background:linear-gradient(90deg, rgba(255,255,255,.16), rgba(255,255,255,.06));
  color:#fff;
  padding-left:20px;
}
.jpicnav-rail-item:hover::after,.jpicnav-rail-item:focus-visible::after{height:58%;}
.jpicnav-rail-item:hover .jpicnav-icon,.jpicnav-rail-item:focus-visible .jpicnav-icon{
  color:var(--jpic-gold);
  transform:scale(1.14);
}
.jpicnav-rail-item[aria-expanded="true"]{
  background:var(--mist);color:var(--jpic-blue);
  border-radius:12px 0 0 12px;width:calc(100% + 8px);padding-right:22px;
  position:relative;z-index:1001;
}
.jpicnav-rail-item[aria-expanded="true"]::before{
  content:'';position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:var(--jpic-gold);
}
.jpicnav-rail-item[aria-expanded="true"]:hover .jpicnav-icon{color:var(--jpic-blue);transform:scale(1.14);}
.jpicnav-rail-item[aria-expanded="true"]::after{display:none;}
.jpicnav-rail-item-cta .jpicnav-icon{color:var(--jpic-gold);}
.jpicnav-rail-item-cta:hover,.jpicnav-rail-item-cta:focus-visible{
  background:linear-gradient(90deg, rgba(73,128,193,.22), rgba(73,128,193,.08));
}
.jpicnav-rail-item-cta:hover .jpicnav-icon{color:var(--jpic-gold);transform:scale(1.18);}

/* ---- Short-window compact rail ----
   At its resting size the rail needs ~945px of viewport height to show every
   item. Almost no real laptop has that: a 1920x1200 screen at 150% (browser zoom
   or Windows scaling) is a 1280x~710 viewport, a 13" MacBook Air is ~810-870,
   a maximised 1080p window ~950. So the breakpoint is set at the height where
   the resting design actually stops fitting — 944px — rather than at a round
   number: below it the lockup and row rhythm tighten until the whole menu fits
   (compact needs ~715px), above it nothing changes.
   The point is to REMOVE the need to scroll, not to make scrolling nicer — a
   scrollbar the visitor does not notice is the same as a menu with missing
   items, which is exactly how this was reported, twice. .jpicnav-rail-scroll
   stays as the safety net below ~715px and for signed-in visitors, whose
   personalised panel adds rows. */
@media (min-width:1024px) and (max-height:944px){
  .jpicnav-rail-brand{padding:16px 0;gap:8px;}
  .jpicnav-mark-full,.jpicnav-30mark-full{height:62px;}
  
  .jpicnav-mark-compact{width:42px;height:42px;}
  .jpicnav-rail-list{padding-top:10px;padding-bottom:4px;}
  .jpicnav-rail-list-utility{padding-bottom:10px;}
  /* 42px still clears the 24px WCAG target minimum with room to spare; this is
     a mouse-only breakpoint (the rail is hidden below 1024px). */
  .jpicnav-rail-item{min-height:42px;padding-top:9px;padding-bottom:9px;}
  .jpicnav-rail-divider-main{margin:4px 16px;}
}

/* ---- 'More below' fade ----
   Shown only while the menu really is scrolled/scrollable (class toggled in
   js/jpic-nav.js), so the rail looks exactly as designed whenever it fits.
   Painted on the RAIL, not the scroll wrapper, so it stays pinned at the edge
   instead of scrolling away with the content. */
.jpicnav-rail::after{
  content:'';position:absolute;left:0;right:0;bottom:0;height:34px;pointer-events:none;
  background:linear-gradient(to top,var(--jpic-blue) 30%,rgba(0,73,144,0));
  opacity:0;transition:opacity .18s var(--jpn-ease);z-index:2;
}


/* ---- Collapsed-rail hover labels ----
   With the rail minimised the item labels are hidden, so hovering (or keyboard-
   focusing) an icon reveals its name in a small pill beside the rail. One shared
   element, placed by JS — position:fixed so it escapes the rail/list overflow
   clipping, and z-index above the rail. Desktop only; never shown while the rail
   is expanded (the real labels are visible then). */
.jpicnav-tip{
  position:fixed;left:0;top:0;z-index:1002;
  max-width:230px;padding:9px 14px;
  border-radius:8px;border-left:3px solid var(--jpic-gold);
  background:var(--mist);color:var(--jpic-blue);
  font-family:var(--jpn-body);font-size:13.5px;font-weight:700;line-height:1.3;
  /* Wraps rather than clips: the pill shrinks to fit short labels, but the
     longest translated ones (Spanish "Trayectorias de Estudio en JPC" needs
     236px) run past the cap and would otherwise spill outside the background. */
  white-space:normal;text-wrap:balance;
  box-shadow:6px 6px 20px rgba(0,20,50,.22);
  opacity:0;visibility:hidden;pointer-events:none;
  transform:translateX(-6px);
  transition:opacity .16s var(--jpn-ease),transform .16s var(--jpn-ease),visibility .16s;
}
.jpicnav-tip::before{
  content:'';position:absolute;left:-8px;top:50%;transform:translateY(-50%);
  width:0;height:0;border:5px solid transparent;border-right-color:var(--jpic-gold);
}
.jpicnav-tip.is-shown{opacity:1;visibility:visible;transform:translateX(0);}
@media (max-width:1023px){ .jpicnav-tip{display:none;} }

/* ================= SCRIM ================= */
.jpicnav-scrim{
  position:fixed;inset:0;background:rgba(8,20,38,.5);z-index:998;
  opacity:0;visibility:hidden;transition:opacity .22s var(--jpn-ease);
}
.jpicnav.has-flyout-open .jpicnav-scrim{opacity:1;visibility:visible;}

/* ================= DESKTOP FLYOUT ================= */
.jpicnav-flyout{
  position:fixed;top:0;left:var(--jpn-rail-w-open);width:var(--jpn-flyout-w);
  height:auto;max-height:calc(100vh - 40px);
  background:var(--mist);z-index:999;padding:32px 36px;overflow-y:auto;
  border-radius:0 20px 20px 20px;
  transform:translateX(-16px);opacity:0;visibility:hidden;
  transition:opacity .2s var(--jpn-ease),transform .2s var(--jpn-ease),visibility .2s;
  box-shadow:8px 8px 24px rgba(0,20,50,.18);
}
.jpicnav.has-flyout-open .jpicnav-flyout{opacity:1;visibility:visible;transform:translateX(0);}









/* ---- grouped submenu: a labelled block per group inside one panel ----
   Emitted by navBody() in js/jpic-nav.js when a NAV_LINKS array carries
   { group: … } markers. Only the Study Pathways panel uses this today; panels
   without markers still render one flat .jpicnav-panel-list and are untouched.
   The gold tick ties the label to the brand without shouting at 4 repeats. */




/* justify-content:flex-start overrides the space-between inherited from the
   base .jpicnav-panel-list rule above (added for the hover-arrow reveal) —
   without it, the flag becomes one flex item and the language name becomes
   a second, and space-between shoves the name to the far right edge. */


/* Neutral chip used instead of a national flag for Traditional Chinese —
   avoids using the Taiwan flag, which is a sensitive political symbol in
   the China market this site also serves. Matches the flag's footprint so
   the language list still lines up visually. */


/* ================= MOBILE / TABLET TOP BAR ================= */
.jpicnav-mobile-bar{
  display:none;position:fixed;top:0;left:0;right:0;height:60px;z-index:1000;
  background:var(--jpic-blue);align-items:center;justify-content:space-between;padding:0 14px;
  box-shadow:0 2px 14px rgba(0,20,50,.18);
}
.jpicnav-mobile-burger,.jpicnav-mobile-account{color:#fff;width:44px;height:44px;display:flex;align-items:center;justify-content:center;border-radius:8px;
  transition:background .2s var(--jpn-ease),transform .2s var(--jpn-ease);}
.jpicnav-mobile-burger:hover,.jpicnav-mobile-account:hover{background:rgba(255,255,255,.14);transform:scale(1.08);}
.jpicnav-mobile-logo img{height:44px;width:auto;display:block;}
/* Dual-logo lockup (mobile bar): JPC shield  |  JPIC 30th, dash divider between.
   Absolutely centred in the bar so it stays viewport-centred regardless of the
   burger (left) and language pill (right) widths. */





/* Right-corner slot that holds the language pill (injected by js/jpic-topbar.js). */

.jpicnav-mobile-bar .jpicnav-icon{font-size:22px;line-height:1;}

/* ================= MOBILE FULL-SCREEN OVERLAY ================= */
.jpicnav-mobile-overlay{
  display:none;position:fixed;inset:0;z-index:1100;background:var(--jpic-blue);
  flex-direction:column;opacity:0;visibility:hidden;transition:opacity .22s var(--jpn-ease);
}
.jpicnav-mobile-overlay.is-open{opacity:1;visibility:visible;}
.jpicnav-mobile-topbar{display:flex;align-items:center;justify-content:space-between;height:60px;padding:0 14px;flex:0 0 auto;}
.jpicnav-mobile-close{color:#fff;width:44px;height:44px;display:flex;align-items:center;justify-content:center;border-radius:8px;
  transition:background .2s var(--jpn-ease),transform .2s var(--jpn-ease);}
.jpicnav-mobile-close:hover{background:rgba(255,255,255,.14);transform:scale(1.08) rotate(90deg);}












/* Full 30th-anniversary crest — no border-radius clip (the artwork is a wider-
   than-tall transparent PNG, so a circular mask would crop the banner/edges). */

















/* grouped submenu, mobile twin of .jpicnav-panel-grouphead above. Slightly
   larger than the desktop label: this sits on a full-width scrolling sheet,
   where 10.5px uppercase reads as noise rather than as a heading. */




/* ================= BREAKPOINT SWITCH ================= */
@media (max-width:1023px){
  .jpicnav-rail,.jpicnav-flyout,.jpicnav-scrim{display:none;}
  .jpicnav-mobile-bar{display:flex;}
  .jpicnav-mobile-overlay{display:flex;}
  body{padding-top:60px;}
}
@media (min-width:1024px){
  body{padding-left:76px;transition:padding-left .22s cubic-bezier(.4,0,.2,1);}
  body.jpicnav-is-expanded{padding-left:250px;}
}

/* ================= REDUCED MOTION ================= */
@media (prefers-reduced-motion:reduce){
  .jpicnav *{transition-duration:.001ms !important;}
  .km-hero-img{animation:none;}
}

/* ================================================================
   FOOTER — .jpic-footer / .jf-*
   ================================================================ */
.jpic-footer{
  --jf-navy:#0b2a52; --jf-navy-deep:#082244;
  font-family:var(--km-body); line-height:1.6; color:rgba(255,255,255,.85);
  background:var(--jf-navy);
  box-sizing:border-box; -webkit-font-smoothing:antialiased;
  border-top:3px solid var(--jpic-gold);
}

/* ----- SharePoint defensive reset (scoped) ----- */
.jpic-footer *{box-sizing:border-box;}
.jpic-footer p,.jpic-footer ul,.jpic-footer li,.jpic-footer h3,.jpic-footer figure{margin:0;padding:0;}
.jpic-footer ul{list-style:none;}
.jpic-footer a{color:inherit;text-decoration:none;background:none;}
.jpic-footer img{max-width:100%;height:auto;border:0;display:block;}
.jpic-footer button{font-family:inherit;cursor:pointer;}

.jf-inner{max-width:1280px;margin:0 auto;padding:0 40px;}
.jf-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;}

/* ---------- MAIN GRID ---------- */
.jf-main{padding:58px 0 50px;}
.jf-grid{
  display:grid;
  /* Quick Links (col 3) carries the longest labels — "Entry Requirements",
     and longer again in Vi/Ko/Ja — so it gets width rather than the .85fr it
     used to have, which wrapped labels onto two lines. */
  grid-template-columns:1.15fr 1fr 1.05fr 1.05fr .95fr;
  gap:40px;
}
.jf-heading{
  font-family:var(--km-display);font-weight:700;font-size:15px;letter-spacing:1px;
  text-transform:uppercase;color:#fff;margin-bottom:18px;position:relative;padding-bottom:12px;
}
.jf-heading::after{content:'';position:absolute;left:0;bottom:0;width:46px;height:2px;background:var(--jpic-gold);}


/* Brand col */
.jf-brand{display:flex;align-items:center;}
.jf-logo{display:block;width:100%;}
.jf-logo img{width:100%;max-width:340px;height:auto;}

/* Contact */
.jf-contact li{display:flex;align-items:flex-start;gap:12px;font-size:14.5px;
  line-height:1.55;padding:7px 0;color:rgba(255,255,255,.85);}
.jf-contact a:hover{color:var(--jpic-gold);}
.jf-ic{color:var(--jpic-gold);font-size:16px;flex:0 0 auto;width:18px;text-align:center;margin-top:1px;}
.jf-btn{margin-top:18px;}
.jf-btn i{font-size:16px;line-height:1;}

/* Quick links */
.jf-links li{padding:6px 0;}
.jf-links a{display:inline-flex;align-items:center;gap:10px;font-size:14.5px;
  color:rgba(255,255,255,.85);transition:color .2s,transform .2s;}
.jf-links a::before{content:'\203A';color:var(--jpic-gold);font-size:16px;font-weight:700;line-height:1;}
.jf-links a:hover{color:var(--jpic-gold);transform:translateX(3px);}

/* Social */






/* Newsletter */







/* College details */


/* ---------- TRUST / ACCREDITATION BAND ---------- */







/* Country NAMES only — the College does not publish national flags
   anywhere on this site (see DESIGN-SYSTEM.md). */






/* ---------- BOTTOM BAR ---------- */
.jf-bottom{background:var(--jf-navy-deep);padding:20px 0;
  border-top:1px solid rgba(255,255,255,.08);}
.jf-bottom-inner{display:flex;align-items:center;justify-content:space-between;gap:24px;flex-wrap:wrap;}
.jf-copy{font-size:13.5px;color:rgba(255,255,255,.7);}
.jf-legal{display:flex;align-items:center;gap:18px;}
.jf-legal a{font-size:13.5px;color:rgba(255,255,255,.85);transition:color .2s;}
.jf-legal a:hover{color:var(--jpic-gold);}








/* "translation on its way" message, shown when a chosen language has no
   translation of the current page yet (mirrors the top-bar .jpt-toast). */


/* ---------- BUTTONS (mirror .km-btn for consistency) ---------- */
.jpic-footer .km-btn{display:inline-flex;align-items:center;gap:8px;font-family:var(--km-display);
  font-weight:700;font-size:14px;letter-spacing:.4px;padding:13px 26px;border-radius:6px;
  text-decoration:none;transition:transform .2s,box-shadow .2s,background .2s,color .2s;
  cursor:pointer;border:2px solid transparent;}
.jpic-footer .km-btn-gold{background:var(--jpic-gold);color:var(--jpic-blue);box-shadow:0 4px 16px rgba(73,128,193,.35);}
.jpic-footer .km-btn-gold:hover{background:var(--jpic-gold-dark);transform:translateY(-2px);box-shadow:0 8px 24px rgba(73,128,193,.45);}

/* Secondary CTA. Defined here rather than reusing .km-btn-outline, which is
   scoped elsewhere and carries !important. Dark ground only — as the footer is. */



/* Stacked CTA pair (Apply Now / Get In Touch) — deterministic column so the
   two buttons never depend on the grid column happening to be wide enough. */
.jf-cta{display:flex;flex-direction:column;align-items:flex-start;gap:10px;margin-top:18px;}
.jf-cta .jf-btn{margin-top:0;}

/* ---------- RESPONSIVE ---------- */
@media(max-width:1100px){
  .jf-grid{grid-template-columns:1fr 1fr 1fr;gap:36px 40px;}
  .jf-brand{grid-column:1 / -1;}
  
  
}
@media(max-width:680px){
  .jf-inner{padding:0 24px;}
  .jf-grid{grid-template-columns:1fr;}
  

  /* ---- DENSITY PASS ----
     Stacked, the footer ran ~2357px on a 375px viewport — nearly three phone
     screens, with the language picker buried at the very bottom. This brings it
     to ~1585px without removing content or touching the markup (the footer is
     inlined into ~500 pages, so markup changes mean a sweep). */
  .jf-main{padding:34px 0 30px;}
  .jf-grid{gap:26px;}
  .jf-logo img{max-width:200px;}

  .jf-heading{font-size:14px;margin-bottom:13px;padding-bottom:9px;}
  

  /* Quick links in two columns rather than one tall stack. */
  .jf-links{display:grid;grid-template-columns:1fr 1fr;column-gap:14px;}
  .jf-links li{padding:5px 0;}
  .jf-links a{font-size:14px;}

  /* Social collapses to an icon row. font-size:0 hides the visible label but
     keeps the link's accessible name, so screen readers still say "Facebook". */
  
  
  
  

  .jf-contact li,.jf-details li{padding:5px 0;font-size:14px;}

  /* Trust band: tighter logos; the country-name pills wrap. */
  
  
  
  
  
  
  
  

  /* Legal links and the language picker share a row; copyright wraps beneath. */
  .jf-bottom{padding:16px 0;}
  .jf-bottom-inner{flex-direction:row;flex-wrap:wrap;align-items:center;gap:10px 16px;}
  .jf-copy{order:3;flex:1 0 100%;font-size:12.5px;}
  .jf-legal{order:1;gap:14px;}
  
}

/* ================================================================
   STICKY QUICK NAVIGATION — .km-qnav (scrollspy sub-nav)
   Sits under a page's hero on load, pins to the top on scroll,
   highlights the section in view via a sliding blue pill, and
   smooth-scrolls to any section. Behaviour lives in the shared
   js/jpic-quicknav.js; each page supplies only the <nav> markup.
   The script tags every target section with .km-qnav-target so the
   scroll-margin below clears the pinned bar regardless of page markup.
   ================================================================ */
:root{--qn-h:64px;}
.km-qnav{
  position:sticky; top:0; z-index:900;
  background:rgba(255,255,255,.94);
  -webkit-backdrop-filter:saturate(180%) blur(14px);
  backdrop-filter:saturate(180%) blur(14px);
  border-bottom:1px solid rgba(0,73,144,.12);
  box-shadow:0 1px 0 rgba(0,32,74,.04);
  transition:box-shadow .35s ease, background .35s ease, border-color .35s ease;
}
/* Gold hairline that slides across the top once the bar is pinned. */
.km-qnav::before{
  content:''; position:absolute; left:0; right:0; top:0; height:3px;
  background:linear-gradient(90deg,var(--jpic-gold),var(--jpic-gold-dark));
  transform:scaleX(0); transform-origin:left center; opacity:0;
  transition:transform .5s cubic-bezier(.22,1,.36,1), opacity .35s ease;
}
.km-qnav.is-stuck{
  background:rgba(255,255,255,.98);
  border-bottom-color:rgba(0,73,144,.06);
  box-shadow:0 12px 30px -14px rgba(0,32,74,.38);
}
.km-qnav.is-stuck::before{transform:scaleX(1); opacity:1;}

/* Inner is the scroll viewport; the track centres when items fit and
   scrolls horizontally when they don't — items are never clipped. */
.km-qnav-inner{
  max-width:1200px; margin:0 auto; padding:0 20px;
  height:var(--qn-h);
  overflow-x:auto; overflow-y:hidden;
  scrollbar-width:none; -ms-overflow-style:none; -webkit-overflow-scrolling:touch;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 22px,#000 calc(100% - 22px),transparent);
  mask-image:linear-gradient(90deg,transparent,#000 22px,#000 calc(100% - 22px),transparent);
}
.km-qnav-inner::-webkit-scrollbar{display:none;}
.km-qnav-track{
  position:relative;
  height:100%; width:max-content; margin:0 auto;
  display:flex; align-items:center; gap:2px;
}

/* Sliding blue pill that glides between items as the section changes. */
.km-qnav-pill{
  position:absolute; left:0; top:50%; height:42px; width:0;
  transform:translate(0,-50%); transform-origin:left center;
  border-radius:999px;
  background:linear-gradient(135deg,var(--jpic-blue-light),var(--jpic-blue) 60%,var(--jpic-blue-dark));
  box-shadow:0 8px 20px -8px rgba(0,73,144,.55), inset 0 1px 0 rgba(255,255,255,.14);
  opacity:0; pointer-events:none; z-index:0;
}
.km-qnav-pill.is-ready{
  opacity:1;
  transition:transform .42s cubic-bezier(.22,1,.36,1), width .42s cubic-bezier(.22,1,.36,1), opacity .3s ease;
}

.km-qnav-link{
  position:relative; z-index:1;
  display:inline-flex; align-items:center; gap:8px;
  height:42px; padding:0 17px;
  font-family:var(--km-display); font-size:14px; font-weight:600; letter-spacing:.2px;
  color:#4a5a70; white-space:nowrap; border-radius:999px;
  text-decoration:none;
  transition:color .25s ease;
}
.km-qnav-link i{font-size:16px; line-height:1; color:#9aa7b6;
  transition:color .25s ease, transform .25s cubic-bezier(.22,1,.36,1);}
.km-qnav-link:not(.is-active):hover{color:var(--jpic-blue); background:rgba(0,73,144,.06);}
.km-qnav-link:not(.is-active):hover i{color:var(--jpic-gold-dark); transform:translateY(-1px);}
.km-qnav-link:focus-visible{outline:2px solid var(--jpic-blue); outline-offset:2px;}
.km-qnav-link.is-active{color:#fff;}
.km-qnav-link.is-active i{color:var(--jpic-gold);}

/* Section landing offset so anchors clear the sticky bar (class added by JS). */
.km-qnav-target{scroll-margin-top:calc(var(--qn-h, 64px) + 16px);}
html{scroll-behavior:smooth;}

@media (max-width:1023px){
  :root{--qn-h:58px;}
  .km-qnav{top:60px;}
  .km-qnav-inner{padding:0 14px;}
  .km-qnav-link{padding:0 15px; font-size:13.5px;}
  .km-qnav-target{scroll-margin-top:calc(60px + var(--qn-h) + 14px);}
}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto;}
  .km-qnav, .km-qnav::before, .km-qnav-link, .km-qnav-link i, .km-qnav-pill.is-ready{transition:none;}
  .km-qnav-link:not(.is-active):hover i{transform:none;}
}



/* ---------- REAL SCHOOL EXPERIENCE ----------
     Slow living-photo zoom (same language as the hero Ken Burns effect),
     a short lead line for warmth, frosted-glass icon badges instead of
     bare floating icons, hover lift, and a scroll-reveal stagger. */
  
  
  
  @keyframes pspRealZoom{from{transform:scale(1);}to{transform:scale(1.08);}}
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  

/* ============================================================
   BRAND HERO LINE-DRAW (.km-hline) — the animated gold "flowing
   line + icon" hero flourish. Geometry is built in JS (js/jpic-
   heroline.js) from hero-relative coordinates, with the viewBox
   matched 1:1 to the hero's pixels, so there's no distortion and
   the stroke stays a constant slim width at every resolution. See
   that file for the required markup + per-page glyph.
   ============================================================ */



/* Gold line — slim, crisp (constant px because the viewBox is 1:1 with the
   hero pixels). Starts hidden via a big dash offset until JS drives it. */


/* End icon badge — navy disc + gold ring + gold line-art glyph (echoes the
   prospectus icon badges & the index journey nodes). #km-hline-endpos (JS)
   sets position + size; .km-hline-end does the CSS pop, so the two
   transforms don't collide. Swap the glyph inside .km-hline-icon per page. */




@keyframes kmHlineEndPop{0%{opacity:0;transform:scale(.3);}
  70%{opacity:1;transform:scale(1.12);}100%{opacity:1;transform:scale(1);}}

/* Leading sparkle-star. JS moves/fades it; the star twinkles while drawing. */





@keyframes kmHlineTwinkle{0%,100%{transform:scale(.7) rotate(0deg);opacity:.85;}
  50%{transform:scale(1.15) rotate(45deg);opacity:1;}}



/* ================================================================
   LOGIN — portal sign-in modal + nav trigger
   Markup + behaviour are injected on every page by js/jpic-login.js
   (no per-page copy). Styles live here so the one shared stylesheet
   remains the single source of truth. Scoped under .jpic-login-* /
   .jpicnav-login-* so nothing collides with page or nav CSS.
   ================================================================ */

/* ---- Rail login trigger + its top/bottom dividers ---- */
.jpicnav-login-sep{height:1px;margin:8px 14px;background:rgba(255,255,255,.18);list-style:none;}



/* ---- Overlay + dialog ---- */









/* ---- Brand header ---- */



/* ---- Views (crossfade) ---- */


@keyframes jpicLoginFade{from{opacity:0;transform:translateY(8px);}to{opacity:1;transform:translateY(0);}}



/* ---- Audience chooser ---- */










/* ---- Back link + audience chip ---- */





/* ---- Form ---- */












/* ---- "or continue with" divider ---- */



/* ---- Social / SSO buttons ---- */









/* ---- Success / status note ---- */




/* ---- Register / "already have an account" links + name row ---- */









/* ================================================================
   NAV — main-nav divider + signed-in personalised panel
   (rail sits between the main-nav divider and the login divider)
   ================================================================ */
.jpicnav-rail-divider-main{margin:6px 16px;}




/* Greeting row — avatar always visible; "Hello Allan" reveals when expanded */







/* Quick links reuse the rail-item look but read as a lighter sub-group */




/* Caret hint on grouped items (opens a flyout mega-menu); only when expanded */




/* Flyout mega-menu list with icons (signed-in groups) */





/* Signed-in Log Out affordance */


/* Mobile signed-in panel (in the overlay's primary column) */






/* Grouped sections inside the mobile signed-in panel */





/* ================================================================
   TOP-CORNER UTILITY CLUSTER — site search + language  (.jpt-*)
   ----------------------------------------------------------------
   Injected by js/jpic-topbar.js. A frosted-glass pill cluster that
   floats in the TOP CORNER of the page, above the hero:
     • desktop (>=1024px): true top-right corner, clear of the left
       rail — a permanent search box + a language pill;
     • mobile (<=1023px): sits just under the 60px blue nav bar —
       a search icon that expands to a field, plus a language pill.

   LANGUAGE / POLITICAL SENSITIVITY:
   The selector lists LANGUAGES, never countries or regions, and
   uses NO national flags anywhere. Chinese is offered as two
   language variants — Simplified (简) and Traditional (繁) — with
   neutral script-glyph chips, so nothing implies a stance on
   Hong Kong, Taiwan or the mainland. Do NOT add flags here.
   ================================================================ */
.jpt{position:fixed;z-index:950;top:70px;right:12px;font-family:var(--km-body);}
.jpt *{box-sizing:border-box;}


/* shared frosted pill / button */



.jpt :focus-visible{outline:3px solid var(--jpic-gold);outline-offset:2px;border-radius:24px;}

/* ---------- SEARCH ---------- */







          /* free up room on small screens */
@keyframes jptField{from{opacity:0;transform:scaleX(.85);transform-origin:right;}to{opacity:1;transform:scaleX(1);}}








/* results panel */









/* "See all results" footer row (Pattern A → search.html) */




/* "English" badge on a result whose page has no translation in this language
   yet (search-index.json marks those entries). Tells a translated visitor what
   they'll get BEFORE they click, rather than surprising them with an English
   page. Same treatment on the full results page: .srch-card-en. */
/* grey-700 on grey-200, not grey-500 on grey-100: at 10.5px this needs to clear
   WCAG AA (4.5:1) for small text, and the lighter pairing sat near 3.5:1. */





/* ---------- LANGUAGE ---------- */














/* transient "translation coming soon" note */

@keyframes jptToast{from{opacity:0;transform:translateY(-6px);}to{opacity:1;transform:translateY(0);}}

/* desktop: true top corner, permanent search box */
@media(min-width:1024px){
  .jpt{top:16px;right:24px;}
  
  
  

  /* scrolled: collapse the permanent box to an icon so it stops covering the
     sticky sub-nav; it re-expands when the icon is clicked. */
  
  
  
  
}

/* scrolled: solid, high-contrast controls so the search + language read clearly
   on the light sticky sub-nav (and still pop on the dark hero). */





@media(prefers-reduced-motion:reduce){
  .jpt *{transition-duration:.001ms !important;animation-duration:.001ms !important;}
  
}



/* ================================================================
   SEARCH + LANGUAGE — MOBILE (mounted inside the burger menu)
   ----------------------------------------------------------------
   On mobile the floating top-corner cluster is hidden; js/jpic-topbar.js
   mounts a search field + a flag-free language picker inside the open
   burger overlay instead (so they appear only after the burger tap).
   ================================================================ */
@media(max-width:1023px){
  .jpt{display:none !important;}                 /* no floating cluster on mobile */
}
















/* language: one globe pill in the burger top bar → dropdown list */









/* ================================================================
   NAV CONTRAST HARDENING
   ----------------------------------------------------------------
   The rail/menu <a> items (About Us, Contact Us, Apply Online) must
   stay white on the blue chrome even if a host stylesheet (e.g. the
   SharePoint master page) sets a global dark `a { color }`. These
   element+class rules out-specify any bare `a` rule; the active /
   hover / CTA states below still win via their own higher specificity.
   ================================================================ */
.jpicnav-rail a.jpicnav-rail-item{color:rgba(255,255,255,.92);}
.jpicnav-rail a.jpicnav-rail-item:hover,.jpicnav-rail a.jpicnav-rail-item:focus-visible{color:#fff;}



/* ================================================================
   GLOBAL 360° VIRTUAL-TOUR COMPONENT  (.jp-tour*)
   ----------------------------------------------------------------
   "Walk Through Our Facilities in 360°" — an embedded YouTour stage
   with a photo-thumbnail picker. Reusable site-wide: drop the markup
   (see below) into any page, load js/jpic-tour360.js, and the picker
   swaps the iframe location. Originated on School/primary-school.html
   (formerly the page-scoped .ps-tour); promoted here so every page
   shares one source of truth.

   MARKUP:
     <div class="jp-tour360" data-jp-tour>
       <div class="jp-tour-head">
         <h3 class="jp-tour-title"><i class="icon-default-play" aria-hidden="true"></i> Walk Through Our Facilities in 360&deg;</h3>
         <p class="jp-tour-sub">…short blurb…</p>
       </div>
       <div class="jp-tour-body">
         <div class="jp-tour-stage">
           <iframe class="jp-tour-frame" src="…first location…" title="…"
                   loading="lazy" allow="fullscreen; accelerometer; gyroscope; xr-spatial-tracking"
                   allowfullscreen referrerpolicy="no-referrer-when-downgrade"></iframe>
           <a class="jp-tour-launch" href="…first location…" target="_blank" rel="noopener"><i class="icon-default-expand" aria-hidden="true"></i> Full screen</a>
         </div>
         <div class="jp-tour-picker" role="tablist" aria-label="Choose a place to explore">
           <button class="jp-tour-loc is-active" type="button" role="tab" aria-selected="true" data-src="…location…"><span class="jp-tour-thumb"><img src="…thumb…" alt="" loading="lazy"></span><span class="jp-tour-locname">…name…</span></button>
           …more .jp-tour-loc buttons…
         </div>
       </div>
     </div>
   ================================================================ */






















/* ══════════════════════════════════════════════════════════════════════════
   RESULTS PANEL + ALUMNI RESULT CARDS  (.ar-*)
   ══════════════════════════════════════════════════════════════════════════
   Promoted here from About-JPIC/academic-results.html once a second page
   (Courses/atar.html) needed the same components. The `ar-` prefix is
   historical ("academic results") — kept rather than renamed so the original
   page and its JS hooks (arPanelTabs, .ar-panel-pane) keep working unchanged.

   NOTE: academic-results.html still carries its own byte-identical copy of
   these rules in its page <style> block. That copy wins on cascade order and
   renders identically, so nothing changed there. De-duplicating it is a
   follow-up that needs its own browser-verified pass — do not delete those
   rules blind.

   Components:
     .ar-panel*      dark navy results band: identity column + data pane
     .ar-dux-strip*  burgundy "top graduate" lead-proof strip
     .ar-metrics/.ar-metric*   2x2 metric card grid (on the dark band)
     .ar-measure*    median measure bar with a marked threshold
     .ar-alum-card*  portrait alumni result card (4/5 frame + gold badge)

   The measure bar's grow-on-reveal animation is intentionally NOT here — it
   lives with academic-results.html's reveal JS. Pages without that JS get a
   static bar drawn at its inline width, which is correct with or without JS.
   ────────────────────────────────────────────────────────────────────────── */

:root{
  /* Shadow/radius tokens these components expect. academic-results.html
     redefines the same names on .ar-page with identical values. */
  --ar-shadow-sm: 0 1px 3px rgba(0,0,0,.04), 0 1px 2px rgba(0,0,0,.06);
  --ar-shadow-md: 0 4px 20px rgba(0,73,144,.07);
  --ar-shadow-lg: 0 12px 40px rgba(0,73,144,.1);
  --ar-radius: 12px;
  /* Accessible mid-grey for small secondary text. The shared --grey-500 measures
     4.38:1 on white at the 11–13px sizes these cards use, just under AA. Same
     hue, darkened ~10%: 5.3:1 on white. */
  --ar-grey-mid: #606f7f;
}

/* ---------- Results panel: dark band, identity column + data pane ---------- */

/* Gold bloom + navy vignette — the same treatment the library uses on its other
   dark bands, so this reads as brand furniture, not a one-off. Decorative. */




/* minmax(0,…) on the data column — a bare 1fr is minmax(auto,1fr) and the wide
   metric numerals would refuse to shrink, pushing the page sideways on mobile. */














/* ---------- Top-graduate strip (lead proof point) ---------- */






/* The top ATAR is the single number parents look for first, so it is the
   largest type in the panel. */



/* ---------- 2x2 metric grid (sits on the dark band) ---------- */









/* "of students achieved" — quiet connective line between the percentage and the
   ATAR value it refers to. */

/* The ATAR band itself (99+ / 95+ / 90+) is a real ATAR score, so it gets real
   type rather than sitting inside a caption. */



/* Comparison pill pushed to the foot so all cards line up even when the labels
   above them wrap to different depths. */


/* Source/footnote line for a pane on the dark band. */


/* ---------- Median measure bar ---------- */







/* Threshold marker (e.g. the "top 10% of the state" line at ATAR 90). */


/* Axis ticks kept above AA — the scale is what gives the median its meaning. */




/* ---------- Alumni result card ----------
   Portrait 4/5 frame (the site's standard portrait ratio) + gold result badge.
   The card is layout-agnostic: academic-results.html puts it in a scroll-snap
   carousel, Courses/atar.html in a plain 3-up grid. */



/* REQUIRED for the random-pick pattern on Courses/atar.html: the author
   `display:flex` above beats the UA stylesheet's `[hidden]{display:none}`, so
   setting el.hidden alone would NOT hide a card. */


















@media(max-width:991px){
  /* Panel collapses to a single column: identity block on top, data below. */
  
  
}

@media(max-width:600px){
  /* One metric per row: two tabular numerals at 36px+ plus padding cannot share
     a 375px screen without the labels wrapping to three lines. */
  
  /* Stack the dux strip so the big ATAR numeral is not fighting the name. */
  
  
  
  
  /* The threshold flag sits at 90% of the track; centring it there overflows the
     right edge on a narrow screen, so pin it to the right instead. */
  
  
}

/* =========================================================================
   THAI (/Th/) — script-specific typography.        Added 2026-08-18.
   -------------------------------------------------------------------------
   Scoped to html[lang="th"] so no other locale is touched. Three problems
   this fixes, all of them specific to how Thai is written:

   1. FONT. Raleway and Roboto ship no Thai glyphs, so Thai fell back to
      whatever the OS had, and font-weight:800 headings got SYNTHETIC bold,
      which smears the tone marks stacked above each consonant. Noto Sans Thai
      is a real 300..800 variable face (self-hosted by
      tools/build-local-fonts.py, thai subset only, 26 KB).
      It is listed FIRST but its @font-face declares only the Thai
      unicode-range, so Latin characters in the same sentence — "Year 7",
      "ATAR", "CRICOS" — still render in Raleway/Roboto. That mixing is
      deliberate: /Th/ copy keeps year levels and acronyms in Latin.

   2. LINE-HEIGHT. Thai stacks an upper vowel AND a tone mark above the
      consonant, plus a vowel below it — four levels where Latin has one.
      Anything at line-height <= 1.25 clips the marks off, which changes the
      word. The display classes are re-set loose enough to clear them.

   3. LETTER-SPACING. Thai is written with no spaces between words, so tracking
      pulls a single word apart and can visually detach a combining mark from
      its consonant. Every tracked display class is reset to normal here.
      (text-transform:uppercase is left alone — Thai has no capitals, so it is
      simply inert.)
   ========================================================================= */
html[lang="th"] {
  --km-display: 'Noto Sans Thai', 'Raleway', sans-serif;
  --km-body:    'Noto Sans Thai', 'Roboto', sans-serif;
}

/* Body copy — a little more air than Latin needs. */
html[lang="th"] body { line-height: 1.75; }

/* Display type: clear the stacked marks. */
html[lang="th"] .km-hero-title   { line-height: 1.4;  letter-spacing: normal; }
html[lang="th"] .km-hero-tagline { line-height: 1.45; }
html[lang="th"] .km-h2,
html[lang="th"] .km-h2-sm        { line-height: 1.42; }

html[lang="th"] .km-lead         { line-height: 1.8; }




/* Tracked / condensed UI type — drop the tracking, give the line room. */
html[lang="th"] .km-label,
html[lang="th"] .km-hero-pillars,
html[lang="th"] .km-btn,
html[lang="th"] .km-qnav-link,
html[lang="th"] .jpicnav-rail-item,
html[lang="th"] .jf-links a { letter-spacing: normal; }

html[lang="th"] .km-label { line-height: 1.6; }

/* Thai runs 15-30% longer than English, so a fixed-height pill can trap a
   descender. Let the chrome pills grow with their content. */
html[lang="th"] .km-qnav-link { height: auto; min-height: 42px; padding-top: 6px; padding-bottom: 6px; }
