/* ===========================================================
   SignalPage — brand token layer (Layer 0)
   -----------------------------------------------------------
   The single source of truth for the brand's colour and type
   tokens, per the Brand & Style Guide. Loaded by the admin
   panel, the customer portal, the staff dashboard and the
   signup funnel — i.e. every surface that is SignalPage
   speaking as itself.

   NOT loaded by tenant public sites. A tenant's site uses its
   own palette from site_settings; the guide's *layout* rules
   are available to tenants as the "instrument" design preset
   (site/settings.php::getDesignStyles()), which deliberately
   references only --color-* tokens, never the brand tokens
   below. See the layering note at the bottom of this file.

   THIS FILE EXISTS TWICE, byte-for-byte identical:
       assets/brand.css            (CMS core tree)
       platform/assets/brand.css   (platform tree)
   platform/ and the CMS core deploy as two entirely separate
   trees (infrastructure/decisions.md), so a shared include is
   not possible. Edit one, copy to the other — enforced by
   `php admin/tools/check-brand-layering.php`.

   -----------------------------------------------------------
   TOKENS ARE ROLES, NOT PIGMENTS.
   --ink is "primary text", not "a dark colour". In dark mode
   --ink resolves to a near-white and --paper to a near-black.
   Never assume a token's literal lightness; that is the whole
   mechanism by which one palette serves both themes.

   Every text token below clears WCAG AA (4.5:1) against BOTH
   backgrounds it can land on (--paper and the --grey
   alternating band) in BOTH themes. The guide's own
   --amber-dark (#B5701E) does not — it measures 3.66:1 on
   paper — so --amber-text carries a corrected value; see the
   note on it. Re-check with the audit method in
   infrastructure/decisions.md before changing any of these.
   =========================================================== */

/* ---- Light (default) ---- */
:root {
    color-scheme: light;

    /* Neutrals */
    --paper: #F6F6F4;   /* page background */
    --grey:  #EAEAE7;   /* alternating band / recessed surface */
    --line:  #D7D7D3;   /* hairline — the primary separation device */
    --ink:   #1A1B1D;   /* primary text, and dark-band backgrounds */
    --stone: #5B5F63;   /* secondary/muted text, captions, eyebrows */

    /* COBALT = ACTIONABLE. Buttons, links, active nav, step numbers.
       Split into a fill and a text form: the fill needs 4.5:1 against
       white *label* text, the text form needs 4.5:1 against the page.
       One value cannot do both jobs across two themes. */
    --cobalt:       #2454A6;  /* solid fill (white label = 7.26:1) */
    --cobalt-hover: #1D4483;  /* fill hover — the guide's --cobalt-dark */
    --cobalt-text:  #2454A6;  /* link/label text (6.71:1 on paper) */

    /* AMBER = VERIFIED/LIVE ONLY. Never on a button, never on a link.
       If it is amber, something outside this app confirmed it. */
    --amber:      #E08A2C;  /* the status dot / lit bar only */
    --amber-text: #8F5817;  /* amber AS TEXT (5.43:1 paper, 4.87:1 grey).
                               Deliberately NOT the guide's #B5701E,
                               which is 3.66:1 and fails AA. */

    /* The one failure colour. Value matches the pre-existing
       --color-error in platform/assets/styles.css rather than
       introducing a sixth hue. */
    --flag-red: #B3261E;
    /* Label ON a flag-red fill. White works on the light theme's deep red but
       drops to 3.28:1 on the dark theme's lifted red, so this flips. */
    --flag-red-label: #FFFFFF;

    /* Type */
    --font-body: 'Open Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-mono: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

    /* Geometry. The guide has no shadows and no gradients; these two
       exist so that "no shadow" is expressible as a token override
       rather than as a deletion at 79 call sites. */
    --radius:  5px;
    --shadow:  none;
    --shadow-lg: none;
}

/* ---- Dark ----
   Only four values genuinely move: the neutrals swap roles, and
   cobalt + stone lift to clear contrast on a dark ground. Amber is
   unchanged in both themes (6.44:1 on the dark page) — the verified
   colour is literally the same pigment everywhere, which is a
   property worth keeping. */
