/*
 * RENEW theme — component styles.
 *
 * Consumes html/css/renew/renew-tokens.css exclusively. Every colour, size,
 * radius and duration below is a var(--rn-*); no raw hex, no magic pixels
 * outside the spacing scale. If you need a value that is not a token, the fix
 * is a token, not a literal.
 *
 * House style, in case it is not obvious from the result: plain. This is an
 * operator/accounting console on small screens. Borders over shadows, density
 * over air, no decoration that does not carry information. The only motion is
 * a token-duration transition on hover/focus — there is not a single @keyframes
 * in this file and there should not be one.
 *
 * Class prefix rn- throughout, so this can coexist with the legacy base.css
 * and with the nerv tree without collisions.
 */

@import url("renew-tokens.css");

/* ---------------------------------------------------------------- reset -- */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    min-height: 100%;
    -webkit-text-size-adjust: 100%;
    background-color: var(--rn-bg);
}

body {
    margin: 0;
    min-height: 100vh;
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    position: relative;
    /* Stacking context so the z-index:-1 wash stays above html's white
       ground and below header/cards. Without this the orbs paint behind
       <html> and vanish. */
    isolation: isolate;
    background-color: transparent;
    color: var(--rn-text);
    font-family: var(--rn-font);
    font-size: var(--rn-text-body);
    font-weight: var(--rn-weight-regular);
    line-height: var(--rn-leading-body);
}

/* Page wash behind the content. Viewport-fixed so the orbs stay the same
   size on a short console as on a long inventory list — percentage stops
   on an absolute layer were relative to document height, so the green
   grew with the page. z-index -1 so it cannot cover the header or title.
   html holds the white ground so this layer stays visible behind content.
   Two orbs only: the four-corner set fought the board-group tints. */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: -1;
    background-image:
        radial-gradient(circle at 0 0,
            color-mix(in srgb, var(--rn-accent) 12%, transparent) 0%,
            color-mix(in srgb, var(--rn-accent) 5%, transparent) 28%,
            color-mix(in srgb, var(--rn-accent) 2%, transparent) 48%,
            transparent 68%),
        radial-gradient(circle at 100% 100%,
            color-mix(in srgb, var(--rn-primary) 10%, transparent) 0%,
            color-mix(in srgb, var(--rn-primary) 4%, transparent) 26%,
            color-mix(in srgb, var(--rn-primary) 2%, transparent) 46%,
            transparent 64%),
        linear-gradient(var(--rn-bg-subtle) 0%,
            var(--rn-bg) 35%,
            var(--rn-bg) 65%,
            var(--rn-bg-subtle) 100%);
}

/* Honour the OS setting. Nothing here is load-bearing, so it all just stops. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        transition-duration: 0.01ms !important;
    }
}

/* Orbs are atmosphere. Flatten to the ice ground when the operator asked
   for more contrast. */
@media (prefers-contrast: more) {
    body::before {
        background-image: none;
        background-color: var(--rn-bg-subtle);
    }
}

/* ----------------------------------------------------------- typography -- */

h1, h2, h3, h4 {
    margin: 0;
    color: var(--rn-text);
    font-weight: var(--rn-weight-bold);
    line-height: var(--rn-leading-tight);
}

h1 {
    font-size: var(--rn-text-h1);
    font-weight: var(--rn-weight-semibold);
    letter-spacing: -0.01em;
}

h2 { font-size: var(--rn-text-h2); }
h3 { font-size: var(--rn-text-h3); }

h4 {
    font-size: var(--rn-text-h4);
    font-weight: var(--rn-weight-medium);
    line-height: var(--rn-leading-snug);
}

p {
    margin: 0 0 var(--rn-space-3);
}

a {
    color: var(--rn-link);
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}

small,
.rn-caption {
    font-size: var(--rn-text-caption);
    font-weight: var(--rn-weight-light);
    color: var(--rn-text-secondary);
    line-height: var(--rn-leading-body);
}

.rn-muted {
    color: var(--rn-text-secondary);
}

/* Serials, MACs, ids, anything meant to be compared character by character. */
.rn-mono {
    font-family: var(--rn-font-mono);
    font-size: var(--rn-text-caption);
}

/* typography.family.displayStrong — big numeric signals only. */
.rn-figure {
    font-family: var(--rn-font-display);
    font-size: var(--rn-text-h1);
    line-height: var(--rn-leading-tight);
    font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------- focus --- */

/* One focus treatment for the whole theme. 3:1 non-text minimum is met by
   --rn-border-focus; the white offset keeps it legible on tinted surfaces. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline: var(--rn-border-width-medium) solid var(--rn-border-focus);
    outline-offset: 2px;
    border-radius: var(--rn-radius-sm);
}

/* -------------------------------------------------------------- layout --- */

.rn-page {
    flex: 1 0 auto;
    width: 100%;
    max-width: var(--rn-content-max);
    margin: 0 auto;
    padding: var(--rn-space-4) var(--rn-space-4) var(--rn-space-6);
}

.rn-page__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--rn-space-3);
    flex-wrap: wrap;
    margin-bottom: var(--rn-space-4);
}

.rn-page__head h1 {
    color: var(--rn-accent);
}

.rn-page__head h1 a {
    color: var(--rn-link);
    text-decoration: none;
}

.rn-page__head h1 a:hover,
.rn-page__head h1 a:focus-visible {
    text-decoration: underline;
}

.rn-page__sep {
    color: var(--rn-text-secondary);
    font-weight: var(--rn-weight-regular);
    margin: 0 0.4em;
}

.rn-page__id {
    color: var(--rn-text-secondary);
    font-family: var(--rn-font-mono);
    font-size: var(--rn-text-caption);
    font-weight: var(--rn-weight-regular);
    letter-spacing: 0;
    margin-left: 0.35em;
}

.rn-page__head h1 a .rn-page__id {
    color: var(--rn-text-secondary);
}

.rn-page__head p {
    margin: var(--rn-space-1) 0 0;
    color: var(--rn-text-secondary);
    font-size: var(--rn-text-caption);
}

.rn-page--narrow {
    max-width: 42rem;
}

.rn-page--wide {
    max-width: min(96rem, 100%);
}

.rn-page--graph {
    max-width: min(80rem, 100%);
}

@media (max-width: 640px) {
    .rn-page {
        padding: var(--rn-space-4) var(--rn-space-3) var(--rn-space-6);
    }
}

/* -------------------------------------------------------------- header --- */

/* Opaque ice bar. No glass — the page orbs stay in the page, not under
   the chrome, so the logo and session type stay clean. */
