/* =============================================================================
   Datalogger Conan - front panel
   The interface borrows from the silkscreened aluminium faceplate of lab
   equipment: engraved rules, condensed uppercase labels, status LEDs, and a
   monospaced readout line for anything the device wants to tell you.
   ============================================================================= */

:root {
    /* Anodised aluminium enclosure */
    --alu-dark:     #b9c0c4;
    --alu:          #cfd5d8;
    --alu-light:    #e4e8ea;

    /* Silkscreen and engraving */
    --panel:        #f3f5f6;
    --ink:          #1b2126;
    --ink-soft:     #5d686f;
    --engrave:      #a6aeb3;

    /* Interaction: petrol, the colour of the connector shells */
    --petrol:       #0f6e7b;
    --petrol-dark:  #0a545e;

    /* Status LEDs. Used for status only, never for decoration. */
    --led-on:       #3fae5a;
    --led-wait:     #d9a123;
    --led-off:      #c14a3e;

    --radius:       3px;
    --rule:         1px solid var(--engrave);

    /* Both columns open with a header of this exact height, so their engraved
       rules line up across the seam. Nothing inside may grow past it. */
    --header-h:     64px;
}

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

/* Several rules below set an explicit display, which outranks the browser's
   [hidden] { display: none }. Restore it once, for everything. */
[hidden] {
    display: none !important;
}

html,
body {
    height: 100%;
}

body {
    margin: 0;
    background: var(--alu);
    background-image:
        repeating-linear-gradient(
            90deg,
            rgba(255, 255, 255, 0.35) 0px,
            rgba(255, 255, 255, 0.35) 1px,
            transparent 1px,
            transparent 3px
        );
    color: var(--ink);
    font-family: "IBM Plex Sans", system-ui, sans-serif;
    font-size: 15px;
    line-height: 1.5;
}

/* Silkscreen labels: condensed, uppercase, tracked out. */
.label,
label,
th,
.nav-item,
button,
legend {
    font-family: "Barlow Condensed", "IBM Plex Sans", sans-serif;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    font-weight: 600;
}

/* The readout: anything the device reports back. */
.readout {
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 12px;
    letter-spacing: 0.02em;
}

/* =============================================================================
   Status LED
   ============================================================================= */

.led {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex: 0 0 auto;
    background: var(--engrave);
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.45);
    transition: background 160ms ease, box-shadow 160ms ease;
}

.led[data-state="on"] {
    background: var(--led-on);
    box-shadow: 0 0 7px var(--led-on), inset 0 1px 1px rgba(255, 255, 255, 0.5);
}

.led[data-state="wait"] {
    background: var(--led-wait);
    box-shadow: 0 0 7px var(--led-wait), inset 0 1px 1px rgba(255, 255, 255, 0.5);
    animation: pulse 900ms ease-in-out infinite;
}

.led[data-state="off"] {
    background: var(--led-off);
    box-shadow: 0 0 7px var(--led-off), inset 0 1px 1px rgba(255, 255, 255, 0.5);
}

@keyframes pulse {
    50% { opacity: 0.35; }
}

@media (prefers-reduced-motion: reduce) {
    .led[data-state="wait"] {
        animation: none;
    }
    * {
        transition: none !important;
    }
}

/* =============================================================================
   Faceplate: the physical panel every screen sits on
   ============================================================================= */

.faceplate {
    background: var(--panel);
    border: var(--rule);
    border-radius: var(--radius);
    box-shadow:
        0 1px 0 rgba(255, 255, 255, 0.85) inset,
        0 2px 6px rgba(27, 33, 38, 0.16);
}

/* Screw heads at the plate corners. Four, like the real thing. */
.faceplate--screwed {
    position: relative;
}

.faceplate--screwed::before,
.faceplate--screwed::after {
    content: "";
    position: absolute;
    top: 10px;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background:
        linear-gradient(180deg, var(--alu-light), var(--alu-dark));
    box-shadow: inset 0 0 0 1px var(--engrave);
}

