/* ============================================================================
   DESIGN TOKENS
   ----------------------------------------------------------------------------
   A "token" is a named value used everywhere instead of hardcoding it. Change
   it here once and every screen updates. This is the only file you need to
   touch to reskin the whole prototype.

   Colour values were read off the Vocabulary iOS app screenshots.
   ========================================================================= */

:root {
  /* --- Colour ------------------------------------------------------------
     Named by ROLE, not appearance. `--accent` not `--teal`, so swapping teal
     for orange later doesn't leave a variable called `--teal` that is orange. */

  --bg:          #EFEDE7;  /* warm cream — every screen background        */
  /* The same colour at zero alpha. Gradients need this spelled out rather than
     `transparent`: transparent is transparent BLACK, and interpolating cream to
     it can leave a grey cast through the middle of the fade. */
  --bg-0:        rgba(239, 237, 231, 0);
  --surface:     #FFFFFF;  /* cards, pills, circular buttons              */
  --sheet:       #F4F1EA;  /* practice sheet — one step warmer than --bg  */

  --ink:         #0D0D0D;  /* the word, headings, icon strokes            */
  /* The same colour as channels, for the eleven places that need it at partial
     alpha — chip fills, dividers, the scrim, pressed states. Those were written
     as literal rgba(13, 13, 13, …), which meant --ink was not actually the
     single reskin point it claims to be: changing it left every tint black.
     Keep the two in step; there is no way to derive one from the other in CSS. */
  --ink-rgb:     13, 13, 13;
  --ink-muted:   #8C8C8C;  /* section labels, sub-copy                    */
  --ink-faint:   #C9C6BE;  /* empty progress track, inactive day circles  */
  /* Unselected tab labels. Darker than --ink-muted because these are 11px and
     interactive: #8C8C8C measured 3.07:1 on the tab bar, under the 4.5:1 WCAG
     needs for text this size. #666 measures 5.2:1 and still reads as recessive
     next to the near-black of the selected tab. */
  --ink-nav:     #666666;

  /* Olive 500. The brand green, and the same value the cream theme has always
     used for its accent — the default theme was the odd one out on a dusty teal
     that belonged to nothing else in the palette.

     Ink on this measures 8.45:1, well clear of the 4.5:1 WCAG asks for button
     text, and 1.96:1 against the page. That second figure is the one that
     improved: the teal sat at 1.63:1, so a primary button now separates from the
     page MORE than it did, not less. */
  --accent:      #9AB46F;  /* olive — primary buttons, NEW badge          */
  --accent-deep: #7F934E;  /* pressed state of the above                  */
  --correct:     #7F934E;  /* olive — "Got it" pressed                    */
  --warm:        #F08A7A;  /* coral — the streak flame                    */

  /* The favourited heart, and the ring and sparks that fire with it.
     Its own token rather than a reuse of --correct, which happens to be the same
     olive today: "you saved this" and "you got it right" are different claims and
     a palette change should be free to move one without the other.
     --liked-rgb is the same colour as components, for the partial-alpha glow. */
  /* Lifted from #7F934E to Olive 500, so the heart ICON matches the particles
     that burst out of it. They were 1.48:1 apart — close enough to read as a
     rendering fault rather than a two-tone, because the Lottie's colour is baked
     into js/heart-fav.lottie.json at build time and cannot take a CSS variable.
     One of the two had to move to the other, and the icon was the one that did
     not match what the animation was asked for. */
  --liked:       #9AB46F;
  --liked-rgb:   154, 180, 111;

  /* The second tone in the burst. Spotify's throws a MIXTURE of green and white
     hearts, and the two-tone is what stops eight identical shapes reading as a
     printed pattern.

     Not white here, though the reference is. Their UI is dark, so white is the
     bright highlight against a dark field; on our light page white measures
     1.06:1 against the background and would be eight invisible hearts. On a light
     field the highlight has to run the other way, so the second tone is a deeper
     olive. Picked by matching the SEPARATION rather than the colour: green to
     white on their dark UI is 2.72:1, and this pair is 2.80:1 apart.

     Moved from #3E4A24 when --liked was lifted to Olive 500. Left alone it would
     have stretched to 4.13:1, and at that distance the darker hearts stop reading
     as a second tone of the same green and start reading as black dots. #5B623E
     restores the 2.80:1 the pair was tuned to, and still sits 5.50:1 against the
     page so the outer hearts do not disappear into it. */
  --liked-alt:   #5B623E;

  /* ------------------------------------------------------------------
     BADGE PASTELS — one hue per kind of card on the word sheet.

     Four identical grey circles told you a card had an icon and nothing
     more; you had to read the icon every time to know which section you
     were looking at. A hue per section means the sheet can be scanned
     rather than read, and the pairing survives being learnt once —
     green is always the root, blue is always the example.

     Desaturated on purpose. The sheet is near-monochrome and these sit
     next to Arabic set in near-black; anything more saturated would pull
     harder than the word itself. Each ink is a deep version of its own
     hue rather than black, which keeps the circle reading as one object.
     All four measure above 7:1 against their own background.            */
  --badge-memory-bg:  #F5F2FC;  /* lilac  — the memory hook    */
  --badge-memory-ink: #4C3A8C;
  --badge-say-bg:     #F1F6FD;  /* blue   — the example        */
  --badge-say-ink:    #2F5C99;
  --badge-root-bg:    #F1F7F2;  /* green  — the root           */
  --badge-root-ink:   #2F6B3F;
  --badge-same-bg:    #FDF5EF;  /* peach  — synonyms           */
  --badge-same-ink:   #8C4E24;


  /* ======================================================================
     TYPE
     ----------------------------------------------------------------------
     ARABIC: Noto Kufi Arabic, everywhere, at every size.

     Why Kufi and not Naskh. Naskh descends from wide-cut-pen handwriting,
     so its strokes start thin, thicken, then taper. That modulation gives it
     serif-like contrast, which reads as a different visual weight next to a
     Latin sans — the Arabic ends up feeling like a separate identity.
     Kufi holds one stroke weight throughout, so it sits at matched optical
     weight with Latin sans. It is effectively the only Arabic style built
     for interfaces rather than for the page.

     Naskh became the regional default by accident, not intent: the earliest
     digital Arabic fonts were Naskh-based and that inheritance went
     unquestioned. Saudi Arabia has since moved its national design system
     to Kufi.

     The tradeoff Kufi brings: its geometric uniformity gives less
     letter-shape differentiation than Naskh, so small running Arabic needs
     more size and leading than you'd give Latin. Handled below.
     ==================================================================== */

  /* Noto Sans Arabic. Monolinear, so it holds weight parity with a Latin sans,
     but with more differentiated letterforms than Kufi — which reads better at
     small sizes.

     It used to be paired with Noto Sans from the same superfamily, where the
     metrics matched by construction. The Latin is SF Pro now (see below), so
     this is a pairing that has to be judged rather than one that is guaranteed.

     js/arabic-metrics.js overrides this at runtime with whichever face the
     switcher last used, and re-derives the leading to match. The value here is
     what applies before that runs, so it should stay in step with the default. */
  --font-arabic: 'Noto Sans Arabic', sans-serif;


  /* --- Latin: SF Pro, via the system stack ------------------------------
     Not a downloaded font, and it cannot be one. SF Pro is licensed for use on
     Apple platforms and for designing for them, not for redistribution as a
     webfont, so the only legitimate way to get it is to ask the system. That
     also keeps it free: no bytes to ship, nothing to fetch, works offline by
     construction.

     `-apple-system` resolves to SF Pro on iOS and macOS. Everywhere else the
     stack degrades to whatever that platform's UI font is, which is the right
     answer — a Windows reader is better served by Segoe than by a forced
     download of a font Apple designed for Apple hardware.

     THIS REPLACES NOTO SANS, and it gives up something real. Noto Sans shares a
     superfamily with Noto Sans Arabic, so their metrics and weight axes lined
     up by construction. SF Pro beside Noto Sans Arabic is a pairing rather than
     a family, so the weight match is now a judgement instead of a guarantee.
     What it buys is that the interface looks like the platform it runs on
     (Jakob's Law), which for an iOS-first app is the stronger argument.

     Dropping Noto Sans also took 1.7 MB out of the font bundle — it was the
     largest family in there by some distance.

     The serif below is kept only so specimen.html can still show the
     comparison that produced these decisions. The app never uses it.        */

  --font-display: var(--font-display-sans);
  --font-ui: -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, 'Segoe UI', sans-serif;

  --font-display-sans: -apple-system, BlinkMacSystemFont, 'SF Pro Display', system-ui, sans-serif;
  --font-display-serif: 'Source Serif 4', Georgia, serif;  /* specimen only */

  /* A sans set large looks loose without slight negative tracking. */
  --track-display: -0.02em;


  /* --- Scale -------------------------------------------------------------
     Arabic display sits smaller in px than you'd expect, because Arabic
     letterforms carry a larger visual body than Latin at equal size. */

  --size-word-ar:  76px;   /* the adjective on the feed                   */
  --size-display:  28px;   /* "Practice", "Good job!"                     */
  /* 19, not 20. "Day 1 of your learning streak" must hold one line beside the
     flame as it does in the reference. Measured: 270px of space, and the string
     needs 263px at 19px but 277px at 20px. */
  --size-title:    19px;   /* streak card heading                         */
  --size-body:     17px;   /* English definition                          */
  --size-ui:       15px;   /* buttons, transliteration pill               */
  --size-small:    13px;   /* English example gloss, counts               */
  --size-label:    11px;   /* small-caps section labels                   */

  /* Arabic running text gets its own size, two steps up from the English
     small size. This is the Kufi legibility compensation: at 13px Kufi's
     geometric forms lose too much differentiation to scan comfortably. */
  --size-example-ar: 15px;

  /* --- The detail sheet's own scale --------------------------------------
     The sheet stacks five kinds of text in one card and the app's four-step
     scale was not enough to separate them: card titles, card bodies, root
     prose and chip Arabic all landed on --size-ui, so a card read as one grey
     block with a bold first line rather than a heading over its body.

     Two extra steps fix it without inventing a second scale — 14 sits in the
     gap the app's 15/13 pair leaves, and 12 gives labels somewhere to go that
     is not the 11px reserved for small-caps section headers.

       17  the meaning — the answer you came for
       14  card headings AND card bodies — see below
       13  example gloss, chip translations
       12  the transliteration key and other fine print                     */
  --size-card-body: 14px;
  --size-card-label: 12px;

  /* Card headings sit at the same 14px as the body they head, and separate on
     colour instead: full ink against --ink-muted. Two sizes were doing the job
     before, 15px titles and 12px labels, which gave the sheet four type sizes
     in a 360px column and still left the labels the same grey as the text
     under them. One size, two colours, reads cleaner and scans faster. */
  --size-card-head: 14px;

  /* Arabic in the sheet's example. Larger than the Latin around it because
     Arabic carries more visual body per point, and this is the one line you are
     meant to read rather than skim. */
  --size-example-ar-sheet: 18px;

  /* Display weight for the Arabic word. 700 was heavy enough to feel shouted at
     76px; 500 keeps presence without the density.

     js/arabic-metrics.js reads this token and measures at the same weight —
     a lighter weight has slightly smaller ink, so measuring at 700 and
     rendering at 500 would derive leading for a word that isn't on screen. */
  --weight-arabic-display: 500;


  /* --- Leading -----------------------------------------------------------
     Arabic diacritics (fatha, sukoon, shadda) sit ABOVE the letter body.
     A normal line-height clips them. This is the most common way Arabic
     typography breaks on the web, and Kufi's marks sit high and flat. */

  /* Both values measured with canvas TextMetrics against all 24 words, not
     guessed. Re-run the check in specimen.html if you add words or resize.

     There are two distinct ways Arabic diacritics break, and they need
     different fixes:

     1. CLIPPED AT A CONTAINER EDGE. Noto Kufi Arabic's font bounding box is
        ~1.9em, far taller than the em square, because its marks stack.
        مْرَتَّب is our worst case — sukoon over the م plus shadda+fatha over the
        ت. At line-height 1.5 its ink overshot the line box by 11.6px, so any
        ancestor with overflow:hidden would shear the marks off. 2.05 keeps
        the tallest word inside its own line box with 9.3px to spare.

     2. COLLIDING WITH THE LINE ABOVE in wrapped text. Fixed by leading, not
        by the box. Worst pairing is مِتْواضِع's ascender under مَبْسوط's
        descender: they need 25.5px and 1.9 leading gives 28.5px. At 1.75 the
        gap drops to 0.7px, which is not a margin.

     Note on ancestors: in this app the Arabic IS inside clipping ancestors and
     has to be. .feed sets overflow-y to scroll (that is what makes the snap
     feed work) and .device sets overflow:hidden (that is the phone bezel).
     Neither can be removed. So the leading above is not belt-and-braces, it is
     the only thing keeping the marks intact — which is why it is measured
     rather than eyeballed. */
     PER-FACE VALUES. Measured across all 24 headwords at 76px/700. مْرَتَّب is
     the worst case for both faces — sukoon over the م, shadda and fatha over
     the ت. Swapping the face means swapping the leading with it:

       Noto Naskh Arabic  → 1.75   (font box 1.70em, headroom 9.6px)  ← in use
       Noto Kufi Arabic   → 2.05   (font box 1.89em, headroom 9.3px)

     Naskh needs less leading for the same safety because its box is shorter
     relative to the em. Set Kufi's face with Naskh's leading and مْرَتَّب loses
     its marks. */
  --leading-arabic-display: 1.75;
  --leading-arabic-text: 1.9;   /* small running Arabic — 4.9px line gap in Naskh */
  --leading-tight: 1.15;
  --leading-body: 1.45;


  /* --- Shape ------------------------------------------------------------ */
  --radius-card: 20px;
  --radius-sheet: 28px;
  --radius-pill: 999px;   /* any value over half the height gives a pill  */

  /* Tab bar height, as a token because four other things measure off it: the
     bottom padding every page needs to clear it, the toast's resting position,
     and the scroll fade's solid zone. Typing 62 in four places is how one of
     them ends up at 51 after a change. */
  --tabbar-h: 62px;
  /* 52 -> 44. Back, close and end-session are all navigation chrome: you need to
     find them instantly and then never look at them again, and at 52 the white
     disc was competing with the word it sits above rather than getting out of its
     way. 44 is Apple's minimum tap target exactly, so it comes down to the floor
     and stops — smaller would need a transparent ::after to keep the target
     legal, which is a trick worth avoiding when the honest size still works. */
  --size-circle: 44px;    /* round icon buttons; Apple's 44pt minimum exactly */

  /* --- Depth -------------------------------------------------------------
     The reference app's shadows are soft and barely there. Heavy shadows
     would break the flat, papery feel. */
  --shadow-card: 0 2px 12px rgba(0, 0, 0, 0.06);
  --shadow-pill: 0 1px 6px rgba(0, 0, 0, 0.05);
  --shadow-sheet: 0 -8px 32px rgba(0, 0, 0, 0.12);

  /* --- Liquid Glass ------------------------------------------------------
     Apple's iOS 26 navigation material: a translucent capsule floating over
     content, tinted by what's behind it, with a specular edge that catches
     light. Reserved for the navigation layer — never stacked glass on glass,
     which Apple's own guidance calls a "glass sandwich".

     The tint is deliberately not pure white. Glass takes colour from what it
     sits on, and this app's ground is a warm cream, so a cold white capsule
     would read as a sheet of paper rather than a lens. */
  --glass-tint: rgba(250, 249, 245, 0.62);
  --glass-blur: saturate(180%) blur(20px);
  --glass-edge-top: rgba(255, 255, 255, 0.85);   /* light catches the top edge */
  --glass-edge-bottom: rgba(13, 13, 13, 0.07);   /* and falls away underneath */
  --glass-ring: rgba(13, 13, 13, 0.08);

  /* --- Space -------------------------------------------------------------
     4px-based scale. Sticking to a scale is what makes spacing look
     deliberate rather than arbitrary. */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 48px;

  /* --- Motion ------------------------------------------------------------
     iOS default easing. 0.42s matches UIKit's modal presentation, so the
     sheet feels native rather than webby. */
  --ease-ios: cubic-bezier(0.32, 0.72, 0, 1);
  --dur-sheet: 0.42s;
  --dur-tap: 0.18s;

  /* The word sheet specifically — the one you open from the ⓘ and then read.

     Slower and gentler than --dur-sheet, and on its own tokens so the things
     that share that one stay quick: the progress bar filling and the verdict
     card are feedback on something you just did, and dragging those out would
     make the app feel sluggish rather than considered.

     The curve matters more than the number. --ease-ios leaves at full speed and
     spends its whole length decelerating, which reads as snappy at 0.42s and as
     "shot up, then crawled" once you stretch it. This one starts from rest,
     which is what makes a longer move look smooth instead of merely slow. */
  --ease-sheet-lg: cubic-bezier(0.2, 0, 0, 1);
  --dur-sheet-lg: 0.58s;

  /* The info sheet's entrance, now a short lift-and-fade rather than a full
     climb from off-screen. Material's motion system ties duration to distance
     travelled — a big move earns a long, decelerating curve, a small one gets
     a quick, brisk one, or the short move reads as sluggish rather than
     gentle. 28px is roughly the band right above the tab bar, where the sheet
     now visually originates instead of the screen's bottom edge. --ease-ios
     rather than --ease-sheet-lg for the same reason: that curve starts from
     rest, built for a climb long enough to need easing into; over 28px it
     would barely move before the transition ended. */
  --dist-sheet-sm: 40px;
  --dur-sheet-sm: 0.3s;

  /* Stepping between words inside the sheet. Shorter than opening it — the
     sheet is already there and only its contents change, and at 0.58s a hop
     three words deep into a root would cost nearly two seconds of waiting.
     0.34s is UIKit's own push. */
  --ease-push: cubic-bezier(0.32, 0.72, 0, 1);
  --dur-push: 0.34s;
}


/* --- Specimen-only override ---------------------------------------------
   Lets specimen.html show the serif comparison that produced the decision
   above. The app sets no data-type-system attribute, so it gets sans from
   :root and nothing outside the specimen can drift.                      */

html[data-type-system='serif'] {
  --font-display: var(--font-display-serif);
  --track-display: 0;
}