.rn-header {
    position: sticky;
    top: 0;
    z-index: var(--rn-z-sticky);
    display: flex;
    align-items: center;
    gap: var(--rn-space-4);
    flex-wrap: wrap;
    padding: var(--rn-space-2) var(--rn-space-4);
    background: var(--rn-bg-subtle);
    border-bottom: var(--rn-border-width) solid var(--rn-border);
    transition:
        padding var(--rn-duration-base) var(--rn-ease-standard),
        gap var(--rn-duration-base) var(--rn-ease-standard),
        box-shadow var(--rn-duration-base) var(--rn-ease-standard);
}

/* Added by html/js/renew/renew.js once scroll passes ~40px. Logo shrinks from
   32px to 20px; padding halves; secondary lines under user and clock fold away. */
.rn-header--slim {
    padding-top: var(--rn-space-1);
    padding-bottom: var(--rn-space-1);
    gap: var(--rn-space-2);
    box-shadow: var(--rn-shadow-sm);
}

.rn-header__brand {
    display: inline-flex;
    align-items: center;
    min-height: var(--rn-touch-target);
    transition: min-height var(--rn-duration-base) var(--rn-ease-standard);
}

.rn-header--slim .rn-header__brand {
    min-height: 24px;
}

.rn-header__brand:hover {
    text-decoration: none;
}

/* Multi-colour lockup, height-locked. No invert, no plate — the header
   is light again so the original art reads as-is. */
.rn-header__logo {
    display: block;
    height: 32px;
    width: auto;
    max-width: 100%;
    transition: height var(--rn-duration-base) var(--rn-ease-standard);
}

.rn-header--slim .rn-header__logo {
    height: 20px;
}

.rn-header__spacer {
    flex: 1 1 auto;
}

/* user | time — session block on the right. */
.rn-header__session {
    display: flex;
    align-items: center;
    gap: var(--rn-space-3);
}

.rn-header__userbox {
    position: relative;
}

.rn-header__userbtn {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0;
    margin: 0;
    padding: var(--rn-space-1) var(--rn-space-2);
    border: none;
    border-radius: var(--rn-radius-md);
    background: transparent;
    font: inherit;
    text-align: right;
    line-height: var(--rn-leading-snug);
    color: var(--rn-text-secondary);
    cursor: pointer;
    min-height: var(--rn-touch-target);
    justify-content: center;
    transition: background-color var(--rn-duration-fast) var(--rn-ease-standard);
}

.rn-header__userbtn:hover,
.rn-header__userbox--open .rn-header__userbtn {
    background: var(--rn-bg-muted);
}

.rn-header__email {
    color: var(--rn-text);
    font-size: var(--rn-text-caption);
    font-weight: var(--rn-weight-medium);
}

.rn-header__level,
.rn-header__tz {
    font-size: var(--rn-text-caption);
    color: var(--rn-text-secondary);
    transition:
        opacity var(--rn-duration-fast) var(--rn-ease-standard),
        font-size var(--rn-duration-fast) var(--rn-ease-standard),
        line-height var(--rn-duration-fast) var(--rn-ease-standard);
}

.rn-header--slim .rn-header__level,
.rn-header--slim .rn-header__tz {
    font-size: 0;
    line-height: 0;
    opacity: 0;
}

.rn-header__timebox {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    padding-left: var(--rn-space-3);
    border-left: var(--rn-border-width) solid var(--rn-border);
    line-height: var(--rn-leading-snug);
    text-align: right;
}

.rn-header__clock {
    font-family: var(--rn-font-mono);
    font-size: var(--rn-text-body);
    font-weight: var(--rn-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--rn-primary);
}

.rn-header__menu {
    position: absolute;
    top: 100%;
    right: 0;
    z-index: var(--rn-z-dropdown);
    min-width: 11rem;
    margin: var(--rn-space-1) 0 0;
    padding: var(--rn-space-1) 0;
    background: var(--rn-bg);
    border: var(--rn-border-width) solid var(--rn-border);
    border-radius: var(--rn-radius-md);
    box-shadow: var(--rn-shadow-md);
}

.rn-header__menu[hidden] {
    display: none;
}

.rn-header__menu-item {
    display: block;
    padding: var(--rn-space-2) var(--rn-space-3);
    font-size: var(--rn-text-label);
    font-weight: var(--rn-weight-bold);
    color: var(--rn-primary);
    text-decoration: none;
    transition: background-color var(--rn-duration-fast) var(--rn-ease-standard);
}

.rn-header__menu-item + .rn-header__menu-item {
    border-top: var(--rn-border-width) solid var(--rn-border);
}

.rn-header__menu-item:hover {
    background: var(--rn-primary-subtle);
    text-decoration: none;
}

