/*
  OuinOual Design System — pilot stylesheet.
  Source of truth: docs/brain/40-design/44-design-system.md
  Self-contained. Does not import, extend, or reference
  ouinoual-design-system.css. Every custom property is prefixed --oq-
  to avoid collision with that file's five existing :root blocks.
  Scope: the auth-flow pilot only — login.html, register.html,
  forgot-password.html, reset-password.html. Do not link this file from
  any other template without a separate rollout decision (see
  docs/brain/30-gaps/33-decisions.md).
*/

:root {
  /* 2.1 Brand */
  --oq-brand-primary: #355CFF;
  --oq-brand-secondary: #7C4DFF;
  --oq-brand-tint: #E9E4FF;

  /* Logo — §1. A dedicated pair, not an alias of brand-primary/secondary:
     the dark-mode logo variant diverges from the dark brand colors. */
  --oq-logo-ring-back: var(--oq-brand-primary);
  --oq-logo-ring-front: var(--oq-brand-secondary);

  /* Text/icon color for content sitting on a solid brand-colored surface
     (e.g. primary button label). Distinct from neutral-0: neutral-0 means
     "surface" and inverts with theme, this always stays light-on-brand. */
  --oq-on-brand: #FFFFFF;

  /* Theme-invariant dark surface for transient overlays (toasts) that
     must stay legible over any page background, in either theme. Found
     while auditing dashboard.html: its toast used `--text-primary` as
     its own background, which flips to a near-white value in dark mode
     — a white-on-white bug of the same class as --oq-on-brand exists to
     prevent. Paired with --oq-on-brand for text, same as neutral-0 was
     wrongly paired with on a solid brand fill. */
  --oq-inverse-surface: #1F2430;

  /* 2.2 Neutral ramp */
  --oq-neutral-0: #FFFFFF;
  --oq-neutral-50: #FAFAFC;
  --oq-neutral-100: #F4F4F7;
  --oq-neutral-200: #E5E7EB;
  --oq-neutral-300: #D3D6DD;
  --oq-neutral-400: #9CA3AF;
  --oq-neutral-500: #6B7280;
  --oq-neutral-700: #414755;
  --oq-neutral-900: #1F2430;

  /* 2.3 Semantic pairs (background / text / solid fill) */
  --oq-success-bg: #E7F6ED;
  --oq-success-text: #15803D;
  --oq-success-solid: #22C55E;
  --oq-warning-bg: #FEF4E6;
  --oq-warning-text: #B45309;
  --oq-warning-solid: #F59E0B;
  --oq-error-bg: #FEECEC;
  --oq-error-text: #B91C1C;
  --oq-error-solid: #EF4444;
  --oq-info-bg: #E9E4FF;
  --oq-info-text: #355CFF;
  --oq-info-solid: #355CFF;

  /* 3. Type scale — Arabic-first line heights. Two weights only: 400, 500. */
  --oq-weight-regular: 400;
  --oq-weight-medium: 500;
  --oq-text-display-size: 28px;
  --oq-text-display-lh: 1.4;
  --oq-text-title-size: 22px;
  --oq-text-title-lh: 1.45;
  --oq-text-heading-size: 18px;
  --oq-text-heading-lh: 1.5;
  --oq-text-subheading-size: 16px;
  --oq-text-subheading-lh: 1.6;
  --oq-text-body-size: 15px;
  --oq-text-body-lh: 1.75;
  --oq-text-body-sm-size: 14px;
  --oq-text-body-sm-lh: 1.7;
  --oq-text-caption-size: 13px;
  --oq-text-caption-lh: 1.6;
  --oq-text-micro-size: 12px;
  --oq-text-micro-lh: 1.5;
  --oq-font-family: 'IBM Plex Sans Arabic', 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  /* 4. Spacing scale — 4px base. Use only these values. */
  --oq-space-1: 4px;
  --oq-space-2: 8px;
  --oq-space-3: 12px;
  --oq-space-4: 16px;
  --oq-space-5: 20px;
  --oq-space-6: 24px;
  --oq-space-8: 32px;
  --oq-space-10: 40px;
  --oq-space-12: 48px;
  --oq-space-16: 64px;

  /* 5. Radius */
  --oq-radius-sm: 6px;
  --oq-radius: 8px;
  --oq-radius-lg: 12px;
  --oq-radius-full: 999px;

  /* 6. Elevation — almost none. Flat and calm. */
  --oq-border-hairline: 0.5px solid var(--oq-neutral-200);
  --oq-shadow-dropdown: 0 4px 16px rgba(31, 36, 48, 0.08);
  --oq-focus-ring: 0 0 0 3px var(--oq-brand-tint);

  /* Loading state — no existing token covers a spinner ring's size/stroke */
  --oq-spinner-size: 16px;
  --oq-spinner-border-width: 2px;
}

