/*
© Copyright 1990-2026 Toptronic® Ltd, all rights reserved; no part of this file may be
reproduced, modified or stored in a retrieval system, or transmitted in any form or by any
means, electronic, mechanical, photocopying, recording or otherwise, without the prior
written permission of Toptronic® Limited.
For copyright inquiries: jacques@toptronic.com

Generated/Updated on: 2026-08-06T19:30:00+1000

styles_006.css — file 6 of 6 (loaded LAST)

WHAT this file does:
  1. Responsive rules: how the layout grows from phone to desktop (768px and
     1100px breakpoints).
  2. The "reveal" scroll-in effect — ONLY for visitors who have not asked
     their device for reduced motion.
  3. CJK guards: special typography care for Chinese, Japanese and Korean.
  4. THE REDUCED-MOTION NET — the very last block in the very last file.

WHY it works this way (for Ryan, 14, and Ava, 9):
  A phone is narrow and a desktop is wide, so this file teaches the site to
  grow: one card per row on a phone, two on a tablet, three on a desktop.
  Some people feel sick when screens move too much, so devices have a
  "please reduce motion" switch. We respect it TWICE: the reveal effect only
  exists for people who said motion is OK, and the giant net at the bottom
  switches every animation OFF for everyone else — so the site never moves
  for someone who asked it not to. Content is NEVER hidden behind animation:
  if the effect can't run, everything is simply visible, like a normal page.
*/

/* ============================================================================
   SECTION 26 — RESPONSIVE: ≥768px (tablets and up)
   Mobile-first: files 001–005 describe the phone layout; this file only ever
   ADDS room as screens get wider. Breakpoints per design §5: 768px, 1100px.
   ========================================================================== */

@media (min-width: 768px) {

  /* Sections breathe deeper on bigger screens (design §1.4 rhythm rule).
     The hero keeps its own --sp-7 rhythm (styles_003.css, session 0034). */
  section:not(.hero),
  .home-tpee, .tools-tpee,
  .home-learn, .learn-list, .tools-more,
  .about-statement, .home-heritage, .about-heritage, .about-founder,
  .contact-card-wrap {
    padding-block: var(--sp-9);
  }

  /* Wider side gutters on the shared page column. */
  .container {
    padding-inline: var(--sp-6);
  }

  /* Header and footer join the same gutters, so the brand mark, the page
     content and the footer all share ONE left and right edge (session 0034
     art-direction: the million-dollar alignment detail). */
  .header-inner,
  .footer-inner {
    padding-inline: var(--sp-6);
  }

  /* Header: the hamburger retires; the nav becomes a permanent inline row.
     (Below 768px the toggle shows and .nav-links is the dropdown panel —
     those rules live in styles_002.css's max-width block.) */
  .nav-toggle {
    display: none;
  }

  /* Card grids open up to two columns (design §3.4). */
  .card-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* Hero: copy left, badge right (badge ~40% viewport width, max 480px). */
  .hero .container {
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  }

  /* Contact card button no longer needs full width. */
  .contact-card .btn-primary {
    width: auto;
  }

  /* Footer lockup lines up in a row on wider screens. */
  .footer-inner {
    flex-direction: row;
    align-items: flex-start;
    justify-content: space-between;
    flex-wrap: wrap;
  }
}

/* ============================================================================
   SECTION 27 — RESPONSIVE: ≥1100px (desktops)
   The widest the design grows: three-column card grids, deepest gutters.
   ========================================================================== */

@media (min-width: 1100px) {
  .card-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .container {
    padding-inline: var(--sp-6);
  }
}

/* ============================================================================
   SECTION 28 — RESPONSIVE: <768px (phones)
   Small-screen-only adjustments that are NOT the mobile-first default:
   things that must change FROM the desktop shape defined above.
   ========================================================================== */

@media (max-width: 767.98px) {
  /* Timeline becomes a sideways-scroll strip with snap points (design §3.6):
     each milestone slides in one at a time and clicks into place. */
  .timeline-strip {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    gap: var(--sp-6);
    padding-bottom: var(--sp-3);
    -webkit-overflow-scrolling: touch;
  }

  .timeline-strip::before {
    /* The connector line stretches across the full scroll width. */
    right: auto;
    width: 100%;
    min-width: 480px;
  }

  .timeline-item {
    scroll-snap-align: start;
    min-width: 140px;
    flex-shrink: 0;
  }

  /* The hero badge shrinks and sits under the copy on phones. */
  .hero-badge {
    width: min(64vw, 320px);
  }

  /* Full-width CTAs are easier to hit with a thumb. */
  .hero-ctas .btn {
    flex: 1 1 auto;
    justify-content: center;
  }
}

/* Very narrow phones (below 480px): the language pill shrinks to the globe
   alone — long native names like "Bahasa Indonesia" would otherwise crowd
   the 72px header (session 0034, art-direction F13). The button keeps its
   48px touch height; the label returns at 480px and up. */
