/* ==========================================================================
   GoldenBearing Design System — Base layer (GB-UI-01)
   ==========================================================================
   Scoping strategy (important — read before editing):

   AdminPortal has a single shared _Layout.cshtml used by every existing
   page (Identity, Organization, HR, Workflow, Recruitment...), all of which
   already have an established look via wwwroot/css/site.css. To let this
   design system become the "foundation for all FUTURE modules" without
   silently changing the appearance of every EXISTING page the moment this
   stylesheet is linked, every base/typography rule below (besides the
   @font-face declarations and a couple of universal, harmless resets) is
   scoped under a single opt-in wrapper class: `.gb-app`.

   A future module's top-level markup starts with:
       <div class="gb-app" dir="rtl" lang="fa"> ... </div>
   and everything inside it gets the full token-driven type/color/RTL
   foundation. Pages that do NOT add `.gb-app` are completely unaffected —
   same convention this codebase already established for `.rtl-page`
   (see site.css's own Stage 7.6 remarks), just generalized to the whole
   design system instead of RTL alone. `.rtl-page` keeps working unchanged
   for the existing Workflow pages that already use it.
   ========================================================================== */

/* ---- Self-hosted Persian typefaces (both SIL OFL) -----------------------

   Noto Sans Arabic is the UX-redesign typeface and the portal's primary
   family; Vazirmatn stays declared right below it as the immediate
   fallback, so a browser that cannot load the new face still gets a real
   Persian font rather than Tahoma.

   Two subsets, split exactly the way Google Fonts splits them, so a page
   only downloads the ~32 KB latin file until it actually paints Persian —
   `unicode-range` is what makes that lazy. Both are the VARIABLE face
   (weight axis 100–900), which is why the whole 400→900 ramp the design
   system asks for costs one file, not six. */

@font-face {
    font-family: "Noto Sans Arabic";
    src: url("/fonts/noto-sans-arabic/NotoSansArabic-Variable-arabic.woff2") format("woff2");
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1,
                   U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41,
                   U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}

@font-face {
    font-family: "Noto Sans Arabic";
    src: url("/fonts/noto-sans-arabic/NotoSansArabic-Variable-latin.woff2") format("woff2");
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                   U+02DC, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212,
                   U+2215, U+FEFF, U+FFFD;
}

/* ---- Vazirmatn — fallback family (SIL OFL, /fonts/vazirmatn/OFL.txt) ---- */

@font-face {
    font-family: "Vazirmatn";
    src: url("/fonts/vazirmatn/Vazirmatn-Variable.woff2") format("woff2-variations"),
         url("/fonts/vazirmatn/Vazirmatn-Variable.woff2") format("woff2");
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}