.faceplate--screwed::before { left: 10px; }
.faceplate--screwed::after  { right: 10px; }

/* =============================================================================
   Login
   ============================================================================= */

.login-stage {
    min-height: 100%;
    display: grid;
    place-items: center;
    padding: 24px;
}

.login-panel {
    width: 100%;
    max-width: 380px;
    padding: 34px 30px 26px;
}

.brand {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding-bottom: 12px;
    border-bottom: var(--rule);
}

.brand h1 {
    font-family: "Barlow Condensed", sans-serif;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    font-size: 26px;
    font-weight: 700;
    margin: 0;
}

.brand .model {
    font-family: "IBM Plex Mono", monospace;
    font-size: 11px;
    color: var(--ink-soft);
}

.login-panel form {
    margin: 24px 0 0;
}

/* =============================================================================
   Fields
   ============================================================================= */

.field {
    margin-bottom: 16px;
}

label {
    display: block;
    font-size: 12px;
    color: var(--ink-soft);
    margin-bottom: 5px;
}

input[type="text"],
input[type="password"],
input[type="email"],
select {
    width: 100%;
    padding: 9px 10px;
    font-family: "IBM Plex Mono", monospace;
    font-size: 13px;
    color: var(--ink);
    background: #fff;
    border: 1px solid var(--engrave);
    border-radius: var(--radius);
    box-shadow: inset 0 1px 2px rgba(27, 33, 38, 0.12);
}

input:focus-visible,
select:focus-visible,
button:focus-visible,
.nav-item:focus-visible {
    outline: 2px solid var(--petrol);
    outline-offset: 1px;
}

/* =============================================================================
   Buttons: engraved keys
   ============================================================================= */

button {
    font-size: 13px;
    padding: 9px 16px;
    color: var(--panel);
    background: linear-gradient(180deg, var(--petrol), var(--petrol-dark));
    border: 1px solid var(--petrol-dark);
    border-radius: var(--radius);
    cursor: pointer;
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.35) inset;
}

button:hover:not(:disabled) {
    filter: brightness(1.08);
}

button:active:not(:disabled) {
    transform: translateY(1px);
    box-shadow: none;
}

button:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

button.ghost {
    color: var(--ink);
    background: linear-gradient(180deg, #fff, var(--alu-light));
    border-color: var(--engrave);
}

button.danger {
    background: linear-gradient(180deg, #cf5648, #a83b2f);
    border-color: #8f3226;
}

button.wide {
    width: 100%;
}

button.tiny {
    font-size: 11px;
    padding: 5px 9px;
}

/* =============================================================================
   Readout strip: the panel talks back here
   ============================================================================= */

.strip {
    display: flex;
    align-items: center;
    gap: 9px;
    min-height: 30px;
    margin-top: 16px;
    padding: 6px 9px;
    background: var(--ink);
    color: var(--alu-light);
    border-radius: var(--radius);
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.6);
}

.strip .readout {
    color: var(--alu-light);
}

.strip[data-state="off"] .readout {
    color: #f0a79c;
}

/* =============================================================================
   Dashboard shell
   ============================================================================= */

.shell {
    display: grid;
    grid-template-columns: 220px 1fr;
    min-height: 100vh;
}

.rack {
    background: var(--panel);
    border-right: var(--rule);
    padding: 0 14px 20px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.rack .brand {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 0;
    height: var(--header-h);
    padding: 0;
    border-bottom: var(--rule);
    margin-bottom: 14px;
}

.rack .brand h1 {
    font-size: 19px;
}

.nav-item {
    display: block;
    width: 100%;
    text-align: left;
    font-size: 13px;
    padding: 9px 11px;
    color: var(--ink);
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius);
    box-shadow: none;
    cursor: pointer;
}

.nav-item:hover {
    background: var(--alu-light);
    filter: none;
}

.nav-item[aria-current="page"] {
    background: var(--alu-light);
    border-color: var(--engrave);
    box-shadow: inset 2px 0 0 var(--petrol);
}

.rack-foot {
    margin-top: auto;
    padding-top: 14px;
    border-top: var(--rule);
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* The identity block is the way into the profile view. It is a button, so it
   inherits the petrol key styling and the uppercase silkscreen label: both are
   undone here. It reads as a name, and behaves as a nav item. */
.who {
    display: block;
    width: 100%;
    text-align: left;
    font-family: "IBM Plex Sans", system-ui, sans-serif;
    text-transform: none;
    letter-spacing: 0;
    font-weight: 400;
    font-size: 12px;
    color: var(--ink-soft);
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius);
    box-shadow: none;
    padding: 8px 11px;
    cursor: pointer;
    word-break: break-word;
}

.who:hover {
    background: var(--alu-light);
    filter: none;
}

.who[aria-current="page"] {
    background: var(--alu-light);
    border-color: var(--engrave);
    box-shadow: inset 2px 0 0 var(--petrol);
}

.who:focus-visible {
    outline: 2px solid var(--petrol);
    outline-offset: 1px;
}

.who strong {
    display: block;
    color: var(--ink);
    font-size: 13px;
    font-weight: 600;
}

.main {
    padding: 0 30px 40px;
    overflow-x: auto;
}

/* Mirrors .rack .brand: same height, same rule, so the two line up across the
   seam. The height is declared, not inherited from the title, so a longer
   heading or a different font size cannot knock the rules out of alignment. */
.view-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    height: var(--header-h);
    padding: 0;
    margin-bottom: 18px;
    border-bottom: var(--rule);
}

