/* Urban Blue — viewing modes for the prototype screens.
 *
 * Day is :root. Sunlight and Night override the SAME token names, scoped to an
 * attribute on <html>, so a screen that reads tokens gets all three modes free.
 *   <html data-ub-mode="sunlight">   <html data-ub-mode="night">
 *
 * Ambient light decides the mode. Dark mode is NOT the answer to sunlight — in
 * direct sun, reflected glare lands on near-black pixels and swallows the
 * low-contrast greys used for labels. The glasshouse mode is therefore light and
 * loud; the dark mode is scoped to dim environments.
 *
 * Canonical source: design-tokens.json → handover/theme/design-tokens.css.
 */

/* Cross-document navigation: killing the black flash between pages.
 *
 * Between documents the browser paints its OWN canvas before any of the next
 * page's CSS applies. `color-scheme` is the only thing that reaches that moment,
 * so it must be declared for Day too — not just Night — and the root element has
 * to carry the app background, because a colour set only on <body> leaves the
 * canvas unpainted during the swap.
 *
 * Deliberately NOT using `@view-transition { navigation: auto }` here. It is the
 * obvious way to crossfade between documents, but a page embedded in an iframe
 * cannot run a cross-document transition: the browser starts one, skips it, and
 * the internal rejection surfaces as an uncaught "Transition was skipped" on
 * EVERY load. A crossfade is not worth a console error on every screen. Enable it
 * in the Angular app, where pages are top-level documents — see
 * docs/VIEWING-MODES.md. */

html {
  color-scheme: light;
  background: var(--ub-surface-app-bg);
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
}

