:root {
  /* Colors */
  --color-absolute-black: #171618;
  --color-paper-white: #ffffff;
  --color-graphite: #727578;
  --color-light-gray: #f7f7f7;
  --color-silver-mist: #efefef;
  --color-slate-border: #dadada;
  --color-primary: #e42426;
  --color-primary-light: #fce8e8;
  --color-primary-dark: #c01a1c;
  --color-agent-blue: #004d60;
  --color-insight-amber: #6c4800;
  --color-pale-lilac: #f5f0ff;
  --color-cloud-blue: #defafe;
  --color-mellow-apricot: #fff6e1;
  --color-soft-lavender: #e7e0fe;
  --color-sky-tint: #cfeff8;
  --color-sun-mist: #feedcc;

  /* Typography — Font Families */
  --font-inter: 'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-eudoxus-sans: 'Eudoxus Sans', ui-sans-serif, system-ui, -apple-system, sans-serif;

  /* Typography — Scale */
  --text-heading: 21px;
  --leading-heading: 1.4;
  --tracking-heading: -0.63px;
  --text-heading-lg: 23px;
  --leading-heading-lg: 1.2;
  --tracking-heading-lg: -0.67px;
  --text-display: 48px;
  --leading-display: 1.05;
  --tracking-display: -1.39px;

  /* Spacing */
  --spacing-12: 12px;
  --spacing-16: 16px;
  --spacing-24: 24px;
  --spacing-32: 32px;
  --spacing-64: 64px;

  /* Border Radius */
  --radius-cards: 20px;
  --radius-badges: 100px;
  --radius-inputs: 8px;
  --radius-buttons: 10px;

  /* Shadows */
  --shadow-md: rgba(239, 239, 239, 0.55) 0px 2px 15px 0px;
  --shadow-subtle: rgba(0, 0, 0, 0.08) 0px 1px 2px 0px, rgba(0, 0, 0, 0.12) 0px 0.5px 0px 0px;
  /* Both of these are named in design.md and were missing here, which is why `.modal` below resolved
     to no shadow at all instead of the elevation the reference asks for. */
  --shadow-subtle-2: rgba(23, 24, 26, 0.1) 0px 0px 0px 1px, rgba(23, 24, 26, 0.03) 0px 8px 16px 0px;
  --shadow-subtle-3: rgba(23, 24, 26, 0.1) 0px 0px 0px 1px, rgba(23, 24, 26, 0.03) 0px 16px 16px 0px, rgba(23, 24, 26, 0.05) 0px 6px 12px 0px;

  /* Palette, completed — design.md names colours the implementation had left out. They arrive with the
     reference's own names and values, so the palette and its document finally agree. The three
     `illustrative` ones are for artwork and never for UI: the reference reserves vivid colour for
     illustrations and keeps the interface on the muted accents above. */
  --color-feedback-violet: #38296c;
  --color-illustrative-yellow: #ffbd00;
  --color-illustrative-violet: #6386fe;
  --color-illustrative-pink: #fd8fe9;

  /* State and surface roles — colours the screens already wear, given one name each.
     The reference describes states in prose ("a warning", the danger zone) without ever naming a value
     for them, so every screen chose its own: sixteen stylesheets had grown 124 colours outside the
     palette, most of them Tailwind's defaults wearing this product's name. The values below are the ones
     the screens already carry, promoted rather than changed — naming a colour is a refactor, and a
     screen reading `--danger-surface` instead of `#fef2f2` looks exactly the same. A screen that needs a
     shade these roles do not cover adds a role here; it does not write a hex of its own. */
  /* Text */
  --text-strong: #1e293b;
  --text-body: #334155;
  --text-subtle: #475569;
  --text-muted: #64748b;
  --text-faint: #94a3b8;
  --ink-deep: #1f2430;                                 /* the payments and activity sheets' darkest grey */
  /* Surfaces */
  --surface-plain: #fafafa;
  --surface-raised: #f8fafc;
  --surface-muted: #f1f5f9;
  --surface-subtle: #eef1f4;
  --surface-sunken: #f7f8fa;
  /* Borders */
  --border-subtle: #e2e8f0;
  --border-soft: #d7dde5;
  --border-strong: #cbd5e1;
  /* Danger */
  --danger-surface: #fef2f2;
  --danger-surface-strong: #fee2e2;
  --danger-border: #fecaca;
  --danger-outline: #fca5a5;
  --danger-fg: #b91c1c;
  --danger-fg-strong: #991b1b;
  --danger-deep: #7f1d1d;
  --danger-solid: #dc2626;
  /* Warning */
  --warning-surface: #fffbeb;
  --warning-surface-strong: #fef3c7;
  --warning-surface-deep: #eccf9a;
  --warning-border: #fde68a;
  --warning-chip: #fcd34d;
  --warning-fg: #92400e;
  --warning-fg-soft: #b45309;
  --warning-fg-deep: #9a3412;
  --warning-solid: #f59e0b;
  --warning-solid-deep: #d97706;
  /* Success */
  --success-surface: #d1fae5;
  --success-surface-soft: #f4fbf6;
  --success-border: #bfe3c9;
  --success-fg: #1c6b38;
  --success-fg-strong: #15803d;
  --success-solid: #059669;
  /* Info */
  --info-surface: #e0f2fe;
  --info-fg: #075985;
  --info-solid: #1d4ed8;
  /* Violet and indigo — the permission matrix and the activity calendar */
  --violet-fg: #4c1d95;
  --indigo-surface: #e0e7ff;
  --indigo-border: #c7d2fe;
  --indigo-fg: #3730a3;

  /* Motion — one rhythm for every panel on the platform.
     A transition says what changes; these say how long it takes and in what shape. They live
     here, with the palette and the spacing scale, because the sidebar, the phone drawer, a
     toast and a card lift all draw from the same set of numbers rather than each carrying its
     own — which is how a drawer came to slide for 0.28s while the scrim in front of it faded
     for 0.25s and the two never landed together.

     The scale is deliberately short, and picking the nearest step is the point: a hover fill
     that answers instantly is `--motion-fast`, anything that opens or moves is `--motion-base`.
     Every page loads this file, so a sheet may read a token without a fallback.

     What is *not* here is shape: an endless spinner, a shimmer, a pulse, a one-shot flourish.
     Those are decoration whose whole effect is their own timing, so they keep their own. */
  --motion-fast: 0.15s;                                 /* a fill under the cursor */
  --motion-control: 0.2s;                               /* a control changing state */
  --motion-base: 0.24s;                                 /* the default: opens, closes, slides, fades */
  --motion-slow: 0.4s;                                  /* a larger surface arriving, or a flourish */
  --motion-spin: 0.9s;                                  /* one turn of a loading spinner */
  --motion-ease: ease;                                  /* the default curve */
  --motion-ease-surface: cubic-bezier(0.4, 0, 0.2, 1);  /* the smoother one, for larger surfaces */

  /* Focus — the one focus ring on the platform.
     A ring is not decoration: it is the only thing telling someone who tabs through a screen where
     they are, and `outline` is the only indicator that costs no layout. The geometry lives here so
     that a screen which draws its own ring still agrees with this one about its thickness and how
     far it stands off the control — the sidebar keeps its own accent colour, because "you are here"
     is already that colour in the menu (see sidebar.css), but nothing else about the ring differs.

     The ring is never switched off. What keeps it out of a mouse user's way is `:focus-visible`,
     which only matches when the keyboard did the pointing — a field that takes typing is the one
     exception and keeps its ring on click, which is exactly what an `outline: none` had hidden. */
  --focus-ring-width: 2px;
  --focus-ring-offset: 2px;
  --focus-ring-color: var(--color-primary);
}

