/*
 * base.css — framework-level token contract.
 *
 * Loaded from index.html before any palette/layout. Contains ONLY :root
 * variable defaults; no element / class / id rules. With no palette and
 * no layout selected, the page renders as plain HTML on top of these
 * neutral defaults.
 *
 *   ## Framework state attributes (theme-readable, no class invention)
 *
 *   Themes set standard `data-tapp-<concept>` attributes on any element
 *   instead of adding bespoke classes. Layout CSS reads them via
 *   `[data-tapp-launcher="active"]`-style selectors.
 *
 *   Convention:
 *     - **Attribute name = concept** (e.g. `data-tapp-launcher`).
 *       Each concept is owned by exactly one widget/affordance and
 *       lives in this framework-level list. Themes should not invent
 *       new concept attributes without promoting them here first.
 *     - **Attribute value = state within that concept**, short and
 *       reusable across concepts (`peeked`, `active`, `open`, `closed`).
 *     - Absence of the attribute is the rest state.
 *
 *   Concepts in current use (extend by editing this list):
 *     data-tapp-launcher        App launcher / spotlight panel.
 *                               Values: 'peeked' (hover-poised),
 *                                       'active' (open / engaged).
 *                               Typically set on :root by the layout.
 *     data-tapp-boot            Set on :root by an inline script in
 *                               index.html and cleared by the shell once
 *                               /api/auth/me has answered. Boolean (present
 *                               or absent). While present the app has not
 *                               yet decided between the chrome and the login
 *                               gate, and a layout hides BOTH — otherwise a
 *                               signed-out visitor watches the whole app
 *                               render and then get replaced by a login
 *                               screen. With JS off it is never set, so the
 *                               plain-HTML baseline still renders.
 *     data-tapp-deck            Where a simulation deck puts its course
 *                               (the trail of steps). Values: 'right',
 *                               'top', 'bottom'; absent = left, the rest
 *                               state. Set on :root by the shell from the
 *                               stored preference. The deck's two parts are
 *                               SIBLINGS in a grid, so a layout places them
 *                               without any change to the markup; top and
 *                               bottom are a strip, which has no room for
 *                               step labels and shows dots alone.
 *     data-tapp-nav-expanded    Feature-nav (sidebar / strip) expansion
 *                               state. Boolean: 'true' = full labels,
 *                               anything else (or absent) = collapsed
 *                               (icon-only). Set on the
 *                               <nav class="tapp_feature_nav"> element by
 *                               whatever toggle the layout provides.
 *
 *   Layer order in index.html:
 *     1. base.css       (this file — neutral token defaults)
 *     2. palette.css    (brand overrides — chooses the colors)
 *     3. layout.css     (a layout's element rules — uses the tokens)
 *
 * Naming: --tapp_<group>-<role>. Groups in current use:
 *   brand-*           — brand identity colors (always overridden by palette)
 *   theme-*           — surfaces, text, links, borders, shadows
 *   theme-input-*     — input-control palette
 *   theme-button-*    — button palette (primary / secondary)
 *   menu-*            — module/feature menu palette
 *   status-*          — semantic status (success / error / warning / info)
 *   footer-*          — footer surface
 *   dialog-*          — dialog backdrop tints
 *   library-*         — library-picker dialog
 *   chart-*           — chart visuals (funnel, flowchart)
 *   sound-*           — UI cues (see the block at the end of :root)
 *
 * Defaults here are deliberately neutral (system grays / generic blues)
 * so a "no-palette" boot still looks coherent.
 */