@media (max-width: 640px) {
    .rn-header {
        gap: var(--rn-space-2);
        padding: var(--rn-space-2) var(--rn-space-3);
    }

    .rn-header__session {
        gap: var(--rn-space-2);
    }

    .rn-header__timebox {
        padding-left: var(--rn-space-2);
    }

    .rn-header__email {
        max-width: 9rem;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
}

/* -------------------------------------------------------------- footer --- */

/* Solid brand ground. Gives the page a bottom edge instead of fading out, and
   it is the one place a large flat brand colour costs nothing: no content sits
   on it that has to stay readable against a tint. */
.rn-footer {
    flex: 0 0 auto;
    margin-top: auto;
    padding: var(--rn-space-4);
    background: var(--rn-primary);
    color: var(--rn-text-on-primary);
}

.rn-footer a {
    color: var(--rn-text-on-primary);
    text-decoration: underline;
}

.rn-footer__inner {
    max-width: var(--rn-content-max);
    margin: 0 auto;
    display: flex;
    gap: var(--rn-space-3);
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    font-size: var(--rn-text-caption);
    /* Inherit the footer's on-primary colour; --rn-text-secondary would be a
       grey mixed for white grounds and is unreadable here. */
    color: inherit;
}

.rn-footer p {
    margin: 0;
}

/* The institutional lockup lives down here. It is provenance, not navigation:
   in the top bar it was 26px of unreadable logo competing with the brand mark
   for the operator's attention. At the foot it can be large enough to actually
   read and costs nothing.
   These are the *_white variants — the dark-on-transparent Iresi_MU.png would
   disappear against the solid ground. */
.rn-footer__partners {
    display: flex;
    align-items: center;
    gap: var(--rn-space-4);
}

.rn-footer__partners img {
    display: block;
    height: 34px;
    width: auto;
    max-width: 100%;
}

/* ---------------------------------------------------------------- card --- */

/* --rn-sec is the card's section colour; it defaults to the neutral so a card
   that never sets one still looks deliberate. Set it once (see the
   .rn-card--<section> rules below) and it drives the spine, the border, the
   header wash and the title together. */
.rn-card {
    --rn-sec: var(--rn-neutral-600);
    display: flex;
    flex-direction: column;
    background: var(--rn-bg-card);
    border: var(--rn-border-width) solid
            color-mix(in srgb, var(--rn-sec) var(--rn-sec-edge), var(--rn-border));
    /* Same 3px left edge as the stat tiles, in the section colour, so a card
       is found by hue before it is read. The other three sides stay the
       tinted 1px rule — a full-strength box would shout. */
    border-left: var(--rn-spine) solid var(--rn-sec);
    /* md, not lg: 12px corners on a dense panel read as a soft consumer card.
       These are instrument panels. */
    border-radius: var(--rn-radius-md);
    padding: var(--rn-space-3);
}

.rn-card--manage   { --rn-sec: var(--rn-sec-manage); }

.rn-page > .rn-card + .rn-card {
    margin-top: var(--rn-space-5);
}
.rn-card--graph    { --rn-sec: var(--rn-sec-graph); }
.rn-card--flux     { --rn-sec: var(--rn-sec-flux); }
/* VIOLATION: only --rn-sec may change per card. The 9% wash of a
   title-legal ink is grey — there is no colour. This second fill is
   the requested sky (#7DCDFF), 60% fainter. Title and hint stay on --rn-sec so
   both clear 4.5:1 on it (the caption grey does not). Do not copy. */
.rn-card--flux .rn-card__head {
    background: var(--rn-sec-flux-head);
}
.rn-card--flux .rn-card__hint {
    color: var(--rn-sec);
}
.rn-card--leaf     { --rn-sec: var(--rn-sec-leaf); }
/* Leaf green is the page wash. A 9% green head sits in the same orb and
   reads as more gradient, not as a banner. Title and spine stay --rn-sec. */
.rn-card--leaf .rn-card__head {
    background: var(--rn-sec-leaf-head);
}
.rn-card--shelly   { --rn-sec: var(--rn-sec-shelly); }
.rn-card--arden    { --rn-sec: var(--rn-sec-arden); }

.rn-table td.is-gap {
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 0.15em;
}

.rn-hole-wrap {
    max-height: 22rem;
    overflow: auto;
}
.rn-card--widget   { --rn-sec: var(--rn-sec-widget); }
.rn-card--telegram { --rn-sec: var(--rn-sec-telegram); }
.rn-card--settings { --rn-sec: var(--rn-sec-settings); }
.rn-card--docs     { --rn-sec: var(--rn-sec-docs); }
.rn-card--warn     { --rn-sec: var(--rn-error-fg); }
/* Same extra fill as flux/leaf: the 9% wash of a deep red is still grey on
   a white graph card. Title and spine stay on --rn-sec (error-fg). */
.rn-card--warn .rn-card__head {
    background: var(--rn-error-bg);
    border-bottom-color: var(--rn-error);
}

/* Only interactive cards react to the pointer. A static card that lifts on
   hover is a lie about what clicking it does. */
.rn-card--link {
    transition:
        border-color var(--rn-duration-base) var(--rn-ease-standard),
        box-shadow var(--rn-duration-base) var(--rn-ease-standard);
}

.rn-card--link:hover {
    border-color: var(--rn-primary);
    box-shadow: var(--rn-shadow-md);
}

/* Negative margins pull the head out to the card's edges so its tint reads as a
   banner rather than a floating swatch. Top-right is re-rounded to match the
   card; top-left stays square so it sits flush against the spine instead of
   leaving a white notch inside the curve. */
.rn-card__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--rn-space-2);
    margin: calc(-1 * var(--rn-space-3)) calc(-1 * var(--rn-space-3)) var(--rn-space-2);
    padding: var(--rn-space-2) var(--rn-space-3);
    border-bottom: var(--rn-border-width) solid
                   color-mix(in srgb, var(--rn-sec) var(--rn-sec-edge), var(--rn-border));
    border-radius: 0 var(--rn-radius-md) 0 0;
    background: color-mix(in srgb, var(--rn-sec) var(--rn-sec-wash), var(--rn-bg));
}

/* The section colour carries the name. Every hue in the --rn-sec-* set clears
   4.5:1 on white; the 9% header wash under it moves that by a hair and is
   accounted for in the ratios noted beside each token. */
.rn-card__title {
    font-size: var(--rn-text-h4);
    font-weight: var(--rn-weight-bold);
    color: var(--rn-sec);
}

/* Category word — what kind of thing this section is (Devices, Telemetry,
   Ingest). Carries real classification, so it earns its place. */
.rn-card__hint {
    font-size: var(--rn-text-label);
    font-weight: var(--rn-weight-bold);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--rn-text-secondary);
}

/* ---------------------------------------------------------------- grid --- */

/* General-purpose equal-height grid, for pages whose cells genuinely should
   line up in rows (forms, paired panels). The index link board deliberately
   does NOT use this — see .rn-board below for why. */
.rn-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: var(--rn-space-4);
    align-items: start;
}

/* The link board. auto-fill + minmax means the column count follows the width,
   so this is the mobile rule too — no extra breakpoint. Cards size to their
   links; align-items:start keeps short sections from stretching to the tallest
   neighbour in the row. */
.rn-board {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: var(--rn-space-4);
    align-items: start;
}

/* Named cluster inside the board. Spans the full row so the nested cards are
   not mixed in with the auto-fill neighbours. Same anatomy as a card — spine,
   tinted edge, coloured head — but the body wash is 25% lighter than the
   head so the nested cards still read as the content. Hue comes from the
   --devices / --operations / --operator modifier so clusters do not share a mix.
   Full page-column width so Devices, Operations and Operator share one spine
   line instead of three different-sized islands. */
.rn-board__group {
    grid-column: 1 / -1;
    justify-self: stretch;
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 100%;
    min-width: 0;
    padding: var(--rn-space-4);
    background: color-mix(
        in srgb,
        var(--rn-bg) 25%,
        color-mix(in srgb, var(--rn-sec) var(--rn-sec-wash), var(--rn-bg))
    );
    border: var(--rn-border-width) solid
            color-mix(in srgb, var(--rn-sec) var(--rn-sec-edge), var(--rn-border));
    border-left: var(--rn-spine) solid var(--rn-sec);
    border-radius: var(--rn-radius-md);
}

.rn-board__group--devices {
    --rn-sec: color-mix(in srgb, var(--rn-sec-leaf) 50%, var(--rn-sec-flux));
}

.rn-board__group--operations {
    --rn-sec: color-mix(in srgb, var(--rn-sec-manage) 50%, var(--rn-sec-graph));
}

.rn-board__group--operator {
    --rn-sec: color-mix(in srgb, var(--rn-sec-telegram) 50%, var(--rn-sec-settings));
}

