/*
 * PTAG Glacier design tokens and element defaults.
 *
 * This app follows the PTAG Glacier design system ("Redwood for PTAG"), so
 * every token below is the value Glacier publishes -- not a local invention.
 * The master spec and the implementation guide live in the ptag-glacier repo;
 * see the Glacier block in CLAUDE.md for the contract. A colour, size or
 * radius that is not in this file does not belong in a component file either.
 *
 * `stylesheet_link_tag :app` in the layout links every file in this directory,
 * so new styles go in their own file here (BEM-named, one block per file)
 * rather than growing this one.
 *
 * Theme: `data-theme` is written onto <html> by the anti-flash script in
 * layouts/_head before the first paint, and by the theme Stimulus controller
 * thereafter. The `prefers-color-scheme` block at the end is the no-JavaScript
 * fallback and is deliberately scoped to `:root:not([data-theme])` so it never
 * fights an explicit choice.
 */

:root {
  /* Native controls -- <select> popups, scrollbars, spinners -- follow this,
     not our custom properties. Glacier dark-mode rule 8. */
  color-scheme: light;

  /* --- Brand ----------------------------------------------------------- */
  --ptag-blue: #195171;
  --ptag-blue-dark: #0E3A54;
  --ptag-blue-light: #E8F1F7;
  --ptag-blue-50: #F0F6FA;
  --ptag-blue-700: #103A52;
  --ptag-green: #3F832F;
  --ptag-green-dark: #2D6321;
  --ptag-green-light: #EBF5E9;
  --ptag-green-50: #F3F9F2;

  /* --- Neutrals --------------------------------------------------------- */
  --neutral-0: #FFFFFF;
  --neutral-50: #F8F8FC;
  --neutral-100: #F2F2F8;
  --neutral-200: #E5E5EE;
  --neutral-300: #D1D1DE;
  --neutral-400: #B0B0C4;
  --neutral-500: #8E8EA8;
  --neutral-600: #6B6B8A;
  --neutral-700: #4A4A68;
  --neutral-800: #2D2D44;
  --neutral-900: #1A1A2E;

  /* --- Semantic --------------------------------------------------------- */
  --status-success: #3F832F;
  --status-warning: #D4880F;
  --status-danger: #C4362A;
  --status-info: #195171;
  --status-neutral: #6B6B8A;

  /* Badge fills, from the Glacier badge table (section 9.6). */
  --status-success-bg: var(--ptag-green-light);
  --status-success-fg: var(--ptag-green-dark);
  --status-warning-bg: #FFF3E0;
  /* Darker than Glacier's #B36D00, which is 3.75:1 on its own badge fill and
     fails the 4.5:1 its section 12 requires. #975C00 is 5.0:1 and still
     reads as the same amber. */
  --status-warning-fg: #975C00;
  --status-danger-bg: #FDECEA;
  --status-danger-fg: #A12E22;
  --status-info-bg: var(--ptag-blue-light);
  --status-info-fg: var(--ptag-blue);
  --status-neutral-bg: var(--neutral-100);
  --status-neutral-fg: var(--neutral-700);

  /* Fills that carry white text: buttons, the avatar, the skip link. Kept
     apart from the colour tokens above because in dark mode one shade cannot
     do both jobs -- a blue light enough to read as text on a dark card is too
     light to hold white text, and the reverse. Identical in light mode. */
  --fill-accent: var(--ptag-blue);
  --fill-danger: var(--status-danger);
  --fill-danger-hover: var(--status-danger-fg);
  --fill-success: var(--ptag-green);

  /* --- Semantic alias layer (Glacier section 16) -------------------------
     Views say what a colour *means*; only this block says which neutral it
     resolves to, so the dark override below is the single place the mapping
     changes. */
  --surface-primary: var(--neutral-0);
  --surface-secondary: var(--neutral-50);
  --surface-tertiary: var(--neutral-100);
  --surface-hover: var(--neutral-50);

  --text-primary: var(--neutral-900);
  --text-secondary: var(--neutral-700);
  --text-tertiary: var(--neutral-600);
  /* Disabled controls and decorative marks only -- 3.2:1 on a card, below
     what text a person must read needs. Captions, hints, timestamps and
     legends are content: use --text-tertiary. */
  --text-muted: var(--neutral-500);
  --text-heading: var(--neutral-800);
  --text-label: var(--neutral-700);

  --border-primary: var(--neutral-200);
  --border-secondary: var(--neutral-300);
  --border-subtle: var(--neutral-100);

  --input-bg: var(--neutral-0);
  --input-border: var(--neutral-300);
  --input-text: var(--neutral-900);

  /* Glacier 9.2: a 3px ring in the brand blue at 20%. A TOKEN, not a literal
     repeated per stylesheet -- the colour has to change with the theme, and
     four copies of an rgba() is four places to forget. It is the whole
     box-shadow rather than just the colour so the 3px cannot drift either.

     Not `color-mix()` on `--ptag-blue`: this has to resolve identically in
     both dark paths, and a token is the plainer way to guarantee that. */
  --focus-ring: 0 0 0 3px rgba(25, 81, 113, 0.2);
  /* Glacier 9.2's error state: the same ring in the danger colour. A token for
     the same reason the blue one is -- it has to change with the theme. */
  --focus-ring-danger: 0 0 0 3px rgba(196, 54, 42, 0.2);

  /* --- Outcome of a transfer ---------------------------------------------
     The pills, the stats counters and the job console all read the same
     vocabulary, so "failed" means one colour everywhere. Each one is an alias
     onto a Glacier status ramp rather than a new shade -- Glacier mistake 18.

     Drift resolves to *info*, not danger: a drift finding means a target and
     PMISync disagree about a project, which an operator reconciles there. It
     is not a delivery failure and must not read as red beside genuine ones.
     Glacier's ramps hold no purple, which is what it used to be. */
  --outcome-success: var(--status-success);
  --outcome-success-fg: var(--status-success-fg);
  --outcome-success-bg: var(--status-success-bg);
  --outcome-failed: var(--status-danger);
  --outcome-failed-fg: var(--status-danger-fg);
  --outcome-failed-bg: var(--status-danger-bg);
  --outcome-pending: var(--status-warning);
  --outcome-pending-fg: var(--status-warning-fg);
  --outcome-pending-bg: var(--status-warning-bg);
  --outcome-drift: var(--status-info);
  --outcome-drift-fg: var(--status-info-fg);
  --outcome-drift-bg: var(--status-info-bg);

  /* --- Typography -------------------------------------------------------- */
  --font-sans: "Inter", "Segoe UI", system-ui, -apple-system, sans-serif;
  --font-mono: "JetBrains Mono", "Fira Code", "Cascadia Code", ui-monospace, monospace;

  --text-display: 2.441rem;
  --text-h1: 1.953rem;
  --text-h2: 1.563rem;
  --text-h3: 1.25rem;
  --text-h4: 1rem;
  --text-body: 1rem;
  --text-body-sm: 0.875rem;
  --text-caption: 0.75rem;
  --text-overline: 0.6875rem;

  /* --- Spacing (4px grid) ------------------------------------------------ */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-16: 64px;

  /* --- Elevation --------------------------------------------------------- */
  --shadow-none: none;
  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.05);
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.04);
  --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
  --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.12);
  --shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.16);

  /* --- Radius ------------------------------------------------------------ */
  --radius-none: 0;
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --radius-xl: 16px;
  --radius-full: 9999px;

  /* --- Shell metrics ----------------------------------------------------- */
  --header-height: 56px;
  --accent-line-height: 2px;
  --sidebar-width-expanded: 240px;
  --sidebar-width-collapsed: 64px;

  /* --- Motion ------------------------------------------------------------ */
  --transition-fast: 100ms ease-in-out;
  --transition-default: 200ms ease-in-out;
  --transition-slow: 300ms ease-in-out;
  --ease-in: cubic-bezier(0.4, 0, 1, 1);
  --ease-out: cubic-bezier(0, 0, 0.2, 1);
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
  --duration-fast: 100ms;
  --duration-normal: 200ms;
  --duration-slow: 300ms;

  /* --- Z-index scale -----------------------------------------------------
     Glacier section 6. A `z-index` anywhere in this app that is not one of
     these tokens is a bug. */
  --z-content: 1;
  --z-sticky: 10;
  --z-l2-overlay: 48;
  --z-l2: 49;
  --z-sidebar: 50;
  --z-sidebar-tooltip: 60;
  --z-header: 100;
  --z-dropdown: 150;
  --z-mobile-overlay: 199;
  --z-mobile-sidebar: 200;
  --z-mobile-l2: 201;
  --z-modal-overlay: 300;
  --z-modal: 310;
  --z-toast: 400;
  --z-command-palette: 500;

  /* Glacier 9.7: the modal overlay is black at 40% in both themes, so it is
     declared once, here, and not redefined for dark mode. */
  --overlay-modal: rgba(0, 0, 0, 0.4);
}

