@tailwind base;
@tailwind components;
@tailwind utilities;

@font-face {
  font-family: 'Manrope Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 200 800;
  src: url('@fontsource-variable/manrope/files/manrope-latin-wght-normal.woff2') format('woff2-variations');
}

/*
 * Surfaces and neutrals.
 *
 * Accent variables are NOT defined here — they are written onto the root
 * element at runtime from the palette in @pig/core, so there is exactly one
 * definition of each colour and the CSS cannot drift from the TypeScript.
 */
:root {
  --bg: 0 0% 100%;
  --surface: 0 0% 100%;
  --surface-2: 240 5% 97%;
  --border: 240 6% 90%;
  --fg: 240 10% 4%;
  --muted: 240 4% 46%;

  --positive: 160 84% 32%;
  --warning: 32 95% 44%;
  --danger: 0 72% 45%;
  --info: 201 90% 40%;
  --shadow: 240 10% 4%;

  /* Safe-area insets, so layout can reference them even at zero. */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);

  /*
   * The application header's height, including the notch it sits under. Both
   * side panes are sticky beneath it and subtract this from the viewport, so
   * it has to be one number rather than a magic constant in three files.
   */
  --app-header-h: calc(3.5rem + var(--safe-top));

  /*
   * The sidebar primitive's palette.
   *
   * Aliases, not values. shadcn's sidebar block wants its own `--sidebar-*`
   * scale; defining literal colours here would be a second palette to keep in
   * step with the first, and it would not follow the user's accent — which is
   * written onto this same element at runtime by lib/theme.tsx. Because these
   * are HSL channel triples pointing at other HSL channel triples, the dark
   * theme and every accent flow through for free and there is nothing to
   * duplicate under [data-theme='dark'].
   */
  --sidebar-background: var(--surface);
  --sidebar-foreground: var(--fg);
  --sidebar-primary: var(--accent);
  --sidebar-primary-foreground: var(--accent-on);
  --sidebar-accent: var(--accent-subtle);
  --sidebar-accent-foreground: var(--accent-fg);
  --sidebar-border: var(--border);
  --sidebar-ring: var(--accent);
}

@media (min-width: 1024px) {
  :root {
    --app-header-h: calc(4rem + var(--safe-top));
  }
}

:root[data-theme='dark'] {
  --bg: 240 10% 4%;
  --surface: 240 8% 7%;
  --surface-2: 240 6% 11%;
  --border: 240 5% 18%;
  --fg: 0 0% 98%;
  --muted: 240 5% 60%;

  --positive: 158 64% 52%;
  --warning: 38 92% 60%;
  --danger: 0 84% 65%;
  --info: 199 89% 60%;
  --shadow: 0 0% 0%;
}

@layer base {
  * {
    border-color: hsl(var(--border));
  }

  html {
    /* Prevents iOS from silently enlarging text in landscape. */
    -webkit-text-size-adjust: 100%;
    /* Keeps the background painted behind the rubber-band overscroll area. */
    background-color: hsl(var(--bg));
  }

  body {
    @apply bg-bg text-fg antialiased;
    font-feature-settings: 'cv02', 'cv03', 'cv04', 'cv11';
    /* Stops the whole page bouncing on iOS while inner panes still scroll. */
    overscroll-behavior-y: none;
  }

  ::selection {
    background: hsl(var(--accent-subtle));
    color: hsl(var(--accent-fg));
  }

  /*
   * Mobile Safari zooms the viewport when a focused input has a font size
   * below 16px, and never zooms back out. This is the fix — not
   * user-scalable=no, which breaks pinch-zoom for everyone.
   */
  input,
  select,
  textarea {
    font-size: max(16px, 1rem);
  }

  /* A visible, consistent focus ring — keyboard users need it, and the
     default varies wildly between browsers. */
  :focus-visible {
    @apply outline-none ring-2 ring-accent ring-offset-2 ring-offset-bg;
  }

  /* Respect a reduced-motion preference rather than animating regardless. */
  @media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
      animation-duration: 0.01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 0.01ms !important;
      scroll-behavior: auto !important;
    }
  }
}

