/* Soc (SOC dashboard, /soc/dashboard) — migrated from Soc.razor.css; scoped under .page-soc. */
.page-soc { display: flex; flex-direction: column; gap: 34px; }

/* ─── Header action buttons ───────────────────────────────────── */

.page-soc .btn-icon,
.page-soc .btn-primary {
    display: inline-flex;
    align-items: center;
    gap: 7px;
}

.page-soc .btn-icon svg,
.page-soc .btn-primary svg { width: 15px; height: 15px; }

.page-soc .btn-primary {
    padding: 9px 16px;
    border: 1px solid var(--accent);
    border-radius: var(--radius-sm);
    background: var(--accent);
    color: #04201D;
    font: 600 13px var(--font-body);
    cursor: pointer;
    transition: filter .18s ease, transform .18s ease;
}

.page-soc .btn-primary:hover { filter: brightness(1.08); transform: translateY(-1px); }

/* ─── Welcome row (under the page title) ──────────────────────── */

.page-soc .welcome {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 12px;
}

.page-soc .welcome-avatar {
    width: 34px;
    height: 34px;
    flex: none;
    display: grid;
    place-items: center;
    border-radius: 50%;
    font-size: 12px;
    font-weight: 700;
    color: #04201D;
    background: linear-gradient(140deg, #5EEAD9, #14B8A6);
    overflow: hidden;   /* the photo below is square; the puck is the circle */
}

/* Profile photo, when the reader has one. The gradient above stays as the backing for the initials. */
.page-soc .welcome-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }

.page-soc .welcome-text {
    font-size: 14px;
    color: var(--muted);
    display: inline-block;
    white-space: nowrap;
    /* typewriter: reveal left-to-right in character-sized steps */
    animation: welcome-type .45s steps(16, end) both;
    animation-delay: .15s;
}
.page-soc .welcome-text strong { color: var(--text); font-weight: 600; }

@keyframes welcome-type {
    from { clip-path: inset(0 100% 0 0); }
    to   { clip-path: inset(0 0 0 0); }
}

/* ─── Time-range selector (page header) ───────────────────────── */

.page-soc .range-select {
    display: inline-flex;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    overflow: hidden;
}

.page-soc .range-btn {
    padding: 8px 15px;
    border: none;
    background: transparent;
    color: var(--muted);
    font: 600 12.5px var(--font-body);
    cursor: pointer;
    transition: color .15s ease, background .15s ease;
}

.page-soc .range-btn + .range-btn { border-left: 1px solid var(--line); }

.page-soc .range-btn:hover { color: var(--text); background: var(--surface-2); }

.page-soc .range-btn.is-active { color: #04201D; background: var(--accent); }

/* ─── Skeleton loading ────────────────────────────────────────────
   No separate placeholder layout. The real content is rendered (so every
   card/panel already has its true size), then while loading we hide its
   contents and paint a shimmer over each block. On load we drop the flag →
   content shows in the exact same boxes and its data animates in. */

/* the shimmer→content swap is the entrance; no separate slide-in.
   .is-pending is one tile whose own read is still out (auto-closed, which is a
   separate Sentinel query) after the rest of the page has painted. */
.page-soc .loading .head-actions > *,
.page-soc .loading .stat-card > *,
.page-soc .stat-card.is-pending > *,
.page-soc .loading .panel > *,
.page-soc .loading .traffic-wrap > * { visibility: hidden; }

.page-soc .loading .head-actions,
.page-soc .loading .stat-card,
.page-soc .stat-card.is-pending,
.page-soc .loading .panel,
.page-soc .loading .traffic-wrap { position: relative; }

.page-soc .loading .traffic-wrap::after,
.page-soc .loading .head-actions::after { border: 1px solid var(--line); }

.page-soc .loading .head-actions::after,
.page-soc .loading .stat-card::after,
.page-soc .stat-card.is-pending::after,
.page-soc .loading .panel::after,
.page-soc .loading .traffic-wrap::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 10;
    /* opaque base so nothing behind (incl. the live map) shows through the sweep */
    background-color: var(--surface-2);
    background-image: linear-gradient(100deg, transparent 30%, rgba(255, 255, 255, 0.06) 50%, transparent 70%);
    background-size: 200% 100%;
    background-repeat: no-repeat;
    animation: skel-shimmer 1.4s linear infinite;
}