/* Dark mode -- Glacier's "warm slate" palette. The ramp is mapped onto the
   neutral slots by role, not by number, so cards read lighter than the page
   behind them: page #1f1e1d < cards/inputs #30302e < borders #3d3d3a. */
[data-theme="dark"] {
  color-scheme: dark;

  /* The lightened brand blue, at a higher alpha: Glacier asks for a stronger
     ring in dark mode because a 20% wash disappears on a dark surface. */
  --focus-ring: 0 0 0 3px rgba(59, 142, 194, 0.3);
  --focus-ring-danger: 0 0 0 3px rgba(224, 80, 80, 0.35);

  --neutral-0: #30302e;   /* cards, header, inputs -- raised surface */
  --neutral-50: #1f1e1d;  /* page canvas, body, rail -- darkest layer */
  --neutral-100: #3d3d3a; /* in-card hover, table head, disabled fill */
  --neutral-200: #3d3d3a; /* default borders, dividers */
  --neutral-300: #3d3d3a; /* input / strong borders */
  --neutral-400: #a8a59a; /* faint icons, chevrons, placeholders */
  --neutral-500: #a8a59a; /* muted text, captions */
  --neutral-600: #d4d2c7; /* secondary text */
  --neutral-700: #f5f4ed; /* primary body text, labels */
  --neutral-800: #f5f4ed; /* headings */
  --neutral-900: #fafaf6; /* strongest text, page titles */

  /* Lighter than Glacier's #3B8EC2, which is 3.7:1 as text on a dark card.
     #6AADDB is 5.4:1 there; buttons use --fill-accent below. */
  --ptag-blue: #6AADDB;
  --ptag-blue-dark: #195171;
  --ptag-blue-light: #1C2D3D;
  --ptag-blue-50: #1A2533;
  --ptag-blue-700: #2E7AAD;
  --ptag-green: #5AAE48;
  --ptag-green-dark: #3F832F;
  --ptag-green-light: #1C2D1A;
  --ptag-green-50: #1A261A;

  --status-success: #5AAE48;
  --status-warning: #F0A030;
  --status-danger: #EE7A7A;
  --status-info: #6AADDB;
  --status-neutral: #a8a59a;

  /* Badge fills are re-derived rather than inherited: the light-mode tints are
     near-white and would blow out on a dark surface. */
  --status-success-bg: var(--ptag-green-light);
  --status-success-fg: var(--status-success);
  --status-warning-bg: #3A2A12;
  --status-warning-fg: var(--status-warning);
  --status-danger-bg: #3A1D1B;
  --status-danger-fg: var(--status-danger);
  --status-info-bg: var(--ptag-blue-light);
  --status-info-fg: var(--status-info);
  --status-neutral-bg: var(--neutral-100);
  --status-neutral-fg: var(--neutral-600);

  /* White text needs a darker fill than the text colours above. */
  --fill-accent: #2A72A3;
  --fill-danger: #C4362A;
  --fill-danger-hover: #A12E22;
  --fill-success: #3F832F;

  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.4), 0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.5);
  --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.6);
  --shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.7);
}

