/*
 * app.css — screen furniture for the NPHIES Auto Poll console.
 *
 * The shell (sidebar + topbar), the cycle ribbon, the KPI row, the live feed, and the
 * empty / loading / stale / disconnected states. Generic components live in theme.css;
 * tokens live in tokens.css.
 *
 * Motion policy for this file: one orchestrated page-load stagger, doc-specified
 * micro-states, and two deliberate loops (reconnect pulse, skeleton) that stop the
 * instant their indeterminate state resolves. Live-feed row insertion is deliberately
 * NOT animated — rows arrive in bursts of 3 x branches every few minutes, and a per-row
 * entrance is a stutter storm on a screen someone watches all day.
 */

/* =========================================================== shell ==== */
.app-shell {
    display: grid;
    grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
    min-height: 100vh;
}

.app-main {
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 100vh;
}

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

.app-footer {
    border-top: 1px solid var(--ds-border);
    background-color: var(--ds-surface);
    color: var(--ds-body-subtle);
    font-size: var(--text-xs);
    padding: var(--space-4) var(--space-6);
}

/* ========================================================= sidebar ==== */
/* sidebars.md: 256px, neutral-primary-soft, 1px right border, 12/16 inner padding. */
.app-sidebar {
    background-color: var(--ds-surface);
    border-right: 1px solid var(--ds-border);
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
    z-index: var(--z-sidebar);
}

.app-sidebar__inner {
    display: flex;
    flex-direction: column;
    height: 100%;
    padding: var(--space-3) var(--space-4);
    gap: var(--space-4);
}

.app-brand {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2);
    color: var(--ds-heading);
    font-size: var(--text-base);
    font-weight: 600;
    text-decoration: none;
    border-radius: var(--ds-radius);
    line-height: var(--leading-tight);
}

.app-brand:hover { color: var(--ds-heading); text-decoration: none; }
.app-brand__mark { color: var(--ds-brand); flex: 0 0 auto; }
.app-brand__sub {
    display: block;
    font-size: var(--text-xs);
    font-weight: 400;
    color: var(--ds-body-subtle);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
}

.app-nav {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    list-style: none;
    margin: 0;
    padding: 0;
}

.app-nav__link {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2);
    border-radius: var(--ds-radius);
    color: var(--ds-body);
    font-size: var(--text-sm);
    font-weight: 500;
    text-decoration: none;
    transition: color var(--dur-color) var(--ease-standard),
                background-color var(--dur-color) var(--ease-standard);
}

.app-nav__link:hover,
.app-nav__link:focus-visible {
    color: var(--ds-heading);
    background-color: var(--ds-surface-3);
    text-decoration: none;
}

.app-nav__link .icon {
    color: var(--ds-body);
    /* 75ms — the doc specifies a faster transition for the icon than the label, and it is
       the reason the nav reads as crisp rather than laggy. */
    transition: color var(--dur-icon) var(--ease-standard);
}

.app-nav__link:hover .icon { color: var(--ds-heading); }

.app-nav__link.active {
    background-color: var(--ds-surface-3);
    color: var(--ds-fg-brand-strong);
    font-weight: 600;
}

.app-nav__link.active .icon { color: var(--ds-fg-brand); }

.app-nav__sep {
    margin: var(--space-2) 0 0;
    padding-top: var(--space-4);
    border-top: 1px solid var(--ds-border);
    list-style: none;
}

.app-nav__cta {
    margin-top: auto;
    padding: var(--space-3);
    border-radius: var(--ds-radius);
    background: var(--ds-brand-softer);
    border: 1px solid var(--ds-brand-border);
}

.app-nav__cta-title {
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--ds-fg-brand-strong);
    margin: 0 0 2px;
}

.app-nav__cta-body {
    font-size: var(--text-xs);
    color: var(--ds-fg-brand);
    margin: 0;
    line-height: var(--leading-normal);
}

/* ========================================================== topbar ==== */
.app-topbar {
    position: sticky;
    top: 0;
    z-index: var(--z-topbar);
    display: flex;
    align-items: center;
    gap: var(--space-3);
    min-height: var(--topbar-h);
    padding: var(--space-2) var(--space-6);
    background-color: var(--ds-surface);
    border-bottom: 1px solid var(--ds-border);
    flex-wrap: wrap;
    transition: box-shadow var(--dur-ui) var(--ease-standard);
}