/* Static fallback for browsers without variable-font support. */
@font-face {
    font-family: "Vazirmatn";
    src: url("/fonts/vazirmatn/Vazirmatn-Regular.woff2") format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

/* ---- Universal, harmless resets (safe even outside .gb-app) ------------- */

.gb-app,
.gb-app *,
.gb-app *::before,
.gb-app *::after {
    box-sizing: border-box;
}

/* ---- .gb-app root ---------------------------------------------------------- */

.gb-app {
    font-family: var(--gb-font-family-base);
    font-size: var(--gb-font-size-md);
    line-height: var(--gb-line-height-normal);
    color: var(--gb-text-primary);
    background: var(--gb-background);
    font-feature-settings: "tnum" 1; /* tabular figures — Jalali/Gregorian dates line up in tables */
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

/* A `.gb-app` that is itself the page's full-bleed root (most common case). */
.gb-app--page {
    min-height: 100vh;
}

/* ---- Direction ---------------------------------------------------------------
   RTL-first: components are authored with logical properties (margin-inline,
   inset-inline-start, border-inline-start, ...) throughout components.css /
   rtl.css, so simply setting `dir="rtl"` on `.gb-app` (or reusing the legacy
   `.rtl-page`) is enough for every component to mirror correctly with no
   per-component LTR/RTL branching. `dir="ltr"` (or omitted — ltr is the
   attribute default) renders the same components mirrored back for English
   admin/ops use. */

.gb-app[dir="rtl"],
.gb-app.rtl-page {
    direction: rtl;
    text-align: right;
}

.gb-app[dir="ltr"] {
    direction: ltr;
    text-align: left;
}

/* ---- Base typography (headings/links/lists), scoped to .gb-app ------------ */

:where(.gb-app) :is(h1, h2, h3, h4, h5, h6) {
    margin: 0 0 var(--gb-space-3);
    font-weight: var(--gb-font-weight-semibold);
    line-height: var(--gb-line-height-tight);
    color: var(--gb-text-primary);
}

/* The two blocks above and below use `:where(.gb-app)` rather than `.gb-app`
   on purpose. As bare element selectors under one class they scored (0,1,1)
   and QUIETLY OUTRANKED every component title — `.gb-card__title` is (0,1,0)
   — so all 290 card headings in the ERP rendered at the ramp's size and weight
   instead of the 13.5px/700 the component specifies, which is what the
   approved design canvas draws. The comment below always claimed those
   components "still win"; measured in a browser, they did not. `:where()`
   zeroes the class contribution, leaving (0,0,1): still ahead of the UA
   default, now behind any component that states its own type. Fourth time
   this codebase has hit this specificity trap — see `.gb-app a` in this file
   and `.gb-field[hidden]` in components.css.

/* UX hardening pass — application scale, not document scale.
   These were 4xl/3xl/2xl/xl/lg/md (36/30/24/20/18/16px): a marketing-page
   ramp. Once `_ViewStart.cshtml` made the app shell the site default, every
   page began rendering inside `.gb-app`, and because a bare element selector
   under one class (0,1,1) outranks any single-class component selector, that
   ramp took over the whole ERP: a card heading rendered at 30px, larger than
   the design system's own specified 24px page title, and a dense operational
   screen ended up with three competing "big text" levels before any data.

   The ramp below is sized for an application: 24px page title / 20px section
   / 18px sub-section, with a real step between each. Nothing else changes —
   components that set their own size (`.gb-card__title`,
   `.gb-shell__page-title`, `.gb-modal__title`) still win, and every value
   still comes from a token. */
:where(.gb-app) h1 { font-size: var(--gb-font-size-2xl); }
:where(.gb-app) h2 { font-size: var(--gb-font-size-xl); }
:where(.gb-app) h3 { font-size: var(--gb-font-size-lg); }
:where(.gb-app) h4 { font-size: var(--gb-font-size-md); }
:where(.gb-app) h5 { font-size: var(--gb-font-size-sm); }
:where(.gb-app) h6 { font-size: var(--gb-font-size-sm); }

/* Same `:where()` reasoning as the heading ramp above: as `.gb-app p` this
   was (0,1,1) and beat every component paragraph that states its own margin,
   so a component could not close the gap under its own title. Components that
   state no margin still get the 12px below — that is the point of the rule —
   which is why the few that must sit tight now say `margin: 0` themselves. */
:where(.gb-app) p {
    margin: 0 0 var(--gb-space-3);
}

.gb-app a {
    color: var(--gb-text-link);
    text-decoration: underline;
    text-decoration-skip-ink: auto;
    text-underline-offset: 2px;
}

.gb-app a:hover {
    color: var(--gb-text-link-hover);
}

/* ---- Navigational / component anchors are not prose links ----------------
   UX hardening pass. The `.gb-app a` rule above is correct for a link inside
   a sentence: underlining is what makes it recognizable without relying on
   color alone (WCAG 1.4.1). But it is a bare element selector under one
   class, so its specificity (0,1,1) beats every single-class component
   selector (0,1,0) — including `.gb-btn`'s own `text-decoration: none`.
   The result was that the ERP underlined its entire chrome: the header logo,
   every sidebar menu item, dashboard tile links, table row actions and
   card-shaped links all rendered underlined, which reads as a page of raw
   hyperlinks rather than an application.

   The exceptions below are all elements whose "link-ness" is already carried
   by their shape (a button, a menu row, a card) — never by underline alone —
   so removing it costs no affordance. Underline returns on hover for the
   text-shaped ones. `.gb-btn--link` is deliberately absent: it is the one
   variant whose entire purpose is to look like a prose link.
   ------------------------------------------------------------------------ */

.gb-app :is(
    .gb-btn,
    .gb-card--link,
    .gb-shell__logo,
    .gb-shell__skip-link,
    .gb-public__brand,
    .gb-public__nav a,
    .gb-sidebar-menu__link,
    /* The record-page section index. Its entries are anchors so they work
       without script and can be opened in a new tab, but they read as a menu
       — underlining them turns a table of contents into a list of raw
       hyperlinks. Third component to hit this rule; see the note above. */
    .gb-recordnav__item,
    .gb-dropdown__item,
    .gb-tab,
    .tile__link,
    .breadcrumb a,
    .row-actions a,
    .data-table a,
    .pagination a,
    .button,
    /* UX Product Redesign patterns whose whole box is the link — an underline
       inside a card reads as noise, and the card's border and hover state
       already signal that it is clickable. */
    .gb-summary__item,
    .gb-oplist__name,
    .gb-trail__label a
):not(.gb-btn--link) {
    text-decoration: none;
}

.gb-app :is(.gb-oplist__name, .gb-trail__label a):hover {
    text-decoration: underline;
}

.gb-app :is(.tile__link, .breadcrumb a, .row-actions a, .data-table a, .gb-public__nav a):hover {
    text-decoration: underline;
}

/* ---- ...and the same specificity problem for COLOR -----------------------
   Found during live verification, in dark mode. `.gb-app a` above also sets
   `color`, and at (0,1,1) it outranks every button variant's own colour rule
   at (0,1,0). Because most call-to-action buttons in this ERP are anchors
   (`<a class="gb-btn gb-btn--primary">`), the link colour won:

     dark theme → --gb-text-link (#4F9CDB, blue) painted on
                  --gb-primary   (#F59E0B, golden orange)  ≈ 1.38:1

   i.e. every primary action on every module's list page was effectively
   unreadable in dark mode. In light mode the link colour happens to be a
   deep navy that still passes on orange, which is why it went unnoticed.

   A button gets its colour from its own variant, whether it is rendered as
   <a> or <button>. `.gb-btn--link` is excluded on purpose — it is meant to
   look like a link. `:where()` keeps this at zero specificity contribution
   so the variant rules themselves stay in control. */

/* `:where(:not(…))`, not a bare `:not(…)`. A bare :not() contributes the
   specificity of its argument, so this rule was (0,2,1) while the variant
   rules below are (0,1,1) — `color: inherit` therefore beat every one of them.
   In light mode the inherited body colour is near-black, which happens to read
   well on amber, so nothing looked wrong; in dark mode it inherited the
   near-white body colour and painted white text on the amber primary button at
   1.95:1. Wrapping the negation in :where() zeroes its contribution, leaving
   this at (0,1,1) — same as the variants, which come later and so win. */
.gb-app a:where(.gb-btn, .button):where(:not(.gb-btn--link, .button--link)) {
    color: inherit;
}

.gb-app a:where(.gb-btn--primary)   { color: var(--gb-on-primary); }
.gb-app a:where(.gb-btn--secondary) { color: var(--gb-text-primary); }
.gb-app a:where(.gb-btn--outline)   { color: var(--gb-text-primary); }
.gb-app a:where(.gb-btn--danger)    { color: var(--gb-on-danger); }
.gb-app a:where(.button--primary)   { color: var(--gb-on-primary); }
.gb-app a:where(.button--secondary) { color: var(--gb-text-primary); }
.gb-app a:where(.button--danger)    { color: var(--gb-on-danger); }

.gb-app a:where(.gb-btn--outline):hover { color: var(--gb-primary); }

/* The same (0,1,1) problem again, found the moment the sidebar moved onto
   the brand charcoal: `.gb-app a` painted every menu row --gb-text-link,
   which is the deep navy #123B5D. On white that read fine and nobody
   noticed; on charcoal it is navy on charcoal, about 1.6:1 — the whole
   navigation was effectively invisible. The menu row takes its colour from
   the sidebar it sits in, not from the link palette. Hover and the collapsed
   state stay with sidebar-menu.css, which loads later and outranks these. */
.gb-app a:where(.gb-sidebar-menu__link) { color: var(--gb-sidebar-text); }
.gb-app a:where(.gb-sidebar-menu__link--active) { color: var(--gb-sidebar-text-strong); }

.gb-app small,
.gb-text-sm {
    font-size: var(--gb-font-size-sm);
}

.gb-text-secondary {
    color: var(--gb-text-secondary);
}

.gb-text-tertiary {
    color: var(--gb-text-tertiary);
}

.gb-font-mono {
    font-family: var(--gb-font-family-mono);
    font-feature-settings: "tnum" 1;
}

/* .gb-code and .gb-qty were written for the shop floor and lived in
   traceability/shopfloor.css, which _AppShellLayout links only on
   /Traceability. Every other page that used them — the DocumentControl
   document list and detail, the HR import wizard, the dealer panel — got the
   class name and no rule at all: codes rendered in the body font, reordered
   by the RTL bidi algorithm, and quantity columns wandered. They are plain
   text utilities, so they belong here beside .gb-font-mono where every page
   can reach them. */

/* Codes are machine strings: always left-to-right, always monospaced, so two
   of them can be compared by eye without one shifting under the other. */
.gb-code {
    font-family: var(--gb-font-family-mono);
    font-variant-numeric: tabular-nums;
    direction: ltr;
    unicode-bidi: isolate;
    white-space: nowrap;
}

/* Quantities line up in columns. Without tabular figures a column of counts
   wanders, and comparing two rows stops being a glance. */
.gb-qty {
    font-variant-numeric: tabular-nums;
}

/* ---- Focus ring — WCAG 2.4.7 visible focus, every interactive .gb-* control */

.gb-app :is(button, a, input, select, textarea, [tabindex]):focus-visible,
.gb-btn:focus-visible,
.gb-input:focus-visible,
.gb-select:focus-visible {
    outline: none;
    box-shadow: var(--gb-shadow-focus);
}

/* ---- Selection color -------------------------------------------------------- */

.gb-app ::selection {
    background: var(--gb-primary-subtle);
    color: var(--gb-on-primary);
}

/* ---- Screen-reader-only utility -------------------------------------------- */

.gb-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ---- Motion respects user preference --------------------------------------- */

@media (prefers-reduced-motion: reduce) {
    .gb-app *,
    .gb-app *::before,
    .gb-app *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }
}
