/* Phronon Design System — shared tokens + footer/navbar components.
 * Harmonization J1/J3/P3.
 *
 * SAFE TO DROP INTO ANY TOOL: this file only defines :root custom
 * properties (which do nothing unless referenced) and component classes
 * prefixed with .ph-* (which only affect elements that opt in). It does
 * NOT restyle bare html/body/a/button, so existing layouts are untouched.
 *
 * ONE DELIBERATE EXCEPTION, added 20 August 2026 (FL-036): the `[hidden]`
 * rule below. It is bare, and it carries `!important`, which is exactly what
 * this header otherwise forbids — so the reason has to be good. It is: any
 * author rule that sets `display` beats the user agent's
 * `[hidden] { display: none }`, specificity never enters into it, and a rule
 * as ordinary as `.btn { display: inline-flex }` is enough. Whiteout's group
 * board showed five buttons at once, every one of them carrying `hidden`, and
 * the state machine above them had been switching a flag nothing read. This
 * does not impose a house style on anything: it affects only elements the
 * markup or a script has ALREADY declared hidden, and it restores what the
 * browser was going to do before this fleet's own stylesheets overrode it.
 *
 * Source of truth: phronon_common/design-tokens.css
 * Deployed copy: each tool's static/css/phronon-tokens.css
 */

/* An element declared hidden is hidden — not a styling question. */
[hidden] { display: none !important; }

:root {
  /* Brand colors */
  /* ONE navy fleet-wide (owner, 13 August 2026): the educator navbar and the
     e-mail shell header now use the SAME #0F1B2D as phronon.org's site header
     (Phronon/static/css/site.css --navy). There were two navies before —
     #1e3a5f here and #0F1B2D on the public site — which is two ways of saying
     "this is the same operator" that disagreed with each other. */
  --ph-color-educator: #0F1B2D;   /* educator navbar — matches phronon.org */
  --ph-color-admin: #8b0000;      /* admin navbar */
  --ph-color-secondary: #2d5a8c;
  --ph-color-success: #28a745;
  --ph-color-danger: #dc3545;
  --ph-color-warning: #ffc107;
  --ph-color-light: #f8f9fa;
  --ph-color-border: #dee2e6;
  --ph-color-text: #333;
  --ph-color-text-light: #666;

  /* Typography */
  --ph-font-serif: "Source Serif 4", Georgia, serif;
  --ph-font-sans: "Source Sans 3", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --ph-font-mono: "Courier New", monospace;
  --ph-font-size-sm: 0.875rem;
  --ph-font-size-xs: 0.75rem;
  --ph-font-size-lg: 1.125rem;

  /* Spacing — 8px scale */
  --ph-space-xs: 0.25rem;
  --ph-space-sm: 0.5rem;
  --ph-space-md: 1rem;
  --ph-space-lg: 1.5rem;
  --ph-space-xl: 2rem;
  --ph-space-2xl: 3rem;

  /* Layout */
  --ph-container-max-width: 1200px;
  --ph-border-radius: 4px;
  --ph-transition: all 0.2s ease-in-out;
}

/* ── Shared footer ────────────────────────────────────────────────
 * Markup (Drawbridge-style, no year):
 *   <footer class="ph-footer">
 *     <nav class="ph-footer__legal" aria-label="Legal">
 *       <a href="/imprint">Imprint</a><span aria-hidden="true">·</span>
 *       <a href="/imprint#privacy">Privacy Policy</a><span aria-hidden="true">·</span>
 *       <a href="/imprint#cookies">Cookie Policy</a>
 *     </nav>
 *     <p class="ph-footer__meta">Part of <a href="https://phronon.org">Phronon</a>
 *        — online tools for practical judgment</p>
 *   </footer>
 */