:root {
  --ub-text-scale: 1;
  /* surfaces */
  --ub-surface-base: #ffffff;
  --ub-surface-subtle: #fafcfd;
  --ub-surface-sunken: #f7fafc;
  --ub-surface-band: #f2f6f9;
  --ub-surface-chip: #eef3f7;
  --ub-surface-hover: #f5f8fa;
  --ub-surface-app-bg: #eef3f7;
  --ub-surface-track: #e3eaf0;
  --ub-surface-track-off: #d3dce4;

  /* text */
  --ub-text-heading: #17233d;
  --ub-text-default: #0d2740;
  --ub-text-muted: #5b7186;
  --ub-text-soft: #8aa0b0;
  --ub-text-faint: #9db0bf;
  --ub-text-ghost: #a9b7c3;
  --ub-text-disabled: #c3ceda;

  /* accent — navy chrome. Only ever another colour when tied to a value. */
  --ub-accent-default: #17233d;
  --ub-accent-hover: #1f396a;
  --ub-accent-on-accent: #ffffff;

  /* borders */
  --ub-border-card: rgba(23, 35, 61, .28);
  --ub-border-hair: rgba(13, 39, 64, .08);
  --ub-border-row: rgba(13, 39, 64, .06);
  --ub-border-control: rgba(13, 39, 64, .14);
  --ub-border-soft: rgba(13, 39, 64, .09);

  /* fields — the warm "this is editable" signal */
  --ub-field-background: #fffbeb;
  --ub-field-border: rgba(202, 138, 4, .34);
  --ub-field-focus-border: #ca8a04;
  --ub-field-focus-ring: rgba(202, 138, 4, .18);
  --ub-field-placeholder: #a9b7c3;

  /* wizard step dot */
  --ub-stepdot-active-background: #fffbeb;
  --ub-stepdot-active-ring: #ca8a04;
  --ub-stepdot-active-ring-ahead: rgba(202, 138, 4, .45);
  --ub-stepdot-active-color: #8a6100;
  --ub-stepdot-done-background: #1f8a54;
  --ub-stepdot-done-color: #ffffff;
  --ub-stepdot-upcoming-background: #e3eaf0;
  --ub-stepdot-upcoming-color: #8aa0b0;

  /* status */
  --ub-status-success-solid: #1f8a54;
  --ub-status-success-bg: #e3f4ea;
  --ub-status-success-text: #1f7a45;
  --ub-status-warning-solid: #d99014;
  --ub-status-warning-bg: #fff4e0;
  --ub-status-warning-text: #8a5a06;
  --ub-status-danger-solid: #e0491f;
  --ub-status-danger-bg: #fdeeea;
  --ub-status-danger-text: #b94a48;
  --ub-status-info-solid: #17c8ec;
  --ub-status-info-bg: #e9f3f7;
  --ub-status-info-text: #0f7c98;
  --ub-status-neutral-solid: #c3ceda;
  --ub-status-neutral-bg: #eef3f7;
  --ub-status-neutral-text: #5b7186;

  /* brand pinwheel — semantic, never decorative */
  --ub-pinwheel-auto-mode: #3cbee3;
  --ub-pinwheel-watchlist: #5eb887;
  --ub-pinwheel-attention: #eb5c32;
  --ub-pinwheel-human: #514b9a;
  --ub-brand-purple: #6241d9;
  --ub-brand-purple-bg: #f0edfb;
  --ub-brand-teal: #0f7c98;
  --ub-brand-cyan-soft: #8fd9ea;

  /* Data Qi flags */
  --ub-flag-excellent: #0ea5e9;
  --ub-flag-good: #10b981;
  --ub-flag-acceptable: #8b5cf6;
  --ub-flag-unacceptable: #ef4444;

  /* chrome pieces that need their own token to survive all three modes */
  --ub-chrome-tile-border: rgba(23, 35, 61, .16);
  /* An idle mode dot is UNFILLED — a filled dot means activated, and that signal
     outranks contrast. So it sits at the card colour and the icon carries the
     contrast instead, using whichever supplied variant suits the ground. */
  --ub-chrome-dot-idle: #fafcfd;
  /* Inactive dial track. Its own token because it is a 10px stroke on a card, not a
     surface fill — it has to stay visible without reading as a filled/active arc. */
  --ub-chrome-dial-track: #eef3f7;
  /* Ground for a Tier-3 device-model tile. Its own token, dark in ALL three modes,
     because the artwork is pure white and must never be recoloured — and the accent
     cannot serve here: it is deliberately light in Night so it can read as an accent. */
  --ub-chrome-icon-tile: #17233d;
  --ub-chrome-icon-tile-ring: transparent;
  /* Ink on a saturated status/state fill. White in ALL modes — the fill is a brand or
     status colour, not a surface, so this must not follow the surface ramp. */
  --ub-chrome-on-solid: #ffffff;
  /* Fill variants of the switch state colours. Separate from the state colour itself
     because a colour tuned to read as a STROKE on a dark ground is too light to sit
     behind a white label — the same split as --ub-status-*-solid vs -text. */
  --ub-state-on-fill: var(--ub-brand-purple);
  /* Deeper than --ub-flag-unacceptable: as a FILL it carries a white label, where the
     flag red only reaches 3.76:1. The flag colour itself is unchanged. */
  --ub-state-off-fill: #d92d2d;
  --ub-state-auto-fill: var(--ub-accent-hover);

  /* An overlay pill sits on a solid dark plate (block timer, info flags, countdowns).
     Both are solids, not surfaces, so neither follows the mode ramp. */
  --ub-chrome-plate: rgba(13, 39, 64, .92);
  --ub-chrome-on-plate: #ffffff;
  --ub-chrome-metric-color: #17233d;
  --ub-chrome-badge-bg: #17c8ec;
  --ub-chrome-badge-fg: #17233d;
  --ub-chrome-chart-stroke: 2;
  --ub-chrome-grid-line: rgba(13, 39, 64, .07);

  /* type scale — Sunlight steps every role up one size and one weight */
  --ub-size-fs0: 10px;
  --ub-size-fs1: 11px;
  --ub-size-fs2: 12px;
  --ub-size-fs3: 13px;
  --ub-size-fs-lead: 14px;
  --ub-size-fs-section: 17px;
  --ub-size-fs-metric: 22px;
  --ub-weight-fw-body: 400;
  --ub-weight-fw-cell: 600;

  /* controls */
  --ub-metric-control-height: 42px;
  --ub-metric-control-height-sm: 36px;
  --ub-metric-control-height-xs: 32px;
  --ub-metric-icon-button: 30px;

  /* shadows */
  --ub-shadow-popover: 0 18px 40px rgba(0, 0, 0, .18);
  --ub-shadow-modal: 0 26px 60px rgba(13, 39, 64, .30);
  --ub-shadow-tooltip: 0 14px 32px rgba(0, 20, 40, .30);
  --ub-shadow-knob: 0 1px 3px rgba(13, 39, 64, .30);
}

