/* dp5_admin_pages.css
 * DP5 P3 admin/configuration page scaffold.
 * Date: 2026-05-25
 * Status: Rev 7, rebased on the live DP5 Wave 1 and Wave 2a hotfixes.
 * Sits next to per-page stylesheets like 01-dashboard.css under static/v2_4/.
 *
 * Scope:
 *   - Canonical configuration-form scaffold reused across 9 admin pages.
 *   - Admin-only empty-state for manager and client tokens (smoke fallback).
 *   - Audit-row hover for table-and-filter admin pages.
 *   - Tab-strip extension (re-uses .ot-toolbar primitives where possible).
 *
 * Out of scope: any colour outside optimal-design-system.css custom properties.
 *               any button or pill primitive (use .ot-btn / .ot-status-pill).
 *               any new shadow, gradient or animation.
 */

/* -------------------------------------------------- *
 * 1. Configuration-form scaffold
 *    Card per section -> .ot-card .ot-card--form
 *    Grid for label / control pairs -> .ot-form-grid
 *    Row within the grid -> .ot-form-row
 *    Action bar bottom-right -> .ot-form-actions
 * -------------------------------------------------- */

.ot-card--form {
    /* Inherits .ot-card chrome: navy header strip, white body, paper alt row. */
    padding: 0;
}

.ot-card--form > .ot-card__header {
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--rule-light);
}

.ot-card--form > .ot-card__body {
    padding: var(--space-4);
}

.ot-form-grid {
    display: grid;
    grid-template-columns: minmax(140px, 220px) 1fr;
    column-gap: var(--space-4);
    row-gap: var(--space-3);
    align-items: start;
}

.ot-form-grid--wide {
    grid-template-columns: minmax(180px, 280px) 1fr;
}

.ot-form-grid--single {
    grid-template-columns: 1fr;
}

.ot-form-row {
    display: contents;
}

.ot-form-row > label {
    font-family: var(--font-sans);
    font-size: 13px;
    line-height: 1.4;
    color: var(--ink-3);
    padding-top: 10px;
}

.ot-form-row > label.ot-form-row__required::after {
    content: " *";
    color: var(--severity-warn, var(--brand-teal));
}

.ot-form-row > .ot-form-row__control {
    min-width: 0;
}

.ot-form-row > .ot-form-row__help {
    grid-column: 2;
    font-size: 12px;
    color: var(--ink-4);
    margin-top: -4px;
    margin-bottom: var(--space-2);
}

/* Input / select / textarea baseline at 40px height to match .ot-controls input. */
.ot-form-row__control input[type="text"],
.ot-form-row__control input[type="number"],
.ot-form-row__control input[type="password"],
.ot-form-row__control input[type="email"],
.ot-form-row__control input[type="url"],
.ot-form-row__control select,
.ot-form-row__control textarea {
    width: 100%;
    box-sizing: border-box;
    height: 40px;
    padding: 8px 12px;
    background: var(--white);
    color: var(--ink);
    border: 1px solid var(--rule);
    border-radius: 6px;
    font-family: var(--font-sans);
    font-size: 14px;
    line-height: 1.4;
    transition: border-color 120ms ease-in-out;
}

.ot-form-row__control textarea {
    height: auto;
    min-height: 80px;
    resize: vertical;
}

.ot-form-row__control input:focus,
.ot-form-row__control select:focus,
.ot-form-row__control textarea:focus {
    outline: 2px solid var(--teal);
    outline-offset: 1px;
    border-color: var(--teal);
}

.ot-form-row__control input[disabled],
.ot-form-row__control select[disabled],
.ot-form-row__control textarea[disabled] {
    background: var(--paper);
    color: var(--ink-4);
    cursor: not-allowed;
}

.ot-form-row__control input[aria-invalid="true"],
.ot-form-row__control select[aria-invalid="true"],
.ot-form-row__control textarea[aria-invalid="true"] {
    border-color: var(--severity-warn, var(--teal));
}

.ot-form-row__control .ot-checkbox,
.ot-form-row__control .ot-radio {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--ink);
    padding: 10px 0;
}

