/* ═══════════════════════════════════════════════════════════════════════════
   TARTIB TOKENS — the palette, the direction, the chrome
   brand/tartib-tokens.css → /brand/tartib-tokens.css

   ⚠️ SAFE FOR ANY PAGE TO LINK. Variables, the top bar and RTL only — no
   .card, no .btn, nothing that could collide with a dashboard that already
   owns those names. The Assets SPA links THIS file and keeps its own
   components; the hub and HR link this plus tartib-ui.css below.

   Hussain, 22 Aug 2026: "make all the dashboards have the same style and theme,
   but with a little colour-coding difference so it will be easy to work with —
   this includes Assets and any other dashboard we create."

   ⚠️ THE ONE RULE THAT MAKES COLOUR CODING WORK.
   The accent identifies the MODULE. The semantic palette describes the DATA.
   They must never borrow each other's colours. If red means "HR" in the chrome
   and "expired" in a table on the same screen, a person stops reading colour as
   meaning and starts ignoring it — and the expiry board is the one screen where
   that costs money. So:

     --accent      changes per dashboard.  Chrome only: the module chip, the
                   active nav item, links, focus rings, primary buttons.
     --ok/--warn/  IDENTICAL EVERYWHERE, on every dashboard, for all time.
     --bad/--info  Green is fine, amber is soon, red is wrong, blue is a note.

   Accents are chosen to sit away from those four hues, which is why HR is teal
   rather than the red it wears as a tile: a red sidebar on a page full of red
   expiry warnings is exactly the collision above.

   ADDING A DASHBOARD: link this file, put data-app="yourname" on <body>, and
   add one line to the accent block. Nothing else.
   ═══════════════════════════════════════════════════════════════════════════ */