body {
  font-family: var(--font-inter);
  background-color: var(--color-paper-white);
  color: var(--color-absolute-black);
  margin: 0;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
}

/* Focus ---------------------------------------------------------------------
   The platform's one focus ring, built from the tokens above. It lives in the file every page
   loads so that no screen has to remember to draw one, and the screens are the reason it is a
   rule rather than a class: a stylesheet that writes `outline: none` to keep the browser's
   default off a styled control removes the ring for keyboard users too, and six of them had
   done exactly that to their search boxes and selects.

   A sheet with a treatment of its own still wins, because `.something:focus-visible` is more
   specific than this — but a sheet with nothing to say now gets the ring for free. */
:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}

h1,
h2,
h3,
h4,
.display-text {
  font-family: var(--font-eudoxus-sans);
  font-weight: 700;
  letter-spacing: var(--tracking-heading);
  margin-top: 0;
}

.container {
  margin: var(--spacing-32) auto;
  padding: var(--spacing-24);
  width: 100%;
  box-sizing: border-box;
}

/* Cards */
.card {
  background: var(--color-paper-white);
  border-radius: var(--radius-cards);
  padding: 24px;
  box-shadow: var(--shadow-md);
  border: 1px solid var(--color-silver-mist);
  transition: transform var(--motion-base) var(--motion-ease-surface);
}