.ot-form-actions {
    display: flex;
    gap: var(--space-2);
    justify-content: flex-end;
    margin-top: var(--space-4);
    padding-top: var(--space-3);
    border-top: 1px solid var(--rule-light);
}

.ot-form-callback {
    margin-top: var(--space-3);
    font-size: 13px;
}

.ot-form-callback[role="status"] {
    color: var(--ink-3);
}

.ot-form-callback[data-state="ok"] {
    color: var(--severity-ok, var(--teal));
}

.ot-form-callback[data-state="error"] {
    color: var(--severity-warn, var(--teal));
}

/* -------------------------------------------------- *
 * 2. Admin-only empty-state for non-admin tokens
 *    Used when a manager or client token loads an admin-only page
 *    and the server returns 403 or scope-empty. Provides the
 *    smoke fallback documented in section 12 of the band-prep note.
 * -------------------------------------------------- */

.ot-admin-only-empty {
    margin: var(--space-6) auto;
    max-width: 520px;
    padding: var(--space-5);
    text-align: center;
    background: var(--paper);
    border: 1px solid var(--rule-light);
    border-radius: 8px;
}

.ot-admin-only-empty__title {
    font-family: var(--font-serif);
    font-size: 18px;
    color: var(--navy);
    margin: 0 0 var(--space-2);
}

.ot-admin-only-empty__body {
    font-family: var(--font-sans);
    font-size: 13px;
    color: var(--ink-3);
    line-height: 1.5;
    margin: 0;
}

.ot-admin-only-empty[hidden] {
    display: none;
}

/* -------------------------------------------------- *
 * 3. Audit-row hover (table-and-filter admin pages)
 *    Used by 22-login-audit.html and the 16-hardware-admin
 *    table-and-filter sub-archetype.
 * -------------------------------------------------- */

.ot-audit-table {
    width: 100%;
    border-collapse: collapse;
    font-family: var(--font-sans);
    font-size: 13px;
}

.ot-audit-table thead th {
    text-align: left;
    font-weight: 600;
    color: var(--ink-3);
    padding: 10px 12px;
    border-bottom: 1px solid var(--rule);
    background: var(--paper);
    font-size: 12px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.ot-audit-table tbody tr {
    transition: background-color 120ms ease-in-out;
}

.ot-audit-table tbody tr:nth-child(2n) {
    background: var(--paper);
}

.ot-audit-table tbody tr:hover {
    background: var(--teal-light);
}

.ot-audit-table tbody tr[aria-selected="true"] {
    background: var(--teal-light);
    outline: 2px solid var(--teal);
    outline-offset: -2px;
}

.ot-audit-table tbody td {
    padding: 8px 12px;
    border-bottom: 1px solid var(--rule-light);
    color: var(--ink);
    vertical-align: top;
}

.ot-audit-table tbody td.ot-audit-table__cell--mono {
    font-family: var(--font-mono, ui-monospace, "SF Mono", Menlo, monospace);
    font-size: 12px;
    color: var(--ink-2);
}

/* -------------------------------------------------- *
 * 4. Tab-strip extension (admin pages with multiple
 *    configuration sections under one page).
 *    Re-uses .ot-toolbar spacing but adds the active
 *    underline rail. No new colour primitive.
 * -------------------------------------------------- */

.ot-tab-strip {
    display: flex;
    gap: 0;
    border-bottom: 1px solid var(--rule);
    margin-bottom: var(--space-4);
    overflow-x: auto;
}

.ot-tab-strip__btn {
    border: none;
    background: transparent;
    padding: 10px 16px;
    font-family: var(--font-sans);
    font-size: 13px;
    color: var(--ink-2);
    cursor: pointer;
    border-bottom: 2px solid transparent;
    transition: color 120ms ease-in-out, border-color 120ms ease-in-out;
    white-space: nowrap;
}

.ot-tab-strip__btn:hover {
    color: var(--navy);
}

.ot-tab-strip__btn[aria-selected="true"] {
    color: var(--navy);
    border-bottom-color: var(--teal);
    font-weight: 600;
}

.ot-tab-strip__btn[disabled] {
    color: var(--ink-4);
    cursor: not-allowed;
}

.ot-tab-panel[hidden] {
    display: none;
}

.ot-tab-panel:not([hidden]) {
    display: block;
}

/* -------------------------------------------------- *
 * 5. Page-level wrapper spacing for admin pages
 *    Slightly tighter rhythm than dashboard pages so
 *    long forms fit without excessive scrolling.
 * -------------------------------------------------- */

.ot-page--admin {
    padding: var(--space-4) var(--space-5);
    max-width: 1280px;
    margin: 0 auto;
}

.ot-page--admin > .ot-page__header {
    margin-bottom: var(--space-4);
}

.ot-page--admin > .ot-page__header h1 {
    font-family: var(--font-serif);
    font-size: 22px;
    color: var(--navy);
    margin: 0 0 4px;
    font-weight: 600;
}

.ot-page--admin > .ot-page__header p {
    font-family: var(--font-sans);
    font-size: 13px;
    color: var(--ink-3);
    margin: 0;
}

/* -------------------------------------------------- *
 * Footer
 * -------------------------------------------------- */
/* www.optimal.world | We are Optimal. Welcome to our World */

/* -------------------------------------------------- *
 * 6. Empty-state cell for data tables
 *    Used across the admin pages for "No configured data"
 *    rows that previously relied on inline style attributes.
 * -------------------------------------------------- */

.ot-audit-table td.ot-empty-state-cell,
.ot-audit-table tr.ot-empty-state-row td {
    text-align: center;
    color: var(--ink-4);
    padding: var(--space-5);
    font-style: italic;
}

/* -------------------------------------------------- *
 * 7. Page-specific helpers (carried by dp5_admin_pages.css
 *    so they apply consistently across the 9 admin pages).
 * -------------------------------------------------- */

.ot-page--admin .ot-kpi-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--space-4);
    margin-bottom: var(--space-5);
}