:root[data-bs-theme="dark"] {
    color-scheme: dark;

    --paper: #1A1B1D;
    --grey:  #232426;
    --line:  #3A3D43;
    --ink:   #F6F6F4;
    --stone: #9AA0A6;   /* 6.53:1 — #5B5F63 would be 2.68:1 */

    --cobalt:       #2F66C2;  /* lifted so the FILL clears 3:1 against
                                 the dark page (1.4.11), white label 5.53:1 */
    --cobalt-hover: #3670CE;
    --cobalt-text:  #5B90E5;  /* 5.39:1 — #2454A6 would be 2.37:1 */

    --amber:      #E08A2C;    /* unchanged */
    --amber-text: #E9A24E;    /* 8.00:1 */

    --flag-red: #E06A5F;      /* 5.25:1 — #B3261E would be 2.64:1 */
    --flag-red-label: #1A1B1D;/* dark text on the lifted red: 5.25:1 */
}

/* ===========================================================
   Bootstrap bridge
   -----------------------------------------------------------
   Bootstrap 5.3 is the structural base (grid, collapse,
   accordion, dropdown JS) but no visual default survives. These
   overrides convert the bulk of existing markup — btn-primary,
   .card, .form-control, borders, radii — without editing the
   call sites. Anything still reading as stock Bootstrap after
   this is a hardcoded inline style, not a missing rule here.
   =========================================================== */
:root {
    --bs-body-bg: var(--paper);
    --bs-body-color: var(--ink);
    --bs-body-font-family: var(--font-body);
    --bs-emphasis-color: var(--ink);
    --bs-secondary-color: var(--stone);
    --bs-secondary-bg: var(--grey);
    --bs-tertiary-bg: var(--grey);
    --bs-border-color: var(--line);
    --bs-border-color-translucent: var(--line);
    --bs-border-radius: var(--radius);
    --bs-border-radius-sm: 3px;
    --bs-border-radius-lg: var(--radius);
    --bs-border-radius-xl: var(--radius);
    --bs-border-radius-pill: var(--radius);   /* the guide has no pills */
    --bs-link-color: var(--cobalt-text);
    --bs-link-hover-color: var(--cobalt-hover);
    --bs-primary: var(--cobalt);
    --bs-primary-rgb: 36, 84, 166;
    --bs-card-bg: var(--paper);
    --bs-card-border-color: var(--line);
    --bs-box-shadow: none;
    --bs-box-shadow-sm: none;
    --bs-box-shadow-lg: none;
}

/* Bootstrap's own shadow utilities are used in 79 places. Rather than
   strip them one by one, neutralise them here — the guide separates
   with hairlines, so a .shadow-sm becomes a border instead. */
.shadow, .shadow-sm, .shadow-lg { box-shadow: none !important; }

/* Buttons: solid cobalt fill, hairline outline, 5px radius, no
   gradient, no shadow. */
.btn {
    --bs-btn-font-family: var(--font-body);
    --bs-btn-font-weight: 600;
    --bs-btn-border-radius: var(--radius);
    --bs-btn-box-shadow: none;
    --bs-btn-focus-box-shadow: 0 0 0 3px color-mix(in srgb, var(--cobalt) 35%, transparent);
    background-image: none;
}
.btn-primary {
    --bs-btn-bg: var(--cobalt);
    --bs-btn-border-color: var(--cobalt);
    --bs-btn-hover-bg: var(--cobalt-hover);
    --bs-btn-hover-border-color: var(--cobalt-hover);
    --bs-btn-active-bg: var(--cobalt-hover);
    --bs-btn-active-border-color: var(--cobalt-hover);
    --bs-btn-disabled-bg: var(--cobalt);
    --bs-btn-disabled-border-color: var(--cobalt);
}
/* EVERY outline variant gets a hairline border, not the stock semantic one.
   Bootstrap paints .btn-outline-success green, -warning yellow and -info cyan
   on the border as well as the label — hues the brand does not have at all,
   and the most visible way stock Bootstrap leaks through. The variant still
   picks its own LABEL colour (admin_styles.css maps those onto brand tokens);
   only the border and the neutral hover are settled here. */
.btn-outline-primary,
.btn-outline-secondary,
.btn-outline-success,
.btn-outline-danger,
.btn-outline-warning,
.btn-outline-info,
.btn-outline-light,
.btn-outline-dark {
    --bs-btn-border-color: var(--line);
    --bs-btn-hover-bg: var(--grey);
    --bs-btn-hover-border-color: var(--line);
    --bs-btn-hover-color: var(--ink);
    --bs-btn-active-bg: var(--grey);
    --bs-btn-active-border-color: var(--line);
    --bs-btn-active-color: var(--ink);
    --bs-btn-disabled-border-color: var(--line);
}