:root{
  /* ── neutrals: the same paper under every product ──────────────────────── */
  --bg:#F6F8FA;
  --surface:#FFFFFF;
  --surface-2:#FAFCFD;
  --line:#E4E9EE;
  --line-soft:#EFF3F7;
  /* ⚠️ KOOBS-LITERAL SINCE 23 Aug 2026. Hussain, sample beside the reference:
     "still not same as hr.koobs.cafe" — then, on the literal rendering: "ok,
     looks good." The teal-tinted ink (#08222D / #3E5C68) was the single
     biggest reason Tartib read as a different product: every cell, label and
     paragraph was a shade of teal the reference does not have. Ink and body
     are now the reference's own near-black; running text is ink, exactly as
     the reference writes it. */
  --ink:#1A202C;          /* headings, table values — hr.koobs.cafe's own    */
  --body:#1A202C;         /* running text — the reference writes in ink      */
  /* ⚠️ #6E8894 UNTIL 22 Aug 2026, WHICH MEASURED 3.74:1 ON WHITE AND 3.60:1
     ON --bg — both under AA, on the one token that paints every table caption,
     sidebar group label and empty state in all three dashboards. It survived
     because contrast-check reads the pairs it is handed and this pair was never
     handed to it. THE SAME TRAP RE-ARMED ON 23 Aug: the reference's own muted
     is #718096, which measures ~3.9:1 on white — the exact failure class this
     note records. #64748B is the same cool slate one AA-safe step darker
     (4.7:1 on white), indistinguishable beside the original. */
  /* ⚠️ #64748B FAILED AA ON THE PAGE, AND HAD SINCE BEFORE PORCELAIN.
     4.31:1 on the old #F0F4F8 and 4.47:1 on the new #F6F8FA — under 4.5 on the
     background that carries sidebar labels, table headers, hints and every
     empty state. Exactly the miss tools/contrast-check.js warns about in its
     own comment ("muted is the one that fails quietly"), and it went unseen
     because THAT CHECKER DOES NOT READ THIS FILE — it checks the Assets
     palette. One step down the same slate ramp: 4.78 on bg, 5.09 on white. */
  --mute:#616F86;         /* labels, captions, empty states                  */

  /* ══ THE TARTIB CHROME — hr.koobs.cafe's SHELL ═══════════════════════════
     Hussain, 22 Aug 2026, having opened the template: "yess, lets use this."

     ⚠️ THIS REVERSES THE WHITE BAR FROM EARLIER TODAY, AND THE REVERSAL IS THE
     CORRECTION OF A MISREADING, NOT A CHANGE OF MIND. The brief was "the top
     bar needs to be a bit lighter so text and logo show better". I read the
     reference screenshot as a light shell and built one. It is not: the bar AND
     the sidebar are both #0D3B4A, and only the content area is light. What was
     actually wrong with #08222D is that it is nearly black and swallows a
     logo — #0D3B4A is four steps lighter, warmer, and lets white and lime sit
     on it cleanly. Both readings of "lighter" are satisfied by this value; only
     one of them was satisfied by white.

     ⚠️ THE ACCENT ON THE CHROME IS LIME, AND LIME IS ONLY EVER LEGIBLE HERE.
     #BBFF3C is 1.20:1 on white and 10.04:1 on this teal. It is the reason the
     shell has to be dark: the action colour does not exist on a light bar. */
  /* ⚠️ PORCELAIN MAKES THE SHELL PAPER — 2026-09-02, and this is the THIRD
     position this file has held on the bar, so the reasoning matters more than
     the values. It went white in the morning of 22 Aug, back to #0D3B4A that
     afternoon (correctly: the brief was "lighter so text and logo show better"
     and the reference's bar IS dark), and it is light again now for a reason
     neither of those had: Hussain asked for a CLEAN LIGHT THEME, twice, looked
     at the deployed Porcelain build and said "no changes on theme yet", then
     "only icons was changed, full page theme is still same". He is right —
     the shell is two thirds of what the eye sees, and while it stays teal the
     page is the old page whatever the neutrals do.

     ⚠️ THE LIME DIES WITH THE DARK BAR, AND IT HAS TO. #BBFF3C is 1.20:1 on
     white — this file already says lime "is only ever legible here", meaning
     on the teal. A light shell that kept it would be unreadable, so position
     is marked by the module's own --accent-ink on white, which is the answer
     .nav's own comment reached the last time the rail was light.

     ⚠️ THE MODULE ACCENT NOW CARRIES THE CHROME, so HR's bar reads teal-ink,
     Assets' indigo, Loyalty's rose — "each module the same with small thin
     branding different", which is what was asked for. --accent-ink is the
     darkest step of each, so every one of them clears AA on paper. */
  --chrome:#FFFFFF;
  --chrome-2:#F1F5F8;                  /* the hover step, one shade of paper  */
  --chrome-deep:#EDF2F6;
  --chrome-ink:#1A202C;                /* the page's own ink, 15.3:1 on white  */
  --chrome-mute:#616F86;               /* 5.09:1 on white — the AA-safe slate  */
  --chrome-fill:rgba(20,28,38,.05);
  --chrome-fill-hi:rgba(20,28,38,.09);
  --chrome-line:#E4E9EE;
  /* ⚠️ NO LONGER var(--accent-ink). On a dark shell the readable end of the
     ramp is the bright end, and the reference does not use the module accent
     here at all — it uses lime, the one action colour, on every page. */
  --chrome-accent:var(--accent-ink);
  --chrome-chip:var(--accent-ink);
  --chrome-chip-ink:#FFFFFF;
  /* the avatar ring was a hardcoded white at 30% — invisible on paper */
  --chrome-ring:var(--line);

  /* ── SEMANTIC. Do not change these per dashboard, ever. ───────────────── */
  /* ⚠️ THESE ARE hr.koobs.cafe's FOUR, RE-MEASURED — NOT COPIED. Hussain,
     22 Aug 2026: "use the theme and create the same for SaaS on DataTech."
     The design is theirs; the numbers could not be, because every one of the
     four fails AA against its own pill background, and this is the module where
     the pill IS the message:

         #1f9d55 on #e3f6ec = 3.10     "Active"
         #d64545 on #fbe6e6 = 3.66     "Expired"
         #e08a1e on #fcf0dd = 2.38     "On Leave · until 29 Aug"
         #c9a800 on #fbf6da = 2.12     "Pending"

     2.12:1 is not a near miss, it is text you cannot read at 10.5px on a laptop
     in daylight. So the HUE and SATURATION are kept exactly — same green, same
     amber, same brick — and the lightness walked down until each pair clears
     4.8:1, which leaves headroom the exact-4.5 answer does not. Side by side
     with the original the difference is invisible; on the screen it is the
     difference between a status you read and one you infer.

     ⚠️ --hold IS NEW AND IS NOT --warn. Koobs runs a fifth colour, yellow, for
     "waiting on somebody else" — submitted, pending approval, awaiting a
     ministry. Amber means YOU are late; yellow means you are BLOCKED, and
     collapsing the two is how "waiting for the ministry" ends up in the same
     list as "you forgot to renew this". */
  --ok:#187A42;      --ok-bg:#E3F6EC;      --ok-line:#187A42;
  --hold:#806B00;    --hold-bg:#FBF6DA;    --hold-line:#C9A800;
  --warn:#975D14;    --warn-bg:#FCF0DD;    --warn-line:#E08A1E;
  /* ⚠️ #DC2626 UNTIL 22 Aug 2026, AND IT FAILED ON THE ONE PAIRING NOBODY
     MEASURED: itself. Every status pill is its own colour on a 6% wash OF THAT
     COLOUR, and #DC2626 on its own wash is 4.41:1 — under AA, on the words
     "lost" and "disposed", which are the two in the register that mean an asset
     is gone. The tint comment in the Assets sheet says "6% and 16%, checked,
     not guessed"; what was checked was the ink against WHITE, and the wash is
     not white. Four steps darker takes the same pairing to 4.76:1 and is
     indistinguishable to the eye. Measured in a rendered page with the alpha
     composited, which is the only way this pair is visible at all. */
  --bad:#C12B2B;     --bad-bg:#FBE6E6;     --bad-line:#D64545;
  /* Blue is ours: Koobs has no fifth hue and a product needs "this is a note"
     to not be one of the four that mean something is wrong. */
  --info:#2563EB;    --info-bg:#EFF6FF;    --info-line:#3B82F6;

  /* ══ THE ACTION COLOUR ═══════════════════════════════════════════════════
     ⚠️ LIME IS A FILL AND NEVER TEXT ON A LIGHT SURFACE. #BBFF3C on white is
     1.20:1 — it is not a colour you can write in, it is a colour you write ON.
     Its ink is always --lime-ink, which clears 10.04:1 against it. Written down
     because a lime "Add Employee" button is obviously right and lime link text
     is invisible, and the two look like the same decision. */
  --lime:#BBFF3C; --lime-hi:#A8F221; --lime-ink:#0D3B4A;

  /* ══ CATEGORICAL — A THIRD FAMILY, AND THE RULE AT THE TOP STILL HOLDS ══
     Hussain, 22 Aug 2026: "have more tags colours to be easily read."

     ⚠️ THESE DESCRIBE KIND, NOT HEALTH. "Espresso machine", "Facilities" and
     "Refrigeration" want telling apart at a glance; not one of them is good or
     bad, and painting a category amber would say something about it that is not
     true. That is the whole reason they cannot be the semantic four.

     ⚠️ HUE ALONE CANNOT CARRY EIGHT CATEGORIES *AND* FOUR STATES, AND
     PRETENDING OTHERWISE IS HOW THIS GOES WRONG. Eight hues spread far enough
     apart to be told apart will inevitably land near green, amber, red or blue.
     So SHAPE is what separates the two families, not colour:

         status    →  .pill   fully rounded, washed, 1px border. Only ever in a
                              status column, only ever ok / warn / bad / info.
         category  →  .ctag   9px corners, a solid dot in front. Never in a
                              status column.

     A person learns "round is how it is going, square is what it is" in about
     four rows, and then hue is free to do its job inside each family. Break the
     shape rule and the colour coding is over — that is not a style preference,
     it is the only thing holding eight hues and four hues apart on one screen.

     ⚠️ NEVER PICK A BUCKET BY MEANING — HASH THE LABEL. Eight stable buckets
     that survive a rename beat a hand-map that goes stale, and a hand-map is
     also how somebody eventually gives "Broken equipment" the red one and
     quietly re-invents the collision this whole file exists to prevent. */
  --cat-1:#4338CA; --cat-1-bg:#EEF0FE;   /* indigo   */
  --cat-2:#7E22CE; --cat-2-bg:#F5EEFD;   /* violet   */
  --cat-3:#A21CAF; --cat-3-bg:#FBEDFC;   /* fuchsia  */
  --cat-4:#9F1239; --cat-4-bg:#FCECF0;   /* rose     */
  --cat-5:#92400E; --cat-5-bg:#FBF1E7;   /* brown    */
  --cat-6:#4D7C0F; --cat-6-bg:#F2F7E8;   /* olive    */
  --cat-7:#0F766E; --cat-7-bg:#E9F6F4;   /* teal     */
  --cat-8:#0E7490; --cat-8-bg:#E8F5F9;   /* cyan     */

  /* ── form ─────────────────────────────────────────────────────────────── */
  /* 10 and 8, from the reference's --radius. Tartib was at 12/9, which reads
     softer; the difference is small and it is the kind of small that makes two
     screens look like two products. */
  --r:9px; --r-sm:7px; --r-pill:99px;
  --shadow:0 1px 2px rgba(20,28,38,.05);
  --shadow-md:0 4px 12px rgba(8,34,45,.10);
  --shadow-lg:0 20px 50px rgba(8,34,45,.15);
  /* Almarai has no monospaced cut. What asked for one here wanted FIGURES
     THAT LINE UP, not a typewriter, and the rules below pair it with
     font-variant-numeric; the monospace stack stays as a last resort only. */
  --mono:"Almarai",ui-monospace,SFMono-Regular,Menlo,monospace;
  /* ⚠️ ALMARAI FIRST, FOR BOTH SCRIPTS — 21 Sep 2026. Hussain: "always use
     Almarai font".
     It was Manrope first, with Almarai behind it to catch the Arabic and an
     html[dir="rtl"] rule to pull Almarai forward in Arabic mode. That is two
     typefaces on one screen the moment a page mixes scripts — an English
     column header over Arabic rows, a Latin brand name in an Arabic
     sentence — and the mixing is constant here: every employee record in the
     console carries an Arabic name beside a Latin one. Almarai draws both, so
     one face draws the whole screen and the direction rule below stops being
     a typeface switch. */
  --sans:"Almarai",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;

  /* Default accent = Tartib itself. A dashboard that forgets its data-app
     gets the brand rather than a broken variable. */
  --accent:#00BEEC; --accent-deep:#078EAF; --accent-ink:#0A5A76;
  --accent-wash:rgba(0,190,236,.12);
  --accent-on:#04303F;    /* text that sits ON the accent                    */
}


