/* DeltaTune — the instrument, repainted (2026-09-05).
   -------------------------------------------------------------------------
   ONE token set, TWO value sets. Every colour in this file comes from a token
   named for its ROLE, never for its hue: a screen that needs "the fault
   colour" must not have to know that the fault colour is amber.

   Themes. :root carries LIGHT, because light is what a customer sees the first
   time and that is the impression the SDK manual photographs. [data-theme]
   on <html> switches; index.html sets it before first paint from
   localStorage, so there is no flash. The OS preference is deliberately NOT
   consulted on a first visit — the first impression is a product decision,
   not the visitor's OS setting.

   The semantic band is fixed by the industry, not by taste. EN 54 spends red
   on FIRE and amber on FAULT, so neither is available for chrome. Chrome
   therefore lives in teal — the one saturated hue left outside the band, and
   far enough from green that a fault lamp is never mistaken for a nav marker.

   Pre-fire (level 1) is drawn in the ALARM hue at lower weight — outline
   instead of fill, dashes instead of a solid rule — and never in yellow.
   Level 1 and level 2 are two steps on one axis; a fault is a different axis
   entirely. Giving pre-fire its own yellow put three warm hues on one screen
   and made "amber" mean two things.

   Data is INK. The trace is the darkest thing on a light chart and the
   lightest on a dark one, the way a chart recorder draws on paper. Limits are
   red because they are limits. Nothing else on a chart gets a colour.

   Numerals do not render in Almoni. MEASURED, not assumed: almoni-regular.otf
   has no `tnum` feature in GSUB and its digit advances spread 41% (one=520,
   zero=878 at em 2048), so a 2 Hz readout would visibly dance. --dt-font-num
   is a real system stack, not the phantom 'Roboto Mono' that was never
   bundled and silently rendered as Consolas.
   ------------------------------------------------------------------------- */

@font-face {
    font-family: 'Almoni';
    src: url('../branding/fonts/almoni-light.otf') format('opentype');
    font-weight: 300;
    font-display: swap;
}

@font-face {
    font-family: 'Almoni';
    src: url('../branding/fonts/almoni-regular.otf') format('opentype');
    font-weight: 400;
    font-display: swap;
}

@font-face {
    font-family: 'Almoni';
    src: url('../branding/fonts/almoni-bold.otf') format('opentype');
    font-weight: 700;
    font-display: swap;
}

:root {
    color-scheme: light;

    /* ---- type ---- */
    --dt-font-ui: 'Almoni', 'Segoe UI', Roboto, system-ui, Arial, sans-serif;
    --dt-font-num: ui-monospace, 'Cascadia Mono', 'Segoe UI Mono', Consolas, 'SF Mono', Menlo, monospace;

    /* A scale, so a size is CHOSEN rather than invented per rule. The old file
       had eleven sizes below 12px -- 8, 9, 10 and 11 -- which is the 2013
       instrument idiom: dense, shouted, and hard to read the moment the ground
       went light. Everything a person READS now starts at 12px.
       --dt-fs-tick is the one exception and it is not prose: SVG tick labels
       live in a fixed-pixel chart whose geometry is deliberate, and enlarging
       them collides the axis rather than clarifying it. */
    --dt-fs-tick: 11px;
    --dt-fs-label: 12px;
    --dt-fs-body: 13px;
    --dt-fs-ui: 14px;
    --dt-fs-lead: 16px;

    /* ---- surfaces, lightest ground to deepest well ---- */
    --dt-canvas: #f7f6f4;
    --dt-surface: #ffffff;
    --dt-surface-2: #f0efec;
    --dt-well: #fbfaf9;
    --dt-rail: #efeeeb;

    /* ---- lines ---- */
    --dt-line: #d5d3ce;
    --dt-line-soft: #e6e4e0;

    /* ---- ink ---- */
    --dt-ink: #17181a;
    --dt-ink-dim: #5f6469;
    --dt-ink-faint: #8a8f95;
    --dt-ink-invert: #ffffff;

    /* ---- state, semantic and not negotiable ---- */
    --dt-alarm: #d71920;              /* FIRE / level 2 — fill, lamps, limit rules */
    --dt-alarm-ink: #a80f14;    /* the same state as TEXT, contrast-corrected */
    --dt-fault: #e39a00;        /* FAULT — fill and lamps */
    --dt-fault-ink: #855700;    /* the same state as TEXT */
    --dt-ok: #0ca149;           /* normal — a dot, never a word, never alone */
    --dt-ok-ink: #0a7a38;

    /* ---- chrome ---- */
    --dt-accent: #0e5c63;
    --dt-accent-ink: #ffffff;
    --dt-accent-hover: #0a4a50;

    /* ---- elevation. A light ground carries shadow badly; keep it thin. ---- */
    --dt-shadow-panel: 0 1px 2px rgb(23 24 26 / .07);
    --dt-shadow-card: 0 1px 2px rgb(23 24 26 / .06), 0 10px 28px rgb(23 24 26 / .08);
    --dt-scrim: rgb(23 24 26 / .40);
    --dt-inset-line: inset 0 1px 0 rgb(255 255 255 / .85);

    /* ---- a lamp GLOWS on dark and RINGS on light ----
       A coloured blur over a white ground reads as a smudge, so the light
       theme spends the same shadow on a crisp ring instead. Every halo in the
       file is written `0 0 var(--dt-halo-blur) var(--dt-halo-spread) <tint>`
       so one pair of numbers switches all of them. */
    --dt-halo-blur: 0;
    --dt-halo-spread: 3px;
    --dt-lamp-halo: 0 0 var(--dt-halo-blur) var(--dt-halo-spread) color-mix(in srgb, currentColor 22%, transparent);

    --dt-focus: 0 0 0 2px var(--dt-canvas), 0 0 0 4px var(--dt-accent);
}

