:root {
  /* Single source of truth for the brand color — read by CSS below,
     and by JS (getComputedStyle) wherever a hex value is needed, e.g.
     Chart.js series colors. Keep in sync with the `brand` Tailwind
     palette declared in each page's tailwind.config. */
  --brand: #F2BF00;
  --brand-hover: #d9a800;
  --brand-active: #b38900;
  --brand-soft: #fff3c4;
  /* Gold fails contrast with white text (~1.9:1), so brand surfaces
     use dark text instead — this is what .btn-primary etc use below. */
  --brand-contrast: #1e293b;
}

/* ---------------------------------------------------------------------
   Global loading system — one shared visual language for every kind
   of "please wait": full navigations, every api() call (CRUD, Excel
   import/export, dashboard, live polling), and first-paint boot.
   --------------------------------------------------------------------- */

/* Slim top progress bar — driven by app.js's showProgress()/doneProgress(),
   wired into the api() wrapper so every async action gets it automatically. */
#tc-progress-bar {
  position: fixed; top: 0; left: 0; height: 3px; width: 0%;
  background: var(--brand); z-index: 9999; pointer-events: none;
  transition: width 0.25s ease-out, opacity 0.25s ease-out;
  box-shadow: 0 0 8px 0 var(--brand);
  opacity: 0;
}
#tc-progress-bar.tc-progress-active { opacity: 1; }
#tc-progress-bar.tc-progress-done { width: 100% !important; opacity: 0; transition: width 0.2s ease-out, opacity 0.4s ease-out 0.15s; }

/* Full-page boot overlay — inline in every page shell (before the
   Tailwind CDN / app.css finish loading) so there is always something
   on screen instead of a blank white flash between navigations. Its
   own colors are hardcoded (not Tailwind classes) since it must
   render correctly even if the stylesheet hasn't applied yet. */
#tc-boot-loader {
  position: fixed; inset: 0; z-index: 10000;
  display: flex; align-items: center; justify-content: center;
  background: #f8fafc;
  transition: opacity 0.25s ease-out;
}
html.dark #tc-boot-loader { background: #0f172a; }
#tc-boot-loader.tc-boot-hidden { opacity: 0; pointer-events: none; }
.tc-boot-spinner {
  width: 34px; height: 34px; border-radius: 9999px;
  border: 3px solid rgba(242, 191, 0, 0.25);
  border-top-color: #F2BF00;
  animation: tc-spin 0.7s linear infinite;
}
@keyframes tc-spin { to { transform: rotate(360deg); } }

/* Small inline spinner for buttons / inline async actions. */
.tc-spinner {
  display: inline-block; width: 1em; height: 1em; vertical-align: -0.15em;
  border-radius: 9999px; border: 2px solid currentColor; border-right-color: transparent;
  animation: tc-spin 0.6s linear infinite; opacity: 0.85;
}

/* Full-panel overlay spinner for a specific container mid-fetch
   (dashboard charts, long-running Excel import, etc). Container needs
   position:relative for this to overlay correctly. */
.tc-loading-overlay {
  position: absolute; inset: 0; z-index: 20;
  display: flex; align-items: center; justify-content: center;
  background: rgba(248, 250, 252, 0.7);
  backdrop-filter: blur(1px);
  border-radius: inherit;
}
.dark .tc-loading-overlay { background: rgba(15, 23, 42, 0.7); }

/* Skeleton placeholders — shown in place of list/grid content on a
   page's first load, before any data has arrived. Brand-tinted
   shimmer so it reads as "this app" rather than a generic gray box. */
.tc-skeleton {
  position: relative; overflow: hidden;
  background: #e2e8f0; border-radius: 0.5rem;
}
.dark .tc-skeleton { background: #334155; }
.tc-skeleton::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(242, 191, 0, 0.25), transparent);
  animation: tc-shimmer 1.4s ease-in-out infinite;
}
@keyframes tc-shimmer {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}
.tc-skeleton-card { height: 6.5rem; }
.tc-skeleton-line { height: 0.75rem; margin-bottom: 0.5rem; }

/* Catches browser-default blue UI that isn't controlled by Tailwind
   utility classes: checkbox/radio accent color, text selection
   highlight, and the keyboard focus ring. */
input[type="checkbox"], input[type="radio"], input[type="range"] { accent-color: var(--brand); }
::selection { background: var(--brand); color: var(--brand-contrast); }
:focus-visible { outline-color: var(--brand); }

/* ---------------------------------------------------------------------
   PERSIAN TYPOGRAPHY — single source of truth.

   .tc-fa / .tc-fa-input are the ONLY rules in this codebase allowed
   to set a Persian-specific font-family. They are applied by exactly
   one piece of code: the global typography engine at the bottom of
   assets/js/jalali.js, which watches the whole document via
   MutationObserver and marks every run of Persian/Arabic text it
   finds — automatically, for any current or future component, with
   no per-page or per-component opt-in. See that file for the full
   explanation.

   The html/body rule below is a passive backstop, not a second
   decision: because the @font-face is scoped with `unicode-range` to
   Persian/Arabic code points only, setting it at the root simply
   means any Persian character that somehow isn't inside a `.tc-fa`
   wrapper (e.g. text rendered before the engine's first pass runs)
   still gets the right glyph immediately, while Latin text is
   completely unaffected either way. Remove it and nothing breaks
   except that very first flash; it exists purely to avoid that.
   --------------------------------------------------------------- */
.tc-fa, .tc-fa-input {
  font-family: var(--persian-font, inherit);
}
html, body { font-family: var(--persian-font, inherit); }

/* Jalali dates additionally get bidi isolation so a date embedded in
   surrounding English/LTR text (e.g. "Created: <date> · By John")
   always renders in the correct visual order. */