.view-head h2 {
    font-family: "Barlow Condensed", sans-serif;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    font-size: 21px;
    font-weight: 700;
    margin: 0;
}

.view-head p {
    margin: 0;
    color: var(--ink-soft);
    font-size: 13px;
    text-transform: none;
    letter-spacing: 0;
}

/* =============================================================================
   Data table: a printed readout, not a web table
   ============================================================================= */

.plate {
    padding: 16px 18px;
    margin-bottom: 22px;
}

.plate > h3 {
    font-family: "Barlow Condensed", sans-serif;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    font-size: 14px;
    margin: 0 0 14px;
    color: var(--ink-soft);
}

table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}

th {
    font-size: 11px;
    color: var(--ink-soft);
    text-align: left;
    padding: 0 10px 7px;
    border-bottom: var(--rule);
    white-space: nowrap;
}

td {
    padding: 9px 10px;
    border-bottom: 1px solid var(--alu-light);
    vertical-align: middle;
}

td.mono {
    font-family: "IBM Plex Mono", monospace;
    font-size: 12px;
}

tr:last-child td {
    border-bottom: none;
}

.row-actions {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
}

.state {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--ink-soft);
}

.role {
    font-family: "IBM Plex Mono", monospace;
    font-size: 11px;
    padding: 2px 6px;
    border: 1px solid var(--engrave);
    border-radius: var(--radius);
    color: var(--ink-soft);
}

.role[data-role="superadmin"] {
    color: var(--petrol-dark);
    border-color: var(--petrol);
}

/* =============================================================================
   Forms laid out on a plate
   ============================================================================= */

.grid-form {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    gap: 14px;
    align-items: end;
}

.grid-form .actions {
    grid-column: 1 / -1;
    display: flex;
    gap: 8px;
}

fieldset {
    border: none;
    padding: 0;
    margin: 0;
}

/* =============================================================================
   Empty state: an invitation, not an apology
   ============================================================================= */

.empty {
    padding: 34px 20px;
    text-align: center;
    color: var(--ink-soft);
    border: 1px dashed var(--engrave);
    border-radius: var(--radius);
}

.empty h3 {
    font-family: "Barlow Condensed", sans-serif;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--ink);
    margin: 0 0 6px;
}

.empty p {
    margin: 0;
    font-size: 13px;
}