/* ── TINTED RULES ───────────────────────────────────────────────────────────
   Hussain, 2 Sep 2026: "what if we give a thin colour border to all the boxes
   and tables for each dashboard also" — then, shown three strengths side by
   side, chose the middle one.

   So --line carries 12% of the module accent over the neutral #E2E8F0, and
   every box, table and divider follows without any component being touched.
   The screen reads COOLER or WARMER rather than blue or indigo: you feel which
   module you are in without being able to name the colour.

   ⚠️ 12% AND NOT MORE, for this file's own reason. A border says "separate
   object"; a SATURATED border says "look at this one". Spend that on identity
   and there is nothing left for the late branch, the failed sync, the count
   that does not balance — which is the same collision the header warns about,
   arriving through the chrome instead of through the palette. The semantic
   four stay the only saturated marks on any screen.

   Full-strength accent borders were the third option and were rejected on
   sight of a twenty-row table: every edge competed with the warning.
   ═══════════════════════════════════════════════════════════════════════════ */
/* ── THE COLOUR CODING ──────────────────────────────────────────────────────
   One hue each, far enough apart to tell at a glance, none of them borrowed
   from the semantic four above. */
[data-app="workspace"]{                     /* the hub — Tartib itself       */
  --accent:#00BEEC; --accent-deep:#078EAF; --accent-ink:#0A5A76;
  --accent-wash:rgba(0,190,236,.12); --accent-on:#04303F;
  --line:#C9E4EE;
}
/* ⚠️ HR'S ACCENT IS NOW hr.koobs.cafe's OWN #0D3B4A, not the mint it was
   standing in for. Same reasoning as the semantic four: this is the module
   being rebuilt in that system's visual language, so it should wear that
   system's teal rather than an approximation of it. --accent-deep and
   --accent-ink are the two darker steps of the SAME hue, which is what the
   light bar reads for its mark and its brand name. */
[data-app="hr"]{                            /* HR & Gov — hr.koobs.cafe's teal */
  --accent:#11475A; --accent-deep:#0D3B4A; --accent-ink:#0A2E39;
  --accent-wash:rgba(13,59,74,.10); --accent-on:#FFFFFF;
  --line:#CBD6DC;
}
[data-app="assets"]{                        /* Assets — indigo, already its own */
  --accent:#4F46E5; --accent-deep:#4338CA; --accent-ink:#3730A3;
  --accent-wash:rgba(79,70,229,.12); --accent-on:#FFFFFF;
  --line:#D2D5ED;
}
[data-app="pos"]{                           /* reserved                      */
  --accent:#7C3AED; --accent-deep:#6D28D9; --accent-ink:#5B21B6;
  --accent-wash:rgba(124,58,237,.12); --accent-on:#FFFFFF;
  --line:#D8D4EE;
}
[data-app="loyalty"]{                       /* reserved                      */
  --accent:#DB2777; --accent-deep:#BE185D; --accent-ink:#9D174D;
  --accent-wash:rgba(219,39,119,.12); --accent-on:#FFFFFF;
  --line:#E3D2E0;
}
/* ⚠️ SETTINGS IS TARTIB'S OWN CHROME, so it wears Tartib's cyan rather than a
   sixth hue. The colour coding above answers "which MODULE am I in"; the
   settings console is not a module, it is the place you configure the business
   that owns them — the same relationship the hub has, and the same accent.
   Giving it a colour of its own would have implied a product that is not one. */
