/**
 * Neo brand tokens.
 *
 * Ported from the Claude Design project "NeoERP brand identity"
 * (133fd438-5ec8-4887-bcf3-c7eedd66dc4a), direction "Module — on light".
 *
 * Load AFTER app.css: the bridge block at the bottom redefines app.css's
 * :root values in Neo terms so ~2,600 lines of component CSS retheme without
 * being edited. See docs/plans/2026-07-29-neo-brand-ui-migration.md.
 */

/*
 * Fonts are loaded via <link rel="preconnect"> + <link rel="stylesheet"> in the
 * base layouts, not @import here: an @import inside a stylesheet is discovered
 * only after this file parses, serialising two round trips before any text can
 * paint. Any layout that loads this file must carry those <link> tags.
 */

:root {
  /* ---- base palette -------------------------------------------------- */
  --carbon: #0C0D10;
  --ink-2: #4A4C52;
  --fog: #6E7178;
  --mute: #85868B;
  --volt: #C7F000;
  --volt-press: #B8DE00;
  --bone: #F2F2EF;
  --surface: #F4F4F1;
  --card: #FFFFFF;
  --line: #E4E4E0;
  --line-strong: #C9CAC6;
  --dark-card: #1A1C21;
  --dark-line: #2A2D33;
  --ok: #1E9E6A;
  --alert: #D14343;

  /* ---- semantic ------------------------------------------------------ */
  --text-primary: var(--carbon);
  --text-secondary: var(--ink-2);
  --text-muted: var(--fog);
  --text-on-dark: var(--bone);
  --surface-app: var(--surface);
  --surface-card: var(--card);
  --surface-inverse: var(--carbon);
  --accent: var(--volt);
  --accent-ink: var(--carbon);
  --border-default: var(--line);
  --border-strong: var(--line-strong);
  --status-ok: var(--ok);
  --status-alert: var(--alert);
  --focus-ring: 0 0 0 2px var(--card), 0 0 0 4px var(--carbon);

  /* ---- type ---------------------------------------------------------- */
  --font-ui: 'Space Grotesk', system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, monospace;
  /* Space Grotesk has no Arabic coverage — sanctioned brand extension (D3). */
  --font-arabic: 'IBM Plex Sans Arabic', sans-serif;

  --text-display-size: 40px;   /* 700, tracking -1px */
  --text-h1-size: 24px;        /* 700 */
  --text-h2-size: 18px;        /* 700 */
  --text-ui-size: 15px;        /* 500, sentence case */
  --text-body-size: 14px;      /* 400, lh 1.55 */
  --text-caption-size: 12px;
  --text-mono-size: 13px;      /* all numbers, IDs, codes */
  --text-label-size: 10px;     /* mono, uppercase, tracking 1.5px */
  --leading-body: 1.55;
  --tracking-display: -1px;
  --tracking-label: 1.5px;

  /* ---- space & shape ------------------------------------------------- */
  --space-1: 4px;  --space-2: 8px;  --space-3: 12px; --space-4: 16px;
  --space-5: 20px; --space-6: 24px; --space-7: 32px; --space-8: 40px;
  --space-9: 48px; --space-10: 64px;

  --radius-sm: 4px;    /* chips */
  --radius-md: 6px;    /* buttons, inputs */
  --radius-lg: 10px;   /* cards */
  --radius-xl: 14px;   /* dialogs */
  --radius-tile: 22%;  /* app icon tiles */
  --radius-pill: 999px;

  /* Cards are flat. Only dialogs float. */
  --shadow-pop: 0 12px 32px rgba(12, 13, 16, 0.14);

  /* ---- app chrome accent --------------------------------------------- */
  /*
   * App chrome is Neo-branded for every tenant: one palette across
   * erp · pos · dlv · acc, products told apart by letter code, never colour.
   * Tenant identity lives on customer-facing artifacts instead — see the
   * --color-primary passthrough in the bridge below.
   */
  --brand-accent: var(--volt);
  --brand-accent-press: var(--volt-press);
  --brand-accent-ink: var(--carbon);

  /*
   * Accent as an INK is a different colour from accent as a SURFACE.
   * On light, volt is never text — it fails contrast outright (volt on white
   * is 1.32:1) — so accent text resolves to carbon. On dark the brand does use
   * volt as an ink, and the .dark block below flips this. Tailwind maps
   * textColor.primary here and backgroundColor.primary at --brand-accent, so
   * bg-primary-600 stays volt while text-primary-600 stays readable.
   */
  --brand-ink: var(--carbon);

  /*
   * Muted text that is safe on every brand surface.
   *
   * --mute (#85868B) is a 3.63:1 colour and --fog (#6E7178) only clears AA
   * against pure white — on --surface it is 4.44:1 and on --line 3.83:1, and
   * the app is 60% --surface. This is the lightest neutral that passes 4.5:1
   * on white, surface, bone and line alike, so secondary copy stays readable
   * wherever it lands. --mute and --fog keep their roles for micro-labels and
   * non-text use.
   */
  --text-muted-aa: #63666D;
}