/* hold the fill/draw animations until content is revealed, then let them play */
.page-soc .loading .sev-bar span,
.page-soc .loading .stat-spark,
.page-soc .stat-card.is-pending .stat-spark,
.page-soc .loading .area-chart,
.page-soc .loading .donut-seg { animation: none !important; }

@media (prefers-reduced-motion: reduce) {
    .page-soc .loading .head-actions::after,
    .page-soc .loading .stat-card::after,
    .page-soc .stat-card.is-pending::after,
    .page-soc .loading .panel::after,
    .page-soc .loading .traffic-wrap::after { animation: none; }
}

/* ─── Stat cards ──────────────────────────────────────────────────
   Big number, Δ vs previous period, sparkline pinned to the bottom. */

.page-soc .stat-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 16px;
}

/* Every dashboard grid has a zero floor (§26). A bare `1fr` is `minmax(auto, 1fr)`, so one child with a
   wide unbreakable row (the traffic map's header, a long legend) widened its track past the column and
   the panel's right edge was cut off once the rows stacked on a narrow screen. */
.page-soc .stat-grid > *,
.page-soc .overview-grid > *,
.page-soc .volume-grid > * { min-width: 0; }

/* The range selector and both raise buttons sit on one row, which is wider than the column on a narrow
   screen; they wrap under each other rather than running off the edge. */
.page-soc .head-actions { flex-wrap: wrap; }

.page-soc .stat-card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 18px 18px 0;
    /* The floor is what sets the height, not the content: a card's bottom slot is
       either a 48px sparkline, a row of severity dots, or nothing at all, and the
       lookback decides which tiles carry a Δ chip. 160px clears the tallest of
       those (18 + label + 12 + 34 + 12 + 48 + 18 ≈ 159), so all four boxes are the
       same size in every lookback rather than sized by whichever variant the data
       produced. Raise it if a taller slot is ever added — don't let it go under. */
    min-height: 160px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    overflow: hidden;
    transition: border-color .2s ease, background .2s ease, box-shadow .2s ease;
}

.page-soc .stat-card:hover {
    border-color: rgba(255, 255, 255, 0.20);
    background: var(--surface-2);
}

/* ─── Card / panel hover elevation ────────────────────────────── */

.page-soc .panel { position: relative; transition: border-color .2s ease, box-shadow .2s ease; }

/* accent line that fades in along the top edge on hover */
.page-soc .stat-card::before,
.page-soc .panel::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 2px;
    background: linear-gradient(90deg, var(--accent), var(--accent-2));
    opacity: 0;
    transition: opacity .22s ease;
    pointer-events: none;
    z-index: 1;
}

.page-soc .stat-card:hover::before,
.page-soc .panel:hover::before { opacity: 0.9; }

.page-soc .stat-card:hover,
.page-soc .panel:hover {
    border-color: rgba(255, 255, 255, 0.16);
    box-shadow: 0 18px 36px -22px rgba(0, 0, 0, 0.75);
}

/* ─── Section header icon + accent underline ──────────────────── */

.page-soc .section-head h2 {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.page-soc .sec-ic {
    display: inline-flex;
    color: var(--accent);
}
.page-soc .sec-ic svg { width: 16px; height: 16px; }

.page-soc .section-head.tight {
    position: relative;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--line-soft);
}

.page-soc .section-head.tight::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: -1px;
    width: 40px;
    height: 2px;
    background: linear-gradient(90deg, var(--accent), var(--accent-2));
}

.page-soc .stat-label {
    font-size: 11.5px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--muted);
}

.page-soc .stat-row {
    display: flex;
    align-items: baseline;
    gap: 10px;
}

.page-soc .stat-value {
    font-family: var(--font-display);
    font-size: 34px;
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.page-soc .stat-delta {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 8px;
    font-size: 12.5px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--faint);
}

.page-soc .stat-delta svg { width: 11px; height: 11px; flex: none; }

.page-soc .stat-delta.tone-good    { color: var(--good); background: rgba(45, 212, 191, 0.14); }
.page-soc .stat-delta.tone-bad     { color: var(--bad);  background: rgba(255, 107, 107, 0.14); }
.page-soc .stat-delta.tone-neutral { color: var(--faint); background: rgba(255, 255, 255, 0.06); }

/* sparkline sits near the bottom, inset from the card edges */
.page-soc .stat-spark {
    margin-top: auto;
    margin-bottom: 18px;
    width: 100%;
    height: 48px;
    display: block;
    /* reveal the line + fill left-to-right */
    animation: wipe-right 1s cubic-bezier(.4, 0, .2, 1) both;
    animation-delay: .1s;
}