:root[data-theme="dark"] {
    color-scheme: dark;

    --dt-canvas: #111315;
    --dt-surface: #181b1e;
    --dt-surface-2: #202428;
    --dt-well: #0b0d0f;
    --dt-rail: #15181b;

    --dt-line: #2c3136;
    --dt-line-soft: #23272b;

    --dt-ink: #e6e9ec;
    --dt-ink-dim: #9aa1a8;
    --dt-ink-faint: #6c737a;
    --dt-ink-invert: #0b0d0f;

    --dt-alarm: #ff4d4d;
    --dt-alarm-ink: #ff6b6b;
    --dt-fault: #f0b429;
    --dt-fault-ink: #f5c244;
    --dt-ok: #27d36e;
    --dt-ok-ink: #3add7d;

    --dt-accent: #4fc3cb;
    --dt-accent-ink: #08282b;
    --dt-accent-hover: #74d6dd;

    --dt-shadow-panel: 0 1px 3px rgb(0 0 0 / .5);
    --dt-shadow-card: 0 20px 52px rgb(0 0 0 / .5);
    --dt-scrim: rgb(0 0 0 / .72);
    --dt-inset-line: inset 0 1px 0 rgb(255 255 255 / .05);

    --dt-halo-blur: 10px;
    --dt-halo-spread: 0;
    --dt-lamp-halo: 0 0 var(--dt-halo-blur) var(--dt-halo-spread) currentColor;
}

/* A lamp pulses in OPACITY only. The halo itself is a token, so it can be a
   glow on a dark ground and a ring on a light one without a second keyframe. */
@keyframes dt-pulse-led {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.5; }
}

@keyframes dt-live-dot {
    0%, 100% { opacity: 1; r: 4; }
    50%      { opacity: 0.4; r: 7; }
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    background: var(--dt-canvas);
    color: var(--dt-ink);
    font-family: var(--dt-font-ui);
    -webkit-font-smoothing: antialiased;
}

/* Numerals never render in Almoni: its digits are proportional (41% spread,
   no `tnum`), so a 2 Hz readout would visibly dance. Anything that shows a
   measurement asks for --dt-font-num, and gets tabular figures with it. */
[style*="--dt-font-num"] { font-variant-numeric: tabular-nums; }

h1:focus { outline: none; }

/* Keyboard focus was invisible in this file — 1434 lines and not one rule.
   Mouse users never see this; keyboard users cannot work without it. */
:where(a, button, select, input, textarea, [tabindex]):focus-visible {
    outline: none;
    box-shadow: var(--dt-focus);
    border-radius: 3px;
}

/* The screen animates a live measurement, so motion here is information, not
   decoration — but nobody needs a pulsing lamp to understand a red word.
   Anything that only decorates stops; the readouts keep updating. */
@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;
    }
}

::selection { background: color-mix(in srgb, var(--dt-accent) 26%, transparent); }