.jalali-date {
  unicode-bidi: isolate;
  direction: rtl;
  white-space: nowrap;
}

/* Split-circle theme toggle — half dark / half light disc that flips
   180° with a smooth animation on click. Used identically on the
   login page and the main app header.
   Built as inline SVG (not a CSS gradient circle) with an explicit
   brand-gold stroke outline that is always drawn regardless of
   surrounding background — a flat CSS gradient circle's light half
   could end up nearly the same color as a light-mode background (and
   its dark half the same as a dark-mode background), making the
   control look like it had disappeared depending on theme. */
.theme-toggle-btn {
  width: 1.875rem; height: 1.875rem; border-radius: 9999px;
  display: flex; align-items: center; justify-content: center;
  border: none; background: transparent; cursor: pointer;
  transition: background-color 0.15s ease-in-out;
}
.theme-toggle-btn:hover { background-color: rgba(148, 163, 184, 0.12); }
.theme-toggle-icon {
  width: 1rem; height: 1rem;
  transition: transform 0.45s cubic-bezier(0.65, 0, 0.35, 1);
  transform: rotate(0deg);
}
html.dark .theme-toggle-icon { transform: rotate(180deg); }
.theme-toggle-btn:hover .theme-toggle-icon circle { stroke: #d9a800; }

/* Dashboard stat numbers: brief brand-colored pulse exactly on the
   value that changed during a live refresh — signals "this updated"
   without rebuilding or flashing the whole card. */
@keyframes tc-value-pulse {
  0% { text-shadow: 0 0 0 rgba(242, 191, 0, 0); }
  30% { text-shadow: 0 0 12px rgba(242, 191, 0, 0.8); }
  100% { text-shadow: 0 0 0 rgba(242, 191, 0, 0); }
}
.tc-value-pulse { animation: tc-value-pulse 0.6s ease-out; }

@keyframes fade-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } }
.animate-fade-in { animation: fade-in 0.2s ease-out; }

/* Smooth theme switching — every themeable surface transitions its
   colors instead of flipping instantly. Deliberately scoped to color
   properties only (not "all") so layout-affecting properties like
   width/height/transform never get an unwanted transition. */
body, header, aside, main,
.bg-white, .bg-slate-50, .bg-slate-100, .bg-slate-800, .bg-slate-900, .bg-slate-950,
[class*="bg-slate-"], [class*="text-slate-"], [class*="border-slate-"],
button, input, select, textarea, .badge, table, tr, td, th {
  transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
}

/* Page transitions between full navigations. This app deliberately
   stays multi-page (no SPA rewrite), so "no full reload" animation
   means: fade the outgoing page out just before the browser navigates,
   and fade the incoming page's content in on load — a lightweight
   illusion of continuity without changing the request/response model. */
.page-enter {
  animation: page-fade-in 0.22s ease-out;
}
@keyframes page-fade-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}
.page-leaving {
  opacity: 0 !important;
  transform: translateY(-4px);
  transition: opacity 0.15s ease-in, transform 0.15s ease-in;
}

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(100, 116, 139, 0.35); border-radius: 9999px; }

.line-clamp-3 {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.line-clamp-1 {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

textarea, input, select { color-scheme: light; }
.dark textarea, .dark input, .dark select { color-scheme: dark; }

.modal-backdrop {
  background: rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(2px);
}

/* Shared component classes — written as plain CSS because the Tailwind
   Play CDN (loaded via <script src="...cdn.tailwindcss.com">) only scans
   class names already present in the DOM; it does not process @apply
   inside custom <style> blocks. */
.btn-primary {
  border-radius: 0.375rem; background-color: var(--brand); color: var(--brand-contrast);
  font-size: 0.875rem; font-weight: 600; padding: 0.5rem 1rem;
  transition: background-color 0.15s ease-in-out; border: none; cursor: pointer;
}
.btn-primary:hover { background-color: var(--brand-hover); }
.btn-primary:disabled { opacity: 0.5; cursor: not-allowed; }

.btn-outline {
  border-radius: 0.375rem; border: 1px solid #cbd5e1; font-size: 0.875rem;
  font-weight: 500; padding: 0.5rem 1rem; background: transparent;
  transition: background-color 0.15s ease-in-out; cursor: pointer;
}
.btn-outline:hover { background-color: #f1f5f9; }
.dark .btn-outline { border-color: #475569; }
.dark .btn-outline:hover { background-color: #334155; }

.input-text, .input-select {
  width: 100%; border-radius: 0.375rem; border: 1px solid #cbd5e1;
  background-color: #fff; padding: 0.5rem 0.75rem; font-size: 0.875rem;
}
.input-text:focus, .input-select:focus {
  outline: none; box-shadow: 0 0 0 2px var(--brand);
}
.dark .input-text, .dark .input-select { border-color: #475569; background-color: #1e293b; color: #f1f5f9; }

.badge {
  display: inline-flex; align-items: center; border-radius: 9999px;
  padding: 0.125rem 0.625rem; font-size: 0.75rem; font-weight: 600;
}
.badge-secondary { background-color: #f1f5f9; color: #334155; }
.dark .badge-secondary { background-color: #334155; color: #e2e8f0; }
.badge-success { background-color: rgba(16,185,129,0.15); color: #059669; }
.dark .badge-success { color: #34d399; }
.badge-warning { background-color: rgba(245,158,11,0.15); color: #d97706; }
.dark .badge-warning { color: #fbbf24; }
.badge-destructive { background-color: rgba(239,68,68,0.15); color: #dc2626; }
.dark .badge-destructive { color: #f87171; }
