/* ALOKE — THE CONSOLE SHELL (2026-09-06).
   ═════════════════════════════════════════════════════════════════════════
   ONE app-shell for the two rooms that are run from a desk: the super
   console (/super) and the unified owner panel (/panel). Loaded LAST, after
   auth.css, loyalty.css and console-theme.css — so it inherits the Aloke
   brand (the deep purple of the card, the wallet and the POS rail) and only
   lays the page out:
     • a sidebar on the reading side (inline-start: right in Arabic, left in
       English) in the POS rail's own purple, carrying the brand, the grouped
       navigation and the session;
     • a sticky top bar naming where you are, with the one control that
       belongs to the whole page (the place picker, the quick links);
     • a content column of brand-tinted cards, tabular numbers, quiet tables.
   On a phone the sidebar becomes a drawer behind a menu button. Nothing in
   the panes changes: every id and every pane rule they carry still applies.
   Tokens only; the one gradient is the rail's, shared with the POS. */
:root {
  --cs-side: 280px;
  --cs-top: 64px;
  --cs-rail: linear-gradient(180deg, #4E2682 0%, #3A1A5E 100%);
  --cs-rail-ink: rgba(255, 255, 255, .82);
  --cs-rail-dim: rgba(255, 255, 255, .56);
  --cs-rail-line: rgba(255, 255, 255, .12);
  --cs-rail-on: rgba(255, 255, 255, .16);

  /* THE THREE SURFACES THAT WERE WRITTEN AS LITERALS, now tokens — because
     this shell is the FIRST thing anybody sees on owner.hwe.sa and it had no
     dark mode at all. A dark frame inside a white shell is a seam, and it is
     the kind that reads as a bug rather than as a style. */
  --cs-top-bg: rgba(255, 255, 255, .88);   /* the blurred top bar */
  --cs-on-rail-sel: #FFFFFF;               /* the selected rail item's ground */
  --cs-on-rail-sel-ink: var(--accent-press);
  --cs-scrim: rgba(36, 28, 51, .45);
}

/* DARK MODE, MATCHING THE FRAME IT WRAPS. The rail stays purple in both — it
   is the brand's own colour and it is already dark, so it needs deepening
   rather than inverting; what changes is everything AROUND it, which was
   white. Guarded the same way `console-theme.css` guards its own block, so an
   explicit light choice still wins over a dark operating system. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --cs-rail: linear-gradient(180deg, #33195A 0%, #241040 100%);
    --cs-rail-ink: rgba(255, 255, 255, .88);
    --cs-rail-dim: rgba(255, 255, 255, .62);
    --cs-rail-line: rgba(255, 255, 255, .10);
    --cs-rail-on: rgba(255, 255, 255, .14);

    /* The top bar takes the dark surface, not a white one at 88% — which is
       what «rgba(255,255,255,.88)» would have painted over a near-black page. */
    --cs-top-bg: rgba(30, 26, 41, .88);
    /* The selected rail item cannot be a white pill in dark mode: the ink on
       it is `--accent-press`, which the dark theme LIGHTENS, so white-on-light
       -purple would be the same 2.8:1 the primary button already taught. The
       pill goes dark and the ink goes light. */
    --cs-on-rail-sel: rgba(255, 255, 255, .16);
    --cs-on-rail-sel-ink: #FFFFFF;
    --cs-scrim: rgba(0, 0, 0, .6);
  }
}

/* THE SAME VALUES UNDER AN EXPLICIT CHOICE. Three states, not two: a
   stamped `dark` must win over a light operating system exactly as the
   block above lets a stamped `light` win over a dark one. Without this,
   a theme toggle would do nothing for the half of readers whose OS is
   already set the other way — which is how a toggle ships broken.
   The two bodies are IDENTICAL and a test holds them to it. */