/* A hatched band, because the claim is about the DATA's provenance, not about
   the detector -- amber and red are spoken for. Hatching is the language of a
   test pattern, and that is exactly what a simulated reading is. */
/* ============ Theme toggle ============
   Two labelled halves, not an icon: a lone sun or moon says which theme you
   would GET, and half the world reads that as which theme you are IN. */
.dt-theme-toggle {
    display: inline-flex;
    border: 1px solid var(--dt-line);
    border-radius: 4px;
    overflow: hidden;
}

.dt-theme-toggle button {
    font-family: inherit;
    font-size: var(--dt-fs-label);
    font-weight: 700;
    letter-spacing: 0.01em;
    padding: 4px 10px;
    border: none;
    background: transparent;
    color: var(--dt-ink-faint);
    cursor: pointer;
    transition: background .15s, color .15s;
}

.dt-theme-toggle button + button { border-left: 1px solid var(--dt-line); }
.dt-theme-toggle button:hover { color: var(--dt-ink); }

.dt-theme-toggle button.on {
    background: var(--dt-accent);
    color: var(--dt-accent-ink);
}
/* Blazor error UI */
#blazor-error-ui {
    background: color-mix(in srgb, var(--dt-alarm) 12%, var(--dt-surface));
    color: var(--dt-alarm-ink);
    bottom: 0;
    box-shadow: 0 -1px 2px var(--dt-scrim);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}
#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 0.75rem;
    top: 0.5rem;
}

.blazor-error-boundary {
    background: var(--dt-alarm-ink);
    padding: 1rem;
    color: white;
}
.blazor-error-boundary::after { content: "An error has occurred."; }

/* WASM loading spinner */
.loading-progress {
    position: relative;
    display: block;
    width: 8rem;
    height: 8rem;
    margin: 20vh auto 1rem auto;
}
.loading-progress circle {
    fill: none;
    stroke: var(--dt-line);
    stroke-width: 0.6rem;
    transform-origin: 50% 50%;
    transform: rotate(-90deg);
}
.loading-progress circle:last-child {
    stroke: var(--dt-accent);
    stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
    transition: stroke-dasharray 0.05s ease-in-out;
}
.loading-progress-text {
    position: absolute;
    text-align: center;
    font-weight: bold;
    color: var(--dt-ink-dim);
    inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
}
.loading-progress-text:after {
    content: var(--blazor-load-percentage-text, "Loading DeltaTune");
}/* A disabled control stays READABLE. At 38% opacity the label was a smudge, so
   the one thing the reader needed — which control is unavailable — was the
   hardest thing on the ribbon to make out. *//* ---- left rail: alarm + failure lamps, signal bars ---- *//* Gray = normal, red = active. Same reading as the legacy screen (manual j.2/j.3), so a
   technician who knows the old tool needs no retraining. */.dt-sigbar {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
}

.dt-sigbar-name {
    font-size: var(--dt-fs-tick);
    letter-spacing: 0.04em;
    color: var(--dt-ink-dim);
    white-space: nowrap;
}

.dt-sigbar-svg { display: block; }
.dt-sigbar-track { fill: var(--dt-well); }
.dt-sigbar-frame { fill: none; stroke: var(--dt-line); stroke-width: 1; }
.dt-sigbar-threshold { stroke: var(--dt-alarm); stroke-width: 1.4; }
/* The column is the MEASUREMENT, so it is ink at every value. It used to turn
   red once it passed the drawn setpoint, which is our arithmetic over two
   numbers, not the detector's verdict — and a red column beside an unlit Alarm
   lamp is a picture arguing with the device. Whether the reading is past the
   line is already visible: the line is right there, and it is the red one. */
.dt-sigbar-fill { fill: var(--dt-ink); opacity: 0.82; }

.dt-sigbar-axis {
    font-family: var(--dt-font-num);
    font-size: var(--dt-fs-tick);
    fill: var(--dt-ink-dim);
}

.dt-sigbar-readout {
    width: 100%;
    text-align: center;
    font-family: var(--dt-font-num);
    font-size: 15px;
    padding: 3px 0;
    background: var(--dt-well);
    border: 1px solid var(--dt-line);
    border-radius: 3px;
    color: var(--dt-ink);
}