.ot-page--admin .ot-kpi-card {
    background: var(--white);
    border: 1px solid var(--rule-light);
    border-radius: 8px;
    padding: var(--space-4);
    text-align: center;
}

.ot-page--admin .ot-kpi-card__label {
    font-family: var(--font-sans);
    font-size: 11px;
    color: var(--ink-3);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin: 0 0 6px;
}

.ot-page--admin .ot-kpi-card__value {
    font-family: var(--font-serif);
    font-size: 28px;
    font-weight: 600;
    color: var(--navy);
    margin: 0 0 4px;
    line-height: 1.15;
}

.ot-page--admin .ot-kpi-card__detail {
    font-family: var(--font-sans);
    font-size: 12px;
    color: var(--ink-4);
    margin: 0;
}

.ot-page--admin .ot-kv-list {
    display: grid;
    grid-template-columns: minmax(130px, max-content) 1fr;
    column-gap: var(--space-3);
    row-gap: 4px;
    margin: 0;
    font-family: var(--font-sans);
    font-size: 13px;
}

.ot-page--admin .ot-kv-list dt {
    color: var(--ink-3);
    font-weight: 600;
}

.ot-page--admin .ot-kv-list dd {
    margin: 0;
    color: var(--ink);
    word-break: break-all;
}

.ot-page--admin .ot-section {
    margin-top: var(--space-5);
}

.ot-page--admin .ot-section__title {
    font-family: var(--font-serif);
    font-size: 17px;
    color: var(--navy);
    margin: 0 0 var(--space-3);
    font-weight: 600;
}

.ot-page--admin .ot-chart-frame {
    background: var(--paper);
    border: 1px solid var(--rule-light);
    border-radius: 8px;
    padding: var(--space-3);
    height: 300px;
    position: relative;
}

/* -------------------------------------------------- *
 * 8. Form-actions inset modifier
 *    Used for inline action buttons inside a form-row
 *    control area (e.g. certificate upload buttons).
 * -------------------------------------------------- */

.ot-form-actions.ot-form-actions--inset {
    margin-top: 0;
    padding-top: 0;
    border: none;
    justify-content: flex-start;
}

/* -------------------------------------------------- *
 * 9. W2a primitives (modal-based admin form pages)
 *    Used by 24-server-config, 25-data-integration,
 *    26-license-management, 27-sensor-import.
 * -------------------------------------------------- */

/* 9.1 Error banner (top-of-page error message)
 *     Replaces the inline `style="display:none"` pattern. */