@layer components {
  /* Horizontal scrollers (pipeline boards, wide tables) get momentum
     scrolling and snap on touch, without hijacking the page. */
  .scroll-x {
    @apply overflow-x-auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    overscroll-behavior-x: contain;
  }

  .scroll-x::-webkit-scrollbar {
    height: 6px;
  }
  .scroll-x::-webkit-scrollbar-thumb {
    background-color: hsl(var(--border));
    border-radius: 3px;
  }

  /* Touch targets. 44px is the documented iOS minimum and the difference
     between a usable and a frustrating phone experience. */
  .tap {
    @apply min-h-[44px] min-w-[44px];
  }

  .card {
    @apply rounded-2xl border border-border/90 bg-surface;
    box-shadow: 0 1px 2px hsl(var(--shadow) / 0.035), 0 12px 36px hsl(var(--shadow) / 0.025);
  }

  .app-canvas {
    background-color: hsl(var(--bg));
    background-image:
      radial-gradient(circle at 78% -12%, hsl(var(--accent-subtle) / 0.7), transparent 34rem),
      linear-gradient(to bottom, hsl(var(--surface) / 0.25), transparent 28rem);
    background-attachment: fixed;
  }

  /*
   * The auth surface is intentionally monochrome even if a signed-in user has
   * selected another accent. It is public brand chrome, and forcing the local
   * dark token set keeps controls legible without changing the stored theme.
   */
  .auth-shell {
    --bg: 240 10% 3%;
    --surface: 240 7% 6%;
    --surface-2: 240 5% 11%;
    --border: 240 4% 22%;
    --fg: 0 0% 98%;
    --muted: 240 5% 67%;
    --accent: 0 0% 98%;
    --accent-fg: 0 0% 98%;
    --accent-on: 240 6% 10%;
    --accent-subtle: 240 4% 16%;
    color-scheme: dark;
  }

  .auth-field-motion {
    animation: auth-field-drift 26s ease-in-out infinite alternate;
    will-change: transform;
  }

  .auth-visual {
    opacity: 0.52;
  }

  .auth-visual::after {
    position: absolute;
    inset: 0;
    content: '';
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 180 180' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.92' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.72'/%3E%3C/svg%3E");
    background-size: 180px 180px;
    mix-blend-mode: soft-light;
    opacity: 0.14;
  }

  .auth-visual-vignette {
    background:
      linear-gradient(to bottom, hsl(var(--bg) / 0.18), hsl(var(--bg) / 0.72) 34%, hsl(var(--bg)) 100%),
      linear-gradient(to right, hsl(var(--bg) / 0.18), hsl(var(--bg) / 0.42));
  }

  @media (min-width: 1024px) {
    .auth-visual {
      opacity: 1;
    }

    .auth-visual-vignette {
      background:
        linear-gradient(to right, transparent 48%, hsl(var(--bg) / 0.28) 78%, hsl(var(--bg) / 0.72)),
        linear-gradient(to bottom, hsl(var(--bg) / 0.06), transparent 18%, hsl(var(--bg) / 0.28));
    }
  }

  @keyframes auth-field-drift {
    0% {
      transform: translate3d(-1.4%, -0.8%, 0) scale(1.045);
    }
    50% {
      transform: translate3d(0.8%, 0.6%, 0) scale(1.075);
    }
    100% {
      transform: translate3d(-0.3%, 1.1%, 0) scale(1.055);
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .auth-field-motion {
      animation: none;
      transform: scale(1.045);
      will-change: auto;
    }
  }

  /* Tabular figures keep money and percentages from jittering as they
     update, which matters on a dashboard that refreshes. */
  .nums {
    font-variant-numeric: tabular-nums;
    font-feature-settings: 'tnum';
  }
}