.card:hover {
  transform: translateY(-2px);
}

/* Buttons */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 12px 20px;
  border-radius: var(--radius-buttons);
  font-family: var(--font-inter);
  font-weight: 500;
  font-size: 15px;
  cursor: pointer;
  transition: all var(--motion-control) var(--motion-ease);
  border: 1px solid transparent;
  gap: 8px;
}

.btn-primary {
  background: var(--color-primary);
  color: var(--color-paper-white);
}

.btn-primary:hover {
  background: var(--color-primary-dark);
  box-shadow: var(--shadow-subtle);
}

.btn-outline {
  background: var(--color-paper-white);
  border-color: rgba(25, 23, 23, 0.16);
  color: var(--color-absolute-black);
}

.btn-outline:hover {
  background: var(--color-light-gray);
}

.btn-ghost {
  background: transparent;
  color: var(--color-graphite);
  padding: 8px 16px;
}

.btn-ghost:hover {
  background: var(--color-light-gray);
  color: var(--color-absolute-black);
}

.btn-danger {
  background: var(--danger-surface-strong);
  color: var(--danger-fg-strong);
  border: 1px solid var(--danger-border);
}

.btn-danger:hover {
  background: var(--danger-border);
}

/* Inputs */
.input-field {
  width: 100%;
  padding: 8px 16px;
  border: 1px solid var(--color-slate-border);
  border-radius: var(--radius-inputs);
  font-family: var(--font-inter);
  font-size: 15px;
  color: var(--color-absolute-black);
  box-sizing: border-box;
  transition: border-color var(--motion-control) var(--motion-ease);
}

.input-field:focus {
  border-color: var(--color-primary);
  background: var(--color-paper-white);
}

/* Badges */
.badge {
  display: inline-flex;
  padding: 4px 12px;
  border-radius: var(--radius-badges);
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.badge-violet {
  background: var(--color-primary-light);
  color: var(--color-primary);
}

.badge-blue {
  background: var(--color-sky-tint);
  color: var(--color-agent-blue);
  text-align: center;
}

.badge-amber {
  background: var(--color-sun-mist);
  color: var(--color-insight-amber);
}

/* Tables */
.data-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  margin-top: var(--spacing-16);
}

.data-table th {
  padding: 16px;
  text-align: left;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  /* The header carries its own tint, and a tinted surface is where `--color-graphite` stops
     clearing AA: measured on `--color-light-gray` it is 4.33:1, under the 4.5 that 13px asks for,
     while the text role it takes instead is 6.9:1. */
  color: var(--text-subtle);
  border-bottom: 1px solid var(--color-silver-mist);
  background: var(--color-light-gray);
}