/* The footer sits at the bottom of the VIEWPORT when the page is shorter
 * than the screen, and after the content when it is longer (owner,
 * 27 August 2026: after short content — a join step, a login, a thank-you —
 * the footer used to hang mid-screen and the page looked unfinished).
 * Scoped with :has to pages whose <body> directly contains this footer, so
 * markup without one is untouched; inside that scope the fixed 3rem gap
 * becomes an auto margin — on a short page it grows to push the footer down,
 * on a long page it collapses to zero and the footer's own border and
 * padding do the separating. Tools that already lay <body> out as a flex
 * column (CG, Moral Mirror, the entrances) declare the same thing twice,
 * which is the compatible direction. */
body:has(> .ph-footer) {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}
body:has(> .ph-footer) > .ph-footer { margin-top: auto; }

.ph-footer {
  margin-top: var(--ph-space-2xl, 3rem);
  padding: var(--ph-space-xl, 2rem) var(--ph-space-md, 1rem);
  border-top: 1px solid var(--ph-color-border, #dee2e6);
  background: var(--ph-color-light, #f8f9fa);
  font-size: var(--ph-font-size-sm, 0.875rem);
  text-align: center;
  color: var(--ph-color-text-light, #666);
}
.ph-footer__legal {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: var(--ph-space-sm, 0.5rem);
  flex-wrap: wrap;
  margin-bottom: var(--ph-space-md, 1rem);
}
.ph-footer__legal a,
.ph-footer__meta a {
  color: var(--ph-color-text-light, #666);
}
.ph-footer__meta a { text-decoration: underline; }
.ph-footer__legal a:hover,
.ph-footer__meta a:hover { color: var(--ph-color-educator, #0F1B2D); }
.ph-footer__meta {
  margin: var(--ph-space-sm, 0.5rem) 0;
  line-height: 1.5;
}

/* ── Shared backoffice navbar ─────────────────────────────────────
 * Opt-in class layer for tool navbars. Each tool keeps its own links;
 * these classes only standardize the look (navy bg, height, active
 * underline, user section). Add .ph-bo-nav--admin for the admin red.
 */
.ph-bo-nav {
  background: var(--ph-color-educator, #0F1B2D);
  color: #fff;
  padding: 0 var(--ph-space-md, 1rem);
  border-bottom: 3px solid var(--ph-color-secondary, #2d5a8c);
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.ph-bo-nav--admin {
  background: var(--ph-color-admin, #8b0000);
  border-bottom-color: #a00000;
}
.ph-bo-nav__container {
  max-width: var(--ph-container-max-width, 1200px);
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: var(--ph-space-lg, 1.5rem);
  min-height: 64px;
}
.ph-bo-nav__brand {
  display: inline-flex;
  align-items: center;
  gap: var(--ph-space-sm, 0.5rem);
  color: #fff;
  font-weight: 700;
  font-size: var(--ph-font-size-lg, 1.125rem);
  text-decoration: none;
  flex-shrink: 0;
}
.ph-bo-nav__brand:hover { opacity: 0.9; }
.ph-bo-nav__icon { width: 28px; height: 28px; }
.ph-bo-nav__links {
  display: flex;
  gap: var(--ph-space-lg, 1.5rem);
  flex: 1;
  overflow-x: auto;
  white-space: nowrap;
}
.ph-bo-nav__link {
  color: rgba(255,255,255,0.9);
  padding: var(--ph-space-sm, 0.5rem) 0;
  border-bottom: 3px solid transparent;
  transition: var(--ph-transition, all .2s ease-in-out);
  text-decoration: none;
}
.ph-bo-nav__link:hover { color: #fff; }
.ph-bo-nav__link--active {
  color: #fff;
  border-bottom-color: #fff;
  font-weight: 500;
}
.ph-bo-nav__user {
  display: flex;
  align-items: center;
  gap: var(--ph-space-md, 1rem);
  flex-shrink: 0;
  margin-left: auto;
}
.ph-bo-nav__user-email {
  font-size: var(--ph-font-size-sm, 0.875rem);
  color: rgba(255,255,255,0.9);
}
.ph-bo-nav__badge {
  background: rgba(255,255,255,0.2);
  padding: 2px var(--ph-space-sm, 0.5rem);
  border-radius: var(--ph-border-radius, 4px);
  font-size: var(--ph-font-size-xs, 0.75rem);
  font-weight: 700;
}
.ph-bo-nav__logout {
  background: rgba(255,255,255,0.2);
  color: #fff;
  border: 1px solid rgba(255,255,255,0.4);
  padding: var(--ph-space-sm, 0.5rem) var(--ph-space-md, 1rem);
  border-radius: var(--ph-border-radius, 4px);
  font-size: var(--ph-font-size-sm, 0.875rem);
  cursor: pointer;
  transition: var(--ph-transition, all .2s ease-in-out);
}
.ph-bo-nav__logout:hover {
  background: rgba(255,255,255,0.3);
  border-color: rgba(255,255,255,0.6);
}

@media (max-width: 768px) {
  .ph-bo-nav__container { flex-wrap: wrap; min-height: 0; padding: var(--ph-space-md, 1rem) 0; }
  .ph-bo-nav__links { width: 100%; order: 3; }
  .ph-bo-nav__user { margin-left: 0; }
}


/* ---- Brand webfonts (P3) — self-hosted Source Serif 4 + Source Sans 3 ---- */
/* Added June 14, 2026. Files in /static/vendor/fonts/. The --ph-font-* vars above now resolve. */
@font-face {
  font-family: "Source Serif 4";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/static/vendor/fonts/SourceSerif4-400-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Source Serif 4";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/static/vendor/fonts/SourceSerif4-400-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Source Serif 4";
  font-style: normal;
  font-weight: 600; /* Semibold — the Phronon wordmark weight */
  font-display: swap;
  src: url("/static/vendor/fonts/SourceSerif4-600-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Source Serif 4";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/static/vendor/fonts/SourceSerif4-600-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Source Serif 4";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/static/vendor/fonts/SourceSerif4-700-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Source Serif 4";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/static/vendor/fonts/SourceSerif4-700-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---------- Source Sans 3 — tagline, body, UI, buttons ---------- */
@font-face {
  font-family: "Source Sans 3";
  font-style: normal;
  font-weight: 400; /* Regular — the tagline / body weight */
  font-display: swap;
  src: url("/static/vendor/fonts/SourceSans3-400-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Source Sans 3";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/static/vendor/fonts/SourceSans3-400-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Source Sans 3";
  font-style: normal;
  font-weight: 600; /* Semibold — buttons, emphasis */
  font-display: swap;
  src: url("/static/vendor/fonts/SourceSans3-600-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Source Sans 3";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/static/vendor/fonts/SourceSans3-600-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---------- Convenience custom properties + fallbacks ---------- */

/* ── Skip link — WCAG 2.4.1 Bypass Blocks ────────────────────────────────────
   Lets a keyboard user jump straight past the header/nav to the main content
   instead of tabbing through it on every page.
   It must stay in the tab order, so it is visually clipped rather than hidden
   with display:none or visibility:hidden — either of those would remove it from
   the tab order entirely and defeat the purpose. It becomes visible on :focus.
   Do NOT hide it with a physical off-screen offset (left: -9999px): under
   direction: rtl the browser counts those pixels as real scrollable overflow,
   and every page in an RTL locale opens on empty ground beside its own content
   (measured in Layoff's Arabic locale before its copy was fixed). Clipping
   keeps the link in the tab order without occupying space in either direction. */
.skip-link {
  position: absolute;
  top: 0;
  inset-inline-start: 0;
  z-index: 2000;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  background: #041A36;
  color: #fff;
  font-weight: 600;
  text-decoration: none;
  border-radius: 0 0 4px 0;
}
.skip-link:focus {
  width: auto;
  height: auto;
  padding: 0.625rem 1rem;
  overflow: visible;
  clip-path: none;
  outline: 3px solid #ffbf47;
  outline-offset: 0;
}

/* ── Accessible ranking controls — WCAG 2.5.7 / 2.1.1 / 2.5.8 ───────────────
   Move up/down buttons that give drag-and-drop ranking lists a single-pointer
   and keyboard alternative (see phronon_common/rank-a11y.js for why a keyboard
   shortcut alone does not satisfy 2.5.7).
   Sized 32×32 — comfortably above the 24×24 CSS-pixel minimum of 2.5.8 Target
   Size (Minimum), which is also new in WCAG 2.2. */
.rank-a11y-controls {
  display: inline-flex;
  gap: 4px;
  margin-left: auto;
  padding-left: 0.5rem;
  flex: 0 0 auto;
  align-self: center;
}
.rank-a11y-btn {
  width: 32px;
  height: 32px;
  min-width: 32px;
  min-height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  font-size: 0.75rem;
  line-height: 1;
  cursor: pointer;
  color: #041A36;
  background: #fff;
  border: 1.5px solid #b9c2cf;
  border-radius: 5px;
  /* The row itself is often draggable; make sure a press on the button is
     treated as a click and never begins a drag gesture. */
  touch-action: manipulation;
}
.rank-a11y-btn:hover:not(:disabled) { background: #eef2f7; border-color: #041A36; }
.rank-a11y-btn:focus-visible {
  outline: 3px solid #ffbf47;   /* 2.4.7 visible focus, high contrast on both themes */
  outline-offset: 1px;
}
.rank-a11y-btn:disabled { opacity: 0.35; cursor: default; }


/* Reduced motion (WCAG 2.3.3): when the OS asks for less movement, collapse
 * every animation and transition to effectively zero. Declared centrally so
 * the accessibility statement's claim holds on every page that loads this
 * sheet — a per-page opt-in would drift. */
@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;
  }
}


/* ── Chart tokens (FL-027, 25 August 2026) ─────────────────────────────────
 * The fleet chart palette, read by the shared SVG chart engine
 * (svg-charts.js) with these exact values as fallbacks — so changing a value
 * HERE changes it everywhere the token sheet is loaded, and a tool without
 * the sheet (Layoff) still draws correctly. Validated pairs and thresholds:
 * server-ops/CHART-STANDARD.md; the gate: server-ops/chart_palette_check.py.
 * Never carry meaning by colour alone — direction, shape and text say it
 * again. */
:root {
  --chart-ink:     #171717;   /* names, printed values */
  --chart-muted:   #666666;   /* axis labels, context marks, ties */
  --chart-range:   #d4d4d4;   /* spread tracks, context lines */
  --chart-grid:    #ececec;   /* hairline gridlines */
  --chart-better:  #2a78d6;   /* the diverging pair: improvement… */
  --chart-worse:   #c0392b;   /* …and decline (ΔE 26.1 under deuteranopia) */
  --chart-surface: #ffffff;   /* mark rings, text on dark fills */
  /* The categorical "agreement family" (Whiteout 04-GR1): three greens told
   * apart by lightness plus red and amber for the two kinds of "no plan".
   * Worst adjacent pair ΔE 15.5 normal / 14.1 CVD (validated 25 Aug 2026). */
  --chart-good-1:  #166b34;
  --chart-good-2:  #44a05b;
  --chart-good-3:  #93cb7c;
  --chart-warn:    #eda100;
  /* Signed effects read "up = good" in green by long convention (owner,
     25 August 2026). The blue/red diverging pair stays the default because
     it survives colour-blind vision at any lightness; THIS green is safe
     against --chart-worse only because the two differ strongly in
     lightness (measured: ΔE 71 under deuteranopia, 51 under protanopia),
     and it is only ever used where the sign and the side of the zero line
     say the same thing. chart_palette_check.py holds that measurement. */
  --chart-up:      #2e9e4f;
}