.dt-sigbar-readout.over { color: var(--dt-alarm); font-weight: 700; }
.dt-trend {
    background: var(--dt-surface);
    border: 1px solid var(--dt-line);
    border-radius: 4px;
    /* The chart draws itself at whatever width this box reports, so the box has to be the one that
       stretches. min-width keeps it readable rather than letting a narrow window squeeze the plot
       into an unreadable sliver — below that the card scrolls sideways instead. */
    width: 100%;
    min-width: 520px;
}

.dt-trend-scroll { overflow-x: auto; }

.dt-trend-svg {
    display: block;
    touch-action: none;      /* the drag is ours, not the WebView's pan gesture */
    cursor: crosshair;
}

.dt-trend-bg { fill: var(--dt-well); }
.dt-trend-legend-bg { fill: var(--dt-well); stroke: var(--dt-line-soft); stroke-width: 1; }
.dt-trend-grid { stroke: var(--dt-line-soft); stroke-width: 1; }
.dt-trend-zero { stroke: var(--dt-line); stroke-width: 1; }
.dt-trend-frame { fill: none; stroke: var(--dt-line); stroke-width: 1; }
.dt-trend-threshold { stroke: var(--dt-alarm); stroke-width: 1.4; }
.dt-trend-level1 { stroke: var(--dt-fault); stroke-width: 1.2; stroke-dasharray: 5 3; }
.dt-trend-line { fill: none; stroke-width: 1.6; stroke-linejoin: round; }

/* The band above a setpoint. Red because it IS the limit — the one thing on a
   chart allowed a colour.
   The gradient runs from the TOP of the scale (offset 0%) down to the setpoint
   line (offset 100%), so the strong end belongs at the LINE. It was the other
   way round, inherited from a dark screen where the whole band read as a tint;
   on a light ground the same numbers flooded the chart pink and put the loudest
   colour furthest from the thing it marks. */
.dt-ribbon-far { stop-color: var(--dt-fault); stop-opacity: 0; }
.dt-ribbon-near { stop-color: var(--dt-fault); stop-opacity: 0.30; }
.dt-ribbon-bar-far { stop-color: var(--dt-alarm); stop-opacity: 0; }
.dt-ribbon-bar-near { stop-color: var(--dt-alarm); stop-opacity: 0.28; }

.dt-trend-cursor { stroke: var(--dt-accent); stroke-width: 1; stroke-dasharray: 3 3; }
.dt-trend-select { fill: color-mix(in srgb, var(--dt-accent) 16%, transparent); stroke: var(--dt-accent); stroke-width: 1; }

.dt-trend-axis {
    font-family: var(--dt-font-num);
    font-size: var(--dt-fs-tick);
    fill: var(--dt-ink-dim);
}

.dt-trend-axis-title {
    font-family: var(--dt-font-num);
    font-size: var(--dt-fs-tick);
    letter-spacing: 0.1em;
    fill: var(--dt-ink-dim);
}

.dt-trend-title {
    font-size: var(--dt-fs-tick);
    letter-spacing: 0.08em;
    fill: var(--dt-ink);
}

.dt-trend-threshold-lbl {
    font-family: var(--dt-font-num);
    font-size: var(--dt-fs-tick);
    fill: var(--dt-alarm-ink);
}

.dt-trend-level1-lbl {
    font-family: var(--dt-font-num);
    font-size: var(--dt-fs-tick);
    fill: var(--dt-fault-ink);
}

.dt-trend-cursor-lbl {
    font-family: var(--dt-font-num);
    font-size: var(--dt-fs-tick);
    fill: var(--dt-accent);
}
/* ============================================================================
   Screen tabs — the customer's order (issue list, item 2): Status, Config, Log.
   Config appears here in Phase 5.
   ========================================================================= */

/* ============================================================================
   Log screen — parity with the DeltaSDK manual's Figure 4.
   One table of recorded peaks: ROR, FIX TEMP, Time.
   ========================================================================= */

/* ============================================================================
   Config screen — parity with the DeltaSDK manual's Figure 3.
   Current Threshold (read from the detector) above, Predefined Thresholds
   (stored on this PC, every row editable) below.
   ========================================================================= */

/* ══════════════════════════════════════════════════════════════════════════
   The boot loader — what is on screen between the page arriving and the WASM
   runtime starting. It is plain CSS on purpose: MudBlazor is not loaded yet.

   This block used to also hold the entry screen, against a palette of its own
   so the two designs could coexist. It does not need to any more: the entry
   screen is built out of the same controls and the same tokens as the rest of
   the program.
   ══════════════════════════════════════════════════════════════════════════ */