:root {
    /* Brand — overridden by every palette */
    --tapp_brand-primary: #444444;
    --tapp_brand-secondary: #888888;

    /* Surfaces & text */
    --tapp_theme-background: #ffffff;
    --tapp_theme-surface: #ffffff;
    --tapp_theme-surface-alt: #f5f5f5;
    --tapp_theme-text: #333333;
    --tapp_theme-text-muted: #888888;
    --tapp_theme-text-inverted: #ffffff;

    --tapp_theme-link: #2a6db4;
    --tapp_theme-link-hover: #1a4a82;
    --tapp_theme-border: #e0e0e0;
    --tapp_theme-border-light: rgba(0, 0, 0, 0.08);
    --tapp_theme-shadow: rgba(0, 0, 0, 0.12);

    /* Inputs */
    --tapp_theme-input-bg: #ffffff;
    --tapp_theme-input-border: #e0e0e0;
    --tapp_theme-input-text: #333333;
    --tapp_theme-input-placeholder: #888888;
    --tapp_theme-input-focus: #2a6db4;
    --tapp_theme-input-disabled: #f5f5f5;

    /* Buttons */
    --tapp_theme-button-primary-bg: #2a6db4;
    --tapp_theme-button-primary-text: #ffffff;
    /* DERIVED, not a literal. A palette that overrides only -bg and -text —
       which is most of them — used to keep this blue on hover, so every brand
       turned navy when a primary button was hovered. Mixing from -bg means any
       palette gets a related shade for free; a palette may still override this
       outright and win. */
    /* SERIES COLOURS — one per slice/band, in order. A chart states WHICH
       series a shape is (data-slice) and never picks a colour, so these are the
       single place the answer lives: the pie, the area bands and the table
       badges that name them all read the same token. Overridable by a palette,
       which is the point of them being tokens rather than literals in a chart. */
    --tapp_series-1: #2a6db4;
    --tapp_series-2: #d97706;
    --tapp_series-3: #059669;
    --tapp_series-4: #7c3aed;
    --tapp_series-5: #dc2626;
    --tapp_series-6: #0891b2;
    /* The remainder is deliberately NOT a series colour: "nobody" is an
       absence, so it reads as grey rather than as another technology. */
    --tapp_series-rest: #9ca3af;

    --tapp_theme-button-primary-hover: color-mix(in srgb, var(--tapp_theme-button-primary-bg) 86%, black);
    --tapp_theme-button-secondary-bg: #f5f5f5;
    --tapp_theme-button-secondary-text: #333333;
    --tapp_theme-button-secondary-hover: #e0e0e0;

    /* Menu */
    --tapp_menu-bg: #333333;
    --tapp_menu-bg-hover: #2a2a2a;
    --tapp_menu-bg-sub: #1f1f1f;
    --tapp_menu-text: #ffffff;
    --tapp_menu-border: rgba(255, 255, 255, 0.2);

    /* Status */
    --tapp_status-success: #28a745;
    --tapp_status-success-light: rgba(40, 167, 69, 0.1);
    --tapp_status-error: #dc3545;
    --tapp_status-error-light: rgba(220, 53, 69, 0.08);
    --tapp_status-warning: #ffc107;
    --tapp_status-warning-light: rgba(255, 193, 7, 0.1);
    --tapp_status-info: #2a6db4;
    --tapp_status-info-light: rgba(42, 109, 180, 0.1);

    /* Footer */
    --tapp_footer-bg: #52565c;
    --tapp_footer-text: #cccccc;

    /* Modal / dialog backdrop */
    --tapp_dialog-backdrop: rgba(0, 0, 0, 0.4);
    --tapp_dialog-backdrop-brand: rgba(0, 0, 0, 0.25);

    /* Input focus accent (halo around focused inputs) */
    --tapp_input-focus-shadow: rgba(42, 109, 180, 0.2);

    /* Section heading underline */
    --tapp_section-heading-border: rgba(0, 0, 0, 0.15);

    /* Library dialog (table-style picker) */
    --tapp_library-border: #d0d0d0;
    --tapp_library-row-hover: #f5f5f5;
    --tapp_library-row-selected: #e8e8e8;
    --tapp_library-text-secondary: #666666;

    /* Chart tokens — consumed by classic theme.css against the framework
       class contract emitted by charts.js (.tapp_flowchart_*, .tapp_funnel_*). */
    --tapp_chart-step-stroke: rgba(0, 0, 0, 0.10);
    --tapp_chart-step-text: #ffffff;
    --tapp_chart-step-text-halo: rgba(0, 0, 0, 0.45);
    --tapp_chart-flowchart-node-bg: #ffffff;
    --tapp_chart-flowchart-node-stroke: rgba(0, 0, 0, 0.18);
    --tapp_chart-flowchart-node-text: #222222;
    --tapp_chart-flowchart-demo-bg: #444444;
    --tapp_chart-flowchart-demo-stroke: rgba(0, 0, 0, 0.25);
    --tapp_chart-flowchart-demo-text: #ffffff;
    --tapp_chart-flowchart-edge-bg: #ffffff;
    --tapp_chart-flowchart-edge-stroke: rgba(0, 0, 0, 0.10);
    --tapp_chart-flowchart-edge-text: #444444;
    --tapp_chart-flowchart-link: #999999;
    --tapp_chart-flowchart-link-prev:   #c1352f;
    --tapp_chart-flowchart-link-inc:    #5fa9d3;
    --tapp_chart-flowchart-link-filter: #1c4e6f;
    /* Leaf nodes — emphasized as the terminal states in the flow. */
    --tapp_chart-flowchart-leaf-bg:     #000000;
    --tapp_chart-flowchart-leaf-stroke: #000000;
    --tapp_chart-flowchart-leaf-text:   #ffffff;

    /* Active-language indicator (next to #tapp_lang select). Each layout
       decides whether to render it (Drop = corner badge; Classic hides
       because the <select> already shows the value). */
    --tapp_active_lang-bg: var(--tapp_brand-primary);
    --tapp_active_lang-text: var(--tapp_theme-text-inverted);

    /* Categorical palette for charts that color by top-level branch
       (sunburst, treemap, etc.). Tokens override-able by palettes. */
    --tapp_chart-cat-1: #c1352f;
    --tapp_chart-cat-2: #e08c3c;
    --tapp_chart-cat-3: #e6c229;
    --tapp_chart-cat-4: #5fa9d3;
    --tapp_chart-cat-5: #3d8275;
    --tapp_chart-cat-6: #1c4e6f;
    --tapp_chart-cat-7: #984e83;
    --tapp_chart-cat-8: #a26769;

    /* Button click — a layout's click, declared the same way as its colors.
       CSS cannot play audio, so scripts/sound.js is the player; these two
       tokens are what it plays: a noise burst through a lowpass that sweeps
       shut (no oscillator, no pitch), synthesised in the browser so there is
       nothing to ship or license. Deliberately the ONLY cue for now.
       Muted by the shell's speaker switch (TApp.prefs 'sound'). */
    --tapp_sound-gain: 0.30;      /* peak level, 0–1 */
    --tapp_sound-click: 4400;     /* lowpass start in Hz — higher = brighter, thinner */
}