/* ==== SUNLIGHT — above ~10'000 lux ==================================
 * Glasshouse, outdoors, direct sun. High-contrast LIGHT: white grounds so the
 * panel emits rather than reflects, every muted grey pushed darker, type one
 * step up and one weight heavier, 48px controls for gloved hands.
 * Strokes stay 1px — separation comes from contrast, not weight.
 * ==================================================================== */
[data-ub-mode='sunlight'] {
  color-scheme: light;

  --ub-surface-base: #ffffff;
  --ub-surface-subtle: #ffffff;
  --ub-surface-sunken: #ffffff;
  --ub-surface-band: #eaf0f5;
  --ub-surface-chip: #dae4ec;
  --ub-surface-hover: #f0f5f9;
  --ub-surface-app-bg: #ffffff;
  --ub-surface-track: #c6d4df;
  --ub-surface-track-off: #b3c4d1;

  --ub-text-heading: #000a14;
  --ub-text-default: #000a14;
  --ub-text-muted: #22364a;
  --ub-text-soft: #33506a;
  --ub-text-faint: #33506a;
  --ub-text-ghost: #5b7186;
  --ub-text-disabled: #7d93a7;

  --ub-accent-default: #0b1526;
  --ub-accent-hover: #17233d;
  --ub-accent-on-accent: #ffffff;

  --ub-border-card: rgba(0, 10, 20, .62);
  --ub-border-hair: rgba(0, 10, 20, .22);
  --ub-border-row: rgba(0, 10, 20, .18);
  --ub-border-control: rgba(0, 10, 20, .40);
  --ub-border-soft: rgba(0, 10, 20, .22);

  --ub-field-background: #fff3c9;
  --ub-field-border: #7a5400;
  --ub-field-focus-border: #5c3f00;
  --ub-field-focus-ring: rgba(122, 84, 0, .28);
  --ub-field-placeholder: #5b4a1e;

  --ub-stepdot-active-background: #fff3c9;
  --ub-stepdot-active-ring: #7a5400;
  --ub-stepdot-active-ring-ahead: rgba(122, 84, 0, .65);
  --ub-stepdot-active-color: #4a3200;
  --ub-stepdot-done-background: #0f6b3d;
  --ub-stepdot-done-color: #ffffff;
  --ub-stepdot-upcoming-background: #dae4ec;
  --ub-stepdot-upcoming-color: #33506a;

  --ub-status-success-solid: #0f6b3d;
  --ub-status-success-bg: #d1efdc;
  --ub-status-success-text: #0a4a29;
  --ub-status-warning-solid: #8a5a06;
  --ub-status-warning-bg: #ffeec0;
  --ub-status-warning-text: #5f3d03;
  --ub-status-danger-solid: #b32d0a;
  --ub-status-danger-bg: #ffdcd2;
  --ub-status-danger-text: #851f06;
  --ub-status-info-solid: #0b5f75;
  --ub-status-info-bg: #d2e9f1;
  --ub-status-info-text: #07404f;
  --ub-status-neutral-solid: #5b7186;
  --ub-status-neutral-bg: #dae4ec;
  --ub-status-neutral-text: #22364a;

  --ub-pinwheel-auto-mode: #0f7fa3;
  --ub-pinwheel-watchlist: #1f7a4e;
  --ub-pinwheel-attention: #bf3510;
  --ub-pinwheel-human: #3b3479;
  --ub-brand-purple: #43299e;
  --ub-brand-purple-bg: #e4defa;
  --ub-brand-teal: #07404f;
  --ub-brand-cyan-soft: #4a9cb8;

  --ub-flag-excellent: #05628f;
  --ub-flag-good: #0a6b4c;
  --ub-flag-acceptable: #5b2ca8;
  --ub-flag-unacceptable: #b01b1b;

  --ub-chrome-tile-border: rgba(0, 10, 20, .50);
  /* Still unfilled — Sunlight gets its contrast from the dark -blue icon variant,
     not from filling the dot, which would read as activated. */
  --ub-chrome-dot-idle: #ffffff;
  --ub-chrome-dial-track: #c6d4df;
  --ub-chrome-icon-tile: #0b1526;
  --ub-chrome-icon-tile-ring: transparent;
  --ub-state-on-fill: var(--ub-brand-purple);
  --ub-state-off-fill: #a01414;
  --ub-state-auto-fill: var(--ub-accent-hover);
  --ub-chrome-plate: rgba(0, 10, 20, .95);
  --ub-chrome-on-plate: #ffffff;
  --ub-chrome-metric-color: #0b1526;
  --ub-chrome-badge-bg: #0b5f75;
  --ub-chrome-badge-fg: #ffffff;
  --ub-chrome-chart-stroke: 2.6;
  --ub-chrome-grid-line: rgba(0, 10, 20, .16);

  --ub-size-fs0: 11px;
  --ub-size-fs1: 12px;
  --ub-size-fs2: 13px;
  --ub-size-fs3: 14px;
  --ub-size-fs-lead: 15px;
  --ub-size-fs-section: 18px;
  --ub-size-fs-metric: 24px;
  --ub-weight-fw-body: 600;
  --ub-weight-fw-cell: 700;

  --ub-metric-control-height: 48px;
  --ub-metric-control-height-sm: 42px;
  --ub-metric-control-height-xs: 36px;
  --ub-metric-icon-button: 34px;

  --ub-shadow-popover: 0 18px 40px rgba(0, 10, 20, .30);
  --ub-shadow-modal: 0 26px 60px rgba(0, 10, 20, .40);
  --ub-shadow-tooltip: 0 14px 32px rgba(0, 10, 20, .38);
}

