/* ===========================================================================
   JACRA Backoffice - design tokens
   ---------------------------------------------------------------------------
   The single source of truth for colour, geometry, type and motion.
   Nothing else in the app may declare a raw colour: if a value is needed twice,
   or needs a name, it belongs here.

   Every token below is consumed by at least one component. The prototype
   carried eight tokens that nothing referenced; they are either wired up now or
   gone. Before adding a token, name its consumer in the comment - that is what
   keeps this file from rotting back into a palette dump.

   Tone: the palette was retuned toward "soft, classy, graceful". Gold went from
   neon to champagne, the cold blue-greys became warm stone, status colours lost
   saturation, shadows got a wider blur at lower alpha and radii grew ~2px.
   Softer is not washed out: every text/ground pair below still clears WCAG AA.
   =========================================================================== */

:root{

  /* --- colour scheme -------------------------------------------------------
     The app is light-only by design (a back-office tool that gets printed and
     projected as often as it is read on screen). Declaring the scheme stops the
     UA from auto-darkening form controls and scrollbars on our light canvas. */
  color-scheme: light;


  /* --- brand · navy --------------------------------------------------------
     A monotonic dark -> light ramp. In the prototype --navy-700 (#3A3D4C) was
     *lighter* than --navy (#2C2E3A), so the numbers ran backwards and picking a
     shade meant reading the hex. Renamed --navy-600, the ramp now sorts.
     The ramp is slightly warmer and lifted than before so the sidebar reads as
     ink rather than as a black hole; the sidebar itself runs a vertical
     gradient from --navy-900 to --navy-800. */
  --navy-900: #1B1D26;   /* sidebar ground, mobile hero, shadow tint            */
  --navy-800: #252834;   /* raised blocks on the sidebar / hero                 */
  --navy:     #323545;   /* solid dark surfaces: buttons, avatars, active chip  */
  --navy-600: #434758;   /* hairlines and dividers inside dark surfaces         */

  /* The bare channel triplet of --navy-900, so the veil below and the shadow
     ramp further down describe the same ink instead of two hand-typed rgba()
     values that drift apart. Also the value behind theme_color and
     background_color in manifest.webmanifest and behind the ground in
     offline.html, both of which have to spell it out because neither can read
     a custom property. */
  --navy-900-rgb: 27, 29, 38;

  /* The wash behind a modal, a drawer or the mobile bottom sheet. Paired with
     --blur-veil in the motion block: ground first, blur second. Alpha is .44 so
     the app stays legible as context underneath while the sheet clearly owns
     the foreground. */
  --veil: rgba(var(--navy-900-rgb), .44);


  /* --- brand · gold --------------------------------------------------------
     --gold-rgb holds the bare channel triplet so every alpha variant is derived
     rather than hand-expanded. Re-tinting the brand is then one edit here, and
     a hand-written gold rgba() anywhere else in the app is a bug.
     Champagne rather than neon: less saturated, a touch darker, so it sits on
     the navy without glaring (9.2:1 on --navy-900). */
  --gold-rgb: 233, 185, 74;

  --gold:     #E9B94A;   /* primary accent: gold button, active nav, brand mark */
  --gold-600: #C99A3A;   /* accent icon / text on light gold tints              */
  --gold-700: #7D6122;   /* gold TEXT that holds contrast on --gold-100 (5.3:1).
                            The prototype hardcoded this hex twice (.b-prog,
                            .b-med) purely because it had no name.              */
  --gold-300: #F1D9A0;   /* border / divider inside a gold-tinted block         */
  --gold-100: #FBF4E4;   /* gold tint surface: in-progress + medium badges      */

  --gold-a05: rgba(var(--gold-rgb), .05);  /* faintest wash: highlighted rows   */
  --gold-a14: rgba(var(--gold-rgb), .14);  /* active sidebar nav background     */
  --gold-a30: rgba(var(--gold-rgb), .30);  /* gold hairline on dark surfaces,
                                              and the text-selection wash       */


  /* --- neutrals ------------------------------------------------------------
     Warm stone rather than cool blue-grey: each step carries a hint of the
     gold's hue so the canvas and the brand agree instead of fighting. */
  --white:    #FFFFFF;   /* every card, panel and topbar surface               */
  --gray-50:  #F8F7F4;   /* app canvas behind the cards                        */
  --gray-100: #F0EEE9;   /* inert tints: tags, segmented track, low badge       */
  --gray-200: #E7E4DD;   /* the default border                                 */
  --gray-300: #D8D4CB;   /* stronger border: ghost buttons, chips, inputs       */
  --gray-400: #B3AFA6;   /* decorative icons, and text on the navy sidebar only */
  --gray-500: #797670;   /* icons, dots and decorative tints; held at 4.5:1 on
                            white so a stray small label still reads           */
  --gray-600: #66635C;   /* tertiary body text (6.0:1 on white)                */


  /* --- text roles ----------------------------------------------------------
     RULE: --ink paints text, --navy paints surfaces. They are one step apart
     today and that is exactly the trap - write the one that matches the job,
     or the next palette change will only land in half the places it should. */
  --ink:   #2B2D38;      /* body copy (12.8:1 on --gray-50)                    */
  --muted: #6E6B65;      /* de-emphasised copy that must still stay readable
                            (5.3:1 on white)                                    */


  /* --- status · solid + tint pairs -----------------------------------------
     Each status owns a solid (dots, bars, icons) and a tint (badge grounds).
     Solids are desaturated so a row of badges reads as a calm system rather
     than a traffic light; the -700 text shades are tuned to their own tint. */
  --green:     #3E9C74;  /* resolved, on shift, healthy                         */
  --green-100: #E8F3EC;
  --green-700: #2A6E52;  /* the SAME status as text on --green-100 (5.4:1)     */
  --red:       #D2605F;  /* high priority, alerts, the unread bell dot          */
  --red-100:   #F9ECEA;
  --red-700:   #A03A3A;  /* the SAME status as text on --red-100 (5.8:1)       */
  --blue:      #5A6FC4;  /* informational: the .tag category chip glyph         */
  --blue-100:  #EBEEF8;  /* and that chip ground                               */


  /* --- radius --------------------------------------------------------------
     Four steps, each with a job. Anything else is a one-off, and wrong.
     Each step grew 2px so corners feel softer without the shell looking
     inflated. */
  --r-sm: 10px;          /* controls: buttons, chips, inputs, the focus ring    */
  --r:    14px;          /* the .card surface primitive                         */
  --r-lg: 18px;          /* panels and mobile cards                             */
  --r-xl: 24px;          /* the mobile hero and the tile-drawer sheet           */


  /* --- shadow --------------------------------------------------------------
     Alpha is tinted with the --navy-900 channels (27, 29, 38) rather than pure
     black, so the shade reads as a cool ink wash against the navy/gold palette
     instead of muddy grey. Blur is wide and alpha low: a surface should feel
     lifted, never outlined. One level per surface role - do not mix them. */
  --sh-sm: 0 1px 2px rgba(27, 29, 38, .04), 0 2px 6px rgba(27, 29, 38, .04);    /* cards at rest        */
  --sh-md: 0 4px 14px rgba(27, 29, 38, .06), 0 1px 3px rgba(27, 29, 38, .04);   /* lifted: hover, sticky */
  --sh-lg: 0 18px 48px rgba(27, 29, 38, .10), 0 4px 12px rgba(27, 29, 38, .05); /* overlays: drawer, hero */


  /* --- spacing -------------------------------------------------------------
     One scale, so gaps agree across screens. This replaces the prototype's
     scattered 6 / 7 / 9 / 10 / 11 / 13 / 14 / 15 / 18px literals, which were
     ad-hoc enough that no two panels lined up. Pick the nearest step; do not
     reintroduce an in-between value. */
  --s-1: 4px;
  --s-2: 8px;
  --s-3: 12px;
  --s-4: 16px;
  --s-5: 20px;
  --s-6: 24px;
  --s-7: 32px;
  --s-8: 48px;


  /* --- layout metrics ------------------------------------------------------
     Named so the shell's dimensions can be reasoned about instead of matched by
     eye. This is the fix for the 70px-vs-64px magic number: mobile content
     clearance was hand-typed as 70px against a 64px tab bar, so the last row of
     every mobile screen sat under it. Clearance is now always computed as
     calc(var(--bottombar-h) + var(--s-2)) - never a literal. */
  --side-w:      236px;  /* desktop sidebar column                             */
  --topbar-h:    64px;   /* desktop topbar                                     */
  --bottombar-h: 64px;   /* mobile tab bar                                     */
  --fab-h:       52px;   /* floating action button on Clients, Inventory, Shifts */
  /* Room a mobile list must leave below its last row so that row is never
     trapped under the floating action button. Written as arithmetic for the
     same reason as the clearance above it: the FAB already sits at
     bottombar + safe + s-4, so anything under it needs its own height plus one
     more gap. Screens with no FAB simply end with a little more air, which
     reads better above the tab bar anyway. */
  --fab-clear:   calc(var(--fab-h) + var(--s-4) + var(--s-4));
  --mobile-max:  520px;  /* width of the centred mobile column below 860px     */
  --content-pad: 24px;   /* gutter inside .content and the mobile .pbody       */


  /* --- safe area -----------------------------------------------------------
     Contract section 4.3. The app ships inside a Median.co WebView with
     viewport-fit=cover, so the window reaches under the iPhone notch and under
     the home indicator. Every piece of fixed chrome has to pay those insets
     back, and the four names below are how it does it.

     Why alias env() instead of calling it at each site: env() takes a fallback
     as its second argument, and a fallback that is written out at forty call
     sites is a fallback that will be forgotten at one of them. Written once
     here, `calc(var(--s-4) + var(--safe-b))` is always arithmetic on a real
     length, on a phone and on a desktop alike, where all four resolve to 0px.

     They are plain lengths, not paddings: compose them with whatever spacing
     the element already wanted rather than letting the inset replace it. */
  /* SISI ATAS SENGAJA NOL, dan ini alasannya.

     Wadah Median di ponsel Jacky TIDAK menggambar halaman di bawah status bar:
     jam, sinyal dan baterai duduk di stripnya sendiri, dan isi aplikasi mulai
     bersih di bawahnya. Tetapi WebView-nya tetap melaporkan
     env(safe-area-inset-top) bernilai setinggi strip itu. Jadi aplikasi
     membayar jarak untuk halangan yang tidak pernah ada, dan hasilnya ruang
     kosong setinggi status bar di atas judul SETIAP layar.

     Dibuktikan dari tangkapan layar ponselnya sendiri, tiga layar berbeda,
     sesudah dua putaran perbaikan yang hanya memindahkan warna pitanya tanpa
     menghilangkan jaraknya.

     KALAU SUATU HARI aplikasi ini dipasang di wadah yang benar benar menembus
     ke bawah notch, misalnya iPhone dengan viewport-fit=cover yang dihormati,
     kembalikan baris ini menjadi env(safe-area-inset-top, 0px). Seluruh
     aritmetika di empat puluh tempat lain sudah siap menerimanya, karena
     semuanya membaca token ini dan bukan env() langsung.

     Tiga sisi lain TIDAK diubah: jarak bawah memang dipakai menghindari
     gesture bar, dan itu penghalang yang benar benar ada. */
  --safe-t: 0px;
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
  --safe-r: env(safe-area-inset-right, 0px);


  /* --- type ----------------------------------------------------------------
     Loaded by the single <link> in index.html, never from inside CSS - an
     imported font sheet cannot start downloading until this one has parsed.
     Each stack ends in a system font so the app stays legible before the
     webfont lands.
     Chosen on the owner's note that the old pairing felt off, and that the app
     should read as clear, elegant and soft. Space Grotesk was the problem: its
     terminals are cut flat and its letterforms are deliberately odd, which
     reads as technical rather than calm, and Inter beside it is accurate but
     cold and tightly spaced at the sizes this app actually uses.

     Plus Jakarta Sans replaces both. It is humanist rather than geometric, so
     the joints are gently rounded and nothing has a hard corner; its x-height
     is large and its apertures are open, which is what keeps a 12px label
     legible on a phone held at arm's length in a corridor. One family carries
     both roles: headings separate themselves by weight and size, which reads
     more composed than two faces arguing. It was drawn by Tokotype in Jakarta,
     which is not why it was picked, but it is a good reason to keep it.

     IBM Plex Mono replaces JetBrains Mono for the same reason, one step down:
     it is the warmer, humanist monospace, so an asset tag sitting inside a
     sentence no longer looks pasted in from a terminal. */
  --f-disp: 'Plus Jakarta Sans', system-ui, sans-serif;  /* headings, figures   */
  --f-ui:   'Plus Jakarta Sans', system-ui, sans-serif;  /* everything else     */
  --f-mono: 'IBM Plex Mono', ui-monospace, monospace;    /* IDs, hosts, values  */


  /* --- motion --------------------------------------------------------------
     One easing vocabulary and four durations, used everywhere and nowhere
     else. A component never writes its own cubic-bezier or millisecond value:
     it picks the token whose comment names its job. That is also what lets the
     reduced-motion rule in base.css collapse motion by overriding tokens
     instead of fighting specificity, so time every transition with these.

     Retuned on the owner's direct note that the app should feel "smoother
     still". Two things changed together, because either one alone would have
     read as sluggish rather than as calm:

       1. Durations grew by roughly a quarter (160/260/420 -> 200/340/560), so
          a state change has room to be read as a movement instead of a jump.
       2. The curves lost their front loading. The old --ease-out started at
          .22/.61, which spends most of its budget near the end; the new one
          starts at .16/.84, so the value covers most of its distance in the
          first third and then glides. A longer duration on the old curve would
          have felt slow; on this one it feels unhurried, which is the ask.

     --ease-spring keeps its job (transform channel of a hover or a selection,
     never colour) but its overshoot came down from 1.25 to 1.18: enough to
     read as alive, not enough to read as a bounce. */
  --ease-out:    cubic-bezier(.16, .84, .34, 1);   /* decelerate: things arriving             */
  --ease-in-out: cubic-bezier(.62, .02, .34, 1);   /* symmetric: screen cross-fades           */
  --ease-spring: cubic-bezier(.34, 1.18, .64, 1);  /* whisper of overshoot: hover lifts only  */

  --t-fast:   200ms var(--ease-out);               /* colour/border/opacity on hover + focus  */
  --t-base:   340ms var(--ease-out);               /* transforms, lifts, reveals              */
  --t-slow:   560ms var(--ease-in-out);            /* stagger envelopes, rails, bars          */
  --t-slower: 760ms var(--ease-in-out);            /* screen changes and full-height sheets   */

  /* Endless loops, duration only: the rule names its own curve. Unlike the
     four above, base.css leaves both alone under reduced motion: a loop cut
     to 1ms but kept infinite repaints a random frame every frame, a strobe.
     The loop stops instead, through the net in base.css or through a reduced
     motion block of its own beside the rule (see base.css). */
  --t-loop:   1150ms;                              /* one pass of a busy sweep                */
  --t-spin:   760ms;                               /* one turn of a spinner                   */

  --stagger: 34ms;                                 /* per-item delay for list entrances       */
  --lift:    -2px;                                 /* hover translateY for cards and tiles    */

  /* Backdrop behind a modal, a drawer or the mobile bottom sheet. The blur is a
     token because the veil is drawn in more than one file (components.css owns
     the modal, mobile.css the sheet) and a backdrop that blurs by a different
     amount in each place reads as two different apps. */
  --blur-veil: 10px;


  /* --- interaction ---------------------------------------------------------
     The global focus ring. The prototype had no focus style at all, so keyboard
     navigation was invisible. Champagne gold at .35 is quiet on the white cards
     yet still reads against the navy-900 sidebar. */
  --focus-ring: 0 0 0 3px rgba(var(--gold-rgb), .35);


  /* --- Books: the reading room (screens/books.css, books-reader.css) --------
     The reader is the one place where the page is not a card on --gray-50: it
     is paper on a desk. No new hue: the papers are tints of the gold and navy
     ramps above, the four highlight meanings reuse the status hues, and every
     shadow is navy-900 ink, as everywhere else. Each theme sets the same four
     roles: the desk around the page, the paper, the ink of reflowed text and
     the chrome that floats over it. */
  --bk-green-rgb: 62, 156, 116;   /* bare channels of --green, for highlight alphas */
  --bk-blue-rgb:  90, 111, 196;   /* bare channels of --blue                        */
  --bk-red-rgb:   210, 96, 95;    /* bare channels of --red                         */

  /* Paper (the page ground in Text Mode, the placeholder before a page draws,
     and the colour the PDF canvas is tinted towards). */
  --bk-paper-white: #FFFFFF;      /* White: the page as printed                     */
  --bk-paper-cream: #F6EFDF;      /* Cream: warm book paper, a pale gold tint       */
  --bk-paper-dim:   #D8D0BF;      /* Dim: evening paper, same warm hue, less light  */
  --bk-paper-night: #1E2029;      /* Night: navy-900 lifted a step, never pure black */

  /* Desk: the ground around the page in each theme. */
  --bk-desk-white: #ECEAE4;
  --bk-desk-cream: #E4DCCB;
  --bk-desk-dim:   #AFA796;
  --bk-desk-night: #121319;

  /* Ink of reflowed text and of the page number line, per theme. */
  --bk-ink-white: #2B2D38;        /* = --ink                                        */
  --bk-ink-cream: #3A3326;        /* warm near black on cream (11.6:1)              */
  --bk-ink-dim:   #2E2A22;        /* on dim paper (7.9:1)                           */
  --bk-ink-night: #D9D3C4;        /* warm light grey on night paper (11.9:1)        */
  --bk-ink-soft-night: #9A958A;   /* secondary text on night paper (5.6:1)          */

  /* Chrome that floats over the page: toolbar, panels, sheets in the reader. */
  --bk-chrome-light: rgba(255, 255, 255, .94);
  --bk-chrome-night: rgba(30, 32, 41, .94);
  --bk-chrome-line-night: #343747;

  /* Highlights are drawn under the text with multiply on light paper and with
     screen on night paper, so the letters on top keep their full contrast. */
  --bk-hl-gold:  rgba(var(--gold-rgb), .42);      /* important                     */
  --bk-hl-green: rgba(var(--bk-green-rgb), .30);  /* idea                          */
  --bk-hl-blue:  rgba(var(--bk-blue-rgb), .28);   /* quote                         */
  --bk-hl-red:   rgba(var(--bk-red-rgb), .28);    /* question                      */
  --bk-hl-gold-night:  rgba(var(--gold-rgb), .30);
  --bk-hl-green-night: rgba(var(--bk-green-rgb), .34);
  --bk-hl-blue-night:  rgba(var(--bk-blue-rgb), .38);
  --bk-hl-red-night:   rgba(var(--bk-red-rgb), .36);
  --bk-search-hit:     rgba(var(--gold-rgb), .55); /* the current search match     */
  --bk-tts-sentence:   rgba(var(--bk-blue-rgb), .20); /* sentence read aloud       */
  --bk-tts-sentence-night: rgba(var(--bk-blue-rgb), .40); /* the same on night paper */

  /* Pen colours for ink (Pencil, finger or mouse). */
  --bk-pen-ink:   #2B2D38;
  --bk-pen-blue:  #3F56B5;
  --bk-pen-red:   #C24A49;
  --bk-pen-green: #2F8A63;
  --bk-pen-gold:  #C99A3A;

  /* The warm reading light is a multiply wash of the brand gold, scaled by the
     reader with --bk-warmth (0 to 1); the spine and the page edges are navy-900
     ink at low alpha, drawn as functional gradients. */
  --bk-warm-wash:   rgba(var(--gold-rgb), .55);
  --bk-spine-shade: rgba(var(--navy-900-rgb), .18);
  --bk-spine-light: rgba(255, 255, 255, .22);
  --bk-edge-line:   rgba(var(--navy-900-rgb), .10);
  --bk-turn-shade:  rgba(var(--navy-900-rgb), .30);
  --bk-ruler-band:  rgba(var(--gold-rgb), .14);
  --bk-ruler-dim:   rgba(var(--navy-900-rgb), .28);

  /* Reflowed text (Text Mode) and quote cards use a face drawn for reading on
     screens; it is loaded by the one Google Fonts link in index.html. */
  --f-read: 'Literata', Georgia, 'Times New Roman', serif;

}