/* ---------------------------------------------------------------- */
/* Dark mode. Mechanism matches services/web_api/static/ouinoual-      */
/* theme.js: an attribute toggle (`data-theme` on <html>), persisted   */
/* in localStorage under the key "ouinoual-theme". login.html already  */
/* sets this attribute pre-paint (see the inline bootstrap script in   */
/* its <head>) even though it doesn't load ouinoual-theme.js itself.   */
/* The prefers-color-scheme block below is a no-JS fallback only: the  */
/* bootstrap script always resolves data-theme to "light" or "dark"    */
/* once it runs, so this media query only ever matters before that     */
/* script runs or if JS is disabled entirely.                          */
/* ---------------------------------------------------------------- */

html[data-theme="dark"] {
  --oq-neutral-0: #1A1F2E;
  --oq-neutral-50: #12151F;
  --oq-neutral-100: #232838;
  --oq-neutral-200: #2E3444;
  --oq-neutral-300: #3A4152;
  --oq-neutral-400: #6B7280;
  --oq-neutral-500: #9CA3AF;
  --oq-neutral-700: #C9CDD6;
  --oq-neutral-900: #F2F3F7;

  --oq-brand-primary: #5B7CFF;
  --oq-brand-secondary: #9B76FF;
  --oq-brand-tint: #2A2545;

  --oq-logo-ring-back: #FFFFFF;
  --oq-logo-ring-front: #AFA9EC;

  --oq-success-bg: #16301F;
  --oq-success-text: #4ADE80;
  --oq-warning-bg: #33260F;
  --oq-warning-text: #FBBF24;
  --oq-error-bg: #3A1A1A;
  --oq-error-text: #F87171;

  /* Not specified by the dark palette brief. Inferred, not invented:
     info already equals brand-tint/brand-primary in the light set
     (compare §2.3 above), so it inherits the same relationship here. */
  --oq-info-bg: var(--oq-brand-tint);
  --oq-info-text: var(--oq-brand-primary);
}

@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]) {
    --oq-neutral-0: #1A1F2E;
    --oq-neutral-50: #12151F;
    --oq-neutral-100: #232838;
    --oq-neutral-200: #2E3444;
    --oq-neutral-300: #3A4152;
    --oq-neutral-400: #6B7280;
    --oq-neutral-500: #9CA3AF;
    --oq-neutral-700: #C9CDD6;
    --oq-neutral-900: #F2F3F7;

    --oq-brand-primary: #5B7CFF;
    --oq-brand-secondary: #9B76FF;
    --oq-brand-tint: #2A2545;

    --oq-logo-ring-back: #FFFFFF;
    --oq-logo-ring-front: #AFA9EC;

    --oq-success-bg: #16301F;
    --oq-success-text: #4ADE80;
    --oq-warning-bg: #33260F;
    --oq-warning-text: #FBBF24;
    --oq-error-bg: #3A1A1A;
    --oq-error-text: #F87171;

    --oq-info-bg: var(--oq-brand-tint);
    --oq-info-text: var(--oq-brand-primary);
  }
}

/* ---------------------------------------------------------------- */
/* 7. Core components — the subset this pilot page actually uses.   */
/* All classes are prefixed oq- so they cannot collide with the     */
/* legacy stylesheet's class names either.                          */
/* ---------------------------------------------------------------- */

.oq-reset,
.oq-reset * {
  box-sizing: border-box;
}

.oq-body-font {
  font-family: var(--oq-font-family);
  color: var(--oq-neutral-900);
  font-size: var(--oq-text-body-size);
  line-height: var(--oq-text-body-lh);
  font-weight: var(--oq-weight-regular);
}

.oq-text-display {
  font-size: var(--oq-text-display-size);
  line-height: var(--oq-text-display-lh);
  font-weight: var(--oq-weight-medium);
}

.oq-text-title {
  font-size: var(--oq-text-title-size);
  line-height: var(--oq-text-title-lh);
  font-weight: var(--oq-weight-medium);
}

.oq-text-subheading {
  font-size: var(--oq-text-subheading-size);
  line-height: var(--oq-text-subheading-lh);
  font-weight: var(--oq-weight-medium);
}

.oq-text-caption {
  font-size: var(--oq-text-caption-size);
  line-height: var(--oq-text-caption-lh);
  color: var(--oq-neutral-500);
}

.oq-text-micro {
  font-size: var(--oq-text-micro-size);
  line-height: var(--oq-text-micro-lh);
  color: var(--oq-neutral-500);
}

/* Button (primary) — §7 */
.oq-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--oq-space-2);
  height: 42px;
  padding-inline: var(--oq-space-5);
  border-radius: var(--oq-radius);
  font-size: var(--oq-text-body-size);
  font-weight: var(--oq-weight-medium);
  border: none;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.05s ease;
  width: 100%;
}