.rn-board__group-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--rn-space-2);
    margin: calc(-1 * var(--rn-space-4)) calc(-1 * var(--rn-space-4)) var(--rn-space-4);
    padding: var(--rn-space-2) var(--rn-space-3);
    border-bottom: var(--rn-border-width) solid
                   color-mix(in srgb, var(--rn-sec) var(--rn-sec-edge), var(--rn-border));
    border-radius: 0 var(--rn-radius-md) 0 0;
    background: color-mix(in srgb, var(--rn-sec) var(--rn-sec-wash), var(--rn-bg));
}

.rn-board__group-cards {
    display: flex;
    flex-wrap: wrap;
    gap: var(--rn-space-4);
    align-items: start;
}

.rn-board__group-cards > .rn-card {
    min-width: 240px;
    flex: 1 1 240px;
}

@media (max-width: 640px) {
    .rn-board__group-cards > .rn-card {
        min-width: 0;
        flex: 1 1 100%;
    }
}

/* ---------------------------------------------------------- stat strip --- */

/* The summary line. This is the reason the page is a console and not a menu:
   it answers "is anything wrong" before the operator picks a destination.
   Counts come from indexFleetJson() and the severity word is decided there —
   the only thing decided here is which colour a word maps to. */
.rn-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: var(--rn-space-3);
    margin-bottom: var(--rn-space-5);
}

.rn-stat {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--rn-space-2-5) var(--rn-space-3);
    background: var(--rn-bg-card);
    border: var(--rn-border-width) solid var(--rn-border);
    /* State lives in this stripe, not in the number's colour: a red figure on
       white is hard to read and colour alone is not an accessible signal. */
    border-left: var(--rn-spine) solid var(--rn-neutral-400);
    border-radius: var(--rn-radius-md);
}

.rn-stat__label {
    font-size: var(--rn-text-label);
    font-weight: var(--rn-weight-bold);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--rn-text-secondary);
}

.rn-stat__value {
    font-family: var(--rn-font-display);
    font-size: 22px;
    line-height: var(--rn-leading-tight);
    font-variant-numeric: tabular-nums;
}

.rn-stat__value small {
    font-family: var(--rn-font);
    font-size: var(--rn-text-caption);
    font-weight: var(--rn-weight-regular);
    color: var(--rn-text-secondary);
}

/* What the number actually measures. A bare "58" tells an operator nothing;
   "no data > 24 h or never" tells them whether to care. */
.rn-stat__sub {
    font-size: var(--rn-text-caption);
    color: var(--rn-text-secondary);
    line-height: var(--rn-leading-snug);
}

.rn-stat--ok      { border-left-color: var(--rn-success); }
.rn-stat--warn    { border-left-color: var(--rn-warning); }
.rn-stat--bad     { border-left-color: var(--rn-error); }
.rn-stat--info    { border-left-color: var(--rn-info); }

/* Bill tile: Arden vs Flux contribution under the merged total. */
.rn-bill-share {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin-top: var(--rn-space-2);
}

.rn-bill-share__row {
    display: grid;
    grid-template-columns: 4.5rem 1fr auto;
    gap: var(--rn-space-2);
    align-items: baseline;
    font-size: var(--rn-text-caption);
}

.rn-bill-share__name {
    font-weight: var(--rn-weight-bold);
}

.rn-bill-share__name--arden { color: var(--rn-sec-arden); }
.rn-bill-share__name--flux  { color: var(--rn-sec-flux); }
.rn-bill-share__name--gap   { color: var(--rn-warning-fg); }

.rn-bill-share__when {
    color: var(--rn-text-secondary);
}

.rn-bill-share__amt {
    font-variant-numeric: tabular-nums;
    font-weight: var(--rn-weight-bold);
}

.rn-bill-share__amt--na {
    font-weight: var(--rn-weight-regular);
    color: var(--rn-text-secondary);
}

.rn-stat__sub--miss {
    color: var(--rn-warning-fg);
}

.rn-stat--online  { border-left-color: var(--rn-success); }
.rn-stat--stale   { border-left-color: var(--rn-warning); }
.rn-stat--offline { border-left-color: var(--rn-error); }
.rn-stat--total   { border-left-color: var(--rn-info); }

/* -------------------------------------------------------------- navlist -- */

/* The index link board. Rows, not buttons — a dense list scans faster than a
   field of pills, and every row still clears the 44px target. */
.rn-navlist {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: 0;
    list-style: none;
}

.rn-navlist li + li {
    border-top: var(--rn-border-width) solid var(--rn-border);
}

.rn-navlist a {
    display: flex;
    align-items: center;
    gap: var(--rn-space-2);
    /* Deliberately NOT --rn-touch-target. That token is a pointer requirement,
       not a layout constant: forcing 44px here turns a six-link card into 264px
       of mostly whitespace on the desktop screens this console actually runs
       on. The requirement is honoured under (pointer: coarse) below, which is
       where it applies. */
    min-height: 28px;
    padding: var(--rn-space-1) var(--rn-space-2);
    margin: 0 calc(var(--rn-space-2) * -1);
    border-radius: var(--rn-radius-sm);
    color: var(--rn-text);
    font-size: var(--rn-text-body);
    transition:
        background-color var(--rn-duration-fast) var(--rn-ease-standard),
        color var(--rn-duration-fast) var(--rn-ease-standard);
}

/* Section colour, same as the card spine. One mark per row so the list
   still reads as a list, not a field of pills. */
.rn-navlist a::before {
    content: "";
    flex: 0 0 auto;
    width: 6px;
    height: 6px;
    border-radius: var(--rn-radius-full);
    background: var(--rn-sec);
}

/* Touch or stylus: restore the full 44px target. */
@media (pointer: coarse) {
    .rn-navlist a {
        min-height: var(--rn-touch-target);
        padding: var(--rn-space-2) var(--rn-space-2);
    }
}

.rn-navlist a:hover {
    background: var(--rn-bg-muted);
    color: var(--rn-primary);
    text-decoration: none;
}

/* Permission marker in the row's trailing column. Tells the operator which
   routes will refuse them before they navigate — the single most useful thing
   a route directory can say. Chips sit in column 2; rows without one simply
   leave it empty, which is what keeps the column straight. */
.rn-navlist .rn-chip {
    grid-column: 2;
    justify-self: start;
    text-align: center;
}

/* External destinations (Telegram, vendor consoles) get a trailing mark so a
   new tab is never a surprise. */
.rn-navlist a[target="_blank"] .rn-chip::after {
    content: " ↗";
}

.rn-chip {
    padding: 1px var(--rn-space-1);
    border-radius: var(--rn-radius-sm);
    background: var(--rn-bg-muted);
    color: var(--rn-text-secondary);
    font-size: 10px;
    font-weight: var(--rn-weight-bold);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    white-space: nowrap;
}