/* ==== NIGHT — below ~50 lux =========================================
 * Night rounds, dim control room, phone after dark. Surfaces lift off the
 * background rather than dropping shadows; text is never pure white.
 *
 * One brand exception, needs sign-off: #17233d is invisible on a dark ground,
 * so the accent rises to the same brand-blue hue at a lightness that clears
 * the surface (#6d97d8, 5.60:1). The warm "editable" field language survives
 * as a dark amber with the same gold border.
 * ==================================================================== */
[data-ub-mode='night'] {
  color-scheme: dark;

  --ub-surface-base: #131f2e;
  --ub-surface-subtle: #0f1926;
  --ub-surface-sunken: #0f1926;
  --ub-surface-band: #1a2634;
  --ub-surface-chip: #1e2c3c;
  --ub-surface-hover: #1a2634;
  --ub-surface-app-bg: #08111c;
  --ub-surface-track: #1e2c3c;
  --ub-surface-track-off: #31445a;

  --ub-text-heading: #eaf1f7;
  --ub-text-default: #eaf1f7;
  --ub-text-muted: #a3b7c8;
  --ub-text-soft: #7d93a7;
  --ub-text-faint: #7d93a7;
  --ub-text-ghost: #63798d;
  --ub-text-disabled: #4d6178;

  --ub-accent-default: #6d97d8;
  --ub-accent-hover: #8fb0e0;
  --ub-accent-on-accent: #08111c;

  --ub-border-card: rgba(255, 255, 255, .17);
  --ub-border-hair: rgba(255, 255, 255, .09);
  --ub-border-row: rgba(255, 255, 255, .07);
  --ub-border-control: rgba(255, 255, 255, .15);
  --ub-border-soft: rgba(255, 255, 255, .10);

  --ub-field-background: #241f10;
  --ub-field-border: rgba(202, 138, 4, .62);
  --ub-field-focus-border: #e0a63c;
  --ub-field-focus-ring: rgba(224, 166, 60, .26);
  --ub-field-placeholder: #9a8a62;

  --ub-stepdot-active-background: #241f10;
  --ub-stepdot-active-ring: #e0a63c;
  --ub-stepdot-active-ring-ahead: rgba(224, 166, 60, .55);
  --ub-stepdot-active-color: #f2d79a;
  --ub-stepdot-done-background: #3fae76;
  --ub-stepdot-done-color: #04220f;
  --ub-stepdot-upcoming-background: #1e2c3c;
  --ub-stepdot-upcoming-color: #7d93a7;

  --ub-status-success-solid: #3fae76;
  --ub-status-success-bg: rgba(78, 201, 138, .15);
  --ub-status-success-text: #6fd9a1;
  --ub-status-warning-solid: #e0a63c;
  --ub-status-warning-bg: rgba(240, 180, 69, .15);
  --ub-status-warning-text: #f4c877;
  --ub-status-danger-solid: #e8613c;
  --ub-status-danger-bg: rgba(255, 122, 85, .15);
  --ub-status-danger-text: #ff9c7e;
  --ub-status-info-solid: #3cd0f0;
  --ub-status-info-bg: rgba(60, 208, 240, .14);
  --ub-status-info-text: #6fdcf3;
  --ub-status-neutral-solid: #3a4d63;
  --ub-status-neutral-bg: #1e2c3c;
  --ub-status-neutral-text: #a3b7c8;

  --ub-pinwheel-auto-mode: #57cdf0;
  --ub-pinwheel-watchlist: #74cf9c;
  --ub-pinwheel-attention: #ff7a52;
  --ub-pinwheel-human: #8b83d6;
  --ub-brand-purple: #9d86ef;
  --ub-brand-purple-bg: rgba(157, 134, 239, .16);
  --ub-brand-teal: #6fdcf3;
  --ub-brand-cyan-soft: #2e6d80;

  --ub-flag-excellent: #4cbdf0;
  --ub-flag-good: #45cd97;
  --ub-flag-acceptable: #a98bf5;
  --ub-flag-unacceptable: #ff6b6b;

  --ub-chrome-tile-border: rgba(255, 255, 255, .15);
  --ub-chrome-dot-idle: #131f2e;
  /* --ub-surface-chip (#1e2c3c) sat only 1.2:1 from the card and read as absent.
     #3d5470 lifts the ring clear of the card while staying well below the mode
     colours, so an empty track still reads as empty. */
  --ub-chrome-dial-track: #3d5470;
  --ub-chrome-icon-tile: #1e2c3c;
  /* On a dark card a dark disc is only 1.17:1 against it and effectively disappears.
     The ground must stay dark for the white artwork, so the disc is defined by a
     hairline ring instead — 1px, a real border, per the stroke rule. */
  --ub-chrome-icon-tile-ring: rgba(255, 255, 255, .40);
  /* Darkened so the white label on an active badge clears 4.5:1. The lighter
     --ub-flag-unacceptable etc. stay as they are for strokes, dots and text. */
  --ub-state-on-fill: #6e5ac4;
  --ub-state-off-fill: #c44343;
  --ub-state-auto-fill: #4a6fa8;
  /* The plate lifts off the dark ground rather than sinking into it, and its ink stays
     white — --ub-accent-on-accent is DARK in Night and was being used here. */
  --ub-chrome-plate: #24354a;
  --ub-chrome-on-plate: #ffffff;
  --ub-chrome-metric-color: #eaf1f7;
  --ub-chrome-badge-bg: #3cd0f0;
  --ub-chrome-badge-fg: #04222b;
  --ub-chrome-chart-stroke: 2.2;
  --ub-chrome-grid-line: rgba(255, 255, 255, .07);

  --ub-shadow-popover: 0 18px 40px rgba(0, 0, 0, .55);
  --ub-shadow-modal: 0 26px 60px rgba(0, 0, 0, .62);
  --ub-shadow-tooltip: 0 14px 32px rgba(0, 0, 0, .55);
  --ub-shadow-knob: 0 1px 3px rgba(0, 0, 0, .5);
}