.oq-btn-primary {
  background: var(--oq-brand-primary);
  color: var(--oq-on-brand);
}

.oq-btn-primary:hover:not(:disabled) {
  background: #2c4ce0;
}

.oq-btn-primary:active:not(:disabled) {
  transform: translateY(1px);
}

.oq-btn-primary:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

/* Button loading state — §7/§8 */
.oq-btn-loading-spinner {
  display: none;
  width: var(--oq-spinner-size);
  height: var(--oq-spinner-size);
  flex-shrink: 0;
  border-radius: var(--oq-radius-full);
  border: var(--oq-spinner-border-width) solid var(--oq-brand-secondary);
  border-top-color: var(--oq-on-brand);
  animation: oq-spin 0.6s linear infinite;
}

.oq-btn[data-loading="true"] .oq-btn-loading-spinner {
  display: inline-block;
}

@keyframes oq-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Button (secondary) — §7 */
/* Reserved: Google sign-in — markup commented out in login.html until the
   backend exists. See CONSTITUTION.md §03 Reminder 7 */
.oq-btn-secondary {
  background: var(--oq-neutral-0);
  border: var(--oq-border-hairline);
  color: var(--oq-neutral-900);
}

.oq-btn-secondary:hover:not(:disabled) {
  border-color: var(--oq-neutral-300);
  background: var(--oq-neutral-50);
}

.oq-btn-secondary:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  color: var(--oq-neutral-500);
}

/* Input — §7 */
.oq-field {
  display: flex;
  flex-direction: column;
  gap: var(--oq-space-1);
  margin-bottom: var(--oq-space-4);
}

.oq-label {
  font-size: var(--oq-text-caption-size);
  line-height: var(--oq-text-caption-lh);
  font-weight: var(--oq-weight-medium);
  color: var(--oq-neutral-900);
}

.oq-input-wrap {
  position: relative;
}

.oq-input {
  width: 100%;
  height: 40px;
  padding-inline: var(--oq-space-3);
  border-radius: var(--oq-radius);
  border: var(--oq-border-hairline);
  background: var(--oq-neutral-0);
  color: var(--oq-neutral-900);
  font-size: var(--oq-text-body-size);
  font-family: var(--oq-font-family);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.oq-input::placeholder {
  color: var(--oq-neutral-400);
}

.oq-input:hover {
  border-color: var(--oq-neutral-300);
}

.oq-input:focus {
  outline: none;
  border-color: var(--oq-brand-primary);
  box-shadow: var(--oq-focus-ring);
}

.oq-input-has-toggle {
  padding-inline-end: 40px;
}

.oq-input-toggle {
  position: absolute;
  inset-inline-end: var(--oq-space-1);
  top: 50%;
  transform: translateY(-50%);
  width: 32px;
  height: 32px;
  border: none;
  background: none;
  border-radius: var(--oq-radius-sm);
  color: var(--oq-neutral-500);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.oq-input-toggle:hover {
  color: var(--oq-neutral-900);
  background: var(--oq-neutral-100);
}

.oq-input-toggle:focus-visible {
  outline: none;
  box-shadow: var(--oq-focus-ring);
}

/* Card / panel — §7 */
.oq-card {
  background: var(--oq-neutral-0);
  border: var(--oq-border-hairline);
  border-radius: var(--oq-radius-lg);
  padding: var(--oq-space-6);
}

/* Alert (uses semantic pairs, §2.3 + §8.3 rule: human cause, not a code) */
.oq-alert {
  display: none;
  border-radius: var(--oq-radius);
  padding: var(--oq-space-3) var(--oq-space-4);
  font-size: var(--oq-text-caption-size);
  line-height: var(--oq-text-caption-lh);
  margin-bottom: var(--oq-space-4);
}

.oq-alert-error {
  background: var(--oq-error-bg);
  color: var(--oq-error-text);
}

.oq-alert-success {
  background: var(--oq-success-bg);
  color: var(--oq-success-text);
}

.oq-alert-info {
  background: var(--oq-info-bg);
  color: var(--oq-info-text);
}

/* Checkbox (remember-me) */
.oq-checkbox-row {
  display: flex;
  align-items: center;
  gap: var(--oq-space-2);
}

.oq-checkbox {
  width: 16px;
  height: 16px;
  accent-color: var(--oq-brand-primary);
  border-radius: var(--oq-radius-sm);
  cursor: pointer;
}

.oq-checkbox-label {
  font-size: var(--oq-text-caption-size);
  color: var(--oq-neutral-700);
  cursor: pointer;
}

/* Divider */
.oq-divider {
  display: flex;
  align-items: center;
  gap: var(--oq-space-3);
  color: var(--oq-neutral-400);
  font-size: var(--oq-text-caption-size);
  margin: var(--oq-space-5) 0;
}

.oq-divider::before,
.oq-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--oq-neutral-200);
}