.page-soc .stat-area {
    fill: url(#statFill);
}

.page-soc .stat-line {
    fill: none;
    stroke: var(--accent);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
}

/* per-severity indicator (replaces the sparkline on some cards) */
.page-soc .stat-sev {
    margin-top: auto;
    margin-bottom: 18px;
    display: flex;
    align-items: center;
    gap: 16px;
}

.page-soc .stat-sev-item {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-variant-numeric: tabular-nums;
}

.page-soc .stat-sev-dot {
    width: 11px;
    height: 11px;
    display: inline-block;
    border-radius: 0;
}

.page-soc .stat-sev-count {
    font-size: 15px;
    font-weight: 700;
    color: var(--text);
}

/* ─── Overview row (severity + traffic map) ───────────────────────
   Severity mix on the left, traffic overview on the right. The map
   is the wider column but does not span the full width. */

.page-soc .overview-grid {
    display: grid;
    grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.7fr);
    gap: 18px;
    align-items: stretch;
}

/* No traffic source configured for this customer — the severity panel takes the row rather than
   leaving the map's column as dead space. */
.page-soc .overview-grid.no-traffic { grid-template-columns: minmax(0, 1fr); }

/* ─── Incident volume + classification row ────────────────────── */

.page-soc .volume-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
    gap: 18px;
    align-items: stretch;
}

/* classification names ("Benign positive") need a wider label column */
.page-soc .class-card .sev-breakdown li { grid-template-columns: 11px 104px 1fr auto; }

/* donut + severity breakdown — fills the panel height */

.page-soc .sev-panel { display: flex; flex-direction: column; }

/* The panel is stretched to its row's height, so something inside it takes the slack. That used to be
   the legend alone, spread with space-around: a closure panel holding two verdicts drew its two rows a
   chart's height apart (UAT 2026-08-25). The ring grows into the space first, bounded top and bottom so
   a tall row can't inflate it past the card and a single-column layout can't shrink it below the size it
   has always been; whatever is left over goes to the legend, which keeps its rows together and centres
   them as a block. */
.page-soc .donut {
    flex: 1 1 214px;
    width: 100%;
    min-height: 214px;
    max-height: 280px;
    display: block;
    margin: 10px auto 24px;
}

.page-soc .donut-track {
    fill: none;
    stroke: rgba(255, 255, 255, 0.08);
    stroke-width: 15;
}

.page-soc .donut-seg {
    /* stroke matches fill (set inline) to cover the anti-aliased seam between sectors.
       The ring sweeps in via geometry (ArrowSegs + the count-up ticker), so no CSS entrance here. */
    stroke-width: 1;
    stroke-linejoin: round;
    transition: filter .2s ease;
}

.page-soc .donut-seg:hover { filter: brightness(1.15); }

.page-soc .donut-total {
    fill: var(--text);
    font: 700 34px var(--font-display);
    text-anchor: middle;
}

.page-soc .donut-caption {
    fill: var(--faint);
    font: 500 11px var(--font-body);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    text-anchor: middle;
}

.page-soc .sev-breakdown {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    /* Together and centred, never spread across the panel: the gap between two rows is the list's
       gap whether the tile holds two verdicts or five (see the donut's note above). */
    justify-content: center;
    gap: 10px;
    flex: 1;
}

.page-soc .sev-breakdown li {
    display: grid;
    grid-template-columns: 11px 76px 1fr auto;
    align-items: center;
    gap: 11px;
    font-size: 13px;
}

.page-soc .sev-dot { width: 9px; height: 9px; border-radius: 0; }

.page-soc .sev-name { color: var(--muted); }

.page-soc .sev-bar {
    height: 7px;
    border-radius: 0;
    background: rgba(255, 255, 255, 0.10);
    overflow: hidden;
}

.page-soc .sev-bar span {
    display: block;
    height: 100%;
    border-radius: inherit;
    /* slide in left-to-right, same wipe as the graph lines */
    animation: wipe-right .9s cubic-bezier(.22, .9, .3, 1) both;
    animation-delay: .1s;
}

/* count and percent sit in their own right-aligned slots: sized as one run, a row
   reading "100%" pushed its count left of the rows reading "0%". */