/* Steps up exactly one shadow level once content scrolls beneath it. */
.app-topbar.is-scrolled { box-shadow: var(--shadow-md); }

.app-topbar__title {
    font-size: var(--text-base);
    font-weight: 600;
    color: var(--ds-heading);
    margin: 0;
    white-space: nowrap;
}

.app-topbar__actions {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-left: auto;
    flex-wrap: wrap;
}

/* ================================================== status cluster ==== */
.status-cluster {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.status-pill,
.conn-pill {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    font-size: var(--text-xs);
    font-weight: 500;
    padding: 3px 8px;
    border-radius: var(--ds-radius);
    border: 1px solid var(--ds-neutral-border);
    background: var(--ds-neutral-soft);
    color: var(--ds-heading);
    white-space: nowrap;
}

.conn-pill__dot {
    width: 8px;
    height: 8px;
    border-radius: var(--ds-radius-full);
    background: var(--ds-body-subtle);
    flex: 0 0 auto;
}

.conn-pill--ok {
    background: var(--ds-success-soft);
    border-color: var(--ds-success-border);
    color: var(--ds-fg-success);
}
.conn-pill--ok .conn-pill__dot { background: var(--ds-success); }

.conn-pill--retry {
    background: var(--ds-warning-soft);
    border-color: var(--ds-warning-border);
    color: var(--ds-fg-warning);
}
.conn-pill--retry .conn-pill__dot {
    background: var(--ds-warning);
    /* The only decorative loop in the app, and it is not decorative: an indeterminate
       "still trying" state is exactly what a looping indicator is for. It stops the
       instant the state resolves. */
    animation: pulse 1400ms ease-in-out infinite;
}

.conn-pill--down {
    background: var(--ds-danger-soft);
    border-color: var(--ds-danger-border);
    color: var(--ds-fg-danger);
}
.conn-pill--down .conn-pill__dot { background: var(--ds-danger); }

/* =================================================== cycle ribbon ==== */
/* The signature element: this is a console for a cyclic process, so the last ten cycles
   are always on screen. Flexbox divs and tokens only — no dependency. */
.cycle-ribbon {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

.cycle-ribbon__bars {
    display: flex;
    align-items: flex-end;
    gap: 3px;
    height: 28px;
}

.cycle-bar {
    position: relative;
    display: block;
    width: 8px;
    height: 28px;
    padding: 0;
    border: 0;
    border-radius: var(--ds-radius-sm);
    background: var(--ds-success);
    cursor: pointer;
    overflow: hidden;
    transition: opacity var(--dur-color) var(--ease-standard);
}

.cycle-bar:hover { opacity: .8; }

.cycle-bar:focus-visible {
    outline: 2px solid var(--ds-brand);
    outline-offset: 2px;
}

/* Failures render as a TOP segment, so the signal is position as well as hue — never
   status by colour alone. */
.cycle-bar__fail {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    background: var(--ds-danger);
}

.cycle-bar--latest {
    outline: 2px solid var(--ds-brand);
    outline-offset: 1px;
}

.cycle-bar--aborted { background: var(--ds-warning); }

.cycle-bar--empty {
    background: var(--ds-surface-3);
    border: 1px solid var(--ds-border);
    cursor: default;
}

.cycle-bar--empty:hover { opacity: 1; }

.cycle-ribbon__next {
    font-size: var(--text-xs);
    color: var(--ds-body-subtle);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.cycle-ribbon__legend {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    font-size: var(--text-xs);
    color: var(--ds-body-subtle);
}

.cycle-ribbon__legend span {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
}

/* Idle is normal (a 3-minute interval), so "stale" means meaningfully overdue. */
.cycle-ribbon--stale .cycle-ribbon__next {
    color: var(--ds-fg-warning);
    font-weight: 500;
}

.cycle-ribbon--stale .cycle-bar:not(.cycle-bar--empty) { opacity: .45; }

/* ========================================================= KPI row ==== */
.stat-grid {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: var(--space-6);
    margin-bottom: var(--space-6);
}

.stat-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    height: 100%;
    margin: 0;
    padding: var(--space-5);
    background-color: var(--ds-surface);
    border: 1px solid var(--ds-border);
    border-radius: var(--ds-radius);
    box-shadow: var(--shadow-xs);
}

.stat-card__label {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-xs);
    font-weight: 500;
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    color: var(--ds-body-subtle);
    margin: 0;
}

.stat-card__value {
    font-size: var(--text-2xl);
    line-height: 1.2;
    font-weight: 600;
    color: var(--ds-heading);
    margin: 0;
    font-variant-numeric: tabular-nums;
}

.stat-card__meta {
    font-size: var(--text-xs);
    color: var(--ds-body-subtle);
    min-height: 1em;
    margin: 0;
}

/* Fires only when the fail count INCREASES. A new failure is precisely the event worth
   interrupting for; the success tile never flashes, because it climbs constantly. */
.stat-card--flash-danger { animation: tile-flash var(--dur-ui) var(--ease-out); }

/* ================================================ current activity ==== */
.activity-grid {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: var(--space-2) var(--space-4);
    margin: 0;
    font-size: var(--text-sm);
}

.activity-grid__term {
    font-size: var(--text-xs);
    font-weight: 500;
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    color: var(--ds-body-subtle);
    margin: 0;
}

.activity-grid__value {
    color: var(--ds-heading);
    font-weight: 500;
    margin: 0;
    min-width: 0;
    overflow-wrap: anywhere;
}

/* ======================================================= live feed ==== */
.feed-scroll {
    max-height: 320px;
    overflow-y: auto;
    position: relative;
}

.feed-scroll:focus-visible {
    outline: 2px solid var(--ds-brand);
    outline-offset: -2px;
}

/* Shown only when the reader has scrolled away from the top and new rows arrived —
   rare, so it earns its motion. */
.feed-jump {
    position: sticky;
    top: var(--space-2);
    z-index: 2;
    display: block;
    margin: 0 auto;
    width: fit-content;
    animation: rise 180ms var(--ease-out);
}

/* Poll-type identification. Three accents from the doc's accent set, used for grouping
   only — not body copy, navigation, or a large surface. */
.poll-tag {
    display: inline-flex;
    align-items: center;
    font-size: var(--text-xs);
    font-weight: 500;
    padding: 2px 6px;
    border-radius: var(--ds-radius-sm);
    background: var(--ds-surface-3);
    color: var(--ds-body);
    white-space: nowrap;
}

.poll-tag--priorauth {
    background: var(--ds-poll-priorauth-soft);
    color: var(--ds-poll-priorauth-fg);
}

.poll-tag--claim {
    background: var(--ds-poll-claim-soft);
    color: var(--ds-poll-claim-fg);
}

.poll-tag--communication {
    background: var(--ds-poll-communication-soft);
    color: var(--ds-poll-communication-fg);
}

.th-actions,
.cell-actions {
    width: 1%;
    white-space: nowrap;
    text-align: right;
}

/* One 600ms pulse on the header dot when rows arrive, throttled to once a second. This
   is the arrival signal, instead of animating every row. */
.feed-beacon.is-active { animation: pulse 600ms var(--ease-out); }

/* ============================================= states: empty/skeleton ==== */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-8) var(--space-4);
    text-align: center;
}