/* --- Base --------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* `hidden` must win over any component's `display`. The browser's own rule
   loses to a class that sets `display: flex` -- which is how the mapping form's
   folder fields stayed visible for an FM target after Stimulus hid them. */
[hidden] {
  display: none !important;
}

html {
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
  /* Expanding a detail row makes the page tall enough to need a scrollbar; a
     stable gutter stops the layout jumping sideways when it appears. */
  scrollbar-gutter: stable;
}

body {
  margin: 0;
  color: var(--text-secondary);
  background: var(--surface-secondary);
  font-family: var(--font-sans);
  font-size: var(--text-body);
  line-height: 1.5;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  color: var(--text-heading);
  line-height: 1.25;
}

h1 { font-size: var(--text-h1); font-weight: 700; line-height: 1.2; }
h2 { font-size: var(--text-h2); font-weight: 600; }
h3 { font-size: var(--text-h3); font-weight: 600; line-height: 1.3; }
h4 { font-size: var(--text-h4); font-weight: 600; line-height: 1.4; }

p { margin: 0; }

a {
  color: var(--ptag-blue);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

code,
pre,
kbd {
  font-family: var(--font-mono);
}

/* Glacier accessibility: 2px ring in PTAG blue, 2px offset, on everything
   interactive. Stated once here so no component has to restate it. */
:focus-visible {
  outline: 2px solid var(--ptag-blue);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* Reachable by keyboard, invisible until focused. The shell's first element,
   so a keyboard user can pass the rail. */
.skip-link {
  position: absolute;
  left: var(--space-4);
  top: var(--space-2);
  z-index: var(--z-command-palette);
  padding: var(--space-2) var(--space-4);
  background: var(--fill-accent);
  color: #fff;
  font-size: var(--text-body-sm);
  font-weight: 600;
  border-radius: var(--radius-sm);
  transform: translateY(-200%);
  transition: transform var(--transition-fast);
}

.skip-link:focus-visible {
  transform: translateY(0);
  text-decoration: none;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}

/* No-JavaScript dark mode. Scoped to a root that carries no explicit choice,
   so it can never override the toggle. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    color-scheme: dark;

  /* The lightened brand blue, at a higher alpha: Glacier asks for a stronger
     ring in dark mode because a 20% wash disappears on a dark surface. */
  --focus-ring: 0 0 0 3px rgba(59, 142, 194, 0.3);
  --focus-ring-danger: 0 0 0 3px rgba(224, 80, 80, 0.35);

    --neutral-0: #30302e;
    --neutral-50: #1f1e1d;
    --neutral-100: #3d3d3a;
    --neutral-200: #3d3d3a;
    --neutral-300: #3d3d3a;
    --neutral-400: #a8a59a;
    --neutral-500: #a8a59a;
    --neutral-600: #d4d2c7;
    --neutral-700: #f5f4ed;
    --neutral-800: #f5f4ed;
    --neutral-900: #fafaf6;

    /* Lighter than Glacier's #3B8EC2, which is 3.7:1 as text on a dark card.
       #6AADDB is 5.4:1 there; buttons use --fill-accent below. */
    --ptag-blue: #6AADDB;
    --ptag-blue-dark: #195171;
    --ptag-blue-light: #1C2D3D;
    --ptag-blue-50: #1A2533;
    --ptag-blue-700: #2E7AAD;
    --ptag-green: #5AAE48;
    --ptag-green-dark: #3F832F;
    --ptag-green-light: #1C2D1A;
    --ptag-green-50: #1A261A;

    --status-success: #5AAE48;
    --status-warning: #F0A030;
    --status-danger: #EE7A7A;
    --status-info: #6AADDB;
    --status-neutral: #a8a59a;

    --status-success-bg: var(--ptag-green-light);
    --status-success-fg: var(--status-success);
    --status-warning-bg: #3A2A12;
    --status-warning-fg: var(--status-warning);
    --status-danger-bg: #3A1D1B;
    --status-danger-fg: var(--status-danger);
    --status-info-bg: var(--ptag-blue-light);
    --status-info-fg: var(--status-info);
    --status-neutral-bg: var(--neutral-100);
    --status-neutral-fg: var(--neutral-600);

    /* White text needs a darker fill than the text colours above. */
    --fill-accent: #2A72A3;
    --fill-danger: #C4362A;
    --fill-danger-hover: #A12E22;
    --fill-success: #3F832F;

    --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.3);
    --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.4), 0 1px 2px rgba(0, 0, 0, 0.3);
    --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.5);
    --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.6);
    --shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.7);
  }
}

