.is-valid {
    border-color: #28a745 !important;
    background-color: #f8fff9 !important;
}

.is-invalid {
    border-color: #dc3545 !important;
    background-color: #fff8f8 !important;
}

#lineapitoken.is-invalid:focus {
    box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
}

#lineapitoken.is-valid:focus {
    box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);
}

/* Fix action column in device table to prevent wrapping and give enough space */
#dmodbustable td:last-child {
    min-width: 180px !important;
    white-space: nowrap !important;
    text-align: right !important;
    vertical-align: middle !important;
}

#dmodbustable th:last-child {
    min-width: 180px !important;
}

/* Better styling for the export progress bar */
.export-progress {
    background-color: #eee !important;
    border: 1px solid #ccc !important;
    box-shadow: inset 0 1px 3px rgba(0,0,0,0.1) !important;
    margin-right: 5px !important;
}

.export-progress .progress-bar {
    text-shadow: 0 1px 1px rgba(0,0,0,0.2);
    box-shadow: inset 0 -1px 0 rgba(0,0,0,0.15);
}

.download-container {
    min-width: 30px;
    text-align: right;
}

/* ============================================================================
   Page toolbar pattern (Phase 3 — visual consistency)
   Adopted by sections that have a Load From Device workflow:
   Schedule & Monitoring, Devices, Tags, Events, Data Log, Buffer, Modbus Spy.
   ============================================================================ */

/* Spinner animation used inside the Load button (refresh icon rotates) */
@keyframes spin-loader { 100% { transform: rotate(360deg); } }
.spin-loader {
    display: inline-block;
    animation: spin-loader 1s linear infinite;
}

/* Toolbar layout — flex container with consistent gap */
.page-toolbar,
[id$="-toolbar"] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 8px;
}

/* Last-loaded timestamp slot — quiet text, doesn't compete with title */
[id$="-last-loaded"] {
    color: #999;
    font-size: 0.9em;
}

/* Numeric badges in toolbars use tabular numerics so digits align as the
   count changes (matters in monitoring screens that update frequently) */
.panel-heading .badge {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
}

/* Tabular numerics for data-heavy tables — operators read scrolling values */
#monitortable td,
#dmodbustable td,
#modbustable td,
#eventtable td,
#datalogtable td,
#buffertable td {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
}

/* Status colour tokens — keep status meanings consistent across the app */
:root {
    --status-ok: #5cb85c;
    --status-warn: #f0ad4e;
    --status-danger: #d9534f;
    --status-info: #5bc0de;
    --status-muted: #999;
}

/* Reduce vertical space below the title hint text under each toolbar */
#monitorcontent .text-muted small,
#dmodbuscontent .text-muted small {
    font-size: 0.85em;
}

/* ============================================================================
   Devices page — inline bulk-select checkbox in front of the device name.
   The checkbox is hidden by default and only appears once the user clicks
   Edit (FooTable toggles .footable-editing-show on the table). Avoids the
   layout glitch caused by a stand-alone _select column being treated as a
   responsive overflow column and stacked under the expand (+) icon.
   Bulk action button visibility is JS-driven (updateBulkDeviceUI).
   ============================================================================ */
.dmodbus-checkbox-slot {
    display: none;
    margin-right: 8px;
    vertical-align: middle;
}
#dmodbustable.footable-editing-show .dmodbus-checkbox-slot {
    display: inline-block;
}
.dmodbus-checkbox-slot input[type="checkbox"] {
    cursor: pointer;
    vertical-align: middle;
}
/* User asked to drop the FooTable expand (+/-) icon and use only our checkbox
   as the leading element. Hide the toggle span — responsive overflow columns
   become invisible on small screens (acceptable for a desktop industrial UI). */
#dmodbustable span.footable-toggle {
    display: none !important;
}

/* Same bulk-checkbox pattern for the schedule (monitor) table. */
.monitor-checkbox-slot {
    display: none;
    margin-right: 8px;
    vertical-align: middle;
}
#monitortable.footable-editing-show .monitor-checkbox-slot {
    display: inline-block;
}
.monitor-checkbox-slot input[type="checkbox"] {
    cursor: pointer;
    vertical-align: middle;
}

/* ============================================================================
   Application design system — extracted from the Backup & Restore page
   (commit cf8d7cf) so every section can use the same visual shell.
   ============================================================================

   .app-panel        outermost container per section. Use bootstrap's
                     .panel.panel-default as the base; .app-panel adds
                     consistent spacing.
   .app-panel-head   header bar (replaces ad-hoc <legend>). Title left,
                     optional meta/actions right.
   .app-row          one logical group inside a panel body, separated by
                     a hair-line. Use for "action rows" or "form section".
   .app-row-head     title + meta line at top of a row.
   .app-row-title    bold title text.
   .app-row-meta     muted right-aligned meta (counts, hints).
   .app-row-desc     muted one-line description under the title.
   .app-row-actions  flex container for action buttons; min-width keeps
                     buttons from collapsing to icon-only.
   ========================================================================== */