.data-table th:first-child {
  border-top-left-radius: 12px;
}

.data-table th:last-child {
  border-top-right-radius: 12px;
}

.data-table td {
  padding: 16px;
  border-bottom: 1px solid var(--color-silver-mist);
  font-size: 15px;
}

.data-table tr:last-child td:first-child {
  border-bottom-left-radius: 12px;
}

.data-table tr:last-child td:last-child {
  border-bottom-right-radius: 12px;
}

.data-table tr:hover td {
  background-color: var(--surface-plain);
}

/* Modal Overlay */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(23, 22, 24, 0.4);
  backdrop-filter: blur(4px);
  display: none;
  align-items: center;
  justify-content: center;
  /* Above the top bar (1200) and the sidebar (1250): a dialog has to cover the
     whole window, including the fixed chrome. */
  z-index: 1400;
}

.modal {
  background: var(--color-paper-white);
  padding: 32px;
  border-radius: var(--radius-cards);
  box-shadow: var(--shadow-subtle-2);
  width: 90%;
  max-width: 480px;
}

/* Nav */
.header-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: var(--spacing-32);
  padding-bottom: var(--spacing-16);
  border-bottom: 1px solid var(--color-silver-mist);
}

.header-bar h2 {
  font-size: var(--text-heading-lg);
  margin-bottom: 0;
}

/* Auth Page */
.auth-page {
  background-color: var(--color-light-gray);
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.login-card {
  background: var(--color-paper-white);
  padding: 48px;
  border-radius: var(--radius-cards);
  box-shadow: var(--shadow-md);
  width: 100%;
  max-width: 400px;
  text-align: center;
}

@keyframes spin {
  from {
    transform: rotate(0deg);
  }

  to {
    transform: rotate(360deg);
  }
}

/* Loading state. A region marked `.loading-region` holds a `.loading-veil` child of its own, and it
   shows that veil for as long as some script keeps `is-loading` on the region (`/shared/js/loading.js`
   is the one that does). The veil veils rather than replaces: a redraw that arrives over last
   period's figures must not blank them first, and nothing on the page moves when it appears. */
.loading-region {
  position: relative;
}

/* The mark sits at the region's top right rather than in the middle of it: a region can be taller than
   the window (the trade half is four cards and four charts), and a mark centred in one of those is a
   mark nobody sees. The corner is where the eye already is when the figures change. */
.loading-veil {
  position: absolute;
  inset: 0;
  display: none;
  align-items: flex-start;
  justify-content: flex-end;
  gap: 10px;
  padding: 14px 18px;
  background: rgba(255, 255, 255, 0.72);
  z-index: 5;
  font-size: 0.9rem;
  color: var(--color-graphite);
  font-weight: 600;
}

.loading-region.is-loading>.loading-veil {
  display: flex;
}

/* The ring is drawn here rather than borrowed from the icon set: the worker caches this stylesheet but
   not the icon library's CDN, so a screen with no signal would lose a borrowed spinner exactly when the
   slow read it is waiting on is most likely. */
.loading-ring {
  width: 20px;
  height: 20px;
  border: 3px solid var(--color-silver-mist);
  border-top-color: var(--color-primary);
  border-radius: 50%;
  animation: spin var(--motion-spin) linear infinite;
}

/* Responsive Table */
.table-responsive {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* Responsive Overrides */
@media (max-width: 768px) {
  .header-bar {
    flex-direction: column;
    align-items: flex-start;
    gap: 16px;
  }

  .container {
    padding: 16px;
    margin: 16px auto;
  }

  .card {
    padding: 16px;
  }

  /* Keep specific elements flex if needed */
  .header-bar>div:last-child {
    width: 100%;
  }

  .header-bar button {
    justify-content: center;
  }
}

/* ─── PWA UI Components ──────────────────────────────────────────────────────── */

/* Offline Banner */
.pwa-offline-banner {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 10px 20px;
  background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
  color: #f0f0f0;
  font-size: 0.85rem;
  font-family: var(--font-inter);
  transform: translateY(-100%);
  transition: transform var(--motion-slow) var(--motion-ease-surface);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
}

.pwa-offline-banner.visible {
  transform: translateY(0);
}

.pwa-offline-banner svg {
  flex-shrink: 0;
  color: #f87171;
}

.pwa-offline-banner strong {
  color: var(--danger-outline);
}

/*
 * What the account may not use is hidden rather than left to fail. `!important` because the
 * elements it is applied to (buttons, links, menu entries) carry a `display` of their own.
 */
.perm-hidden {
  display: none !important;
}

/*
 * The `hidden` attribute is how the app conceals things — a save bar, an empty state, a search
 * suggestion list. It must win over the layout rules those elements carry, because any explicit
 * `display` (`.btn` is inline-flex, panels are flex or grid) outranks the browser's own
 * `[hidden] { display: none }`, and the element then stays on screen with a `hidden` attribute
 * that only the code can see.
 */
[hidden] {
  display: none !important;
}

/* Toast Notifications */
.pwa-toast {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%) translateY(20px);
  opacity: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 20px;
  border-radius: 12px;
  font-size: 0.875rem;
  font-family: var(--font-inter);
  font-weight: 500;
  white-space: nowrap;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2), 0 2px 8px rgba(0, 0, 0, 0.1);
  transition: all var(--motion-slow) var(--motion-ease-surface);
  backdrop-filter: blur(10px);
  max-width: calc(100vw - 48px);
  white-space: normal;
  text-align: center;
}