.empty-state__title {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--ds-heading);
    margin: 0;
}

.empty-state__hint {
    font-size: var(--text-xs);
    color: var(--ds-body-subtle);
    margin: 0;
    max-width: 46ch;
    line-height: var(--leading-normal);
}

.skeleton {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.skeleton__bar {
    height: 12px;
    border-radius: var(--ds-radius-sm);
    /* A solid surface pulsing its opacity, NOT a gradient sweep — layout.md prohibits
       gradient and noise overlays, and a flat pulse honours "flat solid backgrounds". */
    background: var(--ds-surface-3);
    animation: skeleton 1200ms ease-in-out infinite;
}

.skeleton__bar:nth-child(2) { width: 80%; }
.skeleton__bar:nth-child(3) { width: 60%; }

.skeleton-row td { padding: var(--space-3) var(--space-4) !important; }

/* ====================================================== filter bar ==== */
.filter-bar {
    display: flex;
    align-items: flex-end;
    flex-wrap: wrap;
    gap: var(--space-3);
}

.filter-bar__grow { flex: 1 1 220px; min-width: 0; }

.filter-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.filter-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    font-size: var(--text-xs);
    font-weight: 500;
    padding: 4px 10px;
    border-radius: var(--ds-radius-full);
    border: 1px solid var(--ds-border-medium);
    background: var(--ds-surface-2);
    color: var(--ds-body);
    cursor: pointer;
    user-select: none;
    transition: background-color var(--dur-color) var(--ease-standard),
                border-color var(--dur-color) var(--ease-standard),
                color var(--dur-color) var(--ease-standard);
}