/* Theme toggle — pilot (login.html only). Persists to the same
   localStorage key ("ouinoual-theme") and data-theme attribute that
   services/web_api/static/ouinoual-theme.js uses everywhere else; this
   page doesn't load that script, so the toggle is wired directly in
   login.html's own inline script instead. Icon swap follows the same
   established pattern as ouinoual-theme.js: both icons stay in the DOM,
   CSS shows the one that names where a click will take you. */
.oq-theme-toggle {
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--oq-radius);
  border: var(--oq-border-hairline);
  background: transparent;
  color: var(--oq-neutral-500);
  cursor: pointer;
}

.oq-theme-toggle:hover {
  color: var(--oq-neutral-900);
  background: var(--oq-neutral-100);
}

.oq-theme-toggle:focus-visible {
  outline: none;
  box-shadow: var(--oq-focus-ring);
}

html[data-theme="dark"] .oq-theme-icon-moon,
html:not([data-theme="dark"]) .oq-theme-icon-sun {
  display: none;
}

/* Links */
.oq-link {
  color: var(--oq-brand-primary);
  text-decoration: none;
  font-weight: var(--oq-weight-medium);
}

.oq-link:hover {
  text-decoration: underline;
}

.oq-link-muted {
  color: var(--oq-neutral-500);
  text-decoration: none;
  font-size: var(--oq-text-micro-size);
}

.oq-link-muted:hover {
  color: var(--oq-neutral-700);
}

/* Language + theme control row — shared across every auth page. Was
   login.html-only inline CSS until register/forgot-password/reset-password
   needed the identical row; moved here rather than duplicated 4 times. */
.oq-lang-row {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--oq-space-3);
  margin-bottom: var(--oq-space-6);
}

.oq-lang-select {
  appearance: none;
  border: var(--oq-border-hairline);
  border-radius: var(--oq-radius-full);
  background: var(--oq-neutral-0);
  color: var(--oq-neutral-700);
  font-size: var(--oq-text-micro-size);
  font-weight: var(--oq-weight-medium);
  padding-inline: var(--oq-space-4) var(--oq-space-6);
  height: 30px;
  cursor: pointer;
}

/* Two-panel auth shell — shared by login.html and register.html. Was
   login.html-only inline CSS; moved here once register.html needed the
   identical structure rather than duplicating ~60 lines verbatim. */
.oq-auth-shell {
  display: flex;
  min-height: 100vh;
}

.oq-brand-panel {
  flex: 1 1 42%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--oq-space-8);
  padding: var(--oq-space-12) var(--oq-space-10);
  background: var(--oq-neutral-0);
  border-inline-end: var(--oq-border-hairline);
}

.oq-brand-mark-row {
  display: flex;
  align-items: center;
  gap: var(--oq-space-3);
}

.oq-brand-mark-row svg {
  width: 44px;
  height: 44px;
  flex-shrink: 0;
}

.oq-brand-name {
  font-size: var(--oq-text-heading-size);
  font-weight: var(--oq-weight-medium);
  color: var(--oq-neutral-900);
}

.oq-promise-line {
  max-width: 30ch;
}

.oq-benefit-list {
  display: flex;
  flex-direction: column;
  gap: var(--oq-space-4);
}

.oq-benefit-row {
  display: flex;
  align-items: flex-start;
  gap: var(--oq-space-3);
}

.oq-benefit-icon {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  border-radius: var(--oq-radius-full);
  background: var(--oq-brand-tint);
  color: var(--oq-brand-primary);
  display: flex;
  align-items: center;
  justify-content: center;
}

.oq-benefit-text {
  color: var(--oq-neutral-700);
  padding-top: 3px;
}

.oq-form-panel {
  flex: 1 1 58%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--oq-space-8) var(--oq-space-5);
}

.oq-form-wrap {
  width: 100%;
  max-width: 380px;
}

.oq-form-wrap h1 {
  margin: 0 0 var(--oq-space-1);
}

.oq-form-wrap .oq-page-subtitle {
  color: var(--oq-neutral-500);
  margin-bottom: var(--oq-space-6);
}

.oq-field-row-between {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: calc(var(--oq-space-1) * -1) 0 var(--oq-space-5);
  gap: var(--oq-space-3);
  flex-wrap: wrap;
}

.oq-signup-row {
  text-align: center;
  margin-top: var(--oq-space-5);
}

.oq-legal-row {
  display: flex;
  justify-content: center;
  gap: var(--oq-space-5);
  margin-top: var(--oq-space-8);
}

/* Centered-card auth layout — shared by the password-recovery pages
   (forgot-password.html, reset-password.html). Single card, no brand
   panel: per the design brief, the user here is anxious and wants the
   task done, not marketing copy. */