/* ====================================================================== */
/* Dark ramp                                                              */
/*                                                                        */
/* The design system is light-first and ships no dark palette; this is a   */
/* documented brand extension (decision D1). Derived from carbon so it     */
/* stays in-family. On dark, volt MAY be an ink — the brand already does   */
/* this on the TopBar avatar and companion-app banners.                    */
/* ====================================================================== */
.dark {
  --text-primary: var(--bone);
  --text-secondary: #B4B6BB;
  --text-muted: #8A8D93;
  --surface-app: var(--carbon);
  --surface-card: var(--dark-card);
  --surface-inverse: var(--bone);
  --border-default: var(--dark-line);
  --border-strong: #3A3D44;
  --focus-ring: 0 0 0 2px var(--dark-card), 0 0 0 4px var(--bone);
  /* On carbon, volt is a legitimate ink — 14.71:1. */
  --brand-ink: var(--volt);
}

/* ====================================================================== */
/* Bridge — existing variable names, Neo values                           */
/*                                                                        */
/* app.css and the inline layout styles reference these names throughout.  */
/* Redefining them here rethemes that CSS with no edits to it.             */
/* ====================================================================== */
:root {
  /* Neutrals. One ramp serving light (50→300) and dark (700→950) usage. */
  --color-gray-50:  #F4F4F1;
  --color-gray-100: #F2F2EF;
  --color-gray-200: #E4E4E0;
  --color-gray-300: #C9CAC6;
  --color-gray-400: #85868B;
  --color-gray-500: #6E7178;
  --color-gray-600: #4A4C52;
  --color-gray-700: #2A2D33;
  --color-gray-800: #1A1C21;
  --color-gray-900: #0C0D10;
  --color-gray-950: #0C0D10;

  /* Status. Semantic green/red only — never decorative. */
  --color-success-50:  #E9F6F0;
  --color-success-100: #D2EDE1;
  --color-success-500: var(--ok);
  --color-success-600: #1A8A5D;
  --color-success-700: #16744E;
  --color-error-50:  #FBECEC;
  --color-error-100: #F7D9D9;
  --color-error-500: var(--alert);

  /*
   * Warning has no volt equivalent: volt is the accent, not a severity, and
   * the brand allows only semantic green/red for status. Warnings resolve to
   * alert red so nothing renders amber; per-case triage is a residue sweep.
   */
  --color-warning-50:  #FBECEC;
  --color-warning-100: #F7D9D9;
  --color-warning-500: var(--alert);
  --color-warning-600: #BC3A3A;

  /* Off-brand accents retired. Kept as aliases so nothing renders unstyled. */
  --color-amber: var(--volt);
  --color-amber-soft: #F0F7CC;
  --color-teal: var(--ok);
  --color-teal-soft: #D2EDE1;
  --color-rose: var(--alert);
  --color-rose-soft: #F7D9D9;
}

/* ====================================================================== */
/* Base                                                                   */
/* ====================================================================== */
body {
  font-family: var(--font-ui);
  color: var(--text-primary);
  background: var(--surface-app);
}

:lang(ar) body,
[dir='rtl'] body {
  font-family: var(--font-arabic);
}

/*
 * Focus: 2px carbon ring offset by 2px. :focus-visible only, so pointer users
 * don't get a ring on click while keyboard users always do.
 */
/*
 * !important because :where() is zero-specificity by design and every utility
 * class beats it. Without it the page decided its own focus: `focus:ring-2`
 * left a 2px ring inside this outline — one thick edge — while
 * `focus:outline-none` cancelled the outline and left only a ring. Three
 * different focus styles across the app. This is the one.
 */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--text-primary) !important;
  outline-offset: 2px !important;
  box-shadow: none !important;
}