/* Elevated privilege reads as caution, not as an error. */
.rn-chip--admin { background: var(--rn-warning-bg); color: var(--rn-warning-fg); }
.rn-chip--mgr   { background: var(--rn-info-bg);    color: var(--rn-info-fg); }
.rn-chip--ext   { background: var(--rn-bg-muted);   color: var(--rn-text-secondary); }

/* -------------------------------------------------------------- button --- */

.rn-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--rn-space-2);
    min-height: var(--rn-touch-target);
    padding: var(--rn-space-2-5) var(--rn-space-6);
    border: var(--rn-border-width-medium) solid transparent;
    border-radius: var(--rn-radius-md);
    background: var(--rn-bg);
    color: var(--rn-text);
    font-family: inherit;
    font-size: var(--rn-text-label);
    font-weight: var(--rn-weight-bold);
    line-height: var(--rn-leading-snug);
    cursor: pointer;
    transition:
        background-color var(--rn-duration-base) var(--rn-ease-standard),
        border-color var(--rn-duration-base) var(--rn-ease-standard),
        color var(--rn-duration-base) var(--rn-ease-standard),
        box-shadow var(--rn-duration-base) var(--rn-ease-standard);
}

.rn-btn:hover {
    text-decoration: none;
}

.rn-btn--primary {
    background: var(--rn-primary);
    border-color: var(--rn-primary);
    color: var(--rn-text-on-primary);
}

.rn-btn--primary:hover {
    background: var(--rn-primary-hover);
    border-color: var(--rn-primary-hover);
}

.rn-btn--accent {
    background: var(--rn-accent);
    border-color: var(--rn-accent);
    color: var(--rn-text-on-accent);
}

.rn-btn--accent:hover {
    background: var(--rn-accent-hover);
    border-color: var(--rn-accent-hover);
}

/* Outline inverts to solid on hover — a named hover colour, not an opacity
   hack, so the contrast ratio stays a known quantity. */
.rn-btn--outline {
    background: transparent;
    border-color: var(--rn-primary);
    color: var(--rn-primary);
}

.rn-btn--outline:hover {
    background: var(--rn-primary);
    color: var(--rn-text-on-primary);
}

.rn-btn--ghost {
    background: transparent;
    border-color: transparent;
    color: var(--rn-primary);
}

.rn-btn--ghost:hover {
    background: var(--rn-primary-subtle);
}

.rn-btn--danger {
    background: var(--rn-error);
    border-color: var(--rn-error);
    color: var(--rn-text-on-primary);
}

.rn-btn--danger:hover {
    background: var(--rn-error-fg);
    border-color: var(--rn-error-fg);
}

.rn-btn[disabled],
.rn-btn[aria-disabled="true"] {
    background: var(--rn-neutral-400);
    border-color: var(--rn-neutral-400);
    color: var(--rn-text-on-primary);
    cursor: not-allowed;
}

.rn-btn--sm {
    min-height: auto;
    padding: var(--rn-space-1) var(--rn-space-3);
}

.rn-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--rn-space-3);
    margin-top: var(--rn-space-5);
}

/* --------------------------------------------------------------- forms --- */

.rn-field {
    display: flex;
    flex-direction: column;
    gap: var(--rn-space-1);
    margin-bottom: var(--rn-space-4);
}

.rn-label {
    font-size: var(--rn-text-label);
    font-weight: var(--rn-weight-bold);
    color: var(--rn-text);
}

.rn-input,
.rn-select,
.rn-textarea {
    width: 100%;
    min-height: var(--rn-touch-target);
    padding: var(--rn-space-3) var(--rn-space-4);
    border: var(--rn-border-width) solid var(--rn-border);
    border-radius: var(--rn-radius-md);
    background: var(--rn-bg);
    color: var(--rn-text);
    font-family: inherit;
    font-size: var(--rn-text-body);
    transition: border-color var(--rn-duration-fast) var(--rn-ease-standard);
}

.rn-textarea {
    min-height: calc(var(--rn-touch-target) * 2);
    resize: vertical;
}

.rn-input::placeholder,
.rn-textarea::placeholder {
    color: var(--rn-text-disabled);
}

.rn-input:focus,
.rn-select:focus,
.rn-textarea:focus {
    border-color: var(--rn-border-focus);
}

.rn-input[aria-invalid="true"],
.rn-input.is-error {
    border-color: var(--rn-border-error);
}

.rn-input.is-valid {
    border-color: var(--rn-success);
}

.rn-hint {
    font-size: var(--rn-text-caption);
    color: var(--rn-text-secondary);
}

.rn-hint--error {
    color: var(--rn-error-fg);
}

/* --------------------------------------------------------- radio cards --- */

/* Whole-row hit area for a radio group. :has() drives the selected state, so
   there is no JS and no duplicated class on the server side. */
.rn-choice {
    display: flex;
    align-items: flex-start;
    gap: var(--rn-space-3);
    min-height: var(--rn-touch-target);
    padding: var(--rn-space-3) var(--rn-space-4);
    margin-bottom: var(--rn-space-2);
    border: var(--rn-border-width) solid var(--rn-border);
    border-radius: var(--rn-radius-md);
    background: var(--rn-bg-card);
    cursor: pointer;
    transition:
        border-color var(--rn-duration-fast) var(--rn-ease-standard),
        background-color var(--rn-duration-fast) var(--rn-ease-standard);
}

.rn-choice:hover {
    border-color: var(--rn-primary-hover);
}

.rn-choice:has(input:checked) {
    border-color: var(--rn-primary);
    background: var(--rn-primary-subtle);
}

.rn-choice:has(input:focus-visible) {
    outline: var(--rn-border-width-medium) solid var(--rn-border-focus);
    outline-offset: 2px;
}

.rn-choice input {
    margin: 3px 0 0;
    accent-color: var(--rn-primary);
    width: var(--rn-icon-sm);
    height: var(--rn-icon-sm);
    flex: 0 0 auto;
}

.rn-choice__body {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.rn-choice__name {
    font-size: var(--rn-text-body);
    font-weight: var(--rn-weight-bold);
}

.rn-choice__desc {
    font-size: var(--rn-text-caption);
    color: var(--rn-text-secondary);
}

/* --------------------------------------------------------------- badge --- */

.rn-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--rn-space-1);
    padding: 2px var(--rn-space-2);
    border-radius: var(--rn-radius-sm);
    background: var(--rn-bg-muted);
    color: var(--rn-text-secondary);
    font-size: var(--rn-text-label);
    font-weight: var(--rn-weight-bold);
    line-height: var(--rn-leading-snug);
    white-space: nowrap;
}

/* Each variant pairs a tinted background with its accessible foreground —
   never the base colour as text on the tint. */