@media (max-width: 479.98px) {
  #lang-btn .lang-current {
    display: none;
  }
}

/* ============================================================================
   SECTION 29 — THE REVEAL PATTERN (gated — design §4)
   The ONLY scroll animation on the site: elements gently fade up 12px when
   they enter the viewport, once, over 380ms. reveal_001.js watches with an
   IntersectionObserver and adds .revealed.

   THE HIDDEN STATE LIVES ONLY INSIDE THIS @media BLOCK.
   If the visitor asked for reduced motion (or their browser can't say), the
   hidden state DOES NOT EXIST — content is visible by default, with or
   without JavaScript. Progressive enhancement, never content hostage.
   Never applied to header, footer, or nav.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
  .reveal {
    opacity: 0;
    transform: translateY(12px);
    transition: opacity 380ms var(--ease),
                transform 380ms var(--ease);
    will-change: opacity, transform;
  }

  .reveal.revealed {
    opacity: 1;
    transform: none;
  }
}

/* ============================================================================
   SECTION 30 — CJK GUARDS (:lang(zh-Hans), :lang(ja), :lang(ko))
   Chinese, Japanese and Korean are live languages (D2). Their scripts are
   dense square characters, so three Latin habits must be switched off:
     1. letter-spacing — uppercase tracking breaks CJK rhythm → normal
     2. tight line-height — CJK needs more air → at least 1.6
     3. Latin-only font stacks → extend with Noto Sans SC/JP/KR fallbacks
   Same guard pattern as PLWS styles_006.
   ========================================================================== */

/* 30.1 Fonts: extend the stacks with the CJK families. */
:lang(zh-Hans) body,
:lang(zh-Hans) h1, :lang(zh-Hans) h2, :lang(zh-Hans) h3,
:lang(zh-Hans) h4, :lang(zh-Hans) h5, :lang(zh-Hans) h6,
body:lang(zh-Hans),
h1:lang(zh-Hans), h2:lang(zh-Hans), h3:lang(zh-Hans),
h4:lang(zh-Hans), h5:lang(zh-Hans), h6:lang(zh-Hans) {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
               Arial, "Noto Sans SC", "Noto Sans JP", "Noto Sans KR", sans-serif;
}

:lang(ja) body,
:lang(ja) h1, :lang(ja) h2, :lang(ja) h3,
:lang(ja) h4, :lang(ja) h5, :lang(ja) h6,
body:lang(ja),
h1:lang(ja), h2:lang(ja), h3:lang(ja),
h4:lang(ja), h5:lang(ja), h6:lang(ja) {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
               Arial, "Noto Sans JP", "Noto Sans SC", "Noto Sans KR", sans-serif;
}

:lang(ko) body,
:lang(ko) h1, :lang(ko) h2, :lang(ko) h3,
:lang(ko) h4, :lang(ko) h5, :lang(ko) h6,
body:lang(ko),
h1:lang(ko), h2:lang(ko), h3:lang(ko),
h4:lang(ko), h5:lang(ko), h6:lang(ko) {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
               Arial, "Noto Sans KR", "Noto Sans SC", "Noto Sans JP", sans-serif;
}

/* 30.2 Tracking OFF: the eyebrow's +0.08em and headings' -0.02em are Latin
   tricks; CJK characters must sit at their natural spacing. !important wins
   over every component rule above — that is the point of a guard. */
.eyebrow:lang(zh-Hans), .eyebrow:lang(ja), .eyebrow:lang(ko),
h1:lang(zh-Hans), h1:lang(ja), h1:lang(ko),
h2:lang(zh-Hans), h2:lang(ja), h2:lang(ko),
h3:lang(zh-Hans), h3:lang(ja), h3:lang(ko),
h4:lang(zh-Hans), h4:lang(ja), h4:lang(ko),
h5:lang(zh-Hans), h5:lang(ja), h5:lang(ko),
h6:lang(zh-Hans), h6:lang(ja), h6:lang(ko),
.statement:lang(zh-Hans), .statement:lang(ja), .statement:lang(ko),
.timeline-year:lang(zh-Hans), .timeline-year:lang(ja), .timeline-year:lang(ko),
.chip:lang(zh-Hans), .chip:lang(ja), .chip:lang(ko),
.lang-tag:lang(zh-Hans), .lang-tag:lang(ja), .lang-tag:lang(ko),
.brand-name:lang(zh-Hans), .brand-name:lang(ja), .brand-name:lang(ko),
.contact-facts dt:lang(zh-Hans), .contact-facts dt:lang(ja),
.contact-facts dt:lang(ko) {
  letter-spacing: normal !important;
}

/* 30.3 Line-height UP: CJK glyphs fill their em box completely, so they need
   at least 1.6 to breathe (D2: "line-height 1.6+"). */