[data-app="settings"]{                      /* tenant settings — Tartib itself */
  --accent:#00BEEC; --accent-deep:#078EAF; --accent-ink:#0A5A76;
  --accent-wash:rgba(0,190,236,.12); --accent-on:#04303F;
  --line:#C9E4EE;
}
[data-app="payroll"]{                       /* Payroll — slate, decided 23 Aug */
  --accent:#475569; --accent-deep:#334155; --accent-ink:#1E293B;
  --accent-wash:rgba(71,85,105,.12); --accent-on:#FFFFFF;
  --line:#D1D7DE;
}
/* ── The three that had no block, added 9 Sep 2026 ────────────────────────
   The workspace draws a rail with one icon per product a tenant owns, so a
   product with no accent falls through to Tartib's cyan and reads as the hub.
   Teal, amber and a deep cyan: chosen to sit clear of HR's #11475A teal and
   Assets' indigo at rail size, where the swatch is 18px and half of it is a
   glyph. */
[data-app="team"]{                          /* Team — teal                   */
  --accent:#0F766E; --accent-deep:#0C5E58; --accent-ink:#0A4A45;
  --accent-wash:rgba(15,118,110,.12); --accent-on:#FFFFFF;
  --line:#C9DCDA;
}
[data-app="signage"]{                       /* Signage — amber               */
  --accent:#B45309; --accent-deep:#92400E; --accent-ink:#78350F;
  --accent-wash:rgba(180,83,9,.12); --accent-on:#FFFFFF;
  --line:#E5D5C4;
}
[data-app="finance"]{                       /* FinanceOps — deep cyan        */
  --accent:#0E7490; --accent-deep:#155E75; --accent-ink:#164E63;
  --accent-wash:rgba(14,116,144,.12); --accent-on:#FFFFFF;
  --line:#C6DCE4;
}

/* ══ ⚠️ --accent IS CHROME. --accent-deep IS WHAT DATA IS DRAWN IN. ═════════
   Measured 9 Sep 2026, building the workspace dashboard, and it is the reason
   that dashboard does not use --accent for a single mark:

     --accent #00BEEC on #FFFFFF  =  2.19 : 1

   A chart mark has to clear 3:1 against its surface or it is not a mark, it is
   a suggestion. A sparkline in Tartib cyan is a pale smear on a good monitor
   and gone entirely on a phone held outside — which is where the people who
   need it are standing. --accent-deep clears 3:1 on all nine products, so:

     chrome   — rails, chips, rings, the active-tab wash, anything BEHIND or
                BESIDE text                            → --accent
     data     — bars, lines, area fills, progress, any
                mark whose LENGTH or POSITION is the
                number                                 → --accent-deep

   This is not a preference and it is not per-designer. If a chart appears in
   --accent, it is a bug, and the fix is one token, not a lighter background. */

/* ══ ⚠️ DO NOT BUILD A CHART FROM --cat-1…8 IN SLOT ORDER ═══════════════════
   Those eight exist for CATEGORY CHIPS, where each sits alone against paper
   with its own label beside it, and for that they are fine. As a series
   palette they fail, measured:

     cat-1 #4338CA ↔ cat-2 #7E22CE   ΔE 0.7 under protanopia — one colour
     cat-7 #0F766E ↔ cat-8 #0E7490   ΔE 5.8 in NORMAL vision — one colour
     cat-7, cat-8                    below the chroma floor — both read grey

   Three adjacent purples then two adjacent teals: a legend a red-green
   colourblind reader cannot use and, for the teals, one nobody can. A chart
   needing more than one hue needs a re-stepped set validated against the
   surface it is drawn on — not the next slot along. Single-hue magnitude
   (one --accent-deep, length carries the value) needs no palette at all, and
   is what the workspace dashboard uses for every figure on it. */

/* ══ THE DARK HALF OF THE BAR ═══════════════════════════════════════════════
   ⚠️ THIS FILE WAS LIGHT-ONLY AND THAT WAS SURVIVABLE ONLY WHILE THE BAR WAS
   NAVY: a navy bar is already dark, so a dark page under it needed nothing. A
   WHITE bar over a #0F172A page is a torch, and Assets is a real dark theme
   today — it sets data-theme="dark" on <html> and supplies the dark half of
   every token it borrows. The bar is not its token to supply, so it is here.

   ⚠️ ON A DARK BAR IT IS --accent-deep, NOT --accent-ink, and the difference is
   the plate: --accent-ink is the darkest step and would sink into the bar it is
   meant to sit on. Assets' #4338CA carries white at 7.90:1 and HR's #0F766E at
   5.47:1. TARTIB'S OWN CYAN WOULD MEASURE 3.82:1 AND IS THE ONE HOLE HERE — the
   hub is light-only today, so nothing renders it; give the hub a dark theme and
   [data-app="workspace"] needs a darker --accent-deep before it ships. */