/* --- touch targets -------------------------------------------------------
 *
 * Glacier 12 requires a minimum 44x44px touch target on mobile. Its component
 * specs are written for the desktop pointer and are smaller than that by
 * design -- the button ladder is 32/40/48 (9.1), the header actions are 40px
 * (9.5), the avatar is 32px (15) -- so on a phone every one of them is under
 * the floor its own accessibility section sets.
 *
 * That tension is the spec's, not this app's, and it is resolved the way the
 * spec's own mobile note implies ("right zone items collapse", "logo may
 * shrink"): the desktop ladder is left exactly as written, and the floor is
 * applied only where the pointer is actually a finger. Nothing here changes a
 * single pixel above 767px.
 *
 * Height only, not width: a 44px-wide "Edit" link would push a row's action
 * column out of proportion, and the WCAG target is the hit area, which
 * padding on a full-height control already gives. Square controls -- the icon
 * buttons and the avatar -- get both.
 */
@media (max-width: 767px) {
  .button,
  .button--sm,
  .dashboard__clear,
  .pagination__link,
  .skip-link,
  .dashboard__detail-row summary {
    min-height: 44px;
  }

  /* Links that stand alone as controls -- "Forgot password?", "Resend unlock
     instructions" -- rather than sitting inside a sentence. Inline, they were
     18px tall: the line box, not a target. A link inside a sentence ("Already
     have an account? Log in", a hint's "Refresh the list") is exempt under
     WCAG 2.5.8 and keeps the sentence's line height. */
  .auth__link--standalone,
  .form__label-row .form__label-link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }

  /* Glacier 9.2 puts inputs at 40px to match the default button. A field is a
     touch target like any other, so it takes the same floor here -- and the
     reveal toggle that sits inside the password field has to grow with it or
     it stays a 23px tap area inside a 44px control. */
  .form__input,
  .form__reveal,
  .dashboard__filters input,
  .dashboard__filters select,
  .rules__form-table input,
  .rules__form-table select,
  .form--mapping input,
  .form--mapping select,
  .form--schedule input,
  .form--schedule select,
  .form--rules input,
  .form--rules select {
    min-height: 44px;
  }

  .ptag-header__action,
  .ptag-header__avatar,
  .ptag-header__brand,
  .dashboard__action,
  .button--icon {
    min-width: 44px;
    min-height: 44px;
  }

  /* The icon links in a table's action column are inline by default, which
     ignores a min-height. */
  .dashboard__action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
}