body:lang(zh-Hans), body:lang(ja), body:lang(ko),
p:lang(zh-Hans), p:lang(ja), p:lang(ko),
li:lang(zh-Hans), li:lang(ja), li:lang(ko),
.prose:lang(zh-Hans), .prose:lang(ja), .prose:lang(ko),
.card:lang(zh-Hans), .card:lang(ja), .card:lang(ko),
.hero-sub:lang(zh-Hans), .hero-sub:lang(ja), .hero-sub:lang(ko),
.timeline-label:lang(zh-Hans), .timeline-label:lang(ja),
.timeline-label:lang(ko),
.fact-list:lang(zh-Hans), .fact-list:lang(ja), .fact-list:lang(ko) {
  line-height: 1.6;
}

/* 30.4 Uppercase is meaningless in CJK — the eyebrow keeps its size and
   weight but drops the transform so nothing looks shouted. */
.eyebrow:lang(zh-Hans), .eyebrow:lang(ja), .eyebrow:lang(ko) {
  text-transform: none;
}

/* 30.5 Hong Kong Traditional Chinese (:lang(zh-HK)) — same guards as 30.1-30.4
   but with the Traditional families first (Noto Sans TC / HK). */
:lang(zh-HK) body,
:lang(zh-HK) h1, :lang(zh-HK) h2, :lang(zh-HK) h3,
:lang(zh-HK) h4, :lang(zh-HK) h5, :lang(zh-HK) h6,
body:lang(zh-HK),
h1:lang(zh-HK), h2:lang(zh-HK), h3:lang(zh-HK),
h4:lang(zh-HK), h5:lang(zh-HK), h6:lang(zh-HK) {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
               Arial, "Noto Sans HK", "Noto Sans TC", "Noto Sans SC", sans-serif;
}

.eyebrow:lang(zh-HK),
h1:lang(zh-HK), h2:lang(zh-HK), h3:lang(zh-HK),
h4:lang(zh-HK), h5:lang(zh-HK), h6:lang(zh-HK),
.statement:lang(zh-HK), .timeline-year:lang(zh-HK),
.chip:lang(zh-HK), .lang-tag:lang(zh-HK), .brand-name:lang(zh-HK),
.contact-facts dt:lang(zh-HK) {
  letter-spacing: normal !important;
}

body:lang(zh-HK), p:lang(zh-HK), li:lang(zh-HK),
.prose:lang(zh-HK), .card:lang(zh-HK), .hero-sub:lang(zh-HK),
.timeline-label:lang(zh-HK), .fact-list:lang(zh-HK) {
  line-height: 1.6;
}

.eyebrow:lang(zh-HK) {
  text-transform: none;
}

/* ============================================================================
   SECTION 30.6 — ARABIC-SCRIPT GUARDS (:lang(ar), :lang(ur), :lang(fa))
   Arabic, Urdu and Persian are LIVE languages (ruling R2, session 0033) and
   their letters JOIN — any letter-spacing breaks the joining and looks
   broken, so the Latin tracking tricks must be switched off for them too
   (the same rule CJK gets in 30.2; session 0034, typography findings F3/F4).
   Uppercase transforms are a harmless no-op on these scripts, so they stay.
   ========================================================================== */

/* 30.6a Tracking OFF for Arabic-script languages. */
.eyebrow:lang(ar), .eyebrow:lang(ur), .eyebrow:lang(fa),
h1:lang(ar), h1:lang(ur), h1:lang(fa),
h2:lang(ar), h2:lang(ur), h2:lang(fa),
h3:lang(ar), h3:lang(ur), h3:lang(fa),
h4:lang(ar), h4:lang(ur), h4:lang(fa),
h5:lang(ar), h5:lang(ur), h5:lang(fa),
h6:lang(ar), h6:lang(ur), h6:lang(fa),
.statement:lang(ar), .statement:lang(ur), .statement:lang(fa),
.timeline-year:lang(ar), .timeline-year:lang(ur), .timeline-year:lang(fa),
.chip:lang(ar), .chip:lang(ur), .chip:lang(fa),
.lang-tag:lang(ar), .lang-tag:lang(ur), .lang-tag:lang(fa),
.brand-name:lang(ar), .brand-name:lang(ur), .brand-name:lang(fa),
.contact-facts dt:lang(ar), .contact-facts dt:lang(ur),
.contact-facts dt:lang(fa),
.trust-line:lang(ar), .trust-line:lang(ur), .trust-line:lang(fa) {
  letter-spacing: normal !important;
}

/* 30.6b Line-height UP: Naskh (Arabic/Persian) boxes are tall and Nastaliq
   (Urdu) is taller still, so these scripts need more air than Latin. */