.oq-centered-shell {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--oq-space-8) var(--oq-space-5);
}

.oq-centered-card {
  width: 100%;
  max-width: 420px;
  background: var(--oq-neutral-0);
  border: var(--oq-border-hairline);
  border-radius: var(--oq-radius-lg);
  padding: var(--oq-space-8);
}

.oq-centered-brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--oq-space-2);
  margin-bottom: var(--oq-space-6);
}

.oq-centered-brand svg {
  width: 32px;
  height: 32px;
  flex-shrink: 0;
}

.oq-centered-brand-name {
  font-size: var(--oq-text-heading-size);
  font-weight: var(--oq-weight-medium);
  color: var(--oq-neutral-900);
}

.oq-centered-title {
  text-align: center;
  margin: 0 0 var(--oq-space-1);
}

.oq-centered-subtitle {
  text-align: center;
  color: var(--oq-neutral-500);
  margin-top: var(--oq-space-1);
  margin-bottom: var(--oq-space-6);
}

/* Turnstile field wrapper — shared by register.html and
   forgot-password.html, the two pages with a conditional Cloudflare
   Turnstile widget. */
.oq-turnstile-field {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--oq-space-2);
  margin-bottom: var(--oq-space-4);
  padding: var(--oq-space-3) var(--oq-space-4);
  border: var(--oq-border-hairline);
  border-radius: var(--oq-radius);
  background: var(--oq-neutral-50);
}

.oq-turnstile-field .oq-label {
  align-self: flex-start;
}

/* ---------------------------------------------------------------- */
/* Mobile breakpoint — auth-flow pages. Overrides for the two-panel    */
/* shell above (shared by login.html and register.html). .oq-centered-*/
/* (forgot/reset-password) needs no override: it's already narrow and  */
/* responsive at every width.                                          */
/* ---------------------------------------------------------------- */

@media (max-width: 768px) {
  .oq-auth-shell {
    flex-direction: column;
    min-height: auto;
  }

  .oq-brand-panel {
    flex: 0 0 auto;
    gap: var(--oq-space-3);
    padding: var(--oq-space-6) var(--oq-space-5);
    border-inline-end: none;
    border-block-end: var(--oq-border-hairline);
  }

  /* Mobile drops secondary marketing content: logo + name + one
     promise line only, above the fold. The user came to sign in. */
  .oq-brand-panel .oq-benefit-list {
    display: none;
  }

  .oq-promise-line {
    max-width: none;
    margin: 0;
    font-size: var(--oq-text-subheading-size);
    line-height: var(--oq-text-subheading-lh);
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
  }

  .oq-form-panel {
    flex: 1 1 auto;
    padding: var(--oq-space-6) var(--oq-space-5);
  }

  /* 44px minimum touch target (WCAG 2.5.5 / Apple HIG). 44 is not a
     value on the 4px spacing scale, so it's kept literal rather than
     forced onto the nearest token (40 or 48). Surrounding clearance
     still uses existing spacing tokens. */
  .oq-btn {
    height: 44px;
  }

  .oq-input {
    height: 44px;
  }

  .oq-lang-select {
    height: 44px;
  }

  .oq-theme-toggle {
    width: 44px;
    height: 44px;
  }

  .oq-input-toggle {
    width: 44px;
    height: 44px;
  }

  .oq-input-has-toggle {
    padding-inline-end: calc(44px + var(--oq-space-2));
  }
}

/* ---------------------------------------------------------------- */
/* Dashboard pilot (dashboard.html only). The sidebar/topbar/cards use */
/* their EXISTING class names (.sidebar, .nav-item, .topbar-btn, etc.) */
/* — restyled via dashboard.html's own local CSS variables now mapped  */
/* to --oq- tokens, not rebuilt as .oq- markup.                        */
/*                                                                     */
/* dashboard.html no longer links ouinoual-design-system.css. That     */
/* file redeclares `body` four times (three with !important            */
/* backgrounds) across six competing :root token systems — its         */
/* `body:has(.app-layout)` "Premium SaaS correction" layer could not    */
/* be beaten by specificity even with an ID selector, so the link was   */
/* dropped instead (see docs/brain/40-design/44-design-system.md §2.4). */
/* Once that link was gone, dashboard's own body/.topbar/.main-content  */
/* rules (already --oq--token-driven) rendered correctly in both        */
/* themes with no override needed at all. What follows is only the     */
/* small set of rules dashboard.html genuinely had no equivalent for —  */
/* confirmed by grep against its own inline <style>, not assumed —      */
/* now ported here under --oq- tokens (or fixed values where the        */
/* sidebar's theme-invariance requires it) and scoped to class names    */
/* that exist only on this page, since ouinoual-ds.css is linked only   */
/* from the auth pages and this one.                                    */
/* ---------------------------------------------------------------- */