:root[data-theme="dark"]{
  /* The shell is already dark in light mode, so dark theme only deepens it —
     a bar that stayed at #0D3B4A over a #0F172A page would read as the lighter
     surface, which is backwards. */
  --chrome:#0A2E39;
  --chrome-2:#0D3B4A;
  --chrome-deep:#08222B;
  --chrome-ink:#F1F5F9;
  --chrome-mute:rgba(255,255,255,.62);
  --chrome-fill:rgba(255,255,255,.08);
  --chrome-fill-hi:rgba(255,255,255,.16);
  --chrome-line:rgba(255,255,255,.12);
  --chrome-accent:var(--lime);
  --chrome-chip:var(--lime);
  --chrome-chip-ink:var(--lime-ink);
  --chrome-ring:rgba(255,255,255,.3);
  /* ⚠️ --hold NEEDS A DARK VALUE HERE AND NOWHERE ELSE. Assets supplies the dark
     half of --ok/--warn/--bad/--info in its own sheet and cannot supply this one,
     because it was added after that block was written. A token introduced to the
     shared sheet owes a dark value in the shared sheet — the alternative is a
     fifth status colour that is correct in light and near-black in dark, on the
     one theme where nobody would think to look for it. */
  --hold:#E8D44D;    --hold-bg:rgba(201,168,0,.16);   --hold-line:#C9A800;
  /* ⚠️ THE CATEGORICAL SCALE NEEDS A DARK HALF OR IT IS INVISIBLE: the light
     inks are 5-6:1 on white and 1.5:1 on #232E43, and the washes are near-white
     plates. Inverted, not dimmed — the light scale is dark ink on a pale plate,
     the dark scale is pale ink on a translucent plate of the same hue, so a
     category keeps its HUE across themes even though neither value survives. */
  --cat-1:#A5B4FC; --cat-1-bg:rgba(99,102,241,.16);
  --cat-2:#D8B4FE; --cat-2-bg:rgba(168,85,247,.16);
  --cat-3:#F0ABFC; --cat-3-bg:rgba(217,70,239,.16);
  --cat-4:#FDA4AF; --cat-4-bg:rgba(244,63,94,.16);
  --cat-5:#FDBA74; --cat-5-bg:rgba(249,115,22,.16);
  --cat-6:#BEF264; --cat-6-bg:rgba(132,204,22,.16);
  --cat-7:#5EEAD4; --cat-7-bg:rgba(45,212,191,.16);
  --cat-8:#67E8F9; --cat-8-bg:rgba(34,211,238,.16);
}

*{box-sizing:border-box}
/* ⚠️ 14px, DOWN FROM 15. The single biggest reason Tartib read as bulky beside
   the reference: one point of body size compounds through every table cell,
   label, button and nav row on the page. The reference sets 14 and everything
   inside it was proportioned against that. */
body{margin:0;background:var(--bg);color:var(--body);font-family:var(--sans);
     font-size:15px;line-height:1.6;-webkit-font-smoothing:antialiased}
a{color:var(--accent-deep);text-decoration:none}
button{font-family:inherit;cursor:pointer}
.ar{font-family:'Almarai',sans-serif}
.mut{color:var(--mute);font-size:13.5px}

/* ═══ THE TENANT'S OWN MARK ═════════════════════════════════════════════════
   Hussain: "show the tenant logo on the topbar after the keypad, then the
   brand name, then the word Workspace."

       [keypad] [logo] Koobs Cafe  Workspace

   ⚠️ THE LOGO IS OPTIONAL AND THE BAR MUST SURVIVE IT BEING ABSENT. The first
   version of the hub used an <img> for the wordmark, the file 404'd on a
   tenant host, and the chrome was left nameless — which is why it became text
   in the first place. So the name is ALWAYS rendered; the logo sits in front
   of it when the tenant has one, and removes itself on error. A business with
   no logo yet sees its name, not a broken-image glyph. */
.logo{height:28px;width:auto;max-width:132px;object-fit:contain;border-radius:6px;
  background:var(--chrome-fill);padding:2px 5px;flex-shrink:0}
.brand{display:flex;align-items:center;gap:10px;min-width:0}
.brand .co{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:190px}
.word{font-size:11px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  color:var(--chrome-accent);white-space:nowrap}
@media(max-width:520px){ .logo{max-width:84px} .brand .co{max-width:110px} .word{display:none} }

/* ── the language switch ────────────────────────────────────────────────── */
.lang{display:flex;background:var(--chrome-fill);border-radius:var(--r-pill);padding:2px;gap:2px;flex-shrink:0}
.lang button{font:inherit;font-size:11.5px;font-weight:800;color:var(--chrome-mute);
  background:none;border:0;border-radius:var(--r-pill);padding:4px 11px;line-height:1.5}
/* ⚠️ --accent-ink AND WHITE, for the same reason .mark carries it: the selected
   language is a solid accent chip, and on the light bar the mid accent under
   white text measures 3.9:1 in teal. --accent-on is still the right token for a
   chip on a DARK surface, which is why it stays defined; it is simply not what
   a chip on a white bar needs. */
.lang button.on{background:var(--chrome-chip);color:var(--chrome-chip-ink)}
.lang button:hover:not(.on){color:var(--chrome-ink)}

/* ═══ ARABIC ════════════════════════════════════════════════════════════════
   Direction is a document property, so it is set once on <html> and every
   layout below follows from it rather than from a per-component flag.

   ⚠️ NUMBERS, DATES AND MONEY STAY LTR. An Arabic HR screen still shows
   2026-11-12 and 290.000 left-to-right — flipping a date string is not
   translation, it is corruption, and a renewal date read backwards is a
   renewal missed. Anything in --mono is pinned. */
/* Kept as the belt to the braces above: --sans already leads with Almarai,
   and a page that overrides --sans still gets Arabic drawn properly. */
html[dir="rtl"] body{font-family:'Almarai',var(--sans)}
/* ⚠️ THE BAR DOES NOT MIRROR, AND THAT IS ON PURPOSE. Hussain: "always
   Profile is far right of screen". Everything else on the page flips with the
   language; the bar keeps its physical order — keypad far left, account far
   right — so the two controls people reach for without looking are in the
   same corner in both languages. row-reverse cancels the RTL flip of the flex
   line while leaving every label inside it Arabic. The panels that hang off
   the two ends follow the buttons, not the text direction. */
