@use 'sass:color';
@use 'sass:map';
@use 'sass:math';

// Base palette
//
// Override the whole palette via:
//   @use 'ngwr/theme/colors' with (
//     $base-colors: (primary: #...)
//   );

$base-colors: (
  primary: #3969e2,
  secondary: #f51c6a,
  success: #00a400,
  warning: #ffba00,
  danger: #fa383e,
  info: #3b82f6,
  light: #cbd5e1,
  medium: #8594a4,
  dark: #0f172a,
) !default;

// YIQ luminosity threshold (0–255) above which a color is treated as
// "light" and pairs with dark text. Uses the classic Bootstrap formula —
// it weights the green channel higher than blue, which matches human
// perception of brightness far better than HSL lightness (HSL classes
// pure blue as 50%-lightness even though it reads as dark).
$contrast-threshold: 150 !default;

// Dark text used on light backgrounds.
$contrast-dark: #171616 !default;

// Light text used on dark backgrounds.
$contrast-light: #ffffff !default;

// Helpers

@function _rgb-channels($c) {
  @return color.channel($c, 'red'), color.channel($c, 'green'), color.channel($c, 'blue');
}

@function _contrast($c) {
  $r: color.channel($c, 'red');
  $g: color.channel($c, 'green');
  $b: color.channel($c, 'blue');
  $yiq: math.div($r * 299 + $g * 587 + $b * 114, 1000);
  @if $yiq >= $contrast-threshold {
    @return $contrast-dark;
  }
  @return $contrast-light;
}

// CSS variables

:root {
  --wr-color-white: #ffffff;
  --wr-color-white-rgb: 255, 255, 255;
  --wr-color-black: #000000;
  --wr-color-black-rgb: 0, 0, 0;

  // Overlay dim — used by dialog / drawer / image preview / command
  // palette / image cropper for the behind-the-panel scrim. Always
  // black so the dim reads as "covered" regardless of theme. Don't
  // wire to `--wr-color-dark-rgb` — that flips to light in dark mode
  // and turns the backdrop into a white wash.
  --wr-color-backdrop-rgb: 0, 0, 0;

  // Generic subtle hover-surface tint (icon buttons, list rows) — one place
  // so the hover strength stays consistent everywhere.
  --wr-color-hover: rgba(var(--wr-color-light-rgb), 0.4);

  // Border / divider strengths — translucent so they read on any surface and
  // auto-adapt in dark (via the flipping `light` channels). One place each.
  --wr-color-border: rgba(var(--wr-color-light-rgb), 0.5);
  --wr-color-border-subtle: rgba(var(--wr-color-light-rgb), 0.35);
  --wr-color-border-strong: rgba(var(--wr-color-light-rgb), 0.6);

  // Scrim behind modals / drawers — always black so the dim reads as "covered"
  // regardless of theme.
  --wr-color-overlay: rgba(var(--wr-color-backdrop-rgb), 0.45);

  // De-emphasized text — `medium` dimmed to two canonical strengths so muted
  // labels / captions / placeholders read consistently. One place each.
  --wr-color-text-muted: rgba(var(--wr-color-medium-rgb), 0.85);
  --wr-color-text-faint: rgba(var(--wr-color-medium-rgb), 0.6);

  // Neutral gray ramp — a FIXED primitive scale (slate). Each step is a stable
  // job (50 = subtlest surface tint … 950 = strongest ink) and, unlike the
  // semantic neutrals, does NOT flip in dark mode. For theme-aware surface /
  // text jobs reach for the role aliases below instead.
  --wr-color-gray-50: #f8fafc;
  --wr-color-gray-100: #f1f5f9;
  --wr-color-gray-200: #e2e8f0;
  --wr-color-gray-300: #cbd5e1;
  --wr-color-gray-400: #94a3b8;
  --wr-color-gray-500: #64748b;
  --wr-color-gray-600: #475569;
  --wr-color-gray-700: #334155;
  --wr-color-gray-800: #1e293b;
  --wr-color-gray-900: #0f172a;
  --wr-color-gray-950: #020617;

  // Semantic role aliases over the flipping neutrals — prefer these in new code
  // for intent-free surface / text jobs. They resolve through `white` / `dark`
  // / `medium`, so they flip with the theme automatically.
  --wr-color-surface: var(--wr-color-white);
  --wr-color-on-surface: var(--wr-color-dark);
  --wr-color-on-surface-muted: var(--wr-color-medium);

  @each $name, $base in $base-colors {
    --wr-color-#{$name}: #{$base};
    --wr-color-#{$name}-rgb: #{_rgb-channels($base)};
    --wr-color-#{$name}-contrast: #{_contrast($base)};
    --wr-color-#{$name}-dark: #{color.adjust($base, $lightness: -5%)};
    --wr-color-#{$name}-darker: #{color.adjust($base, $lightness: -10%)};
    --wr-color-#{$name}-light: #{color.adjust($base, $lightness: 5%)};
    --wr-color-#{$name}-lighter: #{color.adjust($base, $lightness: 10%)};
  }

  // Soft trio per intent (+ `medium` for neutral surfaces) — tokenizes the
  // ad-hoc `rgba(var(--*-rgb), α)` fills components hand-rolled at ~8
  // different alphas, so each alpha lives in ONE place. `-soft` is the
  // canonical low-alpha fill, `-soft-border` the matching hairline, and
  // `-soft-contrast` the readable same-hue text on it (deep in light,
  // light in dark — follows `--wr-color-dark`). All theme-correct over any
  // background via the -rgb channels.
  @each $name in (primary, secondary, success, warning, danger, info, medium) {
    --wr-color-#{$name}-soft: rgba(var(--wr-color-#{$name}-rgb), 0.12);
    --wr-color-#{$name}-soft-border: rgba(var(--wr-color-#{$name}-rgb), 0.3);
    --wr-color-#{$name}-soft-contrast: color-mix(in srgb, var(--wr-color-#{$name}) 62%, var(--wr-color-dark));
    --wr-color-#{$name}-active: rgba(var(--wr-color-#{$name}-rgb), 0.2);
  }
}

// Public SCSS list
//
// Color names available for `@each` loops in component styles.

$colors: map.keys($base-colors) !default;