.topbar-right .ouinoual-theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  min-width: 36px;
  border-radius: var(--oq-radius);
  border: var(--oq-border-hairline);
  background: transparent;
  color: var(--oq-neutral-500);
  box-shadow: none;
  cursor: pointer;
  transition: transform 160ms ease, border-color 160ms ease, background 160ms ease, color 160ms ease;
}

.topbar-right .ouinoual-theme-toggle:hover {
  transform: none;
  color: var(--oq-neutral-900);
  background: var(--oq-neutral-100);
  border-color: var(--oq-neutral-300);
}

.topbar-right .ouinoual-theme-toggle svg {
  width: 19px;
  height: 19px;
}

.topbar-right .theme-toggle-label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

html[data-theme="dark"] .topbar-right .theme-toggle-moon,
html:not([data-theme="dark"]) .topbar-right .theme-toggle-sun {
  display: none;
}

@media (max-width: 768px) {
  /* Same 44px rule as the auth pages, applied to dashboard's own
     interactive chrome (different class names, same requirement). */
  .lang-selector,
  .topbar-btn,
  .mobile-menu-toggle,
  .collapse-btn,
  .topbar-right .ouinoual-theme-toggle {
    min-height: 44px;
    min-width: 44px;
  }

  .user-profile {
    min-height: 44px;
  }
}

/* ---------------------------------------------------------------- */
/* Scrollbars, page-wide. Legacy equivalent (ouinoual-design-system.css */
/* lines 4305-4339) used a fixed cyan thumb regardless of theme; this   */
/* uses --oq- neutral tokens instead so it inverts with data-theme like */
/* everything else. Unscoped (`*`), matching the legacy rule's own      */
/* scope — this is the only page-wide selector in this pilot section,   */
/* deliberately: a scrollbar has no page-specific meaning to leak.      */
/* ---------------------------------------------------------------- */

* {
  scrollbar-width: thin;
  scrollbar-color: var(--oq-neutral-300) var(--oq-neutral-100);
}

*::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

*::-webkit-scrollbar-track {
  background: var(--oq-neutral-100);
}

*::-webkit-scrollbar-thumb {
  min-height: 48px;
  border: 2px solid transparent;
  border-radius: 999px;
  background: var(--oq-neutral-300) padding-box;
}

*::-webkit-scrollbar-thumb:hover {
  background: var(--oq-neutral-400) padding-box;
}

/* ---------------------------------------------------------------- */
/* Sidebar: permanent dark rail, theme-invariant by design (see        */
/* docs/brain/40-design/44-design-system.md §2.4). Fixed color values, */
/* not --oq- tokens, on purpose — the sidebar must never flip with     */
/* data-theme. Ported from ouinoual-design-system.css lines 3324-3411. */
/* ---------------------------------------------------------------- */

.sidebar {
  background:
    radial-gradient(circle at 18% 0%, rgba(34, 211, 238, 0.16), transparent 34%),
    linear-gradient(180deg, #07111f 0%, #0b1628 58%, #08111f 100%) !important;
  border-inline-end: 1px solid rgba(255, 255, 255, 0.07) !important;
  box-shadow: 12px 0 36px rgba(15, 23, 42, 0.12) !important;
}

.sidebar,
.sidebar-nav {
  scrollbar-width: thin;
  scrollbar-color: rgba(148, 163, 184, 0.42) transparent;
}

.sidebar::-webkit-scrollbar,
.sidebar-nav::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

.sidebar::-webkit-scrollbar-track,
.sidebar-nav::-webkit-scrollbar-track {
  background: transparent;
}

.sidebar::-webkit-scrollbar-thumb,
.sidebar-nav::-webkit-scrollbar-thumb {
  background: rgba(148, 163, 184, 0.34);
  background-clip: padding-box;
  border: 2px solid transparent;
  border-radius: 999px;
}

html[dir="rtl"] .sidebar {
  box-shadow: -12px 0 36px rgba(15, 23, 42, 0.12) !important;
}

.sidebar .logo-text,
.sidebar .workspace-name {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff;
}

.sidebar .logo-sub,
.sidebar .workspace-plan,
.sidebar .nav-section-title {
  color: rgba(203, 213, 225, 0.74) !important;
}

.sidebar .nav-item {
  color: rgba(226, 232, 240, 0.82) !important;
  border: 1px solid transparent !important;
}

.sidebar .nav-item:hover {
  background: rgba(255, 255, 255, 0.07) !important;
  color: #ffffff !important;
  border-color: rgba(255, 255, 255, 0.08) !important;
}

.sidebar .nav-item.active {
  background: linear-gradient(90deg, rgba(34, 211, 238, 0.18), rgba(20, 184, 166, 0.10)) !important;
  border-color: rgba(34, 211, 238, 0.26) !important;
  color: #ffffff !important;
  box-shadow: inset 3px 0 0 #22d3ee !important;
}

html[dir="rtl"] .sidebar .nav-item.active {
  box-shadow: inset -3px 0 0 #22d3ee !important;
}

.sidebar-footer,
.workspace-selector {
  background: rgba(255, 255, 255, 0.06) !important;
  border-color: rgba(255, 255, 255, 0.10) !important;
}

.workspace-selector:hover {
  background: rgba(255, 255, 255, 0.10) !important;
}

/* ---------------------------------------------------------------- */
/* Notification bell + dropdown, mounted by ouinoual-theme.js's        */
/* mountNotificationBell(). Ported from ouinoual-design-system.css     */
/* lines 6178-6355 and 6492-6560, condensed under --oq- tokens (the    */
/* legacy file's separate light/dark blocks collapse away since the    */
/* tokens already invert per theme).                                   */
/* ---------------------------------------------------------------- */

.notification-wrapper {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}

.notification-count-badge {
  position: absolute;
  inset-block-start: -5px;
  inset-inline-end: -5px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--oq-radius-full);
  background: var(--oq-error-solid);
  color: var(--oq-on-brand);
  border: 2px solid var(--oq-neutral-0);
  font-size: 10px;
  font-weight: 700;
  line-height: 1;
  pointer-events: none;
}