.ot-error-banner {
    margin: 0 0 var(--space-4);
    padding: var(--space-3) var(--space-4);
    background: var(--teal-light);
    border: 1px solid var(--rule);
    color: var(--navy);
    border-radius: 6px;
    font-family: var(--font-sans);
    font-size: 13px;
}

.ot-error-banner[hidden] {
    display: none;
}

/* 9.2 Grid-span-all helper
 *     Used for full-width children inside an ot-form-grid or
 *     ot-status-cards-grid (e.g. loading spinners). Replaces inline
 *     style="grid-column: 1/-1". */
.ot-grid-span-all {
    grid-column: 1 / -1;
}

/* 9.3 Status cards (server/service status panels)
 *     Used by 24-server-config and similar pages that show a small
 *     grid of running/stopped service tiles. */
.ot-status-cards-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: var(--space-3);
}

.ot-status-card {
    background: var(--white);
    border: 1px solid var(--rule-light);
    border-radius: 8px;
    padding: var(--space-3) var(--space-4);
}

.ot-status-card__header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: var(--space-3);
}

.ot-status-card__title {
    font-family: var(--font-sans);
    font-size: 13px;
    font-weight: 600;
    color: var(--navy);
    margin: 0;
}

.ot-status-card__row {
    display: flex;
    justify-content: space-between;
    font-size: 12px;
    color: var(--ink-3);
    padding: 4px 0;
    border-bottom: 1px solid var(--rule-light);
}

.ot-status-card__row:last-child {
    border-bottom: none;
}

.ot-status-card__row__value {
    color: var(--ink);
    font-weight: 500;
}

/* 9.4 Modal primitive
 *     Used by 24, 25 and 26 for edit / add forms. Hidden by default,
 *     shown when JS adds the .active class. */
.ot-modal {
    position: fixed;
    inset: 0;
    background: var(--navy-dark);
    display: none;
    align-items: flex-start;
    justify-content: center;
    z-index: 1000;
    overflow-y: auto;
    padding: var(--space-6) var(--space-4);
}

.ot-modal.active {
    display: flex;
}

.ot-modal__content {
    background: var(--white);
    border-radius: 10px;
    max-width: 560px;
    width: 100%;
    border: 1px solid var(--rule-light);
    overflow: hidden;
}

.ot-modal__header {
    background: var(--navy);
    color: var(--white);
    padding: var(--space-3) var(--space-4);
    font-family: var(--font-serif);
    font-size: 16px;
    font-weight: 600;
}

.ot-modal__body {
    padding: var(--space-4);
}

.ot-modal__actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    background: var(--paper);
    border-top: 1px solid var(--rule-light);
}

/* 9.5 Page-header meta strip
 *     Used by 24/25/26 to show timezone/UTC offset next to the page
 *     title. Replaces .header-info inline pattern. */
.ot-page__header__meta {
    display: flex;
    gap: var(--space-3);
    color: var(--ink-3);
    font-family: var(--font-sans);
    font-size: 12px;
    margin-top: var(--space-2);
}

/* 9.6 Section header with action button
 *     Used inside .ot-card--form headers where an inline Edit button
 *     sits on the right. */