/* =============================================================================
   Responsive
   ============================================================================= */

@media (max-width: 720px) {
    .shell {
        grid-template-columns: 1fr;
    }

    /* Stacked columns: there is no seam to align, and a fixed height would
       clip a heading that wraps. */
    .rack .brand,
    .view-head {
        height: auto;
        padding: 14px 0;
    }

    .rack {
        border-right: none;
        border-bottom: var(--rule);
    }

    .rack-foot {
        margin-top: 14px;
    }

    .main {
        padding: 20px 16px 32px;
    }
}

/* =============================================================================
   Device table: rows are clickable
   ============================================================================= */

tr.pickable {
    cursor: pointer;
}

tr.pickable:hover td {
    background: var(--alu-light);
}

tr.pickable[aria-selected="true"] td {
    background: var(--alu-light);
    box-shadow: inset 2px 0 0 var(--petrol);
}

/* =============================================================================
   Pager
   ============================================================================= */

.pager {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 12px;
    margin-top: 14px;
    padding-top: 12px;
    border-top: var(--rule);
}

/* =============================================================================
   Device cards

   Each card is a small module on the rack: engraved id, a battery gauge, and
   the time since the equipment last spoke. Clicking one opens its readings.
   ============================================================================= */

.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 14px;
}

.device-card {
    display: flex;
    flex-direction: column;
    gap: 12px;
    text-align: left;
    padding: 14px 15px 13px;
    background: linear-gradient(180deg, #fff, var(--alu-light));
    border: 1px solid var(--engrave);
    border-radius: 6px;
    box-shadow:
        0 1px 0 rgba(255, 255, 255, 0.9) inset,
        0 1px 3px rgba(27, 33, 38, 0.12);
    cursor: pointer;
    transition: box-shadow 140ms ease, transform 140ms ease;
}

.device-card:hover {
    transform: translateY(-1px);
    box-shadow:
        0 1px 0 rgba(255, 255, 255, 0.9) inset,
        0 3px 8px rgba(27, 33, 38, 0.18);
}

.device-card:active {
    transform: translateY(0);
}

.device-card:focus-visible {
    outline: 2px solid var(--petrol);
    outline-offset: 2px;
}

.device-card[aria-selected="true"] {
    border-color: var(--petrol);
    box-shadow:
        inset 3px 0 0 var(--petrol),
        0 1px 3px rgba(27, 33, 38, 0.14);
}

/* --- head: the engraved identifier --------------------------------------- */

.card-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--engrave);
}

.card-id {
    font-family: "IBM Plex Mono", monospace;
    font-size: 21px;
    font-weight: 500;
    letter-spacing: 0.02em;
    color: var(--ink);
}

.card-flag {
    font-family: "Barlow Condensed", sans-serif;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    font-size: 11px;
    color: var(--led-off);
}

.card-comment {
    font-size: 12px;
    color: var(--ink-soft);
    margin-top: -6px;
    min-height: 1em;
    word-break: break-word;
}

/* --- battery gauge -------------------------------------------------------- */