.pwa-toast.visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

.pwa-toast.success {
  background: rgba(16, 185, 129, 0.95);
  color: var(--color-paper-white);
}

.pwa-toast.error {
  background: rgba(239, 68, 68, 0.95);
  color: var(--color-paper-white);
}

.pwa-toast.info {
  background: rgba(30, 58, 138, 0.95);
  color: var(--color-paper-white);
}

.pwa-toast.update {
  background: rgba(124, 58, 237, 0.95);
  color: var(--color-paper-white);
  bottom: 80px;
}

.pwa-toast svg {
  flex-shrink: 0;
}

.pwa-toast-action {
  margin-left: 8px;
  padding: 4px 12px;
  border: 1.5px solid rgba(255, 255, 255, 0.6);
  background: transparent;
  color: var(--color-paper-white);
  border-radius: 6px;
  font-size: 0.8rem;
  font-weight: 600;
  cursor: pointer;
  font-family: var(--font-inter);
  transition: background var(--motion-control) var(--motion-ease);
  white-space: nowrap;
}

.pwa-toast-action:hover {
  background: rgba(255, 255, 255, 0.15);
}

/* Sync Badge */
.pwa-sync-badge {
  position: fixed;
  bottom: 24px;
  right: 24px;
  z-index: 9998;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  background: var(--color-primary);
  color: var(--color-paper-white);
  border-radius: 50px;
  font-size: 0.8rem;
  font-weight: 600;
  font-family: var(--font-inter);
  cursor: pointer;
  box-shadow: 0 4px 16px rgba(228, 36, 38, 0.4);
  transition: all var(--motion-control) var(--motion-ease-surface);
  animation: pwa-pulse 2s infinite;
}

.pwa-sync-badge:hover {
  transform: scale(1.05);
  box-shadow: 0 6px 20px rgba(228, 36, 38, 0.5);
}

@keyframes pwa-pulse {

  0%,
  100% {
    box-shadow: 0 4px 16px rgba(228, 36, 38, 0.4);
  }

  50% {
    box-shadow: 0 4px 24px rgba(228, 36, 38, 0.7);
  }
}