/* ===== Almoni — Lehavot brand font ===== */

/* boot loader */
.dt-boot{ height:100vh; display:flex; flex-direction:column; gap:14px; align-items:center; justify-content:center; }
.dt-boot-mark{ width:34px; height:34px; border-radius:8px; background:var(--dt-accent); animation:dt-bp 1.2s ease-in-out infinite; }
.dt-boot-text{ letter-spacing:.42em; color:var(--dt-ink-dim); font-size:13px; font-weight:700; padding-left:.42em; }
@keyframes dt-bp{ 50%{ opacity:.45; transform:scale(.9); } }

/* ============================================================================
   MudBlazor screens.
   The library carries the controls; this file only says what MudBlazor has no
   opinion about -- the shape of a measurement readout and of a lamp.
   ========================================================================= */

.dt-mono { font-family: var(--dt-font-num); font-variant-numeric: tabular-nums; }

/* The measurement, as the loudest thing on its card. Almoni cannot set these:
   its digits are proportional (41% spread, no `tnum`), so a 2 Hz readout would
   visibly dance. */
.dt-metric {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin-top: 2px;
    font-family: var(--dt-font-num);
    font-variant-numeric: tabular-nums;
}

.dt-metric .v { font-size: 54px; font-weight: 600; line-height: 1.05; letter-spacing: -0.01em; }
.dt-metric .u { font-family: var(--dt-font-ui); font-size: 15px; color: var(--dt-ink-dim); }

/* Four lamps in one row. They report BITS the detector sends, so an unlit lamp
   says "not reported", never "healthy". */
.dt-lamprow {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: 10px;
}

.dt-lamp2 {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 12px 14px;
    border: 1px solid var(--dt-line);
    border-radius: 6px;
    font-size: var(--dt-fs-body);
    line-height: 1.35;
}

.dt-lamp2 span { color: var(--dt-ink-dim); font-size: var(--dt-fs-label); }

.dt-lamp2.lit {
    border-color: var(--dt-alarm);
    background: color-mix(in srgb, var(--dt-alarm) 7%, transparent);
}

.dt-lamp2.lit span { color: var(--dt-alarm-ink); font-weight: 700; }

/* The charts are fixed-pixel by design, so their paper scrolls rather than the page. */
.dt-chartpaper { overflow-x: auto; }

/* A preset row whose text does not parse, or is out of range. The cells mark themselves too;
   this marks the ROW, so a table of twenty says at a glance which one blocks the save. */
.dt-row-bad td { background: color-mix(in srgb, var(--dt-fault) 9%, transparent); }

/* A screen's action row. MudToolBar is a fixed-height nowrap flex row, so on a narrow window the
   last controls simply left the page -- Save CSV and Clear were off the right edge with nothing to
   say they were there. Wrapping is the honest behaviour: every control stays reachable. */
.dt-actions { flex-wrap: wrap; height: auto; min-height: 0; row-gap: 8px; padding-block: 4px; }

/* The entry screen. One card, vertically centred, because it holds one decision:
   which detector to open. */
.dt-entry {
    min-height: calc(100dvh - 48px);
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding-block: 32px;
}

/* Explanatory text stays near 60 characters -- these paragraphs are read by someone
   meeting a DELTA for the first time, and a full-width line is read once and skipped. */
.dt-entry-lead { max-width: 46ch; }

/* MudBlazor 9 ships no text-alignment utility, so `text-center` on a card did nothing at all.
   Measured, not guessed: no loaded stylesheet defines the selector. The entry card's icon,
   heading and button therefore sat flush left while the lead paragraph, centred by its own
   mx-auto, looked indented against them -- on the first screen a stranger opens. */
.text-center { text-align: center; }
.text-left   { text-align: left; }
.text-right  { text-align: right; }

.dt-bar { background: var(--dt-surface); color: var(--dt-ink); border-bottom: 1px solid var(--dt-line); }
.dt-drawer { border-inline-end: 1px solid var(--dt-line); }

/* MudBlazor shouts its button labels (Material's default). The rest of this
   program stopped shouting, so its buttons do too. */
.mud-button-root { text-transform: none; letter-spacing: 0.01em; }
.mud-typography-overline { letter-spacing: 0.08em; }