.page-soc .sev-val {
    display: flex;
    align-items: baseline;
    justify-content: flex-end;
    gap: 6px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    min-width: 64px;
    text-align: right;
}

.page-soc .sev-val small { font-weight: 500; color: var(--faint); min-width: 32px; text-align: right; }

/* ─── Incident volume — area / line chart ─────────────────────────── */

.page-soc .area-wrap { display: flex; flex-direction: column; gap: 8px; }

.page-soc .area-chart {
    width: 100%;
    height: auto;
    display: block;
    overflow: visible;
    /* reveal the line + fill left-to-right */
    animation: wipe-right 1.2s cubic-bezier(.4, 0, .2, 1) both;
    animation-delay: .1s;
}

.page-soc .area-chart .grid {
    stroke: rgba(255, 255, 255, 0.10);
    stroke-width: 1;
    vector-effect: non-scaling-stroke;
}

/* y-axis tick labels — an HTML column in the chart's own left gutter, not <text> inside the SVG:
   the viewBox scales its own text with the panel, so the counts rendered half again larger than the
   day labels below them on a wide monitor. The column's right edge is where the SVG text's
   text-anchor: end sat, (PadL - 9) / VW, and each label's top is its tick's Y as a share of VH —
   .area-plot is exactly as tall as the SVG, so the percentage lands on the gridline. */
.page-soc .y-axis {
    position: absolute;
    left: 0;
    width: 4.833%;    /* (PadL - 9) / VW */
    top: 0;
    bottom: 0;
    pointer-events: none;   /* the hover bands own the plot */
}

