/* Tarsier site design system.
   Shared by every page. Change the nav, footer, tokens or type here and
   it lands everywhere at once. Page-specific rules go in that page's
   own <style> block.

   !! After editing this file, bump the cache-buster in EVERY page that
   links it, or browsers keep serving the old stylesheet and the change
   looks like it silently did nothing:

     sed -i '' 's|styles.css?v=OLD|styles.css?v=NEW|g' \
       site/index.html site/faq/index.html site/release-notes/index.html \
       site/privacy/index.html site/terms/index.html site/sources/index.html

   Write the numbers out rather than pasting the current version on both
   sides: a same-to-same substitution rewrites this comment into a no-op
   and silently leaves every page on the old stylesheet.

   Currently at v24. Vercel caches aggressively, so this matters in
   production as much as it does locally. (site/links/index.html is
   self-contained and does not link this file, so it is not in the list.) */

    :root {
      --purple: #5B48E0;
      --purple-dark: #4938BE;
      --purple-light: #EEE9FF;
      --gold: #F5A100;
      --green: #58CC02;
      --red: #FF4B4B;
      --dark: #1A1A2E;
      --cream: #F8F8FC;
      --text-primary: #1A1A2E;
      --text-secondary: #6B7280;
      --border: #E5E7EB;

      --shell: 1160px;
      --gutter: 24px;
    }

    * { margin: 0; padding: 0; box-sizing: border-box; }

    ::selection { background: var(--purple); color: #fff; }

    html { scroll-behavior: smooth; scroll-padding-top: 96px; }

    body {
      font-family: ui-rounded, 'SF Pro Rounded', -apple-system, BlinkMacSystemFont, 'Nunito', system-ui, sans-serif;
      background: #fff;
      color: var(--text-primary);
      -webkit-font-smoothing: antialiased;
      text-rendering: optimizeLegibility;
    }

    img { max-width: 100%; display: block; }

    .shell {
      width: 100%;
      max-width: var(--shell);
      margin: 0 auto;
      padding: 0 var(--gutter);
    }

    /* ---------- Nav ---------- */
    .nav {
      position: sticky;
      top: 0;
      z-index: 50;
      background: rgba(255, 255, 255, 0.82);
      -webkit-backdrop-filter: saturate(180%) blur(16px);
      backdrop-filter: saturate(180%) blur(16px);
      border-bottom: 1px solid transparent;
      transition: border-color 0.2s ease;
    }

    .nav.scrolled { border-bottom-color: var(--border); }

    .nav-inner {
      height: 76px;
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 24px;
    }

    .brand {
      display: inline-flex;
      align-items: center;
      gap: 10px;
      text-decoration: none;
      color: var(--text-primary);
      font-weight: 800;
      font-size: 19px;
      letter-spacing: -0.4px;
    }

    .brand img { width: 38px; height: 38px; border-radius: 10px; }

    .nav-links {
      display: flex;
      align-items: center;
      gap: 30px;
      margin-left: auto;
    }

    .nav-links a {
      color: var(--text-primary);
      text-decoration: none;
      font-size: 15px;
      font-weight: 600;
      transition: color 0.15s ease;
    }

    .nav-links a:hover { color: var(--purple); }

    .btn {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 9px;
      border: none;
      cursor: pointer;
      font-family: inherit;
      font-weight: 700;
      text-decoration: none;
      border-radius: 999px;
      transition: transform 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
    }

    .btn:active { transform: scale(0.98); }

    .btn-purple {
      background: var(--purple);
      color: #fff;
      font-size: 15px;
      padding: 12px 22px;
    }

    .btn-purple:hover { background: var(--purple-dark); }

    .btn-dark {
      background: var(--dark);
      color: #fff;
      font-size: 18px;
      padding: 16px 30px;
    }

    .btn-dark:hover {
      background: #000;
      box-shadow: 0 10px 26px rgba(26, 26, 46, 0.22);
    }

    .btn-dark svg { width: 21px; height: 21px; }

    /* Android green (#3DDC84, the official brand green) with DARK text, not
       white. White on this green is about 1.7:1 and fails WCAG outright; the
       green is a light colour and Android's own material uses it behind dark
       ink for exactly this reason. Dark ink here is ~11:1.

       Sized to match .btn-dark so the two platform CTAs read as a pair rather
       than a primary and an afterthought. */
    .btn-android {
      background: #3DDC84;
      color: var(--dark);
      font-size: 18px;
      padding: 16px 30px;
    }

    .btn-android:hover {
      background: #2FCB74;
      box-shadow: 0 10px 26px rgba(61, 220, 132, 0.35);
    }

    .btn-android svg { width: 21px; height: 21px; }

    .nav-toggle {
      display: none;
      background: none;
      border: none;
      cursor: pointer;
      padding: 8px;
      color: var(--text-primary);
    }

    .nav-toggle svg { width: 24px; height: 24px; }

    /* ---------- Hero ---------- */
    .hero { padding: 72px 0 40px; }

    .hero-grid {
      display: grid;
      grid-template-columns: minmax(0, 1fr) 340px;
      align-items: center;
      gap: 56px;
    }

    /* Plain line, no pill. A tinted badge with an emoji in it is the
       stock AI-landing-page tell. */
    .eyebrow {
      display: block;
      color: var(--purple);
      font-size: 14px;
      font-weight: 700;
      margin-bottom: 18px;
    }

    h1 {
      font-size: clamp(40px, 5.6vw, 68px);
      font-weight: 900;
      line-height: 1.03;
      letter-spacing: -2px;
      margin-bottom: 20px;
    }

    h1 .accent { color: var(--purple); }

    .hero-sub {
      font-size: 20px;
      line-height: 1.5;
      color: var(--text-secondary);
      max-width: 520px;
      margin-bottom: 32px;
    }

    /* Shrink-wraps the button so its microcopy can centre on the button
       rather than on the whole text column. */
    .hero-action { width: fit-content; }

    .hero-cta { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; }

    .hero-note {
      font-size: 13px;
      color: var(--text-secondary);
      margin-top: 14px;
      font-weight: 500;
      text-align: center;
    }

    /* ---------- Trust row ----------
       One quiet line under the CTA. Numbers come from the live App Store
       lookup; the markup carries the last known values as a fallback. */
    .trust {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: 10px 20px;
      margin-top: 22px;
      font-size: 14.5px;
      font-weight: 500;
      color: var(--text-secondary);
    }

    .trust-item { display: inline-flex; align-items: center; gap: 7px; position: relative; }
    .trust-item[hidden] { display: none; }
    .trust-item b { color: var(--text-primary); font-weight: 800; }
    /* The focus ring is the only affordance saying these are interactive, so
       it is not suppressed. :focus-visible keeps it off a mouse click. */
    .trust-item:focus { outline: none; }
    .trust-item:focus-visible { outline: 2px solid var(--purple); outline-offset: 4px; border-radius: 6px; }

    /* "Last updated" chip.
       Both figures here are hardcoded and refreshed by hand at release time,
       so the page would otherwise state them as if they were live and give a
       reader no way to tell this morning's number from a six-week-old one. */
    .stat-chip {
      position: absolute;
      bottom: calc(100% + 9px);
      left: 50%;
      transform: translate(-50%, 4px);
      white-space: nowrap;
      background: var(--dark);
      color: #fff;
      font-size: 12.5px;
      font-weight: 600;
      letter-spacing: -0.1px;
      padding: 7px 11px;
      border-radius: 8px;
      box-shadow: 0 6px 18px rgba(26, 26, 46, 0.18);
      opacity: 0;
      visibility: hidden;
      pointer-events: none;
      transition: opacity 0.16s ease, transform 0.16s ease, visibility 0.16s;
      z-index: 5;
    }

    /* Arrow, same colour as the chip body. */
    .stat-chip::after {
      content: "";
      position: absolute;
      top: 100%;
      left: 50%;
      margin-left: -5px;
      border: 5px solid transparent;
      border-top-color: var(--dark);
    }

    .trust-item:hover .stat-chip,
    .trust-item:focus-visible .stat-chip {
      opacity: 1;
      visibility: visible;
      transform: translate(-50%, 0);
    }

    /* Touch has no hover, and a chip that only a mouse can reach would leave
       the mobile reader with the bare number this exists to qualify. Shown
       inline underneath instead, always. */
    @media (hover: none) {
      .trust-item { flex-wrap: wrap; }
      .stat-chip {
        position: static;
        transform: none;
        opacity: 1;
        visibility: visible;
        background: none;
        color: var(--text-secondary);
        box-shadow: none;
        padding: 0;
        font-size: 12px;
        font-weight: 500;
        flex-basis: 100%;
      }
      .stat-chip::after { display: none; }
    }

    /* Dot between items, never leading */
    .trust-item + .trust-item::before {
      content: "";
      width: 3px;
      height: 3px;
      border-radius: 50%;
      background: var(--border);
      margin-right: 13px;
    }

    /* Partial-fill stars: a grey row with a gold row clipped over it */
    .stars { position: relative; display: inline-block; line-height: 0; }

    .stars-row { display: flex; gap: 3px; }
    .stars-row svg { width: 15px; height: 15px; flex-shrink: 0; }
    .stars-row { gap: 2px; }

    .stars-base { color: #DEDAEC; }

    .stars-clip {
      position: absolute;
      top: 0;
      left: 0;
      bottom: 0;
      overflow: hidden;
      width: var(--star-fill, 92%);
    }

    .stars-fill { width: max-content; color: var(--gold); }

    /* Stretch + centre, NOT `justify-self: center`. Centring makes the grid
       item content-sized, so `.device { width: 100% }` had nothing to resolve
       against once the screenshot became absolutely positioned — the phone
       collapsed to 18px. The flex centre keeps the same visual result with a
       real width to measure from. */
    .hero-shot {
      justify-self: stretch;
      display: flex;
      justify-content: center;
      align-items: flex-start;
    }

    /* ---------- Device placeholder ----------
       SWAP POINT: when the new screenshots exist, replace the inner
       .device-screen contents with <img src="screenshots/N.png" alt="...">
       and delete the .shot-label span. Nothing else needs to change. */
    /* No aspect-ratio here on purpose. It used to live on this outer box, but
       the bezel is a fixed padding (9px here, 7px on cards and rows), and
       subtracting a constant from both sides of a 0.4613 box leaves an INNER
       box of ~0.444. The screenshots are 0.4601, so object-fit: cover scaled
       them to height and chopped ~4px off each side, eating the right edge of
       the UI. The ratio belongs on .device-screen, the box that has to match
       the screenshot; this one now sizes from its contents plus the bezel. */
    .device {
      position: relative;
      width: 100%;
      background: var(--dark);
      border-radius: 44px;
      padding: 9px;
      box-shadow: 0 24px 60px rgba(26, 26, 46, 0.18), 0 2px 6px rgba(26, 26, 46, 0.1);
    }

    .device-screen {
      position: relative;
      width: 100%;
      /* Matches the captured screenshots (iPhone 17 Pro, 1206x2622) so cover
         crops nothing. Keep this in step with the source shots. */
      aspect-ratio: 1206 / 2622;
      border-radius: 36px;
      overflow: hidden;
      background: linear-gradient(165deg, #F4F1FF 0%, #FBFAFF 48%, #F7F4FF 100%);
      display: flex;
      align-items: center;
      justify-content: center;
    }

    /* Absolutely positioned so the screen's padding-top — which exists only to
       lift the PLACEHOLDER label into the visible band on cropped variants —
       cannot push a real screenshot down inside the phone. Leaving it in flow
       left a blank gradient band at the top of every card and clipped the shot
       at the bottom. Placeholder labels still lay out normally. */
    .device-screen img {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      object-fit: cover;
    }

    /* Anchor the crop to the TOP of the capture rather than its middle.
       `cover` defaults to `50% 50%`, which on a card whose content sits high
       eats the status bar and the chapter pills at the top while also cutting
       Continue off the bottom — the affix shot showed a sliced pill row as its
       first visible element. Top-anchoring shows the top two-thirds, which is
       how the other feature shots already read (Ean, 2026-07-30).

       Scoped to the shot rather than changed on `.device-screen img`, because
       the app-store and hero frames are sized to the capture exactly and
       centring is correct for them. */
    .device-screen img.shot-top { object-position: 50% 0; }

    /* Drawn ONLY for placeholder shots. A real screenshot is a full-screen
       capture that already contains the Dynamic Island, so painting another
       one on top double-stacks it. */
    .device::after {
      content: "";
      position: absolute;
      top: 20px;
      left: 50%;
      transform: translateX(-50%);
      width: 30%;
      height: 3.6%;
      background: var(--dark);
      border-radius: 999px;
      z-index: 2;
    }

    .device:has(.device-screen img)::after { content: none; }

    .shot-label {
      font-size: 13px;
      font-weight: 700;
      letter-spacing: 0.4px;
      text-transform: uppercase;
      color: #B9AEF0;
      padding: 0 20px;
      text-align: center;
    }

    .hero-shot .device { max-width: 320px; }

    /* ---------- Stats strip ---------- */
    .stats { padding: 44px 0 8px; }

    .stats-inner {
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      gap: 12px;
      background: var(--cream);
      border: 1px solid var(--border);
      border-radius: 20px;
      padding: 26px 20px;
    }

    .stat { text-align: center; }

    .stat-num {
      font-size: 30px;
      font-weight: 900;
      letter-spacing: -1px;
      color: var(--purple);
      line-height: 1.1;
    }

    .stat-label {
      font-size: 13px;
      font-weight: 600;
      color: var(--text-secondary);
      margin-top: 4px;
    }

    /* ---------- Section header ---------- */
    section.block { padding: 76px 0; }

    .section-head { text-align: center; max-width: 760px; margin: 0 auto 44px; }

    .section-head h2 {
      font-size: clamp(30px, 3.6vw, 44px);
      font-weight: 900;
      letter-spacing: -1.2px;
      line-height: 1.1;
      margin-bottom: 14px;
    }

    .section-head h2 .accent { color: var(--purple); }

    .section-head p {
      font-size: 19px;
      line-height: 1.5;
      color: var(--text-secondary);
    }

    /* ---------- Feature cards ---------- */
    .cards {
      display: grid;
      grid-template-columns: repeat(3, minmax(0, 1fr));
      gap: 40px 32px;
    }

    /* min-width: 0 so an oversized child (the 560px zoomed device) cannot
       set the card's min-content and blow out its grid track. Flex and grid
       children default to min-width: auto, which is what lets that happen. */
    .card { display: flex; flex-direction: column; min-width: 0; }

    .card-frame {
      position: relative;
      height: 320px;
      min-width: 0;
      background: var(--purple-light);
      border-radius: 16px;
      overflow: hidden;
      display: flex;
      align-items: flex-start;
      justify-content: center;
    }

    /* The PHONE lifts, not the card. The tinted panel stays put and its
       overflow:hidden keeps the phone clipped to it, so the phone reads as
       rising inside a window rather than the whole tile nudging upward. */
    .card-frame .device {
      width: 224px;
      margin-top: 30px;
      flex-shrink: 0;
      border-radius: 34px;
      padding: 7px;
      box-shadow: 0 14px 34px rgba(26, 26, 46, 0.16);
      transition: transform 0.28s cubic-bezier(0.22, 0.61, 0.36, 1),
                  box-shadow 0.28s ease;
      will-change: transform;
    }

    /* Trigger is the PHONE, not the card. Hovering the heading or the body
       copy used to lift the phone, which reads as the page twitching at
       something you are only reading (Ean, 2026-07-30). Matches the feature
       rows, which already scope this to `.hf-shot .device:hover`. */
    .card-frame .device:hover {
      transform: translateY(-12px);
      box-shadow: 0 26px 52px rgba(26, 26, 46, 0.28),
                  0 4px 12px rgba(26, 26, 46, 0.12);
    }

    /* Bottom-anchored variant. Most shots put the payload in the TOP of the
       screen, so the default hangs the phone down and shows its head. A few
       screens carry the interesting part LOW — the post-check quiz feedback,
       the ube counter — and cropping those to the top shows a header and
       nothing else. `shot-bottom` pins the phone's foot to the card instead,
       so the lower two-thirds is what survives the crop. Hover pushes it
       further down rather than lifting, matching the direction the eye is
       already travelling in these cards. */
    /* Zoomed corner shot. The whole phone is drawn 2.5x its normal size and
       pinned to the card's right edge, so what survives the crop is the
       top-right CORNER of the device — bezel curve included — rather than a
       flat blow-up of the pixels. Used for the ube counter, a small pill
       that vanishes when a whole screen is scaled down into a card. */
    .card-frame.shot-zoom { justify-content: flex-end; }

    .card-frame.shot-zoom .device {
      width: 560px;          /* 2.5x the 224px the other cards use */
      margin-top: 40px;
      /* Pulls the phone left until the ube pill sits on the card's centre
         line. The pill's centre is ~121px in from the device's right edge
         at this width, so half the card minus that lands it dead centre at
         ANY card width — a flat px margin only holds at one viewport. */
      margin-right: calc(50% - 121px);
      /* The bezel is a fixed padding, so at 2.5x it stayed 7px and read as
         a hairline against a magnified screen. Scale it, and both radii,
         by the same 2.5 so the corner keeps the proportions of the phone
         drawn on every other card. */
      padding: 17.5px;
      border-radius: 85px;
    }

    .card-frame.shot-zoom .device-screen { border-radius: 70px; }

    /* Lifts rather than slides: a cropped corner shifting sideways reads as
       a glitch, straight up reads as the same hover the other cards have. */
    .card-frame.shot-zoom .device:hover { transform: translateY(-10px); }

    .card-frame.shot-bottom { align-items: flex-end; }

    .card-frame.shot-bottom .device {
      margin-top: 0;
      margin-bottom: 30px;
    }

    .card-frame.shot-bottom .device:hover { transform: translateY(12px); }

    @media (prefers-reduced-motion: reduce) {
      .card-frame .device { transition: box-shadow 0.28s ease; }
      .card-frame .device:hover { transform: none; }
      .card-frame.shot-bottom .device:hover { transform: none; }
    }

    /* The card crops the phone, so pull the placeholder label up into the
       visible band instead of centring it in the full device height. */
    .card-frame .device-screen { border-radius: 28px; align-items: flex-start; padding-top: 112px; }
    .card-frame .device::after { top: 15px; height: 2.6%; }
    .card-frame .shot-label { font-size: 11px; }

    .card h3 {
      font-size: 19px;
      font-weight: 800;
      letter-spacing: -0.3px;
      margin-top: 20px;
    }

    .card p {
      font-size: 15px;
      line-height: 1.55;
      color: var(--text-secondary);
      margin-top: 6px;
    }

    /* ---------- Hero features (the three differentiators) ----------
       One column, one full-width row each, device and copy alternating
       sides. These carry more weight than the grid cards below. */
    .hero-features { display: flex; flex-direction: column; gap: 24px; }

    .hf-row {
      display: grid;
      grid-template-columns: 1fr 1fr;
      align-items: center;
      background: var(--purple-light);
      border-radius: 24px;
      /* NOT overflow:hidden. The row only needs to clip the phone, and
         .hf-shot already does that. Clipping here also cut the tooltip and
         drop shadow off the inline `po` / `Alam Mo Ba` pills in the copy
         column, which is why they looked chopped on desktop but fine on
         mobile, where the row goes auto-height and stacks. */
      overflow: visible;
      /* Fixed so the tall device crops instead of stretching the row */
      height: 400px;
    }

    .hf-copy { padding: 56px 52px; }

    .hf-copy h3 {
      font-size: clamp(24px, 2.6vw, 32px);
      font-weight: 900;
      letter-spacing: -0.8px;
      line-height: 1.15;
      margin-bottom: 14px;
    }

    .hf-copy p {
      font-size: 17px;
      line-height: 1.6;
      color: #4B4A63;
      max-width: 420px;
    }

    .hf-shot {
      align-self: stretch;
      display: flex;
      align-items: flex-start;
      justify-content: center;
      overflow: hidden;
      /* Carries the row's rounded corners on its own side now that the row
         no longer clips, so the phone still cannot poke past the curve. */
      border-radius: 0 24px 24px 0;
    }

    .hf-row:nth-child(even) .hf-shot { border-radius: 24px 0 0 24px; }

    .hf-shot .device {
      width: 248px;
      flex-shrink: 0;
      margin-top: 56px;
      border-radius: 36px;
      padding: 7px;
      box-shadow: 0 18px 40px rgba(26, 26, 46, 0.18);
    }

    .hf-shot .device-screen {
      border-radius: 30px;
      align-items: flex-start;
      padding-top: 130px;
    }

    .hf-shot .device::after { top: 16px; height: 2.6%; }
    .hf-shot .shot-label { font-size: 11px; }

    /* Two phones in one row, for a claim that needs a pair to land (the
       culture row shows the respect choice AND the Alam Mo Ba card).
       Level, not staggered, and sitting a little lower than the
       single-phone rows so each shot stops short of its dead space.

       Width is a min() against the column, NOT a flat px value. The column
       is ~556px at 1440 but shrinks well below that on smaller screens, so
       a fixed pair sized to look right on a wide display silently overflows
       and clips the outer phone. */
    .hf-shot.two-up { gap: 20px; }

    .hf-shot.two-up .device {
      width: min(196px, calc((100% - 20px) / 2));
      margin-top: 88px;
    }

    /* The Alam Mo Ba card sits a little lower, so the pair reads as two
       phones rather than one wide slab. */
    .hf-shot.two-up .device:nth-child(2) { margin-top: 116px; }

    /* Same lift as the grid cards: the tinted row holds still and the phone
       rises inside it. Covers the affix-breakdown, Taglish-variant and
       cultural-card shots. */
    .hf-shot .device {
      transition: transform 0.28s cubic-bezier(0.22, 0.61, 0.36, 1),
                  box-shadow 0.28s ease;
      will-change: transform;
    }

    /* Hover the PHONE, not the row. Keying off .hf-row:hover meant the
       mouse anywhere in the tinted panel — including the paragraph — lifted
       the phone, and on the two-up row it lifted both at once. */
    .hf-shot .device:hover {
      transform: translateY(-12px);
      box-shadow: 0 30px 58px rgba(26, 26, 46, 0.3),
                  0 4px 12px rgba(26, 26, 46, 0.12);
    }

    /* Two-up keeps the lift but drops the shadow: side by side, one phone's
       shadow falls across its neighbour. */
    .hf-shot.two-up .device:hover {
      box-shadow: 0 18px 40px rgba(26, 26, 46, 0.18);
    }

    @media (prefers-reduced-motion: reduce) {
      .hf-shot .device { transition: box-shadow 0.28s ease; }
      .hf-shot .device:hover { transform: none; }
    }

    /* Alternate: device on the left */
    .hf-row:nth-child(even) .hf-copy { order: 2; }
    .hf-row:nth-child(even) .hf-shot { order: 1; }

    /* Tinted variants so a long grid does not read as one flat block */
    .tint-gold  { background: #FFF3DC; }
    .tint-green { background: #E9F8DC; }
    .tint-red   { background: #FFECEC; }
    .tint-cream { background: var(--cream); }

    /* ---------- More chips ---------- */
    .chips {
      display: flex;
      flex-wrap: wrap;
      justify-content: center;
      gap: 10px;
      margin-top: 52px;
    }

    .chip {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      background: #fff;
      border: 1px solid var(--border);
      border-radius: 999px;
      padding: 10px 18px;
      font-size: 14.5px;
      font-weight: 600;
      color: var(--text-primary);
    }

    .chip svg { width: 15px; height: 15px; color: var(--green); flex-shrink: 0; }

    /* ---------- Affix showcase ---------- */
    .affix {
      background: var(--dark);
      border-radius: 28px;
      padding: 56px 40px;
      color: #fff;
      text-align: center;
    }

    .affix h2 {
      font-size: clamp(26px, 3.2vw, 38px);
      font-weight: 900;
      letter-spacing: -1px;
      margin-bottom: 12px;
    }

    .affix-lede {
      font-size: 18px;
      color: rgba(255, 255, 255, 0.66);
      max-width: 620px;
      margin: 0 auto 40px;
      line-height: 1.5;
    }

    .affix-word {
      display: flex;
      /* Block-level flex, so text-align on the parent cannot centre it. */
      margin-inline: auto;
      width: fit-content;
      flex-wrap: wrap;
      align-items: flex-start;
      justify-content: center;
      gap: 6px;
      font-size: clamp(34px, 5vw, 56px);
      font-weight: 900;
      letter-spacing: -1px;
    }

    .morph { display: flex; flex-direction: column; align-items: center; gap: 10px; }

    .morph span:first-child { line-height: 1; }

    .morph .bar { width: 100%; height: 4px; border-radius: 999px; }

    .morph .tag {
      font-size: 12px;
      font-weight: 700;
      letter-spacing: 0.6px;
      text-transform: uppercase;
    }

    .morph.affix-part span:first-child { color: #A99BFF; }
    .morph.affix-part .bar { background: #A99BFF; }
    .morph.affix-part .tag { color: #A99BFF; }

    .morph.root-part span:first-child { color: #fff; }
    .morph.root-part .bar { background: rgba(255, 255, 255, 0.85); }
    .morph.root-part .tag { color: rgba(255, 255, 255, 0.6); }

    .affix-result {
      margin-top: 52px;
      max-width: 640px;
      margin-inline: auto;
      font-size: 18px;
      color: rgba(255, 255, 255, 0.8);
      line-height: 1.6;
    }

    .affix-result b { color: #fff; }

    .affix-row {
      display: flex;
      flex-wrap: wrap;
      justify-content: center;
      gap: 10px;
      margin-top: 28px;
    }

    .affix-pill {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      background: rgba(255, 255, 255, 0.08);
      border: 1px solid rgba(255, 255, 255, 0.14);
      border-radius: 999px;
      padding: 9px 16px;
      font-family: inherit;
      font-size: 15px;
      font-weight: 600;
      color: rgba(255, 255, 255, 0.9);
      cursor: pointer;
      transition: background 0.15s ease, border-color 0.15s ease, transform 0.12s ease;
    }

    .affix-pill:hover { background: rgba(255, 255, 255, 0.15); border-color: rgba(255, 255, 255, 0.28); }
    .affix-pill.playing { background: rgba(169, 155, 255, 0.28); border-color: #A99BFF; transform: scale(0.97); }

    /* Play-on-tap affordance */
    .affix-pill-label { white-space: nowrap; }

    .speak-icon { width: 13px; height: 13px; opacity: 0.55; flex-shrink: 0; }
    .affix-pill:hover .speak-icon, .speak.playing .speak-icon { opacity: 1; }

    .affix-word.speak {
      background: none;
      border: none;
      padding: 0;
      cursor: pointer;
      font-family: inherit;
      transition: transform 0.12s ease;
    }

    .affix-word.speak:hover { transform: scale(1.02); }
    .affix-word.speak.playing { transform: scale(0.98); }

    .speak-inline {
      background: none;
      border: none;
      padding: 0;
      cursor: pointer;
      font: inherit;
      color: inherit;
      display: inline-flex;
      align-items: center;
      gap: 5px;
      transition: opacity 0.15s ease;
    }

    .speak-inline:hover { opacity: 0.75; }
    .speak-inline .speak-icon { width: 12px; height: 12px; }

    .speak:focus-visible { outline: 2px solid #A99BFF; outline-offset: 4px; border-radius: 8px; }

    .affix-pill b { color: #A99BFF; }

    /* ---------- About ---------- */
    /* Single column since the mascot art was removed. Capped so the prose
       keeps a readable measure instead of running the full 1160px shell. */
    /* .shell also sets a max-width, so this needs the extra specificity. */
    .about .about-grid { max-width: 720px; }

    .about h2 {
      font-size: clamp(28px, 3.4vw, 38px);
      font-weight: 900;
      letter-spacing: -1px;
      margin-bottom: 20px;
    }

    .about p {
      font-size: 16.5px;
      line-height: 1.65;
      color: var(--text-secondary);
      margin-bottom: 16px;
    }

    .about p b { color: var(--text-primary); font-weight: 700; }

    .about-pron {
      font-size: 14.5px !important;
      color: var(--text-secondary);
      margin-top: -12px;
      margin-bottom: 24px !important;
    }

    .baybayin { font-size: 17px; color: var(--purple); }

    .person-link {
      font-size: 13px;
      font-weight: 700;
      color: var(--purple);
      text-decoration: none;
      margin-top: -6px;
    }

    .person-link:hover { text-decoration: underline; }

    .people { display: flex; flex-wrap: wrap; gap: 40px; margin-top: 30px; }

    .person { display: flex; flex-direction: column; gap: 10px; }

    .person-name { font-size: 16px; font-weight: 700; }

    .person-role { font-size: 13px; color: var(--text-secondary); margin-top: -8px; }

    .person img,
    .person .avatar-blank {
      width: 52px;
      height: 52px;
      border-radius: 14px;
      object-fit: cover;
      background: var(--purple-light);
      border: 1px solid var(--border);
    }

    /* The mascot is a transparent SVG and sits on the page directly, with
       no tile behind it. */
    .person img.avatar-tarso {
      border-color: transparent;
      background: none;
      border-radius: 0;
      object-fit: contain;
    }

    /* ---------- Android waitlist ---------- */
    .waitlist { background: var(--cream); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }

    .waitlist-inner {
      display: grid;
      grid-template-columns: minmax(0, 1fr) 380px;
      gap: 56px;
      align-items: center;
    }

    .waitlist h2 {
      font-size: clamp(28px, 3.4vw, 40px);
      font-weight: 900;
      letter-spacing: -1.2px;
      line-height: 1.1;
      margin-bottom: 14px;
    }

    .waitlist p { font-size: 17.5px; line-height: 1.55; color: var(--text-secondary); }

    .waitlist-badge {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      background: #DDF5CC;
      color: #3D8B00;
      font-size: 13px;
      font-weight: 800;
      padding: 7px 14px;
      border-radius: 999px;
      margin-bottom: 18px;
    }

    .waitlist-badge svg { width: 15px; height: 15px; }

    .waitlist-form {
      background: #fff;
      border: 1px solid var(--border);
      border-radius: 20px;
      padding: 24px;
      box-shadow: 0 8px 24px rgba(26, 26, 46, 0.05);
      /* Held to the width the two-column layout gives it, so the card does
         not stretch into a letterbox once the section stacks. */
      width: 100%;
      max-width: 420px;
      margin-inline: auto;
    }

    .waitlist-form label {
      display: block;
      font-size: 13px;
      font-weight: 700;
      color: var(--text-secondary);
      margin-bottom: 8px;
    }

    .waitlist-form input {
      width: 100%;
      font-family: inherit;
      font-size: 16px;
      font-weight: 500;
      padding: 14px 16px;
      border: 1.5px solid var(--border);
      border-radius: 14px;
      background: var(--cream);
      color: var(--text-primary);
      outline: none;
      transition: border-color 0.15s ease, background 0.15s ease;
    }

    .waitlist-form input:focus { border-color: var(--purple); background: #fff; }

    /* Matches .btn-dark's type size so the Android CTA carries the same weight
       as Download on iOS rather than reading as a lesser, secondary ask.
       Full width because it closes a form, where a hugging button looks
       unfinished. */
    .waitlist-form .btn { width: 100%; margin-top: 12px; padding: 16px 22px; font-size: 18px; }

    /* Resting note, success and error all share this one line, and it
       reserves two lines of height, so submitting never resizes the card. */
    .waitlist-note {
      font-size: 12.5px;
      font-weight: 500;
      color: var(--text-secondary);
      margin-top: 12px;
      text-align: center;
      min-height: 2.9em;
      transition: color 0.2s ease;
    }

    .waitlist-note.ok { color: #3D8B00; font-weight: 700; }
    .waitlist-note.err { color: var(--red); font-weight: 700; }

    /* ---------- Closing CTA ---------- */
    .closing { text-align: center; }

    .closing h2 {
      font-size: clamp(30px, 4vw, 46px);
      font-weight: 900;
      letter-spacing: -1.4px;
      line-height: 1.08;
      margin-bottom: 16px;
    }

    .closing p { font-size: 19px; color: var(--text-secondary); margin-bottom: 30px; }

    .closing .btn-dark { margin: 0 auto; }

    .closing-mascot { width: 120px; margin: 0 auto 24px; }

    /* ---------- Footer ---------- */
    footer {
      background: var(--purple);
      color: #fff;
      padding: 60px 0 32px;
    }

    footer .brand { color: #fff; }

    .foot-grid {
      display: grid;
      grid-template-columns: 1.4fr 1fr 1fr 1.6fr;
      gap: 40px;
    }

    .foot-brand p {
      font-size: 14.5px;
      color: rgba(255, 255, 255, 0.72);
      line-height: 1.6;
      margin-top: 14px;
      max-width: 260px;
    }

    .foot-col h4 {
      font-size: 14px;
      font-weight: 800;
      margin-bottom: 14px;
      color: #fff;
    }

    .foot-col a {
      display: block;
      font-size: 14.5px;
      color: rgba(255, 255, 255, 0.78);
      text-decoration: none;
      margin-bottom: 10px;
      transition: color 0.15s ease;
    }

    .foot-col a:hover { color: #fff; }

    .socials { display: flex; gap: 16px; margin-top: 16px; }

    .socials a { color: rgba(255, 255, 255, 0.78); transition: color 0.15s ease; }
    .socials a:hover { color: #fff; }
    .socials svg { width: 22px; height: 22px; }

    .foot-bottom {
      margin-top: 44px;
      padding-top: 24px;
      border-top: 1px solid rgba(255, 255, 255, 0.18);
      display: flex;
      flex-wrap: wrap;
      justify-content: space-between;
      gap: 12px;
      font-size: 13.5px;
      color: rgba(255, 255, 255, 0.7);
    }

    /* ---------- Responsive ---------- */
    @media (max-width: 980px) {
      .hero-grid { grid-template-columns: 1fr; gap: 44px; text-align: center; }
      .hero-sub { margin-left: auto; margin-right: auto; }
      .hero-cta { justify-content: center; }
      .hero-action { margin-inline: auto; }
      .trust { justify-content: center; }
      .eyebrow { margin-inline: auto; }
      .hero-shot .device { max-width: 268px; }
      .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
      .hf-copy { padding: 44px 36px; }
      .hf-shot .device { width: 220px; }
      /* Stacked, the two columns each inherit the full shell width, so the
         heading, the paragraph and the form card all ran edge to edge. Cap
         and centre the block so it keeps a readable measure. */
      .waitlist-inner {
        grid-template-columns: 1fr;
        gap: 32px;
        max-width: 540px;
        margin-inline: auto;
      }
      .foot-grid { grid-template-columns: 1fr 1fr; gap: 32px; }
    }

    @media (max-width: 720px) {
      :root { --gutter: 20px; }

      .nav-links {
        position: fixed;
        inset: 76px 0 auto;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        background: #fff;
        border-bottom: 1px solid var(--border);
        padding: 8px 20px 20px;
        margin: 0;
        display: none;
        box-shadow: 0 14px 30px rgba(26, 26, 46, 0.08);
      }

      .nav-links.open { display: flex; }
      .nav-links a { padding: 14px 4px; font-size: 16px; border-bottom: 1px solid var(--border); }
      .nav-links a:last-child { border-bottom: none; }
      .nav .btn-purple { display: none; }
      .nav-toggle { display: inline-flex; }

      .hero { padding: 44px 0 24px; }
      section.block { padding: 56px 0; }

      .stats-inner { grid-template-columns: repeat(2, 1fr); gap: 22px 12px; }

      /* minmax(0, …), never a bare 1fr. A grid track's automatic minimum is
         its min-content, so one oversized child drags the whole column past
         the container: the 560px zoomed device on the ube card pushed this
         to 439px inside 335px, and every other card inherited the sideways
         scroll, which read as the body text being cut off. */
      .cards { grid-template-columns: minmax(0, 1fr); gap: 32px; max-width: 420px; margin: 0 auto; }
      .card-frame { height: 300px; }

      /* Stack the hero-feature rows: copy on top, cropped device below */
      .hf-row { grid-template-columns: 1fr; height: auto; }
      .hf-row:nth-child(even) .hf-copy,
      .hf-row:nth-child(even) .hf-shot { order: 0; }
      .hf-copy { padding: 36px 26px 4px; }
      .hf-copy p { max-width: none; }
      .hf-shot { height: 300px; }
      .hf-shot .device { width: 216px; margin-top: 34px; }
      .hf-shot .device-screen { padding-top: 106px; }

      .affix { padding: 40px 22px; }
      .affix-word { font-size: 34px; }

      .foot-grid { grid-template-columns: 1fr; gap: 30px; }
      .foot-bottom { flex-direction: column; }
    }

    @media (prefers-reduced-motion: reduce) {
      html { scroll-behavior: auto; }
      * { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
    }

    /* ==========================================================
       SUBPAGE SHELL
       Used by /faq, /release-notes, /privacy, /terms, /sources.
       The nav and footer MARKUP is duplicated per page (no build
       step here), but every rule that styles them lives in this
       file, so a header change is a one-file change.
       ========================================================== */

    /* padding-block only: the horizontal gutter belongs to .shell, and a
       padding shorthand here would silently zero it. */
    .subpage { padding-block: 56px 24px; }

    .subpage-narrow { max-width: 820px; margin: 0 auto; }

    .back-link {
      display: inline-flex;
      align-items: center;
      gap: 7px;
      font-size: 14.5px;
      font-weight: 700;
      color: var(--text-secondary);
      text-decoration: none;
      margin-bottom: 28px;
      transition: color 0.15s ease;
    }

    .back-link:hover { color: var(--purple); }
    .back-link svg { width: 16px; height: 16px; }

    .page-head { margin-bottom: 44px; }

    .page-head h1 {
      font-size: clamp(34px, 4.6vw, 52px);
      font-weight: 900;
      letter-spacing: -1.6px;
      line-height: 1.06;
      margin-bottom: 14px;
    }

    .page-head h1 .accent { color: var(--purple); }

    .page-head .page-sub {
      font-size: 18.5px;
      line-height: 1.55;
      color: var(--text-secondary);
      max-width: 640px;
    }

    /* ---------- Accordion (FAQ) ---------- */
    .faq-group {
      font-size: 15px;
      font-weight: 800;
      letter-spacing: 0.6px;
      text-transform: uppercase;
      color: var(--purple);
      margin: 44px 0 16px;
      padding-bottom: 10px;
      border-bottom: 1.5px solid var(--purple-light);
    }

    .faq-group:first-of-type { margin-top: 0; }


    .accordion { display: flex; flex-direction: column; gap: 12px; }

    .acc-item {
      background: var(--cream);
      border: 1px solid var(--border);
      border-radius: 16px;
      overflow: hidden;
      transition: border-color 0.2s ease, background 0.2s ease;
    }

    .acc-item.open { background: #fff; border-color: var(--purple); }

    .acc-q {
      width: 100%;
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 16px;
      text-align: left;
      background: none;
      border: none;
      cursor: pointer;
      font-family: inherit;
      font-size: 17px;
      font-weight: 700;
      color: var(--text-primary);
      padding: 20px 22px;
      line-height: 1.4;
    }

    .acc-q .chevron {
      width: 20px;
      height: 20px;
      flex-shrink: 0;
      color: var(--text-secondary);
      transition: transform 0.25s ease, color 0.2s ease;
    }

    .acc-item.open .acc-q .chevron { transform: rotate(180deg); color: var(--purple); }

    .acc-a { max-height: 0; overflow: hidden; transition: max-height 0.3s ease; }

    .acc-a-inner {
      padding: 0 22px 22px;
      font-size: 16px;
      line-height: 1.65;
      color: var(--text-secondary);
    }

    .acc-a-inner a { color: var(--purple); font-weight: 600; }

    /* ---------- Prose (privacy, terms, sources) ---------- */
    .prose { font-size: 16.5px; line-height: 1.7; color: var(--text-secondary); }

    .prose h2 {
      font-size: 24px;
      font-weight: 800;
      letter-spacing: -0.6px;
      color: var(--text-primary);
      margin: 40px 0 12px;
    }

    .prose h3 {
      font-size: 18px;
      font-weight: 800;
      color: var(--text-primary);
      margin: 28px 0 8px;
    }

    .prose p { margin-bottom: 16px; }
    .prose ul, .prose ol { margin: 0 0 16px 22px; }
    .prose li { margin-bottom: 8px; }
    .prose a { color: var(--purple); font-weight: 600; }

    .prose-meta {
      font-size: 14px;
      font-weight: 600;
      color: var(--text-secondary);
      background: var(--cream);
      border: 1px solid var(--border);
      border-radius: 12px;
      padding: 12px 16px;
      margin-bottom: 32px;
    }

    /* ---------- Release notes ----------
       Class names match the existing markup in /release-notes. */
    .release {
      background: var(--cream);
      border: 1px solid var(--border);
      border-radius: 18px;
      margin-bottom: 14px;
      overflow: hidden;
    }

    .release[open] { background: #fff; border-color: var(--purple); }

    .release > summary {
      cursor: pointer;
      list-style: none;
      display: flex;
      align-items: baseline;
      gap: 14px;
      padding: 20px 24px;
    }

    .release > summary::-webkit-details-marker { display: none; }
    .release > summary::after {
      content: "";
      width: 9px;
      height: 9px;
      border-right: 2.5px solid var(--text-secondary);
      border-bottom: 2.5px solid var(--text-secondary);
      transform: rotate(45deg) translate(-3px, -3px);
      transition: transform 0.2s ease, border-color 0.2s ease;
    }
    .release[open] > summary::after {
      transform: rotate(-135deg) translate(-2px, -2px);
      border-color: var(--purple);
    }

    .release-version {
      font-size: 21px;
      font-weight: 900;
      letter-spacing: -0.5px;
      color: var(--text-primary);
    }

    .release-build {
      font-size: 15px;
      font-weight: 700;
      color: var(--text-secondary);
      letter-spacing: 0;
    }

    /* Date sits on the right, beside the chevron, not trailing the version. */
    .release-date {
      font-size: 14px;
      font-weight: 600;
      color: var(--text-secondary);
      margin-left: auto;
    }

    .release-body { padding: 4px 24px 24px; }

    .user-notes p {
      font-size: 16px;
      line-height: 1.65;
      color: var(--text-secondary);
      margin-bottom: 14px;
    }

    .user-notes strong { color: var(--text-primary); font-weight: 800; }

    .user-notes .section-label {
      font-size: 12px;
      font-weight: 800;
      letter-spacing: 0.8px;
      text-transform: uppercase;
      color: var(--purple);
      background: var(--purple-light);
      display: inline-block;
      padding: 5px 12px;
      border-radius: 999px;
      margin: 22px 0 14px;
    }

    .user-notes .section-label:first-child { margin-top: 6px; }

    .first-release-note { font-style: italic; }

    .full-changelog {
      margin-top: 20px;
      border-top: 1px solid var(--border);
      padding-top: 16px;
    }

    .full-changelog > summary {
      cursor: pointer;
      list-style: none;
      font-size: 14px;
      font-weight: 700;
      color: var(--purple);
    }

    .full-changelog > summary::-webkit-details-marker { display: none; }
    .full-changelog > summary::before { content: "+ "; }
    .full-changelog[open] > summary::before { content: "- "; }

    .changelog-body { margin-top: 16px; }

    .category { margin-bottom: 22px; }

    .category-label {
      font-size: 13px;
      font-weight: 800;
      letter-spacing: 0.4px;
      color: var(--text-primary);
      margin-bottom: 8px;
    }

    .category ul { margin: 0 0 0 20px; }

    .category li {
      font-size: 14.5px;
      line-height: 1.6;
      color: var(--text-secondary);
      margin-bottom: 6px;
    }

    @media (max-width: 720px) {
      .subpage { padding-block: 32px 16px; }
      .page-head { margin-bottom: 32px; }
      .acc-q { font-size: 16px; padding: 17px 18px; }
      .acc-a-inner { padding: 0 18px 18px; font-size: 15.5px; }
      .release > summary { flex-wrap: wrap; gap: 4px 12px; padding: 17px 18px; }
      .release-body { padding: 2px 18px 18px; }
    }

    /* ==========================================================
       TAPPABLE TAGALOG WORD
       Mirrors TappableWordTooltip.swift: purple word, dashed
       underline, tap for pronunciation + translation, audio plays
       on open. One open at a time.
       ========================================================== */
    .tg {
      position: relative;
      display: inline-block;
      color: var(--purple);
      font-weight: 700;
      cursor: pointer;
      border: none;
      background: none;
      padding: 0;
      font: inherit;
      font-weight: 700;
      /* Dashed underline, drawn so it never collides with descenders. */
      background-image: linear-gradient(to right, currentColor 60%, transparent 60%);
      background-size: 5px 2px;
      background-repeat: repeat-x;
      background-position: 0 100%;
      padding-bottom: 2px;
      transition: opacity 0.15s ease;
    }

    .tg:hover { opacity: 0.75; }
    .tg:focus-visible { outline: 2px solid var(--purple); outline-offset: 3px; border-radius: 3px; }

    .tg-pop {
      position: absolute;
      bottom: calc(100% + 10px);
      left: 50%;
      transform: translateX(-50%) scale(0.9);
      transform-origin: bottom center;
      z-index: 60;
      background: var(--purple);
      color: #fff;
      border-radius: 12px;
      padding: 10px 14px;
      min-width: 150px;
      /* Keeps the bubble inside a narrow screen when its word sits near the
         right edge (the "luto" chip in the affix panel is the tight one). It
         never caused a sideways scroll, since the bubble is hidden until
         tapped, but it could still overhang visually while open. */
      max-width: min(240px, calc(100vw - 28px));
      text-align: left;
      box-shadow: 0 10px 28px rgba(26, 26, 46, 0.24);
      opacity: 0;
      pointer-events: none;
      transition: opacity 0.15s ease, transform 0.15s ease;
    }

    .tg.open .tg-pop { opacity: 1; transform: translateX(-50%) scale(1); pointer-events: auto; }

    /* The little arrow */
    .tg-pop::after {
      content: "";
      position: absolute;
      top: 100%;
      left: 50%;
      transform: translateX(-50%);
      border: 7px solid transparent;
      border-top-color: var(--purple);
    }

    .tg-pron {
      display: block;
      font-size: 13px;
      font-style: italic;
      font-weight: 400;
      color: rgba(255, 255, 255, 0.85);
      white-space: nowrap;
    }

    .tg-mean {
      display: block;
      font-size: 13.5px;
      font-weight: 700;
      color: #fff;
      margin-top: 2px;
    }

    .tg-speaker {
      display: inline-flex;
      align-items: center;
      gap: 5px;
      margin-top: 7px;
      font-size: 11.5px;
      font-weight: 700;
      letter-spacing: 0.3px;
      text-transform: uppercase;
      color: rgba(255, 255, 255, 0.75);
    }

    .tg-speaker svg { width: 13px; height: 13px; }

    /* Near the viewport edge the popover would clip, so flip its anchor. */
    .tg-pop.edge-l { left: 0; transform: translateX(0) scale(0.9); }
    .tg.open .tg-pop.edge-l { transform: translateX(0) scale(1); }
    .tg-pop.edge-l::after { left: 24px; }

    .tg-pop.edge-r { left: auto; right: 0; transform: translateX(0) scale(0.9); }
    .tg.open .tg-pop.edge-r { transform: translateX(0) scale(1); }
    .tg-pop.edge-r::after { left: auto; right: 24px; }