/* "Showing cached data" chip. The sync badge owns the bottom right and the offline
   banner the top, so this one sits bottom left where nothing else competes. */
.pwa-cache-chip {
  position: fixed;
  bottom: 24px;
  left: 24px;
  z-index: 9996;
  display: flex;
  align-items: center;
  padding: 8px 14px;
  background: var(--text-strong);
  color: var(--color-paper-white);
  border: none;
  border-radius: 50px;
  font-size: 0.8rem;
  font-weight: 600;
  font-family: var(--font-inter);
  cursor: pointer;
  box-shadow: 0 4px 16px rgba(15, 23, 42, 0.35);
  opacity: 0;
  transform: translateY(12px);
  transition: all var(--motion-base) var(--motion-ease-surface);
}

.pwa-cache-chip.visible {
  opacity: 1;
  transform: translateY(0);
}

.pwa-cache-chip:hover {
  background: #111827;
}

/* Install Button */
.pwa-install-btn {
  position: fixed;
  bottom: 20px;
  right: 45%;
  z-index: 9997;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 18px;
  background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-primary-dark) 100%);
  color: var(--color-paper-white);
  border: none;
  border-radius: 50px;
  font-size: 0.875rem;
  font-weight: 600;
  font-family: var(--font-inter);
  cursor: pointer;
  box-shadow: 0 6px 24px rgba(228, 36, 38, 0.35);
  opacity: 0;
  transform: translateY(20px);
  transition: all var(--motion-slow) var(--motion-ease-surface);
}

.pwa-install-btn.visible {
  opacity: 1;
  transform: translateY(0);
}

.pwa-install-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 30px rgba(228, 36, 38, 0.45);
}

@media (max-width: 768px) {
  .pwa-toast {
    bottom: 16px;
    padding: 10px 16px;
  }

  .pwa-sync-badge {
    bottom: 16px;
    right: 16px;
  }

  /* Leave room for the sync badge on the right rather than overlapping it, and
     shorten to one line instead of wrapping into a tall block. */
  .pwa-cache-chip {
    bottom: 16px;
    left: 16px;
    max-width: calc(100vw - 130px);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    display: block;
  }

  .pwa-install-btn {
    bottom: 70px;
    right: 16px;
  }
}

/* ─── App feedback toast ───────────────────────────────────────────────────── */
/*
 * The transient messages the invoice, profile and admin screens show. They live here
 * rather than in each screen's own stylesheet, because one component in three places is
 * how its three copies drift apart; a screen now only names the layer it has to sit on.
 *
 * The stack is centred under the top bar, so a message is read before the eye has to
 * travel to the bottom of a long page. `--topbar-height` comes from topbar.css, which
 * every page that shows a toast loads; the fallback keeps the rule valid without it.
 */
.toast-container {
  position: fixed;
  top: calc(var(--topbar-height, 0px) + 16px);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  pointer-events: none;
  max-width: min(380px, calc(100vw - 40px));
}

/* The stack ignores clicks so it never covers the page, but each message stays readable
   and selectable. */
.toast {
  pointer-events: auto;
  padding: 11px 14px;
  border-radius: 10px;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-paper-white);
  background: var(--text-body);
  box-shadow: 0 10px 22px -10px rgba(0, 0, 0, 0.5);
  opacity: 0;
  /* A message drops in from above, so the movement agrees with where it lands. */
  transform: translateY(-10px);
  transition: opacity var(--motion-base) var(--motion-ease), transform var(--motion-base) var(--motion-ease);
}

.toast-visible {
  opacity: 1;
  transform: translateY(0);
}

.toast-success {
  background: #047857;
}

.toast-info {
  background: #004d60;
}

.toast-error {
  background: var(--danger-fg);
}

.toast-warning {
  background: var(--warning-fg-soft);
}

@media (max-width: 768px) {

  /* The top bar is hidden on a phone, so nothing may reserve its height above a toast. */
  .toast-container {
    top: 16px;
  }
}