.rn-badge--success { background: var(--rn-success-bg); color: var(--rn-success-fg); }
.rn-badge--error   { background: var(--rn-error-bg);   color: var(--rn-error-fg); }
.rn-badge--warning { background: var(--rn-warning-bg); color: var(--rn-warning-fg); }
.rn-badge--info    { background: var(--rn-info-bg);    color: var(--rn-info-fg); }

.rn-card__head .rn-badge {
    align-self: center;
    flex: none;
}

/* Compact action on the trailing edge of a card head (title stays left). */
.rn-card__head-link {
    align-self: center;
    flex: none;
    font-size: var(--rn-text-label);
    font-weight: var(--rn-weight-bold);
    white-space: nowrap;
}

/* -------------------------------------------------------------- notice --- */

.rn-notice {
    display: flex;
    gap: var(--rn-space-3);
    padding: var(--rn-space-3) var(--rn-space-4);
    margin-bottom: var(--rn-space-4);
    border-left: var(--rn-space-1) solid var(--rn-info);
    border-radius: var(--rn-radius-sm);
    background: var(--rn-info-bg);
    color: var(--rn-info-fg);
    font-size: var(--rn-text-body);
}

.rn-notice--success { border-left-color: var(--rn-success); background: var(--rn-success-bg); color: var(--rn-success-fg); }
.rn-notice--error   { border-left-color: var(--rn-error);   background: var(--rn-error-bg);   color: var(--rn-error-fg); }
.rn-notice--warning { border-left-color: var(--rn-warning); background: var(--rn-warning-bg); color: var(--rn-warning-fg); }

.rn-notice[hidden],
.rn-actions[hidden] {
    display: none;
}

/* --------------------------------------------------------------- table --- */

/* Square corners per radius.none: tables are structure, not surfaces. */
.rn-table-wrap {
    overflow-x: auto;
    border: var(--rn-border-width) solid var(--rn-border);
    border-radius: var(--rn-radius-md);
}

.rn-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--rn-text-body);
}

.rn-table th,
.rn-table td {
    padding: var(--rn-space-2) var(--rn-space-3);
    text-align: left;
    border-bottom: var(--rn-border-width) solid
                   color-mix(in srgb, var(--rn-border) 70%, transparent);
    border-right: var(--rn-border-width) solid
                  color-mix(in srgb, var(--rn-border) 35%, transparent);
}

.rn-table th:last-child,
.rn-table td:last-child {
    border-right: 0;
}

.rn-table thead th {
    position: sticky;
    top: 0;
    background: color-mix(in srgb, var(--rn-sec, var(--rn-primary)) 14%, var(--rn-bg-subtle));
    font-size: var(--rn-text-label);
    font-weight: var(--rn-weight-bold);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--rn-sec, var(--rn-primary));
    white-space: nowrap;
}

.rn-table .rn-col-compact,
.rn-table .rn-num {
    width: 1%;
    white-space: nowrap;
}

.rn-table .rn-col-check {
    text-align: center;
}

.rn-table .rn-col-check input[type="checkbox"] {
    accent-color: var(--rn-primary);
    width: var(--rn-icon-sm);
    height: var(--rn-icon-sm);
    margin: 0;
    vertical-align: middle;
}

.rn-table tbody tr:nth-child(odd) {
    background: color-mix(in srgb, var(--row-type, var(--rn-bg-muted)) 5%, var(--rn-bg));
}

.rn-table tbody tr:nth-child(even) {
    background: color-mix(in srgb, var(--row-type, var(--rn-bg-muted)) 10%, var(--rn-bg-subtle));
}

.rn-table tbody tr:last-child td {
    border-bottom: 0;
}

.rn-table tbody tr:hover {
    background: color-mix(in srgb, var(--row-type, var(--rn-primary)) 12%, var(--rn-bg-subtle));
}

/* Right-align and tabular-align anything countable, so columns of figures
   compare by eye. */
.rn-table .rn-num,
.rn-table td.rn-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.rn-table th.rn-num {
    text-align: right;
}

.rn-table tfoot th,
.rn-table tfoot td {
    position: sticky;
    bottom: 0;
    background: var(--rn-bg-subtle);
    font-weight: var(--rn-weight-bold);
    border-top: var(--rn-border-width-medium) solid var(--rn-border);
    border-bottom: 0;
}

.rn-table tfoot.rn-table__ctrl td {
    font-weight: inherit;
    padding: var(--rn-space-2) var(--rn-space-3);
}

.rn-table tbody td .rn-btn,
.rn-table tbody td input[type="button"] {
    width: max-content;
    min-height: auto;
    padding: var(--rn-space-1) var(--rn-space-3);
}

.rn-pager {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--rn-space-2);
    margin-bottom: var(--rn-space-3);
}

.rn-table tfoot .rn-pager {
    margin-bottom: 0;
}

.rn-pager__nav {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--rn-space-2);
}

.rn-pager__status {
    font-size: var(--rn-text-caption);
    color: var(--rn-text-secondary);
    font-variant-numeric: tabular-nums;
}

.rn-pager__size {
    margin-left: auto;
    font-size: var(--rn-text-caption);
    font-weight: var(--rn-weight-bold);
    color: var(--rn-text-secondary);
}

.rn-select--sm {
    width: auto;
    min-height: auto;
    min-width: 4.5rem;
    padding: var(--rn-space-1) var(--rn-space-3);
    font-size: var(--rn-text-caption);
}

.rn-table tbody tr.is-picked {
    background: color-mix(in srgb, var(--rn-primary) 14%, var(--rn-bg-subtle));
}

.rn-table tbody tr.is-pickable {
    cursor: pointer;
}

.rn-table tbody tr.is-link {
    cursor: pointer;
    position: relative;
}

.rn-table tbody tr.is-link a {
    color: inherit;
    text-decoration: none;
}

.rn-table tbody tr.is-link a:hover {
    color: var(--rn-link);
    text-decoration: underline;
}

/* Real href on the name (or id) cell; ::after stretches the hit area
   across the row so a click anywhere navigates. Middle-click / ctrl-click
   still open a new tab because the overlay belongs to the <a>. */
.rn-table tbody tr.is-link a.row-link::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
}

/* Filter / action row above a table. Fields sit on one line; actions
   share the baseline so Apply is next to the input, not under it. */
.rn-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--rn-space-3);
    margin-bottom: var(--rn-space-4);
}

.rn-toolbar .rn-field {
    margin-bottom: 0;
    flex: 1 1 14rem;
    min-width: 12rem;
    max-width: 22rem;
}

.rn-toolbar .rn-field--compact {
    flex: 0 0 auto;
    min-width: 6rem;
    max-width: 8rem;
}