/* The one outline variant that is genuinely an action: it fills cobalt. */
.btn-outline-primary {
    --bs-btn-color: var(--cobalt-text);
    --bs-btn-hover-bg: var(--cobalt);
    --bs-btn-hover-border-color: var(--cobalt);
    --bs-btn-hover-color: #fff;
    --bs-btn-active-bg: var(--cobalt-hover);
    --bs-btn-active-border-color: var(--cobalt-hover);
    --bs-btn-active-color: #fff;
}
.btn-outline-secondary { --bs-btn-color: var(--ink); }

/* Destructive actions keep their red fill on hover — the neutral hover above
   would make "Delete" look the same as "Cancel" at the moment of clicking. */
.btn-outline-danger {
    --bs-btn-color: var(--flag-red);
    --bs-btn-hover-bg: var(--flag-red);
    --bs-btn-hover-border-color: var(--flag-red);
    --bs-btn-hover-color: var(--flag-red-label);
    --bs-btn-active-bg: var(--flag-red);
    --bs-btn-active-border-color: var(--flag-red);
    --bs-btn-active-color: var(--flag-red-label);
}

/* Solid semantic fills the brand has no hue for. Bootstrap's green/yellow/cyan
   buttons become the neutral surface treatment; a filled button that is
   genuinely an action should be .btn-primary. */
.btn-success, .btn-warning, .btn-info, .btn-light, .btn-secondary {
    --bs-btn-bg: var(--grey);
    --bs-btn-border-color: var(--line);
    --bs-btn-color: var(--ink);
    --bs-btn-hover-bg: var(--line);
    --bs-btn-hover-border-color: var(--line);
    --bs-btn-hover-color: var(--ink);
    --bs-btn-active-bg: var(--line);
    --bs-btn-active-border-color: var(--line);
    --bs-btn-active-color: var(--ink);
}
.btn-danger {
    --bs-btn-bg: var(--flag-red);
    --bs-btn-border-color: var(--flag-red);
    --bs-btn-color: var(--flag-red-label);
    /* Hover mixes toward --ink, not toward black: --ink is near-black on the
       light theme and near-white on the dark one, so the fill deepens in
       light and lifts in dark, keeping the label's contrast either way. */
    --bs-btn-hover-bg: color-mix(in srgb, var(--flag-red) 85%, var(--ink));
    --bs-btn-hover-border-color: color-mix(in srgb, var(--flag-red) 85%, var(--ink));
    --bs-btn-hover-color: var(--flag-red-label);
    --bs-btn-active-bg: color-mix(in srgb, var(--flag-red) 85%, var(--ink));
    --bs-btn-active-border-color: color-mix(in srgb, var(--flag-red) 85%, var(--ink));
    --bs-btn-active-color: var(--flag-red-label);
}

.card {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: none;
}

/* ===========================================================
   Typography
   =========================================================== */
h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-body);
    font-weight: 800;
    letter-spacing: -0.02em;
    line-height: 1.08;
    color: var(--ink);
}

/* Mono eyebrow / kicker. Neutral by rule — NOT amber, NOT cobalt.
   An eyebrow is a label, not a status and not an action. */
.eyebrow {
    font-family: var(--font-mono);
    font-weight: 600;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--stone);
}

/* ===========================================================
   Signature components
   =========================================================== */

/* Logo mark — three ascending bars, only the tallest lit. */
.signal-mark {
    display: inline-flex;
    align-items: flex-end;
    gap: 2px;
    height: 15px;
    vertical-align: -2px;
}
.signal-mark i { width: 3px; border-radius: 1px; background: var(--line); display: block; }
.signal-mark i:nth-child(1) { height: 6px; }
.signal-mark i:nth-child(2) { height: 10px; }
.signal-mark i:nth-child(3) { height: 15px; background: var(--cobalt); }

/* ---- State vocabulary -------------------------------------
   Five states, one meaning each. This replaces Bootstrap's
   success/warning/danger/info badges throughout the app.

   The distinction that makes the guide's amber rule workable:
   "Published" is a toggle YOU control, "Connected" is something
   an external system CONFIRMED. Only the second is amber. That
   keeps amber rare enough to still mean something, which is
   what the guide is actually asking for.

       .state-live     amber   an external system confirmed it
                               (SSL issued, DNS resolving, GA4
                               receiving, backup completed)
       .state-on       ink     an internal boolean you set
                               (Published, Active, Featured)
       .state-pending  stone   waiting on an external system
       .state-off      stone   Draft, Hidden, disabled
       .state-failed   red     genuine failure

   Use the state_chip() helper rather than writing the markup
   by hand — see admin/lib/state.php.
   ---------------------------------------------------------- */