/* Numbers, prices, dates, IDs, SKUs and codes are always mono. */
.neo-mono,
.tabular-nums {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* Mono micro-label: the one place ALL CAPS is allowed. */
.neo-label {
  font-family: var(--font-mono);
  font-size: var(--text-label-size);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--mute);
}

/* Cards are flat: white, 1px line, radius 10, no shadow. */
.neo-card {
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-lg);
}

/*
 * Volt is a surface, never an ink on light. Always carbon content on top.
 * On dark, volt as an ink is allowed — see the dark ramp above.
 */
.neo-chip {
  background: var(--volt);
  color: var(--carbon);
  font-family: var(--font-mono);
  font-size: 11px;
  padding: 1px 6px;
  border-radius: var(--radius-sm);
}

/* ====================================================================== */
/* Readable ink on light accent fills                                     */
/*                                                                        */
/* Templates pair a primary fill with text-white, which was right when    */
/* primary was indigo. Volt is a light colour: white on it is 1.32:1, so  */
/* those pairings became unreadable the moment the accent changed.        */
/*                                                                        */
/* The accent steps below are light whatever the tenant picks (they are   */
/* mixed toward white), and 500-700 are light whenever the tenant's own   */
/* colour is. --brand-accent-ink is computed per tenant, so a dark tenant */
/* colour still resolves to white here and nothing regresses for them.    */
/*                                                                        */
/* This is a net, not the fix: templates should say what they mean, and   */
/* the sweep replaces text-white with text-carbon at the call site. It    */
/* stays afterwards so a future text-white on a volt fill cannot ship an  */
/* unreadable button. Specificity 0,2,0 to beat .text-white at 0,1,0.     */
/* ====================================================================== */
[class~='bg-primary-50'].text-white,
[class~='bg-primary-100'].text-white,
[class~='bg-primary-200'].text-white,
[class~='bg-primary-300'].text-white,
[class~='bg-primary-400'].text-white,
[class~='bg-primary-500'].text-white,
[class~='bg-primary-600'].text-white,
[class~='bg-primary-700'].text-white,
[class~='bg-gray-50'].text-white,
[class~='bg-gray-100'].text-white,
[class~='bg-gray-200'].text-white,
[class~='bg-gray-300'].text-white,
[class~='bg-gray-400'].text-white,
[class~='bg-gray-500'].text-white,
[class~='bg-gray-600'].text-white,
[class~='bg-gray-700'].text-white,
[class~='bg-volt'].text-white,
[class~='bg-brand-primary'].text-white {
  color: var(--brand-accent-ink);
}

/* Boosted-nav keeps the text-gray-* an item rendered inactive with, so bone
   must outrank it on the carbon fill — dark selector beats the dark: variant. */
.bg-carbon.text-bone,
.dark .bg-carbon.text-bone {
  color: var(--bone);
}

/*
 * Green is not volt, and was briefly treated as though it were.
 *
 * #1E9E6A gives white 3.41:1 and carbon 5.66:1, so the higher ratio said paint
 * the ink black. It measured better and looked wrong — black text on a
 * saturated mid-green reads as a rendering fault, and the eye is right: a
 * green that dark a foreground needs is a green that should have been darker.
 *
 * The fill is fixed instead. green/emerald 500-700 resolve to #16744E, where
 * white clears AA at 5.57:1, so no ink override is needed here at all. Volt
 * keeps its override above because volt genuinely is a light fill.
 */

/* ====================================================================== */
/* Tables                                                                 */
/*                                                                        */
/* Numbers, prices, dates, IDs, SKUs and codes are always mono — the       */
/* brand's most recognisable habit, and tables are where an ERP shows      */
/* nearly all of them.                                                     */
/*                                                                        */
/* Reaching 526 hand-rolled tables by editing them is not realistic, but   */
/* they are strikingly consistent: 2,435 of ~2,500 headers already share   */
/* one class pattern. None of those utilities set font-family, so this     */
/* applies without fighting specificity, and the utilities keep owning     */
/* size, weight and colour.                                                */
/* ====================================================================== */
thead th {
  font-family: var(--font-mono);
  font-weight: 500;
  /*
   * The brand's micro-label metrics, as the default. Headers that already
   * carry text-xs / tracking-wider keep them — a utility outranks this — so
   * this only fills in the headers that specify nothing and would otherwise
   * inherit 14px body type.
   */
  font-size: var(--text-label-size);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
}