.ot-card__header--with-action {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

/* 9.7 Counter bar (used by 26-license-management for device allocation) */
.ot-counter-bar {
    height: 8px;
    background: var(--rule-light);
    border-radius: 4px;
    overflow: hidden;
    margin: var(--space-2) 0 var(--space-3);
}

.ot-counter-bar__fill {
    height: 100%;
    width: var(--ot-counter-fill, 0%);
    background: var(--teal);
    border-radius: 4px;
    transition: width 240ms ease-out;
}

/* 9.8 Code chip (replaces inline-style code element in JS template strings) */
.ot-code-chip {
    display: inline-block;
    font-family: var(--font-mono, ui-monospace, "SF Mono", Menlo, monospace);
    font-size: 11px;
    color: var(--ink-2);
    background: var(--paper);
    padding: 2px 6px;
    border-radius: 4px;
    border: 1px solid var(--rule-light);
}

/* 9.9 Source-type badge (for 25-data-integration) */
.ot-type-badge {
    display: inline-block;
    font-family: var(--font-sans);
    font-size: 11px;
    font-weight: 600;
    color: var(--navy);
    background: var(--teal-light);
    padding: 2px 8px;
    border-radius: 10px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* 9.10 Mapping field (for 25-data-integration field mappings list) */
.ot-mapping-field {
    background: var(--paper);
    border: 1px solid var(--rule-light);
    border-radius: 6px;
    padding: var(--space-3);
    margin-bottom: var(--space-2);
}

.ot-mapping-field__source {
    margin-top: var(--space-2);
    color: var(--ink-4);
    font-size: 12px;
}

/* 9.11 Section spacer (replaces empty <div style="margin-top:..."></div>) */
.ot-section--spaced {
    margin-top: var(--space-5);
}

/* 9.12 Upload zone (used by 27-sensor-import) */
.ot-upload-zone {
    min-height: 176px;
    border: 1px dashed var(--rule);
    background: var(--paper);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: var(--space-6);
    color: var(--ink-3);
    text-align: center;
    cursor: pointer;
    transition: border-color 160ms ease, background-color 160ms ease, color 160ms ease;
}

.ot-upload-zone:hover,
.ot-upload-zone.is-dragover {
    border-color: var(--teal);
    background: var(--teal-light);
    color: var(--navy);
}

.ot-upload-zone:focus-within {
    outline: 2px solid var(--teal);
    outline-offset: 2px;
}

.ot-upload-zone__title {
    margin: 0;
    font-family: var(--font-serif);
    font-size: 22px;
    color: var(--navy);
}

.ot-upload-zone__subtitle {
    margin: 0;
    font-family: var(--font-sans);
    font-size: 14px;
    color: var(--ink-4);
}

.ot-upload-zone__input {
    display: none;
}


/* UI correction 2026-05-26 */
.ot-ai-console { max-width: none; }
.ot-ai-console #panel-overview:not([hidden]) { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--space-4); align-items: start; }
.ot-ai-console #panel-overview > .ot-card:nth-child(1) { grid-column: span 4; }
.ot-ai-console #panel-overview > .ot-card:nth-child(2) { grid-column: span 5; }
.ot-ai-console #panel-overview > .ot-card:nth-child(3) { grid-column: span 3; }
.ot-ai-console .ot-tab-panel:not([hidden]) .ot-card--form { margin-bottom: var(--space-4); }
.ot-hierarchy-tree { display: flex; flex-direction: column; gap: 6px; max-height: 560px; overflow: auto; padding: var(--space-2); border: 1px solid var(--rule-light); background: var(--paper); }
.ot-hierarchy-node { position: relative; }
.ot-hierarchy-node--depth-0 { margin-left: 0; }
.ot-hierarchy-node--depth-1 { margin-left: 18px; }
.ot-hierarchy-node--depth-2 { margin-left: 36px; }
.ot-hierarchy-node--depth-3 { margin-left: 54px; }
.ot-hierarchy-node--depth-4 { margin-left: 72px; }
.ot-hierarchy-node--depth-5 { margin-left: 90px; }
.ot-hierarchy-node--depth-6 { margin-left: 108px; }
.ot-hierarchy-node::before { content: ""; position: absolute; left: -10px; top: 0; bottom: 0; border-left: 1px solid var(--rule-light); }
.ot-hierarchy-node--depth-0::before { display: none; }
.ot-hierarchy-node__button { width: 100%; min-height: 40px; display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); border: 1px solid var(--rule-light); background: var(--white); color: var(--navy); padding: var(--space-2) var(--space-3); font-family: var(--font-sans); text-align: left; cursor: pointer; }
.ot-hierarchy-node__button:hover, .ot-hierarchy-node__button:focus { border-color: var(--teal); outline: none; }
.ot-hierarchy-node__label { font-weight: 700; }
.ot-hierarchy-node__meta { font-size: var(--text-xs); color: var(--ink-4); text-transform: uppercase; letter-spacing: 0.08em; }
@media (max-width: 900px) { .ot-ai-console #panel-overview:not([hidden]) { grid-template-columns: 1fr; } .ot-ai-console #panel-overview > .ot-card:nth-child(n) { grid-column: 1; } }