.notification-count-badge[hidden] {
  display: none !important;
}

.notification-dropdown {
  position: absolute;
  inset-block-start: calc(100% + var(--oq-space-2));
  inset-inline-end: 0;
  width: min(340px, calc(100vw - 28px));
  max-height: min(420px, calc(100vh - 110px));
  overflow: hidden;
  display: none;
  border: var(--oq-border-hairline);
  border-radius: var(--oq-radius-lg);
  background: var(--oq-neutral-0);
  box-shadow: var(--oq-shadow-dropdown);
  z-index: 260;
}

.notification-wrapper.open .notification-dropdown {
  display: block;
}

/* Mobile-safe bell popover (ported from ouinoual-design-system.css
   6543-6552 / 7070-7075, 2026-08-25 pre-launch pass): the base
   position:absolute + width:min(340px, calc(100vw - 28px)) rule above can
   still clip off-viewport on narrow phones depending on the notification
   wrapper's actual position in a page's specific topbar layout -- this was
   already found and fixed in ouinoual-design-system.css, but ouinoual-ds.css
   (loaded standalone, with no fallback, by dashboard.html/create-post.html/
   posts.html/scheduled-posts.html/accounts.html) never received it despite
   this file's own header claiming a full port of that line range. */
@media (max-width: 520px) {
  .notification-dropdown {
    position: fixed;
    inset-inline: 14px !important;
    inset-block-start: 76px;
    width: auto;
    min-width: 0;
    max-width: none;
    max-height: min(360px, calc(100vh - 98px));
    border-radius: 16px;
    transform: none !important;
  }
}

.notification-dropdown-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--oq-space-3);
  padding: var(--oq-space-4) var(--oq-space-4) var(--oq-space-3);
  border-bottom: var(--oq-border-hairline);
}

.notification-dropdown-title {
  color: var(--oq-neutral-900);
  font-size: var(--oq-text-body-sm-size);
  font-weight: var(--oq-weight-medium);
}

.notification-mark-all {
  border: 0;
  background: transparent;
  color: var(--oq-brand-primary);
  cursor: pointer;
  font: inherit;
  font-size: var(--oq-text-caption-size);
  font-weight: var(--oq-weight-medium);
  padding: var(--oq-space-1) 0;
  white-space: nowrap;
}

.notification-mark-all:disabled {
  color: var(--oq-neutral-400);
  cursor: default;
  opacity: 0.62;
}

.notification-dropdown-list {
  max-height: 286px;
  overflow: auto;
  padding: var(--oq-space-2);
}

.notification-item {
  width: 100%;
  display: grid;
  gap: var(--oq-space-1);
  padding: var(--oq-space-3);
  border: 0;
  border-radius: var(--oq-radius-lg);
  background: transparent;
  color: var(--oq-neutral-900);
  cursor: pointer;
  font: inherit;
  text-align: start;
}

.notification-item:hover {
  background: var(--oq-neutral-100);
}

.notification-item.is-unread {
  background: var(--oq-brand-tint);
}

.notification-item strong {
  font-size: var(--oq-text-caption-size);
  font-weight: var(--oq-weight-medium);
}

.notification-item span,
.notification-item small,
.notification-empty {
  color: var(--oq-neutral-500);
  font-size: var(--oq-text-micro-size);
  line-height: 1.45;
}

.notification-empty {
  padding: var(--oq-space-6) var(--oq-space-4);
  text-align: center;
}