html[dir="rtl"] .top{flex-direction:row-reverse}
html[dir="rtl"] .prof-panel{inset-inline-end:auto;inset-inline-start:0}
html[dir="rtl"] .side{border-right:0;border-left:0}
html[dir="rtl"] .nav{text-align:right}
html[dir="rtl"] .table th,html[dir="rtl"] td{text-align:right}
html[dir="rtl"] .num,
html[dir="rtl"] [class*="num"],
html[dir="rtl"] .table th.num{direction:ltr;text-align:left;unicode-bidi:isolate}
html[dir="rtl"] .stat .v{direction:ltr;text-align:right;unicode-bidi:isolate}
html[dir="rtl"] .grp{text-align:right}
@media(max-width:900px){ html[dir="rtl"] .side{border-left:0;border-bottom:0} }
/* A date or an amount anywhere, in either direction, is left-to-right. */
.ltr,time,.money{direction:ltr;unicode-bidi:isolate}

/* ⚠️ THE SAFETY NET FOR ANYTHING NOT TRANSLATED YET.
   An English sentence sitting inside an RTL document is re-ordered by the
   bidi algorithm: "9 branches between them" renders as "branches 9 between
   them", and a trailing full stop jumps to the front of the line. That is not
   a translation gap, it is corruption — the words are wrong, not merely
   English. Any string still in English while the page is Arabic gets isolated
   so it reads correctly until it is translated. */
html[dir="rtl"] .en{direction:ltr;unicode-bidi:isolate;display:inline-block;text-align:left}

/* ── top bar ────────────────────────────────────────────────────────────── */
.top{position:sticky;top:0;z-index:40;background:var(--chrome);color:var(--chrome-ink);
  height:58px;display:flex;align-items:center;gap:14px;padding:0 20px}
/* The module's own colour, on the smallest surface that identifies it.

   ⚠️ SOLID --accent-ink, NOT --accent ON --accent-wash, AND THIS IS THE MOST
   LOAD-BEARING LINE IN THE LIGHTENING. On the navy bar a 12% wash was a dark
   plate and the accent read off it cleanly. On white, --accent-wash IS white,
   and the mark became HR's #0D9488 on near-white — 3.3:1, on 12px bold, which
   is the module's own identity failing AA. --accent-ink is the dark step of
   every accent and clears 5.4:1 with white in the worst of the five (teal);
   the palest, Tartib's cyan, would have measured 3.8:1 even at --accent-deep.
   The same arithmetic is why .co and .word moved off --accent. */
.mark{width:34px;height:34px;border-radius:8px;background:var(--chrome-chip);
  display:flex;align-items:center;justify-content:center;font-weight:800;font-size:12px;
  letter-spacing:-.5px;color:var(--chrome-chip-ink);flex-shrink:0}
.co{font-weight:800;font-size:15px;color:var(--chrome-accent)}
.ttl{font-weight:600;font-size:15px;color:var(--chrome-ink)}
/* ⚠️ TWO SEPARATORS, DOING DIFFERENT JOBS, WHICH IS WHY THEY LOOK DIFFERENT.
   .top-div splits the one CONTROL in the bar from the identity that follows
   it — a rule, because it is a boundary. .top-sep joins tenant to module into
   one readable phrase — a slash at mute weight, because it is punctuation.
   A bar that uses the same mark for both reads as four items in a row. */
.top-div{width:1px;height:22px;background:var(--chrome-line);flex:none;margin:0 -4px}
.top-sep{color:var(--chrome-mute);font-weight:400;font-size:15px;
  margin:0 -3px;flex:none;user-select:none}
.sub{color:var(--chrome-mute);font-size:12.5px}
.sp{flex:1}
.btn-out{font:inherit;font-size:13px;font-weight:600;color:var(--chrome-ink);background:var(--chrome-fill);
  border:0;border-radius:8px;padding:8px 16px;text-decoration:none;display:inline-block}
.btn-out:hover{background:var(--chrome-fill-hi)}

/* ═══ THE BAR'S OWN CONTROLS ════════════════════════════════════════════════
   Keypad, language, profile — the same three on every page, in the same
   order, at the same size. */
.key-btn{width:34px;height:34px;border-radius:8px;border:0;background:var(--chrome-fill);
  color:var(--chrome-ink);display:flex;align-items:center;justify-content:center;flex-shrink:0}
.key-btn:hover{background:var(--chrome-fill-hi)}

.prof-wrap{position:relative;flex-shrink:0}
.prof-chip{display:flex;align-items:center;gap:5px;background:none;border:0;padding:2px;border-radius:99px}
.prof-chip:hover{background:var(--chrome-fill)}
.prof-av{width:34px;height:34px;border-radius:50%;color:#fff;border:2px solid var(--chrome-ring);display:flex;align-items:center;
  justify-content:center;font-weight:700;font-size:11.5px;flex-shrink:0}
.prof-av.lg{width:38px;height:38px;font-size:14px}
.prof-caret{color:var(--chrome-mute);font-size:10px}
.prof-panel{position:absolute;top:calc(100% + 9px);inset-inline-end:0;width:264px;background:var(--surface);
  border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--shadow-lg);z-index:60;padding:5px 0;display:none}