.card-battery {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.battery-gauge {
    display: flex;
    align-items: center;
    gap: 10px;
}

.battery {
    flex: 0 0 auto;
}

.battery .shell {
    fill: none;
    stroke: var(--ink-soft);
    stroke-width: 1.5;
}

.battery .cap {
    fill: var(--ink-soft);
}

.battery .fill[data-level="high"] { fill: var(--led-on); }
.battery .fill[data-level="mid"]  { fill: var(--led-wait); }
.battery .fill[data-level="low"]  { fill: var(--led-off); }

.battery[data-level="none"] .shell {
    stroke-dasharray: 3 2;
}

.battery-mv {
    font-family: "IBM Plex Mono", monospace;
    font-size: 15px;
    font-weight: 500;
    text-transform: none;
    color: var(--ink);
}

.battery-pct {
    font-family: "Barlow Condensed", sans-serif;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-size: 12px;
    color: var(--ink-soft);
}

/* --- foot: how long since it spoke ---------------------------------------- */

.card-foot {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    padding-top: 10px;
    border-top: 1px solid var(--alu-dark);
}

.card-foot .label {
    font-size: 10px;
    color: var(--ink-soft);
}

.card-since {
    font-family: "IBM Plex Mono", monospace;
    font-size: 12px;
    color: var(--ink);
}

.card-since[data-stale="true"] {
    color: var(--led-off);
}

/* =============================================================================
   Device detail
   ============================================================================= */

/* Spec list: label on the left, value on the right, engraved rule between rows */
.spec {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 0;
    margin: 0;
}

.spec dt {
    font-family: "Barlow Condensed", sans-serif;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-size: 12px;
    color: var(--ink-soft);
    padding: 8px 20px 8px 0;
    border-bottom: 1px solid var(--alu-light);
}

.spec dd {
    font-family: "IBM Plex Mono", monospace;
    font-size: 13px;
    color: var(--ink);
    margin: 0;
    padding: 8px 0;
    border-bottom: 1px solid var(--alu-light);
}

.spec dt:last-of-type,
.spec dd:last-of-type {
    border-bottom: none;
}

/* The readings table sits inside a fixed-height frame: rows scroll internally
   so the page height never grows with the row count. */
.table-frame {
    max-height: 420px;
    overflow-y: auto;
    border: 1px solid var(--alu-light);
    border-radius: var(--radius);
}

.table-frame table {
    margin: 0;
}

/* Keep the header visible while the body scrolls under it. */
.table-frame thead th {
    position: sticky;
    top: 0;
    background: var(--panel);
    z-index: 1;
}

/* =============================================================================
   BLE configuration
   ============================================================================= */

.ble-bar {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 16px;
}

.ble-bar .state {
    flex: 1;
    min-width: 140px;
}

.ble-log {
    height: 150px;
    overflow-y: auto;
    white-space: pre-wrap;
    background: var(--ink);
    color: var(--alu-light);
    border-radius: var(--radius);
    padding: 10px;
    margin-top: 5px;
    font-size: 11px;
    line-height: 1.5;
}

.ble-log .tx { color: #7fb2ff; }
.ble-log .rx { color: #7ee0a0; }
.ble-log .err { color: #f0a79c; }

/* =============================================================================
   Device detail: two-column layout

   Data + Bluetooth stack on the left; the readings table takes the right.
   The left column is capped so the table gets the room it needs, which also
   removes the wide empty margins the single stacked column used to leave.
   ============================================================================= */

.device-layout {
    display: grid;
    grid-template-columns: minmax(320px, 400px) minmax(0, 1fr);
    gap: 18px;
    align-items: start;
}

.device-col-left,
.device-col-right {
    display: flex;
    flex-direction: column;
    gap: 18px;
    min-width: 0;
}

.device-col-left .plate,
.device-col-right .plate {
    margin-bottom: 0;
}

/* One column once there is no room for two. */
@media (max-width: 860px) {
    .device-layout {
        grid-template-columns: 1fr;
    }
}

/* =============================================================================
   Flag toggle (active / listed) in the device spec list
   ============================================================================= */

.flag-toggle {
    font-family: "IBM Plex Mono", monospace;
    text-transform: none;
    letter-spacing: 0;
    font-size: 12px;
    padding: 3px 12px;
    color: var(--panel);
    background: linear-gradient(180deg, var(--led-off), #a83b2f);
    border: 1px solid #8f3226;
    border-radius: 999px;
    cursor: pointer;
    box-shadow: none;
}

.flag-toggle[data-on="true"] {
    background: linear-gradient(180deg, var(--led-on), #2e8446);
    border-color: #256b39;
}

.flag-toggle:hover:not(:disabled) {
    filter: brightness(1.08);
}

.flag-toggle:disabled {
    opacity: 0.5;
    cursor: wait;
}