.app-panel {
    margin-bottom: 16px;
}
.app-panel-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 8px;
}
.app-panel-head .app-panel-title {
    font-weight: 600;
}
.app-panel-head .app-panel-sub {
    color: #999;
    font-size: 0.85em;
}
.app-row {
    padding: 14px 18px;
    border-bottom: 1px solid #eee;
}
.app-row:last-child {
    border-bottom: none;
}
.app-row-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 4px;
}
.app-row-title {
    font-weight: 600;
    font-size: 1.05em;
}
.app-row-meta {
    color: #999;
    font-size: 0.85em;
}
.app-row-desc {
    color: #666;
    font-size: 0.9em;
    margin: 4px 0 10px;
}
.app-row-actions {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    align-items: center;
}
.app-row-actions .btn {
    min-width: 140px;
}

/* Form fields inside an app-row keep Bootstrap's grid but match the
   row's spacing + smaller, consistent typography. */
.app-row .form-group {
    margin-bottom: 12px;
}
.app-row .control-label {
    font-weight: 500;
    padding-top: 5px;
}
.app-row .info-popover {
    color: #999;
    margin-left: 6px;
    cursor: help;
}

/* Bootstrap modal polish so dialogs sit visually next to the new
   app-panel pages. Targets ALL .modal-content unless a modal opts
   out by overriding. Pairs with the app-* tokens above. */
.modal-header {
    padding: 12px 18px;
    background-color: #f5f5f5;
    border-bottom: 1px solid #ddd;
    border-top-left-radius: 6px;
    border-top-right-radius: 6px;
}
.modal-header .modal-title {
    font-weight: 600;
    font-size: 1.05em;
}
.modal-header .close {
    margin-top: 0;
}
.modal-body {
    padding: 16px 18px;
}
.modal-footer {
    padding: 12px 18px;
    background-color: #fafafa;
    border-top: 1px solid #eee;
}
/* Variants for danger / warning / info modals — set
   .modal-content.modal-content-danger (etc.) to pick. */
.modal-content-danger .modal-header  { background-color: #f2dede; }
.modal-content-warning .modal-header { background-color: #fcf8e3; }
.modal-content-info .modal-header    { background-color: #d9edf7; }

/* Form fields inside modals should follow the same control-label
   pattern as the app-row pages. */
.modal-body .form-group { margin-bottom: 14px; }
.modal-body .control-label { font-weight: 500; padding-top: 5px; }
.modal-body .info-popover { color: #999; margin-left: 6px; cursor: help; }

/* Status-page connection cards (Ethernet / Wi-Fi / 4G / LoRaWAN).
   Replaces the old .well well-sm + inline gray inline style.
   Tints green when the inner #stat_X holds the .online class and
   red on .offline so the dashboard reads at a glance. */
.stat-card {
    padding: 12px 6px;
    background-color: #f9f9f9;
    border: 1px solid #e7e7e7;
    border-radius: 4px;
    transition: background-color 0.2s, border-color 0.2s;
}
.stat-card > .glyphicon { font-size: 1.5em; color: #999; }
.stat-card > small { display: block; margin: 4px 0; color: #666; }
.stat-card.online {
    background-color: #dff0d8;
    border-color: #b6d6a8;
}
.stat-card.online > .glyphicon { color: #3c763d; }
.stat-card.offline > .glyphicon { color: #bbb; }
/* Card stays in the row when the radio isn't installed on this
   hardware so the 4-column grid never collapses. Use very low
   opacity and a striped background to read as "this slot is empty,
   not just offline." */
.stat-card.not-installed {
    background-color: #fafafa;
    border-color: #eee;
    opacity: 0.55;
    background-image: repeating-linear-gradient(
        45deg,
        transparent,
        transparent 6px,
        rgba(0,0,0,0.025) 6px,
        rgba(0,0,0,0.025) 12px
    );
}
.stat-card.not-installed > .glyphicon { color: #ccc; }
.stat-card.not-installed > small { color: #aaa; font-style: italic; }
.stat-card.not-installed > .label { background-color: #ccc; }

/* Status-page tables still use <caption> as their section title.
   Style captions to look like an app-panel-head so they sit visually
   alongside the new design system without a structural rewrite. */
#statuscontent .panel-default { margin-bottom: 16px; }
#statuscontent .panel-default > .table-responsive > table > caption,
#statuscontent .panel-default > table > caption,
#statuscontent .table > caption {
    padding: 10px 15px;
    color: inherit;
    font-weight: 600;
    background-color: #f5f5f5;
    border-bottom: 1px solid #ddd;
    text-align: left;
    caption-side: top;
    border-top-left-radius: 4px;
    border-top-right-radius: 4px;
}