.prof-panel.open{display:block}
.prof-head{display:flex;align-items:center;gap:11px;padding:13px 15px}
.prof-nm{display:block;font-weight:700;font-size:13px;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.prof-em{display:block;font-size:11.5px;color:var(--mute);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.prof-chips{display:flex;flex-wrap:wrap;gap:5px;padding:0 15px 10px}
.prof-tag{font-size:10.5px;font-weight:700;color:var(--accent-ink);background:var(--accent-wash);padding:2px 7px;border-radius:5px}
.prof-sep{border-top:1px solid var(--line-soft);margin:4px 0}
.prof-link{display:block;width:100%;text-align:start;padding:10px 15px;font:inherit;font-size:13px;
  font-weight:600;color:var(--ink);background:none;border:0;text-decoration:none}
.prof-link:hover{background:var(--surface-2)}
.prof-link.danger{color:var(--bad)}
/* company switcher in the account menu (16 Sep 2026) */
.prof-ws-h{padding:8px 15px 4px;font-size:10.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3,#6b7280)}
.prof-link.prof-ws{display:flex;align-items:center;gap:9px;padding:8px 15px;text-decoration:none;color:inherit}
.prof-link.prof-ws.on{cursor:default;font-weight:600}
.prof-av.sm{width:22px;height:22px;font-size:9.5px;flex:none}
.prof-ws-nm{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.prof-ws-on{color:var(--accent-ink,#1a73e8);font-weight:700}

/* ══ BREADCRUMBS ════════════════════════════════════════════════════════════
   Hussain: "when we are going deep into each section the top is showing where
   we are as Governance - Companies - Koobs - Abu Hallifa … we need to do this
   with each part of our dashboard so we can go back to where ever quickly."

   ⚠️ IN THE TOKENS SHEET, NOT THE COMPONENTS SHEET. tartib-ui.css is linked by
   the pages that do not own names like .card and .btn — HR and the hub do,
   Assets does not, and Assets is a page that needs crumbs. Anything every
   dashboard must have goes here, with the top bar, or it silently works on two
   screens out of three.

   ⚠️ THE LAST CRUMB IS NOT A LINK. It is where you already are, and making it
   clickable teaches people that clicking a crumb sometimes does nothing. */
.crumbs{display:flex;align-items:center;gap:6px;flex-wrap:wrap;
  font-size:12px;margin:0 0 14px;min-height:18px}
.crumbs a,.crumbs button{font:inherit;font-size:12px;color:var(--accent-deep);background:none;
  border:0;padding:0;cursor:pointer;text-decoration:none;border-radius:4px}
.crumbs a:hover,.crumbs button:hover{text-decoration:underline}
.crumbs .sep{color:var(--mute);user-select:none}
.crumbs .here{color:var(--ink);font-weight:700}
/* The separator is a slash and it is FLIPPED IN ARABIC. A "/" between
   right-to-left crumbs leans the wrong way and reads as a fraction; the
   mirrored form is the same character the OS uses in an RTL path. */
html[dir="rtl"] .crumbs .sep::before{content:"\\"}
html[dir="rtl"] .crumbs .sep{font-size:0}
html[dir="rtl"] .crumbs .sep::before{font-size:12px}

/* A "back to the thing above" control, for when the crumb trail is not enough
   — a deep screen wants one obvious way out, not only a small trail. */
.backlink{display:inline-flex;align-items:center;gap:6px;font:inherit;font-size:12.5px;
  font-weight:700;color:var(--accent-deep);background:none;border:0;padding:4px 0;
  cursor:pointer;margin-bottom:10px}
.backlink:hover{text-decoration:underline}
.backlink .ar{font-size:14px;line-height:1}
html[dir="rtl"] .backlink .ar{transform:scaleX(-1)}

/* ══ THE CATEGORY TAG ═══════════════════════════════════════════════════════
   The square half of the pair described up in the palette: .pill is round and
   says how something is GOING, .ctag is square and says what it IS.

   ⚠️ THE DOT IS NOT DECORATION. It is the second channel: about one man in
   twelve cannot separate the rose bucket from the brown one, and at 11px the
   plate wash is too pale to carry the hue on its own. The dot is a saturated
   6px of the full colour, which is the smallest patch most people can still
   name — and it is what makes the shape rule readable at a glance, because a
   dotted square tag never looks like an undotted round pill.

   ⚠️ NO .ctag EVER GOES IN A STATUS COLUMN. See the palette. */
.ctag{display:inline-flex;align-items:center;gap:6px;border-radius:9px;padding:2px 8px;
  font-size:11px;font-weight:700;line-height:1.55;white-space:nowrap;
  background:var(--ct-bg,var(--surface-2));color:var(--ct,var(--mute))}
.ctag::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;flex-shrink:0}
/* ⚠️ THE BUCKET IS AN ATTRIBUTE, NOT A CLASS ON .ctag, SO A COMPONENT THAT IS
   NOT A .ctag CAN STILL USE THE SCALE. HR's licence chips are a bigger, icon-
   led chip and will never be a .ctag, but "Health Certificate" has to be the
   same colour there as everywhere else or the scale is decorative. Anything
   that sets data-cat gets --ct and --ct-bg and paints itself however it likes.
   TartibUI.catBucket() is the only thing that should be choosing the number. */
[data-cat="1"]{--ct:var(--cat-1);--ct-bg:var(--cat-1-bg)}
[data-cat="2"]{--ct:var(--cat-2);--ct-bg:var(--cat-2-bg)}
[data-cat="3"]{--ct:var(--cat-3);--ct-bg:var(--cat-3-bg)}
[data-cat="4"]{--ct:var(--cat-4);--ct-bg:var(--cat-4-bg)}
[data-cat="5"]{--ct:var(--cat-5);--ct-bg:var(--cat-5-bg)}
[data-cat="6"]{--ct:var(--cat-6);--ct-bg:var(--cat-6-bg)}
[data-cat="7"]{--ct:var(--cat-7);--ct-bg:var(--cat-7-bg)}
[data-cat="8"]{--ct:var(--cat-8);--ct-bg:var(--cat-8-bg)}
/* An unset or empty category is grey and still square: absent is a KIND of
   answer, and rendering it as plain text would make "no category" the only
   value in the column that is not a tag. */
[data-cat="0"]{--ct:var(--mute);--ct-bg:var(--surface-2)}

/* ══ THE ROLE BADGE ═══════════════════════════════════════════════════════
   Hussain, 23 Aug 2026: "all job type and other details needs to have a proper
   universal Badge like (Team Leader - TL, Super Visor SB, Manager - MNG) with
   proper color coding and emoji or other."

   ⚠️ A ROLE IS A KIND, NOT A STATE — this is the ctag's square family and
   obeys the same shape rule: never in a status column, never wearing the
   semantic four. The EMOJI stands where the ctag's dot stands (the second
   channel) and the mono ABBR chip is the constant a person learns to scan
   for. Colours ride the same data-cat buckets: TartibUI.roleTag() curates the
   bucket for the roles every tenant has and hashes the rest, so "Manager" is
   the same colour on every list of every dashboard. */
.rtag{display:inline-flex;align-items:center;gap:5px;border-radius:9px;padding:2px 8px;
  font-size:11px;font-weight:700;line-height:1.55;white-space:nowrap;
  background:var(--ct-bg,var(--surface-2));color:var(--ct,var(--mute))}
.rtag .em{font-size:12px;line-height:1;display:inline-flex;align-items:center}
/* the mark is a stroked glyph now, and it takes the tag's own category ink
   rather than carrying a colour of its own */
.rtag .em svg{display:block;width:13px;height:13px}
.rtag .ab{font-family:var(--mono);font-size:10px;font-weight:700;letter-spacing:.4px;
  background:rgba(255,255,255,.65);border-radius:4px;padding:0 4px}
[data-theme="dark"] .rtag .ab{background:rgba(0,0,0,.35)}

/* ── the keypad's launcher ──────────────────────────────────────────────── */
/* ⚠️ A QUICK LINK, NOT A DESTINATION. Hussain: "on topbar keypad should be
   Quick link to Workspace links like (HR&GOV, Assets, ...)". It used to darken
   the whole screen and open a 560px dialog in the middle of it — the weight of
   a decision, for what is one click to the next module. It hangs off the button
   that opens it now, the overlay is invisible and exists only to catch the
   click that closes it, and the box is the width of the links inside it.
   `left`, not `inset-inline-start`: the bar keeps the keypad on the physical
   left in both languages, so the panel under it does too. */
.apps-ov{position:fixed;inset:0;background:transparent;z-index:80}
.apps-ov[hidden]{display:none}
/* ⚠️ THE LAUNCHER (1 Oct 2026): one tile per APP, each in its own colour, the
   way Google, Microsoft and Zoho draw theirs — a coloured square with a white
   mark, the name under it, the one you are in ringed. `top` and the side are
   set from the button that opened it (TartibUI.openApps); these are the
   fallback. console.ordertech.me's .keypad is the same panel; change both. */
.apps-box{position:fixed;top:62px;left:12px;background:var(--surface);border:1px solid var(--line);
  border-radius:12px;box-shadow:var(--shadow-lg);width:min(320px,calc(100vw - 16px));
  max-height:min(76vh,560px);display:flex;flex-direction:column;overflow:hidden}
.apps-hd{display:flex;align-items:center;justify-content:space-between;padding:12px 16px 4px}
.apps-hd b{color:var(--mute);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.8px}
.apps-x{background:none;border:0;font-size:14px;color:var(--mute);padding:4px 6px;border-radius:6px;cursor:pointer}
.apps-x:hover{background:color-mix(in srgb,var(--ink) 7%,transparent);color:var(--ink)}
.apps-bd{padding:6px 10px 0;overflow-y:auto}
/* ⚠️ NOT .apps-grid: the Workspace's own app drawer owns that name (a flex
   row), and on the one page that loads both, it won — the launcher's three
   columns collapsed to the left with a gap on the right. */
.apps-tiles{display:grid;grid-template-columns:repeat(3,1fr);gap:2px}
.app-go{display:flex;flex-direction:column;align-items:center;gap:7px;padding:12px 4px 10px;border-radius:10px;
  border:1px solid transparent;text-decoration:none;transition:background .12s}
.app-go:hover,.app-go:focus-visible{background:color-mix(in srgb,var(--ink) 6%,transparent);outline:none}
.app-go.here{background:color-mix(in srgb,var(--ink) 5%,transparent);border-color:var(--line)}
.app-go-i{width:36px;height:36px;border-radius:10px;color:#fff;display:flex;align-items:center;justify-content:center;
  box-shadow:inset 0 -2px 0 rgba(0,0,0,.12)}
.app-go-i svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}
.app-go-n{font-size:12px;font-weight:600;color:var(--ink);text-align:center;line-height:1.25;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.apps-wait{grid-column:1/-1}
.apps-wait .spin{margin:12px auto}
.apps-ft{display:flex;flex-wrap:wrap;gap:4px;margin:8px 0 0;padding:8px 0 10px;border-top:1px solid var(--line-soft)}
.apps-ft a{display:flex;align-items:center;gap:7px;padding:7px 10px;border-radius:8px;color:var(--ink-2,var(--ink));
  font-size:13px;font-weight:500;text-decoration:none;flex:1 1 auto}
.apps-ft a:hover{background:color-mix(in srgb,var(--ink) 6%,transparent)}
.apps-ft a svg{width:16px;height:16px;color:var(--mute)}
.apps-empty{color:var(--mute);font-size:13.5px;text-align:center;padding:24px 0}

.spin{width:22px;height:22px;border:2.5px solid var(--line);border-top-color:var(--accent);
  border-radius:50%;animation:t-sp .7s linear infinite;margin:30px auto}
@keyframes t-sp{to{transform:rotate(360deg)}}

@media(max-width:760px){
  /* ⚠️ The bar is the thing that overflows on a phone, not the tables — seven
     un-wrapping flex items in a 390px row. Learned on the HR dashboard. */
  .top{gap:9px;padding:0 12px}
  .top .sub,.top .who{display:none}
  .ttl{font-size:13.5px}
}
/* ⚠️ THE SEPARATOR GOES WITH THE TITLE IT SEPARATES. Dropping .ttl alone left
   the bar reading "Koobs Cafe /" with a slash pointing at nothing — punctuation
   outliving the thing it punctuated, which looks like a rendering fault. */
@media(max-width:420px){ .ttl,.top-sep{display:none} }