/* On brand-navy grounds the brand mandates the reversed (white) lock-up. Night makes
   every ground a dark ground, so swap to the reversed asset — never a filter, which
   would recolour the mark.

   ub-logo-lockup-reversed.png is the supplied startup banner with its navy FIELD made
   transparent; the pinwheel, wordmark and tagline are untouched. Transparent rather
   than black on purpose: one asset then sits correctly on the app ground, a card and
   brand navy alike, with no field colour to keep in sync with the tokens. */
[data-ub-mode='night'] img[src*="ub-logo-full"],
[data-ub-mode='night'] img[src*="ub-logo-navy"] { content: url(assets/ub-logo-lockup-reversed.png); }

/* ub-footnote.png is NOT a monochrome glyph — it carries the full four-colour
   pinwheel beside navy text, so `filter: invert()` here recoloured all four semantic
   brand colours. ub-footnote-reversed.png instead maps only the navy ink
   (rgb(22,36,61)) to white and leaves the 1962 pinwheel pixels byte-identical. */
[data-ub-mode='night'] img[src*="ub-footnote"] { content: url(assets/ub-footnote-reversed.png); }

/* Mode marks ship a reversed variant — use the supplied artwork on dark grounds
   rather than filtering it, so the mark itself is never recoloured. */
[data-ub-mode='night'] img[src$="ub-aimo-mode-icon.png"],
[data-ub-mode='night'] img[src$="ub-aimo-mode-icon-gray.png"],
[data-ub-mode='night'] img[src$="ub-aimo-mode-icon-blue.png"] { content: url(assets/ub-aimo-mode-icon-white.png); }
[data-ub-mode='night'] img[src$="ub-schedule-mode-icon-gray.png"],
[data-ub-mode='night'] img[src$="ub-schedule-mode-icon-blue.png"] { content: url(assets/ub-schedule-mode-icon-white.png); }
[data-ub-mode='night'] img[src$="ub-setpoint-mode-icon.png"],
[data-ub-mode='night'] img[src$="ub-setpoint-mode-icon-gray.png"],
[data-ub-mode='night'] img[src$="ub-setpoint-mode-icon-blue.png"] { content: url(assets/ub-setpoint-mode-icon-white.png); }
[data-ub-mode='night'] img[src$="ub-timer-mode-icon.png"],
[data-ub-mode='night'] img[src$="ub-timer-mode-icon-gray.png"],
[data-ub-mode='night'] img[src$="ub-timer-mode-icon-blue.png"] { content: url(assets/ub-timer-mode-icon-white.png); }