.notification-view-all {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 42px;
  margin: var(--oq-space-2);
  padding: var(--oq-space-3) var(--oq-space-4);
  border-top: var(--oq-border-hairline);
  border-radius: var(--oq-radius);
  color: var(--oq-brand-primary);
  background: var(--oq-brand-tint);
  font-size: var(--oq-text-caption-size);
  font-weight: var(--oq-weight-medium);
  text-align: center;
  text-decoration: none;
}

.notification-view-all:hover {
  color: var(--oq-neutral-900);
}

/* ---------------------------------------------------------------- */
/* Avatar fallback. What actually ships on dashboard.html (checked      */
/* directly, not assumed): a static <span class="avatar-fallback"> is   */
/* server-rendered inside both #top-user-avatar and #workspace-avatar   */
/* (the initial letter), sitting alongside <img class="avatar-img">     */
/* whose inline onload/onerror attributes (already in the template,     */
/* unchanged) toggle .avatar-has-image/.avatar-broken on the container  */
/* and set the image's own inline display. ouinoual-theme.js's          */
/* mountAvatarFallbacks() additionally injects a second, functionally   */
/* identical <span class="generated-avatar-fallback"> into the same     */
/* containers (it doesn't recognize the static one as "already there"), */
/* so both classes are styled identically here.                         */
/*                                                                       */
/* The previous port used `grid-area: 1/1` to stack image and fallback, */
/* copied from the legacy file — but .user-avatar/.workspace-avatar are */
/* `display: flex` in dashboard.html's own inline <style>, not `grid`,  */
/* so `grid-area` was a no-op and the fallback rendered as an extra flex */
/* item next to the image instead of underneath it. Fixed with absolute */
/* stacking instead, which works regardless of the container's own      */
/* display mode: both containers are already `position: relative;       */
/* overflow: hidden` in dashboard.html.                                 */
/*                                                                       */
/* The img rule below also carries the sizing (width/height/object-fit) */
/* that fills the container and crops the photo to a circle. dashboard  */
/* .html and accounts.html both happen to also declare this locally, so */
/* the gap was invisible there; scheduled-posts.html and posts.html do  */
/* not, and had no img sizing at all, leaving the avatar effectively    */
/* invisible (unsized, uncropped, clipped by the container's            */
/* `overflow: hidden`) even though `user_avatar_url` and the <img> tag  */
/* itself were both present and correct. This is the single shared      */
/* layer all four pages load, so the fix belongs here, not per-page.    */
/* ---------------------------------------------------------------- */

.user-avatar .avatar-fallback,
.user-avatar .generated-avatar-fallback,
.workspace-avatar .avatar-fallback,
.workspace-avatar .generated-avatar-fallback {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: grid;
  place-items: center;
  color: var(--oq-on-brand);
  font-weight: var(--oq-weight-medium);
}

.user-avatar img,
.workspace-avatar img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 2;
}

.avatar-has-image .avatar-fallback,
.avatar-has-image .generated-avatar-fallback {
  display: none;
}

/* ---------------------------------------------------------------- */
/* Mobile sidebar: close button, dimmed backdrop, body scroll-lock.    */
/* The slide-in/out transform itself is already self-sufficient in     */
/* dashboard.html's own inline <style> (.sidebar is `position: fixed`  */
/* at its base rule, not just under this media query, so it already    */
/* overlays rather than pushing layout) — confirmed by reading that    */
/* rule directly. These three effects had no equivalent anywhere:      */
/* ported from ouinoual-design-system.css lines 8858-8999.             */
/* ---------------------------------------------------------------- */

@media (max-width: 768px) {
  body.mobile-sidebar-open {
    overflow: hidden;
  }

  /* Keeps the hamburger tappable (as a second way to close, alongside
     tapping the backdrop and the close button) — without this it sits at
     the topbar's normal z-index (50), under the backdrop (90), and
     becomes unreachable while the sidebar is open. */
  body.mobile-sidebar-open .topbar {
    z-index: 190;
  }

  body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 90;
    background: rgba(2, 6, 23, 0.48);
    pointer-events: none;
    visibility: hidden;
    opacity: 0;
    transition: opacity 160ms ease;
  }

  body.mobile-sidebar-open::before {
    pointer-events: auto;
    visibility: visible;
    opacity: 1;
  }

  .mobile-sidebar-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    align-self: flex-end;
    position: sticky;
    top: 8px;
    z-index: 2;
    width: 38px;
    height: 38px;
    margin: 10px 12px 0;
    border: 1px solid rgba(255, 255, 255, 0.16);
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.12);
    color: #ffffff;
    cursor: pointer;
  }

  .mobile-sidebar-close svg {
    width: 16px;
    height: 16px;
  }
}

@media (min-width: 769px) {
  body::before {
    content: none;
  }

  .mobile-sidebar-close {
    display: none;
  }
}