:root[data-theme="dark"] {
    --cs-rail: linear-gradient(180deg, #33195A 0%, #241040 100%);
    --cs-rail-ink: rgba(255, 255, 255, .88);
    --cs-rail-dim: rgba(255, 255, 255, .62);
    --cs-rail-line: rgba(255, 255, 255, .10);
    --cs-rail-on: rgba(255, 255, 255, .14);

    /* The top bar takes the dark surface, not a white one at 88% — which is
       what «rgba(255,255,255,.88)» would have painted over a near-black page. */
    --cs-top-bg: rgba(30, 26, 41, .88);
    /* The selected rail item cannot be a white pill in dark mode: the ink on
       it is `--accent-press`, which the dark theme LIGHTENS, so white-on-light
       -purple would be the same 2.8:1 the primary button already taught. The
       pill goes dark and the ink goes light. */
    --cs-on-rail-sel: rgba(255, 255, 255, .16);
    --cs-on-rail-sel-ink: #FFFFFF;
    --cs-scrim: rgba(0, 0, 0, .6);
}


/* ------------------------------------------------------------ the frame */
.cs-app { display: grid; grid-template-columns: var(--cs-side) minmax(0, 1fr); min-height: 100vh; }
.cs-app.hidden { display: none; }
/* `scroll-padding` BELONGS ON THE SCROLLER, and this is the scroller — the nav
   inside it has `overflow: visible` and never scrolls anything, so the same
   declaration sat there doing nothing at all. The cost was not cosmetic: with
   the rail scrolled down, moving keyboard focus to a tab above the fold
   scrolled it to y=0..44, and the sticky brand owns y=0..64 — the focused row
   was ENTIRELY behind the brand, which is the exact failure WCAG 2.2 «focus
   not obscured» names. 8px past the brand so the row clears it with a margin
   rather than touching it. */
.cs-side {
  background: var(--cs-rail); color: #fff;
  position: sticky; top: 0; height: 100vh; overflow-y: auto;
  scroll-padding-block-start: calc(var(--cs-top) + 8px);
  display: flex; flex-direction: column;
  scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, .28) transparent;
}
.cs-side::-webkit-scrollbar { width: 6px; }
.cs-side::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .28); border-radius: 3px; }
.cs-main { min-width: 0; display: flex; flex-direction: column; }

/* ------------------------------------------------------------ the brand */
/* STICKY, so scrolling a long nav never takes the shop's name off screen —
   which is the one line that says WHICH shop these settings belong to.

   IT IS THE SAME HEIGHT AS THE TOP BAR, and that is the whole point of this
   block. The rail and the main column are two panes side by side, and each
   opens with a header: the console name here, the section title there. They
   used to be 74px and 65px, so the two headers sat at different heights and
   the line under them was a 9px STEP across the middle of the screen — the
   first thing an eye lands on, and the reason the page read as two pages
   stapled together. Pinning both to `--cs-top` makes one band across the full
   width and one continuous rule under it.

   `min-height`, not `height`: if a long console name ever wraps, the band
   grows and the seam moves rather than the name being cut off. A shop's name
   losing its last word is a worse bug than a seam.

   THE GRADIENT IS SIZED TO THE RAIL, NOT TO THIS BOX. The rail's background is
   a gradient over the whole 100vh column. A sticky child with `background:
   inherit` repaints that gradient at ITS OWN height — so the brand ran the
   full #4E2682→#3A1A5E ramp inside 74px, and the rail below it restarted near
   #4E2682. That is an 18-step jump in red at exactly the y the eye is already
   drawn to. Painting the same 100vh slice from the same origin makes the band
   invisible: the brand is a window onto the rail's gradient, not its own. */
.cs-brand {
  display: flex; align-items: center; gap: var(--s3);
  min-height: var(--cs-top); box-sizing: border-box;
  padding: 8px 16px;
  border-bottom: 1px solid var(--cs-rail-line);
  position: sticky; top: 0; z-index: 2;
  background-image: var(--cs-rail);
  background-size: 100% 100vh;
  background-repeat: no-repeat;
  background-position: top center;
}
.cs-brand .logo { width: 38px; height: 38px; border-radius: 12px; flex: 0 0 auto; }
/* THE TEXT COLUMN MUST BE ALLOWED TO SHRINK. A flex item's floor is its
   content, so without `min-width: 0` the two lines below push the column wider
   than the rail and `text-overflow` never fires — the classic reason an
   ellipsis that is declared does nothing. */