.rn-toolbar .rn-actions {
    margin-top: 0;
}

.rn-toolbar .rn-choice {
    margin-bottom: 0;
}

/* ---------------------------------------------------------- price band --- */

/* Backend-supplied band only. Never derive one of these from raw c/kWh. */
.rn-band {
    display: inline-block;
    width: var(--rn-space-2);
    height: var(--rn-space-2);
    border-radius: var(--rn-radius-full);
    vertical-align: baseline;
}

.rn-band--cheap     { background: var(--rn-band-cheap); }
.rn-band--typical   { background: var(--rn-band-typical); }
.rn-band--expensive { background: var(--rn-band-expensive); }

/* --------------------------------------------------------------- utils --- */

.rn-divider {
    height: var(--rn-border-width);
    margin: var(--rn-space-5) 0;
    background: var(--rn-border);
    border: 0;
}

.rn-vsep {
    width: var(--rn-border-width);
    height: calc(var(--rn-touch-target) - var(--rn-space-4));
    background: var(--rn-border);
    flex-shrink: 0;
    align-self: center;
}

.rn-visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* -------------------------------------------------------------- state --- */

.rn-state {
    display: inline-block;
    font-size: var(--rn-text-caption);
    font-weight: var(--rn-weight-bold);
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.rn-state--online { color: var(--rn-success-fg); }
.rn-state--stale  { color: var(--rn-warning-fg); }
.rn-state--offline { color: var(--rn-error-fg); }
.rn-state--warn { color: var(--rn-error-fg); }

.rn-state-cell {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--rn-space-2);
}

.rn-flow--in  { color: var(--rn-primary); }
.rn-flow--out { color: var(--rn-accent); }

.rn-count {
    font-size: var(--rn-text-caption);
    color: var(--rn-text-secondary);
    white-space: nowrap;
}

.rn-count strong {
    color: var(--rn-text);
    font-variant-numeric: tabular-nums;
}

/* Type chip on inventory rows. Colour is --row-type from a type class. */
.rn-chip {
    display: inline-block;
    padding: 0 var(--rn-space-2);
    border: var(--rn-border-width) solid color-mix(in srgb, var(--row-type, var(--rn-border)) 50%, var(--rn-border));
    border-radius: var(--rn-radius-sm);
    background: color-mix(in srgb, var(--row-type, var(--rn-bg-muted)) 12%, var(--rn-bg));
    color: var(--row-type, var(--rn-text));
    font-size: var(--rn-text-caption);
    font-weight: var(--rn-weight-bold);
}

.rn-type--SmartPlug { --row-type: var(--rn-sec-shelly); }
.rn-type--Leaf      { --row-type: var(--rn-sec-leaf); }
.rn-type--Flux      { --row-type: var(--rn-sec-flux); }
.rn-type--Generator { --row-type: var(--rn-sec-arden); }
.rn-type--Meter     { --row-type: var(--rn-sec-graph); }
.rn-type--AirSensor { --row-type: var(--rn-sec-widget); }
.rn-type--EV        { --row-type: var(--rn-sec-telegram); }
.rn-type--Battery   { --row-type: var(--rn-sec-docs); }

.rn-fresh {
    display: flex;
    align-items: center;
    gap: var(--rn-space-2);
}

.rn-fresh__track {
    position: relative;
    flex: 0 0 3.5rem;
    height: var(--rn-space-2);
    background: var(--rn-bg-muted);
    border-radius: var(--rn-radius-full);
    overflow: hidden;
}

.rn-fresh__fill {
    position: absolute;
    inset: 0 auto 0 0;
    background: var(--rn-success);
}

.rn-fresh--stale .rn-fresh__fill { background: var(--rn-warning); }
.rn-fresh--offline .rn-fresh__fill { background: var(--rn-error); }

.rn-fresh__txt {
    font-size: var(--rn-text-caption);
    font-variant-numeric: tabular-nums;
    color: var(--rn-text-secondary);
}

.rn-sort,
.rn-table .nerv-sort {
    margin-left: var(--rn-space-1);
    color: var(--rn-accent);
}

.rn-table thead th[data-key],
.rn-table thead th[data-col] {
    cursor: pointer;
    user-select: none;
}

.rn-table tbody tr.is-offline {
    color: var(--rn-text-secondary);
}

.rn-page a.paddedLink2 {
    display: inline-block;
    padding: var(--rn-space-1) var(--rn-space-3);
    border: var(--rn-border-width) solid var(--rn-border);
    border-radius: var(--rn-radius-sm);
    color: var(--rn-link);
    text-decoration: none;
}

.rn-page a.paddedLink2:hover {
    border-color: var(--rn-border-focus);
    text-decoration: underline;
}

/* Column chooser on inventory / flux list. */
.rn-page .coltog {
    --coltog-bg: var(--rn-bg);
    --coltog-fg: var(--rn-text);
    --coltog-border: var(--rn-border);
    --coltog-accent: var(--rn-accent);
}

.rn-page .coltog__btn,
.rn-page .coltog__item,
.rn-page .coltog__act {
    font-family: inherit;
    font-size: var(--rn-text-caption);
}

/* ---------------------------------------------------------- telegram --- */

.rn-qr {
    display: inline-block;
    padding: var(--rn-space-3);
    background: var(--rn-bg);
    border: var(--rn-border-width) solid var(--rn-border);
    border-radius: var(--rn-radius-md);
    line-height: 0;
}

.rn-code-xl {
    font-family: var(--rn-font-mono);
    font-size: var(--rn-text-h2);
    letter-spacing: 0.2em;
    font-variant-numeric: tabular-nums;
}

.rn-telegram-cta {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--rn-touch-target);
    padding: var(--rn-space-3) var(--rn-space-5);
    background: var(--rn-sec-telegram);
    color: var(--rn-text-on-primary);
    border-radius: var(--rn-radius-md);
    font-weight: var(--rn-weight-bold);
}

.rn-telegram-cta:hover {
    color: var(--rn-text-on-primary);
    text-decoration: none;
    filter: brightness(1.08);
}

/* -------------------------------------------------------------- labels --- */

.rn-label-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
    gap: var(--rn-space-4);
}

.rn-label-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--rn-space-2);
    padding: var(--rn-space-3);
    border: var(--rn-border-width) solid var(--rn-border);
    border-radius: var(--rn-radius-md);
    background: var(--rn-bg-subtle);
}

.rn-label-item img {
    display: block;
    max-width: 100%;
    height: auto;
}

.rn-label-grid--leaf img { max-height: 90px; }
.rn-label-grid--flux img { max-height: 110px; }

.rn-sheet {
    display: flex;
    flex-direction: column;
    gap: var(--rn-space-5);
    margin-top: var(--rn-space-5);
}