body:lang(ar), body:lang(ur), body:lang(fa),
p:lang(ar), p:lang(ur), p:lang(fa),
li:lang(ar), li:lang(ur), li:lang(fa),
.prose:lang(ar), .prose:lang(ur), .prose:lang(fa),
.card:lang(ar), .card:lang(ur), .card:lang(fa),
.hero-sub:lang(ar), .hero-sub:lang(ur), .hero-sub:lang(fa),
.timeline-label:lang(ar), .timeline-label:lang(ur),
.timeline-label:lang(fa),
.fact-list:lang(ar), .fact-list:lang(ur), .fact-list:lang(fa) {
  line-height: 1.7;
}

body:lang(ur), p:lang(ur), li:lang(ur),
.prose:lang(ur), .card:lang(ur), .hero-sub:lang(ur),
.timeline-label:lang(ur), .fact-list:lang(ur) {
  line-height: 1.9;               /* Nastaliq needs the most room of all */
}

/* ============================================================================
   SECTION 30B — RTL SUPPORT (:dir rtl — Arabic, Urdu, Persian)
   When the i18n engine switches to ar/ur/fa it stamps dir="rtl" on <html>.
   Text, flex rows and inline flow flip BY THEMSELVES (that is what direction
   does); the rules below only mirror the few PHYSICAL properties we used
   (left/right, margin-left, border-left...) and pin machine text (code,
   numbers, emails, the brand wordmark) to left-to-right so it never garbles.
   ========================================================================== */

/* Chrome mirrors */
[dir="rtl"] .skip-link { left: auto; right: var(--sp-2); }
[dir="rtl"] .nav-links { margin-left: 0; margin-right: auto; }
[dir="rtl"] .nav-toggle { margin-left: 0; margin-right: auto; }
[dir="rtl"] #lang-dropdown { right: auto; left: 0; }
[dir="rtl"] .more-card { text-align: right; }

/* Session 0034 removed two rules that used to live here:
   - the .hero-arc mirror (the arc is now centered on the badge by
     construction — direction-neutral, styles_003.css §14.1)
   - the .heritage-strip p mirror (logical margin-inline-end now flips
     by itself, styles_005.css §22) */

/* Fact-list bullets move to the right side. */
[dir="rtl"] .fact-list li { padding-left: 0; padding-right: var(--sp-5); }
[dir="rtl"] .fact-list li::before { left: auto; right: 0; }

/* Light-section blockquote accent bar moves to the right. */
[dir="rtl"] .section--light blockquote {
  border-left: none;
  border-right: 3px solid var(--clr-yellow);
}

/* Machine text stays left-to-right inside an RTL page: code, numbers,
   emails, phone numbers, and the Latin brand wordmark. */
[dir="rtl"] pre, [dir="rtl"] code, [dir="rtl"] .code-sample {
  direction: ltr;
  text-align: left;
}
[dir="rtl"] .nums {
  direction: ltr;
  unicode-bidi: isolate;
}
[dir="rtl"] .contact-facts dd,
[dir="rtl"] .brand-name {
  direction: ltr;
  unicode-bidi: isolate;
}
[dir="rtl"] .contact-facts dd { text-align: right; }

/* ============================================================================
   SECTION 31 — THE REDUCED-MOTION NET (BINDING — design §4)
   *** THIS MUST BE THE LAST BLOCK OF THE LAST STYLESHEET. ***
   Every animated element is named EXPLICITLY (no bare `*`), so nothing can
   leak into reduce mode. Transitions and animations are switched off, smooth
   scrolling reverts to instant jumps, and .reveal content is forced fully
   visible. reveal_001.js also short-circuits under reduce — this net is the
   guarantee that holds even with JavaScript off.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .site-header, .header-inner, .brand, .brand-logo, .brand-name,
  .nav-links, .nav-toggle, .nav-toggle .bar, .nav-toggle-bar,
  .lang-switch, #lang-btn, #lang-dropdown, .lang-tag,
  .skip-link,
  .hero, .hero-copy, .hero-sub, .hero-ctas, .hero-badge, .hero-arc,
  .btn, .btn-primary, .btn-secondary,
  .card, .card-grid, .guide-card, .chip, .card-meta, .more-card,
  .tpee-card, .code-sample, .fact-list,
  .section--light,
  .timeline-strip, .timeline-item, .timeline-year, .timeline-label,
  .contact-card, .contact-facts,
  .contact-card input, .contact-card textarea,
  .nf, .nf-code,
  .statement, .heritage-strip,
  .site-footer, .footer-inner, .footer-lockup, .footer-links, .footer-lang,
  .reveal,
  a {
    transition: none !important;
    animation: none !important;
  }

  /* Content is never hostage: reveal elements are simply visible. */
  .reveal {
    opacity: 1 !important;
    transform: none !important;
  }
}

/* End of styles_006.css — and the end of the cascade.
   Six files, loaded in order, no @import. The net above is the final word. */