/*
 * Right-aligned cells in an ERP table are quantities, money and counts
 * essentially without exception, so they take mono with tabular figures —
 * which also makes columns of numbers line up on the decimal.
 *
 * A right-aligned cell that is genuinely text can opt out with .not-numeric.
 */
td.text-right:not(.not-numeric),
td[align='right']:not(.not-numeric) {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* Flat, hairline-separated rows — no zebra striping, no shadow. */
tbody tr {
  border-color: var(--border-default);
}

/* ====================================================================== */
/* Brand helper classes                                                   */
/*                                                                        */
/* Previously triplicated inline in three base layouts, alongside ~53     */
/* rules that re-declared Tailwind's own primary utilities with           */
/* !important. Those are gone: the Tailwind config maps primary at        */
/* --brand-accent (fills) and --brand-ink (text), so overriding it here   */
/* was both redundant and a specificity fight the utilities could not     */
/* win. Text and fill deliberately resolve to different tokens.           */
/* ====================================================================== */
.bg-brand-primary { background-color: var(--brand-accent); }
.bg-brand-primary-dark { background-color: var(--brand-accent-press); }
.bg-brand-primary-light { background-color: var(--color-primary-light); }
.bg-brand-secondary { background-color: var(--color-secondary); }
.bg-brand-accent { background-color: var(--color-accent); }

/* Accent as an ink, never the raw accent — see --brand-ink. */
.text-brand-primary { color: var(--brand-ink); }
.text-brand-primary-dark { color: var(--brand-ink); }
.text-brand-secondary { color: var(--color-secondary); }
.text-brand-accent { color: var(--brand-ink); }

.border-brand-primary { border-color: var(--brand-accent); }
.hover\:bg-brand-primary-dark:hover { background-color: var(--brand-accent-press); }
.focus\:ring-brand-primary:focus { --tw-ring-color: var(--brand-accent); }

/* Contents of a filled button take the ink computed for that fill, so a
   light brand colour gets carbon and a dark one gets white. */
.btn-brand-primary {
  background-color: var(--brand-accent);
  color: var(--brand-accent-ink);
  transition: background-color 140ms ease-out;
}
.btn-brand-primary:hover { background-color: var(--brand-accent-press); }
.btn-brand-secondary { background-color: var(--color-secondary); color: #ffffff; }
.btn-brand-accent { background-color: var(--color-accent); color: var(--brand-accent-ink); }

/* Motion: colour and border only, 120–160ms. No bounce, no parallax. */
.neo-transition {
  transition: background-color 140ms ease-out, border-color 140ms ease-out,
    color 140ms ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .neo-transition {
    transition: none;
  }
}

/* -----------------------------------------------------------------------
 * Breadcrumbs
 *
 * The trail is a block each page fills with its own markup — some pages use
 * chevrons, some use slashes, some use neither — so the container carries the
 * type rather than every call site. Mono at 11px, links in fog, the current
 * page in carbon, and the separator reduced to the line colour so the path
 * reads as one string instead of a row of arrows.
 * -------------------------------------------------------------------- */
.neo-crumbs {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 11px;
  line-height: 1.4;
}

/* A layout may offer crumbs that a page declines to fill; no empty row. */
.neo-crumbs:empty {
  display: none;
}

.neo-crumbs a {
  color: var(--text-muted-aa);
  text-decoration: none;
  transition: color 140ms ease-out;
}

.neo-crumbs a:hover {
  color: var(--carbon, #0C0D10);
}

.neo-crumbs > span:not([class*="text-"]),
.neo-crumbs span[aria-current="page"] {
  color: var(--carbon, #0C0D10);
}

/* Chevrons the pages supply: shrink them and drop them to the hairline. */
.neo-crumbs svg {
  width: 12px;
  height: 12px;
  color: var(--line-strong, #C9CAC6);
  flex-shrink: 0;
}

.dark .neo-crumbs a:hover,
.dark .neo-crumbs span[aria-current="page"] {
  color: var(--bone, #F2F2EF);
}

.dark .neo-crumbs svg {
  color: var(--dark-line, #2A2D33);
}