.state {
    display: inline-flex;
    align-items: center;
    gap: 0.4em;
    font-family: var(--font-mono);
    font-weight: 600;
    font-size: 0.7rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    padding: 0.15em 0.5em;
    border: 1px solid var(--line);
    border-radius: 3px;
    background: transparent;
    color: var(--stone);
    white-space: nowrap;
    line-height: 1.5;
}
.state-live   { color: var(--amber-text); border-color: color-mix(in srgb, var(--amber) 45%, var(--line)); }
.state-on     { color: var(--ink); background: var(--grey); }
.state-pending{ color: var(--stone); }
.state-off    { color: var(--stone); }
.state-failed { color: var(--flag-red); border-color: color-mix(in srgb, var(--flag-red) 40%, var(--line)); }

/* Counts are not errors. An unread count is something you can act
   on, so by the guide's mapping it is cobalt — never red. */
.state-count {
    display: inline-block;
    font-family: var(--font-mono);
    font-weight: 600;
    font-size: 0.7rem;
    padding: 0.15em 0.45em;
    border-radius: 3px;
    background: var(--cobalt);
    color: #fff;
    line-height: 1.5;
}

/* Status dot. The brand amber is 2.48:1 on paper — below the 3:1
   floor for non-text graphics — so the dot carries a ring in
   --amber-text (5.43:1) rather than being darkened. Keeps the lit
   amber reading while the shape itself stays perceivable. */
.sdot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--amber);
    border: 1px solid var(--amber-text);
    flex-shrink: 0;
    display: inline-block;
}
.state-pending .sdot,
.state-off .sdot { background: transparent; border-color: var(--stone); }
.state-failed .sdot { background: var(--flag-red); border-color: var(--flag-red); }
.state-on .sdot { background: var(--ink); border-color: var(--ink); }

/* ---- Diagnostic readout panel -----------------------------
   The guide's replacement for annotated-screenshot-with-floating-
   callouts. A bordered panel, a chrome header carrying a path and
   a live badge, then mono key:value rows.
   ---------------------------------------------------------- */
.readout {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--paper);
    overflow: hidden;
}
.readout-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.6rem 0.85rem;
    border-bottom: 1px solid var(--line);
    background: var(--grey);
    font-family: var(--font-mono);
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--ink);
}
.readout-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.5rem 0.85rem;
    border-bottom: 1px solid var(--line);
    font-family: var(--font-mono);
    font-size: 0.78rem;
}
.readout-row:last-child { border-bottom: 0; }
.readout-key {
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--stone);
    font-weight: 600;
}
.readout-val {
    color: var(--ink);
    font-weight: 500;
    text-align: right;
}

/* ---- Spec list --------------------------------------------
   Left label / right detail rows, divided by hairlines. The
   guide's explicit replacement for icon-in-a-rounded-square
   feature grids.
   ---------------------------------------------------------- */
.spec-list { border-top: 1px solid var(--line); }
.spec-row {
    display: flex;
    gap: 1.5rem;
    padding: 0.9rem 0;
    border-bottom: 1px solid var(--line);
}
.spec-label {
    flex: 0 0 34%;
    font-weight: 700;
    color: var(--ink);
}
.spec-detail { flex: 1; color: var(--stone); }
@media (max-width: 575.98px) {
    .spec-row { flex-direction: column; gap: 0.25rem; }
    .spec-label { flex: none; }
}

/* ===========================================================
   Layering rule (enforced by the qa-directory guard)
   -----------------------------------------------------------
   BRAND layer  — this file. --cobalt/--amber/--ink/--paper and
                  the components above. Admin, portal, staff and
                  the signup funnel only. Never a tenant site.

   PATTERN layer — the .pb-* classes in assets/styles.css and
                  the "instrument" preset in getDesignStyles().
                  Layout mechanics only (hairlines, left spine,
                  5px radius, label/detail rows), expressed
                  through a TENANT's --color-* tokens.

   The guard: no .pb-* rule may reference a brand token by name.
   If it needs --cobalt, it belongs in this file instead. Checked
   by `php admin/tools/check-brand-layering.php`, along with the
   amber-is-never-clickable rule above.
   =========================================================== */