/* Pref toggles (animations, sound) — structural contract only. The
   markup mirrors the dark-theme toggle above: a <label class="tapp_label">
   + <label class="tapp_switch tapp_pref_switch"> wrapping a native
   checkbox. Plain HTML renders text + native checkbox; themes hide
   both and paint their own affordance (Drop: icon + prohibit-sign
   overlay; Classic: iOS-style slider, same as the theme toggle).
   No structural rules needed here — the existing .tapp_switch /
   .tapp_switch_slider rules in each theme cover the visual layer. */

/* ── THE BOOT GATE HAS TO LIVE HERE ────────────────────────────────────────
   `[data-tapp-boot]` hides the shell, the pane, the footer and the login gate
   until the app knows which of them to show. Every layout also states this
   rule — and stating it ONLY there could never work:

     1. base.css loads (a real <link>, so it blocks painting)
     2. the layout/palette <link>s carry NO href — the shell sets them from
        localStorage during mount(), which is JS, and long after first paint
     3. so the page paints UNSTYLED, with nothing hiding it
     4. the layout finally arrives and its copy of this rule starts applying,
        moments before the shell removes the attribute altogether

   The gate shipped inside the file whose absence IS the thing it was written
   to hide. Here it blocks paint like any other stylesheet, so the app shows
   nothing rather than showing itself raw.

   Consequence worth knowing: with no theme at all (dev, "Plain"), the page
   stays blank until /api/auth/me answers, instead of flashing raw markup and
   then settling. Blank-then-content reads as loading; raw-then-styled reads as
   broken. The layouts keep their own copy — harmless, and it means a layout
   loaded on its own still gates correctly.

   EVERY top-level child, not a list of ids. The layouts name four
   (#tapp_shell, #tapp_pane, #tapp_footer, #tapp_gate) and the page has since
   grown #tapp_status and #tapp_start_menu, which were never added — so the
   start menu's items sat there in raw markup through every boot. A list of
   members goes stale silently the next time somebody adds an element; the
   SHAPE — "whatever is directly in the body" — cannot. Scripts and the hidden
   template holders are display:none already, so this costs them nothing. */
:root[data-tapp-boot] body > * { display: none; }

/* ── SIGNED OUT: the gate is the ONLY thing there is ───────────────────────
   Same reasoning, same shape. `showChrome(false)` hid three ids by name and
   left #tapp_start_menu behind — so a signed-out visitor had "Open file…",
   "Profile…" and "Settings…" in front of them, and the file pipeline actually
   opened. Not merely untidy: it is the app's chrome operating outside a
   session.

   Stated as "everything except the gate" rather than as a list, because the
   list is exactly what went stale. A future top-level element is covered the
   day it is added, without anyone remembering this rule exists. */
:root[data-tapp-signedout] body > *:not(#tapp_gate) { display: none; }

/* ── A CHART DRAWN ONLY TO BE PHOTOGRAPHED ────────────────────────────────
   An export renders its comparison chart into the document, captures it as a
   PNG, and removes it. It has to be IN the document — an element outside it
   has no computed styles and no measurable width, so the chart would come out
   unstyled and the wrong size — but it must never be seen.

   In base.css, not in a theme: this is structure, not paint, and a deployment
   running an unfinished theme must not get a stray chart landing mid-page for
   a second during every export. Off-screen rather than display:none, because a
   hidden element has no dimensions to draw into.

   The width is fixed here so the capture is the same shape whatever the window
   is doing; charts.render clears its target's inline width, which is why the
   width sits on the wrapper and never on the target. */
.tapp_export_offscreen {
    position: absolute; left: -9999px; top: 0;
    width: 820px; pointer-events: none;
}
/* WIDE, because an epi cascade IS wide — two arms, four leaves each. Shaping
   the box like the PORTRAIT PAGE was the wrong instinct: charts.js fits the
   content into the box, so a wide tree in a tall box comes out small with
   letterboxing above and below, and the capture takes the box. The box should
   match the DRAWING; the writers then place that drawing as large as their
   page or their sheet allows. */
.tapp_export_offscreen[data-shape="wide"] { width: 1400px; }

/* Body-level scoping hooks for prefs. Themes can layer further. */
body.tapp-no-animations *,
body.tapp-no-animations *::before,
body.tapp-no-animations *::after {
    /* Disable CSS transitions/animations when the user has opted out
       of motion. transition-property is forced (not zeroed-duration)
       so no in-flight transition completes. */
    transition: none !important;
    animation: none !important;
}