.page-soc .y-axis span {
    position: absolute;
    right: 0;
    transform: translateY(-50%);
    font-size: 11.5px;      /* matches .x-axis — the two axes read as one scale */
    font-weight: 500;
    line-height: 1;
    color: var(--faint);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.page-soc .area-chart .area {
    fill: url(#areaFill);
}

.page-soc .area-chart .line {
    fill: none;
    stroke: var(--accent);
    stroke-width: 2.5;
    stroke-linecap: round;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
}

/* ─── Incident volume — hover readout ─────────────────────────────
   One band per slice over the plot area, revealing that slice's guide line, marker and value card
   (see Soc.razor / VolHovers). Percentages, not pixels: the SVG scales with the panel, so the
   overlay is inset by the same padding as a share of the 600×240 viewBox — PadL 38, PadR 10,
   PadT 18, PadB 14. Keep these four in step with the constants in Soc.razor.cs. */

.page-soc .area-plot { position: relative; }

.page-soc .vol-hits {
    position: absolute;
    left: 6.333%;     /* PadL / VW  */
    right: 1.667%;    /* PadR / VW  */
    top: 7.5%;        /* PadT / VH  */
    bottom: 5.833%;   /* PadB / VH  */
}

/* Bands tile the plot with no gaps, each centred on its own point, so the pointer is always inside
   the band of the slice nearest to it. --px is that point's x within the band, --py its value's
   depth down the plot. */
.page-soc .vol-hit { position: absolute; top: 0; bottom: 0; }

.page-soc .vh-guide,
.page-soc .vh-dot,
.page-soc .vh-tip {
    position: absolute;
    opacity: 0;
    transition: opacity .12s ease;
    pointer-events: none;   /* the band owns the hover — a child must never take it back */
}

.page-soc .vol-hit:hover .vh-guide,
.page-soc .vol-hit:hover .vh-dot,
.page-soc .vol-hit:hover .vh-tip { opacity: 1; }

.page-soc .vh-guide {
    left: var(--px);
    top: 0;
    bottom: 0;
    width: 0;
    border-left: 1px dashed var(--accent-line);
}

.page-soc .vh-dot {
    left: var(--px);
    top: var(--py);
    width: 9px;
    height: 9px;
    margin: -4.5px 0 0 -4.5px;   /* centre it on the point rather than hang it below/right */
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 0 3px rgba(45, 212, 191, 0.20);
}

.page-soc .vh-tip {
    left: var(--px);
    bottom: calc(100% - var(--py) + 14px);
    transform: translateX(-50%);
    z-index: 2;
    display: flex;
    flex-direction: column;
    gap: 1px;
    padding: 7px 10px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface-2);
    box-shadow: 0 8px 22px rgba(0, 0, 0, 0.45);
    white-space: nowrap;
}

.page-soc .vh-when { font-size: 11px; color: var(--faint); }

.page-soc .vh-count {
    font-size: 14px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.page-soc .vh-count small { font-size: 11px; font-weight: 500; color: var(--faint); margin-left: 3px; }

/* The first and last points sit ON the plot edges, so a centred card there loses half of itself to
   the panel's clip (.content .panel is overflow: hidden) — anchor those two inside instead. A point
   near the axis top has no room above it either, so its card flips below the marker. */
.page-soc .vol-hit.is-start .vh-tip { transform: none; }
.page-soc .vol-hit.is-end .vh-tip { transform: translateX(-100%); }
.page-soc .vol-hit.is-below .vh-tip { top: calc(var(--py) + 14px); bottom: auto; }

/* Each label is placed at its point's x (inline `left`, VolXPct) and centred on it. A space-between
   row spaced the labels' edges rather than their centres, so the hover guide missed the day. */
.page-soc .x-axis {
    position: relative;
    height: 14px;
    font-size: 11.5px;
    line-height: 14px;
    color: var(--faint);
    font-variant-numeric: tabular-nums;
}

.page-soc .x-axis span {
    position: absolute;
    top: 0;
    transform: translateX(-50%);
    white-space: nowrap;
}

@keyframes fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* ─── Response times (incident SLA clocks) ────────────────────────
   One full-width panel holding the two clocks side by side. Both tracks carry a zero floor (§26):
   .content .panel is overflow:hidden, so a track with a pixel minimum would push its own contents
   past the panel edge rather than letting them shrink. */

.page-soc .sla-metrics {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 18px;
}

.page-soc .sla-metric {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 0;
    padding: 16px 18px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface-2);
    /* A floor that clears the taller variant, not the height the data happened to produce (§28): a
       measured clock carries a meter and a target line that an unmeasured one does not, so without
       this the two boxes differ in height whenever one clock never ran, and the panel changes shape
       as the reader moves between ranges. Raise it if a taller row is added; never let it go under. */
    min-height: 168px;
}

.page-soc .sla-figures { display: flex; align-items: baseline; gap: 8px; min-width: 0; }

.page-soc .sla-value {
    font-family: var(--font-display);
    font-size: 30px;
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

/* Nothing measured reads as an absence, not as a fast number. */
.page-soc .sla-value.is-none { color: var(--muted); font-size: 22px; }

.page-soc .sla-unit,
.page-soc .sla-median {
    margin: 0;
    font-size: 12px;
    color: var(--muted);
}

.page-soc .sla-median { font-size: 12.5px; }

.page-soc .sla-meter {
    height: 6px;
    margin-top: 2px;
    border-radius: 999px;
    background: var(--surface);
    overflow: hidden;
}

.page-soc .sla-meter-fill {
    display: block;
    height: 100%;
    border-radius: inherit;
    background: linear-gradient(90deg, var(--accent), var(--accent-2));
}

.page-soc .sla-target { margin: 0; font-size: 12px; color: var(--muted); }
.page-soc .sla-target strong { color: var(--text); font-variant-numeric: tabular-nums; }

/* A missed target is the one thing on this panel the reader has to act on, so it is drawn in --bad
   rather than the accent. */
.page-soc .sla-breach { margin-left: 8px; color: var(--bad); }

/* A window with no incidents in it. Sized to the metric row's floor so switching to a quiet range
   doesn't collapse the panel's height (§28). */
.page-soc .sla-empty {
    display: flex;
    align-items: center;
    margin: 0;
    min-height: 168px;
    padding: 16px 18px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface-2);
    font-size: 13px;
    color: var(--muted);
}

/* Sits beside the heading as state, never as an explanation of it (§14). */
.page-soc .sla-note {
    margin-left: auto;
    font-size: 11.5px;
    color: var(--muted);
    white-space: nowrap;
}

/* ─── Responsive ──────────────────────────────────────────────── */

@media (max-width: 1280px) {
    .page-soc .stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .page-soc .overview-grid { grid-template-columns: minmax(0, 1fr); }
    .page-soc .volume-grid { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 640px) {
    .page-soc .stat-grid { grid-template-columns: minmax(0, 1fr); }
    .page-soc .sla-metrics { grid-template-columns: minmax(0, 1fr); }
}

@media (prefers-reduced-motion: reduce) {
    .page-soc .stat-spark,
    .page-soc .area-chart,
    .page-soc .sev-bar span,
    .page-soc .welcome-text,
    .page-soc .donut-seg { animation: none; clip-path: none; }
}