/* The SURF wave mark is a monochrome UI glyph, and it sits beside Material Symbol
   icons that track currentColor. Filters cannot follow the text colour, so mask the
   artwork and paint it with currentColor instead — the glyph then behaves exactly
   like the icon next to it, active or muted, in every mode. */
img[src*="surf-wave-icon"] {
  content: "";
  background-color: currentColor;
  -webkit-mask-image: url(assets/surf-wave-icon.png);
  mask-image: url(assets/surf-wave-icon.png);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  filter: none !important;
}
/* These three ARE monochrome UI glyphs — decoded: 100% pure black, zero brand-hue
   pixels — so inverting them is the sanctioned case, and there is no reversed variant
   to swap in. Plain invert(1): hue-rotate does nothing to a grey and only implied that
   a colour was being moved. Never extend this list to an asset carrying brand colour;
   check the pixels first. */
[data-ub-mode='night'] img[src*="smart-action-icon"],
[data-ub-mode='night'] img[src*="aimo-icon"] { filter: invert(1) !important; }

/* Reading-size control (trial): scales chart axis/tick labels and legends across
   screens. Mounted into the same popover as the viewing-mode switch. */
html[data-ub-textsize="md"] { --ub-text-scale: 1.2; }
html[data-ub-textsize="lg"] { --ub-text-scale: 1.4; }

/* Content sitting on a PHOTOGRAPH is not on a surface: it is white in every mode,
   and the assets over it keep their light-ground artwork. Mark that wrapper
   [data-ub-on-photo] and quote literals inside it. */
[data-ub-on-photo] img { content: normal !important; filter: none !important; }

/* A specimen documents a fixed value, so it must not follow the viewing mode —
   a brand swatch that adapts stops documenting the brand and starts documenting
   the mode. Mark those blocks [data-ub-specimen] and quote literals inside them. */
[data-ub-specimen] img { content: normal !important; filter: none !important; }

/* The warm fill is only half the "this is editable" signal — the placeholder
   carries the worked example, so it must stay legible in every mode. */
input::placeholder,
textarea::placeholder { color: var(--ub-field-placeholder); opacity: 1; }

/* Sunlight and Night both lose the subtle browser focus default. */
:where(button, [role='button'], a, input, select, textarea, summary):focus-visible {
  outline: 2px solid var(--ub-accent-default);
  outline-offset: 2px;
}