.cs-brand .txt { min-width: 0; }
/* BOTH LINES ARE CLAMPED TO ONE, the same treatment `.cs-title` gets in the
   bar opposite. Not a flourish: the strapline is 26 Arabic characters on the
   appointments console and 32-34 in English on all of them, against about 160px
   of room, so it wrapped to two lines — and a two-line strapline made the brand
   79px against the bar's 64px. The band this whole block exists to hold cannot
   be at the mercy of a marketing line, and a strapline is exactly the text
   where losing the last word costs nothing. The h1 is clamped for the same
   reason and with the same precedent: the shop's own name, in the bar opposite,
   has been clamped this way since the shell was written. */
.cs-brand h1, .cs-brand .sub {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cs-brand h1 { margin: 0; font-size: 17px; font-weight: 700; color: #fff; line-height: 1.3; }
.cs-brand .sub { margin: 0; font-size: 12px; color: var(--cs-rail-dim); }

/* -------------------------------------------------------------- the nav
   THE SIDE MENU, redesigned 2026-09-09.

   IT IS THE ONLY THING ON owner.hwe.sa THAT IS ALWAYS ON SCREEN, so it is the
   one component where «where am I» has to be answerable without reading. Three
   changes, each answering a rule rather than a taste:

   1. THE GROUP HEADING WAS 11.5px AND DIM — under the 12px floor for body
      text, and it is the label that says which of three CONSOLES a row belongs
      to. It is now 12px and brighter, with the letter-spacing that makes a
      short uppercase-ish Arabic label read as a heading rather than as a
      disabled item.

   2. THE ACTIVE STATE WAS CARRIED BY A TINT AND A 3px EDGE — both colour, and
      «current section» is exactly what must not be colour alone. It now also
      carries WEIGHT, so a row reads as selected in greyscale, to a colour-blind
      owner, and on a phone in sunlight.

   3. THE RAIL SCROLLS AND THE BRAND IS STICKY. With three consoles open the
      nav is taller than a laptop viewport, and scrolling used to take the shop
      name off screen — the one thing that says WHICH shop you are editing.
      `scroll-padding` comes with it so a keyboard focus landing at the top of
      the list is not tucked under the sticky brand (WCAG 2.2 «focus not
      obscured», the AA half). */
.cs-nav { flex: 1 1 auto; padding: 4px 10px 16px; }
.cs-group { margin-top: 14px; }
.cs-group + .cs-group { border-top: 1px solid var(--cs-rail-line); padding-top: 6px; }
.cs-group-h {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 10px 12px 4px; margin: 0;
  background: none; border: 0; color: var(--cs-rail-dim); text-align: start;
  font: inherit; font-size: 12px; font-weight: 700; letter-spacing: .04em; cursor: pointer;
}
.cs-group-h .ic { width: 16px; height: 16px; opacity: .9; }
.cs-group-h:hover { color: #fff; }
.cs-group-h.on { color: #fff; }
.cs-group-h .cs-console { font-weight: 500; opacity: .75; }
.cs-tab {
  display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: 44px; padding: 6px 12px; margin: 1px 0;
  border: 0; border-inline-start: 3px solid transparent; border-radius: 10px;
  background: transparent; color: var(--cs-rail-ink);
  font: inherit; font-weight: 500; text-align: start; cursor: pointer;
  transition: background-color .12s ease, color .12s ease;
}
.cs-tab .ic { flex: 0 0 auto; opacity: .85; }
.cs-tab:hover { background: rgba(255, 255, 255, .08); color: #fff; }
.cs-tab:hover .ic { opacity: 1; }
/* THE FOCUS RING IS LIGHT ON THIS RAIL. The theme's ring is the purple accent,
   which on a purple ground is a ring nobody can see — the one place in the
   product where the shared focus style would silently fail. */
.cs-tab:focus-visible, .cs-group-h:focus-visible, .cs-link:focus-visible {
  outline: 2px solid #fff; outline-offset: -2px;
}
.cs-tab.on, .cs-tab[aria-current="true"], .cs-tab[aria-selected="true"] {
  font-weight: 700;                 /* selected in greyscale too, not by tint alone */
  background: var(--cs-rail-on); color: #fff; border-inline-start-color: #fff;
}
.cs-tab .cs-t, .cs-tab .ptab-t, .cs-tab .t { display: block; font-size: 14px; font-weight: 600; line-height: 1.35; }
.cs-tab .cs-s, .cs-tab .ptab-s, .cs-tab .s { display: block; font-size: 11.5px; font-weight: 400; color: var(--cs-rail-dim); line-height: 1.4; }
.cs-tab.on .cs-s, .cs-tab.on .ptab-s, .cs-tab[aria-current="true"] .s { color: rgba(255, 255, 255, .78); }
.cs-tab > span:first-child { flex: 1 1 auto; min-width: 0; }
.cs-tab.pending { opacity: .7; }
.cs-tab .nav-b, .cs-group-h .nav-b {
  margin-inline-start: auto; flex: 0 0 auto;
  min-width: 20px; height: 20px; padding: 0 7px; border-radius: var(--r-pill);
  background: var(--cs-on-rail-sel); color: var(--cs-on-rail-sel-ink);
  font-size: 11px; font-weight: 700; line-height: 20px; direction: ltr; text-align: center;
}
/* The super console's nav keeps its `.pgroup` / `.ptab` names for the one
   click-wiring every arrival runs through; the ID out-specifies the page's
   own strip rules, so the same names lay out as rows here. */
#superNav .pgroup-bar, #superNav .panel-tabs { display: block; border: 0; margin: 0; overflow: visible; }
#superNav .pgroup {
  border: 0; background: none; min-height: 0; justify-content: flex-start;
  flex-direction: row; gap: 8px; font-size: 11.5px; padding: 10px 12px 4px; border-radius: 0;
}
#superNav .pgroup.on { background: none; border: 0; }
#superNav .ptab { white-space: normal; border-bottom: 0; flex-direction: row; }
#superNav .ptab.on { border-bottom: 0; }
#superNav .ptab.on .ptab-s { color: rgba(255, 255, 255, .78); }
#superNav .pgroup.on .nav-b, #superNav .ptab.on .nav-b {
  background: var(--cs-on-rail-sel); color: var(--cs-on-rail-sel-ink);
}

/* ---------------------------------------------------------- the session */
.cs-side-foot { padding: 12px 14px 16px; border-top: 1px solid var(--cs-rail-line); display: flex; flex-direction: column; gap: 8px; }
.cs-side-foot .whoami { color: var(--cs-rail-ink); text-align: start; font-size: 12.5px; }
.cs-side-foot .whoami .who-phone { color: #fff; }
.cs-links { display: flex; flex-wrap: wrap; gap: 6px; }
.cs-link {
  display: inline-flex; align-items: center; gap: 6px; min-height: 36px; padding: 0 10px;
  border-radius: var(--r-btn); border: 1px solid var(--cs-rail-line);
  color: var(--cs-rail-ink); text-decoration: none; font-size: 12.5px; font-weight: 600;
  background: rgba(255, 255, 255, .05);
}
.cs-link:hover { background: rgba(255, 255, 255, .12); color: #fff; }
.cs-link .ic { width: 16px; height: 16px; }
.cs-side-foot .ghost, .cs-side-foot .cs-btn {
  color: #fff; border-color: rgba(255, 255, 255, .28); background: rgba(255, 255, 255, .06);
  /* 44, not 40: these are the rail's own controls and «خروج» sits next to
     «EN» — a near-miss between two adjacent buttons signs somebody out. */
  min-height: 44px; height: auto; border-radius: var(--r-btn);
}
.cs-side-foot .ghost:hover:not(:disabled) { background: rgba(255, 255, 255, .14); border-color: rgba(255, 255, 255, .4); }
.cs-side-foot-row { display: flex; gap: 8px; }
.cs-side-foot-row > * { flex: 1 1 auto; }

/* THE GROUP FOLDS. `console-ui.js` makes the heading a real button and moves
   the tabs into `.cs-group-b`; everything here is the affordance. */
/* 44px BECAUSE IT IS NOW A BUTTON. It was a 34px label when it was a `div`
   and nothing happened when you touched it; the moment `console-ui.js` gives
   it `role="button"` it owes the same target as everything else you can tap. */
.cs-group-h { position: relative; padding-inline-end: 30px; min-height: 44px; }
/* THE CHEVRON IS DRAWN WITH PHYSICAL EDGES. It is a corner turned to point, so
   its direction comes from WHICH corner — and logical edges mirror that corner
   in Arabic: `border-inline-end` is the LEFT edge there, and an open group
   pointed «‹», the sign for «closed». With right + bottom it is the same corner
   in both directions: 45° points down (open), and folded turns it along the
   reading direction — right in English, left in Arabic. The POSITION stays
   logical (`inset-inline-end`), because where it sits should mirror. */
.cs-group-h::after {
  content: ""; position: absolute; inset-inline-end: 10px; top: 50%;
  width: 8px; height: 8px; margin-top: -5px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg); opacity: .7;
  transition: transform .15s ease;
}
.cs-group-h[aria-expanded="false"]::after { transform: rotate(-45deg); }
html[dir="rtl"] .cs-group-h[aria-expanded="false"]::after { transform: rotate(135deg); }
.cs-group-h[role="button"] { cursor: pointer; }
.cs-group-b[hidden] { display: none; }

/* ------------------------------------------------------------ the top bar */
/* THE BAR IS EXACTLY `--cs-top` TALL, and the vertical padding is 8px rather
   than 10px to make that true. The title block is 44px (an 18px line over a
   12.5px one, both clamped to one line), so at 10px padding plus the 1px rule
   the bar came to 65px and `min-height` never bound — the bar's height was
   decided by its CONTENT, which means it was 64px on a page with no subtitle
   and 65px on a page with one. Nothing in the rail can match a header that
   changes height depending on what is written in it. At 8px the content fits
   inside the floor with 3px to spare, `min-height` binds, and the bar is 64px
   on every page — which is what lets the brand opposite it be 64px too. */
.cs-top {
  position: sticky; top: 0; z-index: 30;
  min-height: var(--cs-top); display: flex; align-items: center; gap: var(--s3);
  padding: 8px var(--s5); background: var(--cs-top-bg);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line); box-shadow: none;
  justify-content: flex-start;
}
.cs-title { min-width: 0; }
.cs-title h2, .cs-title h1 { margin: 0; font-size: 18px; font-weight: 700; line-height: 1.3; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cs-title p { margin: 0; font-size: 12.5px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cs-top-actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; justify-content: flex-end; }
.cs-menu { display: none; width: 44px; height: 44px; padding: 0; flex: 0 0 auto; }
.cs-menu .ic { width: 22px; height: 22px; }
.cs-place { display: flex; align-items: center; gap: var(--s2); }
.cs-place label { font-size: 12px; color: var(--muted); white-space: nowrap; }
.cs-place select { min-width: 220px; max-width: 360px; min-height: 44px; }

/* -------------------------------------------------------------- content */
.cs-main > main.wrap, .cs-main > .cs-content { max-width: 1240px; width: 100%; margin: 0 auto; padding: var(--s5) var(--s5) var(--s6); }
.section { box-shadow: var(--card-shadow); }
.section > h2 { font-size: 19px; }
.stat { box-shadow: var(--card-shadow); border-color: transparent; }
.stat .stat-num, .stat .num, .bnum, .n { font-variant-numeric: tabular-nums; }
table.data thead th, .b2-t thead th, .bill-sched-t thead th, .pl-t thead th {
  background: var(--bg); color: var(--muted); font-size: 12px; font-weight: 700; letter-spacing: .02em;
}
.chip.ok { background: var(--accent-weak); color: var(--accent-press); }
/* The warn chip was three hex literals; the theme already owns this pair. */
.chip.warn { background: var(--warn-weak); color: var(--warn); }
.cs-scrim { display: none; }

/* ---------------------------------------------------- the phone drawer */
@media (max-width: 1023px) {
  .cs-app { grid-template-columns: 1fr; }
  .cs-side {
    position: fixed; top: 0; bottom: 0; inset-inline-start: 0;
    width: min(86vw, var(--cs-side)); height: 100vh; z-index: 50;
    transform: translateX(100%); transition: transform .2s ease;
    box-shadow: var(--overlay-shadow);
  }
  html[dir="ltr"] .cs-side { transform: translateX(-100%); }
  body.nav-open .cs-side { transform: none; }
  .cs-menu { display: inline-flex; }
  .cs-scrim {
    display: block; position: fixed; inset: 0; z-index: 45;
    background: var(--cs-scrim); opacity: 0; pointer-events: none; transition: opacity .2s ease;
  }
  body.nav-open .cs-scrim { opacity: 1; pointer-events: auto; }
  body.nav-open { overflow: hidden; }
  .cs-top { padding: 8px var(--s4); }
  .cs-main > main.wrap, .cs-main > .cs-content { padding: var(--s4); }
  .cs-place select { min-width: 150px; }
}
@media (prefers-reduced-motion: reduce) { .cs-side, .cs-scrim { transition: none; } }

/* ------------------------------------------------------- the top-bar search */
.cs-search { position: relative; min-width: 260px; flex: 1 1 320px; max-width: 460px; }
.cs-search input { width: 100%; min-height: 44px; }
.cs-search-out {
  position: absolute; top: calc(100% + 6px); inset-inline: 0; z-index: 40;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-card);
  box-shadow: var(--overlay-shadow); padding: var(--s2); max-height: 60vh; overflow-y: auto;
}
.cs-search-h { font-size: 11.5px; font-weight: 700; color: var(--muted); padding: var(--s2) var(--s2) var(--s1); letter-spacing: .04em; }
.cs-search-it {
  display: flex; align-items: center; gap: var(--s2); width: 100%; text-align: start;
  background: none; border: 0; border-radius: var(--r-btn); padding: var(--s2) var(--s3);
  font: inherit; color: var(--ink); cursor: pointer; min-height: 44px;
}
.cs-search-it:hover, .cs-search-it:focus-visible { background: var(--accent-weak); }
.cs-search-it .t { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; unicode-bidi: plaintext; }
.cs-search-it .s { font-size: 12px; color: var(--muted); direction: ltr; unicode-bidi: isolate; }
.cs-search-none { font-size: 13px; color: var(--muted); padding: var(--s2) var(--s3); }
/* ------------------------------------------------------- the platform notice */
.cs-notice {
  margin: var(--s3) var(--s5) 0; padding: var(--s3) var(--s4); border-radius: var(--r-card);
  font-size: 14px; line-height: 1.8; unicode-bidi: plaintext;
  background: var(--accent-weak); color: var(--accent-press); border: 1px solid var(--line);
}
.cs-notice.warn { background: var(--warn-weak); color: var(--warn); border-color: var(--warn); }
.cs-notice.danger { background: var(--danger-weak); color: var(--danger); }
.cs-notice:empty { display: none; }
@media (max-width: 1023px) { .cs-notice { margin: var(--s3) var(--s4) 0; } .cs-search { min-width: 0; } }