.rn-sheet__page img {
    display: block;
    max-width: 100%;
    height: auto;
    border: var(--rn-border-width) solid var(--rn-border);
    background: var(--rn-bg);
}

/* --------------------------------------------------------- commission --- */

.rn-lamp {
    display: inline-block;
    font-size: var(--rn-text-caption);
    font-weight: var(--rn-weight-bold);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.rn-lamp--open { color: var(--rn-success-fg); }
.rn-lamp--connecting { color: var(--rn-warning-fg); }
.rn-lamp--closed { color: var(--rn-error-fg); }

.rn-flux-list {
    display: flex;
    flex-direction: column;
    gap: var(--rn-space-4);
}

.rn-flux-card {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: var(--rn-space-4);
    padding: var(--rn-space-4);
    border: var(--rn-border-width) solid var(--rn-border);
    border-radius: var(--rn-radius-md);
    background: var(--rn-bg-subtle);
}

.rn-flux-card.is-new {
    border-color: var(--rn-accent);
}

.rn-dl {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--rn-space-1) var(--rn-space-4);
    margin: var(--rn-space-3) 0 0;
}

.rn-dl dt {
    color: var(--rn-text-secondary);
    font-size: var(--rn-text-caption);
}

.rn-dl dd {
    margin: 0;
    font-family: var(--rn-font-mono);
    font-size: var(--rn-text-caption);
}

.rn-label-preview {
    display: block;
    max-width: 12rem;
    background: var(--rn-bg);
    border: var(--rn-border-width) solid var(--rn-border);
}

.rn-label-preview.placeholder {
    min-height: 6rem;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--rn-text-secondary);
    font-size: var(--rn-text-caption);
    text-align: center;
    padding: var(--rn-space-3);
}

/* ----------------------------------------------------- shelly channels --- */

.rn-ch-metrics {
    border-collapse: collapse;
    font-family: var(--rn-font-mono);
    font-size: var(--rn-text-caption);
    line-height: var(--rn-leading-snug);
    margin: 0;
}

.rn-ch-metrics th,
.rn-ch-metrics td {
    border: none;
    padding: 0.12rem 0.55rem;
    white-space: nowrap;
}

.rn-ch-metrics thead th {
    background: transparent;
    color: var(--rn-text-secondary);
    font-weight: var(--rn-weight-medium);
    text-align: right;
    position: static;
}

.rn-ch-metrics .ch-id { text-align: left; }
.rn-ch-metrics .rn-num { text-align: right; font-variant-numeric: tabular-nums; }

.rn-ch-tone-0 .ch-id { color: var(--rn-sec-graph); }
.rn-ch-tone-1 .ch-id { color: var(--rn-sec-flux); }
.rn-ch-tone-2 .ch-id { color: var(--rn-sec-widget); }
.rn-ch-tone-3 .ch-id { color: var(--rn-sec-leaf); }

.rn-ch-metrics tr.stale-row {
    color: var(--rn-text-secondary);
}

/* -------------------------------------------------------------- login --- */

.rn-login {
    flex: 1 0 auto;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: var(--rn-space-6) var(--rn-space-4);
}

.rn-login__card {
    width: 100%;
    max-width: 22rem;
}

.rn-login__brand {
    display: block;
    margin: 0 auto var(--rn-space-5);
    height: 40px;
    width: auto;
}

.rn-password-row {
    display: flex;
    gap: var(--rn-space-2);
}

.rn-password-row .rn-input {
    flex: 1;
    min-width: 0;
}

.rn-page input[type="button"],
.rn-page #addButton {
    min-height: var(--rn-touch-target);
    padding: var(--rn-space-2) var(--rn-space-3);
    border: var(--rn-border-width) solid var(--rn-border);
    border-radius: var(--rn-radius-sm);
    background: var(--rn-bg);
    color: var(--rn-text);
    font: inherit;
    cursor: pointer;
}

/* -------------------------------------------------------------- tabs --- */

.rn-tabs {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: var(--rn-space-1);
    margin: 0 0 var(--rn-space-4);
    padding: var(--rn-space-1);
    background: var(--rn-bg-muted);
    border: var(--rn-border-width) solid var(--rn-border);
    border-radius: var(--rn-radius-lg);
}

a.rn-tabs__tab {
    text-decoration: none;
}

.rn-tabs__tab {
    appearance: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--rn-space-2);
    min-height: var(--rn-touch-target);
    padding: var(--rn-space-2) var(--rn-space-5);
    border: var(--rn-border-width) solid transparent;
    border-radius: var(--rn-radius-md);
    background: transparent;
    color: var(--rn-text-secondary);
    font: inherit;
    font-size: var(--rn-text-label);
    font-weight: var(--rn-weight-bold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    cursor: pointer;
    transition:
        background-color var(--rn-duration-fast) var(--rn-ease-standard),
        color var(--rn-duration-fast) var(--rn-ease-standard),
        border-color var(--rn-duration-fast) var(--rn-ease-standard),
        box-shadow var(--rn-duration-fast) var(--rn-ease-standard);
}

.rn-tabs__tab:hover:not(.is-active) {
    color: var(--rn-text);
    background: var(--rn-bg);
}

.rn-tabs__tab:focus-visible {
    outline: var(--rn-border-width-medium) solid var(--rn-border-focus);
    outline-offset: 2px;
}

.rn-tabs__tab.is-active {
    background: var(--rn-primary);
    border-color: var(--rn-primary);
    color: var(--rn-text-on-primary);
    box-shadow: var(--rn-shadow-sm);
}

.rn-tabs__tab.is-warn::before {
    content: "";
    width: 7px;
    height: 7px;
    flex: none;
    border-radius: var(--rn-radius-full);
    background: currentColor;
}

.rn-tabs__tab.is-warn:not(.is-active) {
    color: var(--rn-error-fg);
}

.rn-tabs__tab.is-warn.is-active {
    background: var(--rn-error);
    border-color: var(--rn-error);
    color: var(--rn-text-on-primary);
}

.rn-tabpanel[hidden] {
    display: none;
}

.rn-table tr.is-open td {
    background: var(--rn-error-bg);
}

.rn-table .rn-ticket-note {
    max-width: 28rem;
}

.rn-table .rn-ticket-note a {
    color: inherit;
    text-decoration: none;
}

.rn-table .rn-ticket-note a:hover {
    color: var(--rn-link);
    text-decoration: underline;
}

.rn-table tr[hidden],
.rn-table tfoot[hidden] {
    display: none;
}

.rn-table tr.rn-ticket-detail td {
    background: var(--rn-bg-subtle);
    white-space: normal;
}

.rn-table tr.rn-ticket-detail .rn-actions {
    margin-top: var(--rn-space-3);
}