.filter-chip:hover {
    border-color: var(--ds-border-hover);
    color: var(--ds-heading);
}

.filter-chip input { position: absolute; opacity: 0; pointer-events: none; }

.filter-chip:has(input:checked) {
    background: var(--ds-brand-softer);
    border-color: var(--ds-brand-border);
    color: var(--ds-fg-brand);
}

.filter-chip:has(input:focus-visible) {
    outline: 2px solid var(--ds-brand);
    outline-offset: 2px;
}

.filter-meta {
    font-size: var(--text-xs);
    color: var(--ds-body-subtle);
}

/* ========================================================= id cell ==== */
.id-cell {
    display: inline-block;
    font-family: var(--ds-font-mono);
    font-size: var(--text-xs);
    color: var(--ds-body-subtle);
    max-width: 160px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: bottom;
}

/* ==================================================== log messages ==== */
.log-message {
    font-family: var(--ds-font-mono);
    font-size: var(--text-xs);
    line-height: var(--leading-normal);
    color: var(--ds-body);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    margin: 0;
}

.log-highlight {
    background: var(--ds-warning-soft);
    color: var(--ds-fg-warning);
    border-radius: 2px;
    padding: 0 2px;
}

/* ==================================================== code viewers ==== */
.json-toolbar {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
    padding-bottom: var(--space-3);
}

.json-view {
    font-family: var(--ds-font-mono);
    font-size: var(--text-xs);
    line-height: var(--leading-normal);
    color: var(--ds-body);
    background: var(--ds-surface-2);
    border: 1px solid var(--ds-border);
    border-radius: var(--ds-radius);
    padding: var(--space-3);
    margin: 0;
    max-height: 60vh;
    overflow: auto;
    white-space: pre;
    tab-size: 2;
}

.tok-key { color: var(--ds-fg-brand); }
.tok-str { color: var(--ds-fg-success); }
.tok-num { color: var(--ds-fg-warning); }
.tok-lit { color: var(--ds-fg-danger); }

/* Inline expander for stored-procedure T-SQL: you want three open side by side to
   compare parameters, which a modal cannot do. */
.detail-row > td {
    background: var(--ds-surface-2);
    padding: var(--space-4) var(--space-6) !important;
}

.row-expander .icon {
    transition: transform var(--dur-color) var(--ease-standard);
}

.row-expander[aria-expanded="true"] .icon { transform: rotate(180deg); }

/* ================================================ page-load stagger ==== */
/* The one orchestrated entrance in the app. The doc asks for a single well-sequenced
   page-load animation using staggered animation-delay rather than scattered effects;
   the whole sequence finishes inside ~500ms. */
.page-enter > * {
    animation: rise var(--dur-enter) var(--ease-out) both;
    animation-delay: calc(var(--i, 0) * 40ms);
}

/* ====================================================== keyframes ==== */
@keyframes rise {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
}

@keyframes pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: .35; }
}

@keyframes tile-flash {
    from { background-color: var(--ds-danger-soft); }
    to   { background-color: var(--ds-surface); }
}

@keyframes skeleton {
    0%, 100% { opacity: .6; }
    50%      { opacity: 1; }
}

/* ===================================================== responsive ==== */
@media (max-width: 1399.98px) {
    .app-content { max-width: none; }
}

@media (max-width: 1199.98px) {
    .stat-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Below lg the sidebar becomes an offcanvas drawer (Bootstrap, already loaded). */
@media (max-width: 991.98px) {
    .app-shell { grid-template-columns: minmax(0, 1fr); }
    .app-sidebar { display: none; }
}

@media (max-width: 767.98px) {
    .app-content { padding: var(--space-4); }
    .app-topbar { padding: var(--space-2) var(--space-4); }
    .stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4); }
    .id-cell { max-width: 96px; }
    .feed-scroll { max-height: 50vh; }
    .cycle-ribbon__legend { display: none; }
    /* Labels collapse to their dots; the text stays available as a tooltip. */
    .status-pill__text,
    .conn-pill__text { display: none; }
}

/* The offcanvas drawer reuses the sidebar's inner styling. */
.offcanvas .app-sidebar__inner { height: auto; min-height: 100%; }

.offcanvas {
    --bs-offcanvas-bg: var(--ds-surface);
    --bs-offcanvas-color: var(--ds-body);
    --bs-offcanvas-border-color: var(--ds-border);
    --bs-offcanvas-width: var(--sidebar-w);
}
