﻿/*
   plenkin-admin.css — styles for the staff dashboard under /admin.

   Kept out of plenkin.css because the two have opposite jobs: plenkin.css paints a
   375px phone frame, this paints a full-width desktop console. Class names are all
   prefixed `admin-` so neither can reach into the other.

   Referenced from Plenkin.Web/Components/App.razor as
   _content/Plenkin.Shared/css/plenkin-admin.css.
*/

:root {
    --adm-bg: #f6f7f9;
    --adm-surface: #ffffff;
    --adm-border: #e4e7ec;
    --adm-text: #16191f;
    --adm-muted: #6b7280;
    --adm-green: #2d6a4f;
    --adm-green-soft: #eef6f1;
    --adm-amber: #b45309;
    --adm-amber-soft: #fef4e6;
    --adm-red: #b42318;
    --adm-red-soft: #fdecea;
    --adm-shadow: 0 1px 2px rgba(16, 24, 40, .06), 0 1px 3px rgba(16, 24, 40, .04);
}

.admin-root {
    min-height: 100vh;
    background: var(--adm-bg);
    color: var(--adm-text);
    font-family: 'DM Sans', 'Segoe UI', system-ui, sans-serif;
    font-size: 14px;

    /* plenkin.css centres the phone frame with `body { display: flex; justify-content:
       center; align-items: center }`. As a flex item this root would otherwise shrink to
       its content — a narrow vertical strip around the gate spinner, and a short column
       once the dashboard loads. Stretch it back out to the full viewport. */
    flex: 1 1 100%;
    width: 100%;
    align-self: stretch;
}

/* ── Gate states (spinner, sign-in, not-found) ──────────────────────────── */

.admin-gate {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem;
}

.admin-spinner {
    width: 28px;
    height: 28px;
    border: 3px solid var(--adm-border);
    border-top-color: var(--adm-green);
    border-radius: 50%;
    animation: admin-spin .7s linear infinite;
}

@keyframes admin-spin {
    to { transform: rotate(360deg); }
}

.admin-signin {
    width: 100%;
    max-width: 340px;
    background: var(--adm-surface);
    border: 1px solid var(--adm-border);
    border-radius: 14px;
    box-shadow: var(--adm-shadow);
    padding: 2rem;
    display: flex;
    flex-direction: column;
    gap: .75rem;
}

.admin-signin h1 {
    font-family: 'DM Serif Display', Georgia, serif;
    font-size: 1.6rem;
    margin: 0;
}

.admin-signin-sub {
    margin: -.5rem 0 .5rem;
    color: var(--adm-muted);
    font-size: .85rem;
    letter-spacing: .04em;
    text-transform: uppercase;
}

.admin-signin-error {
    margin: 0;
    color: var(--adm-red);
    font-size: .85rem;
}

.admin-notfound {
    text-align: center;
    color: var(--adm-muted);
}

.admin-notfound a {
    color: var(--adm-green);
}

.admin-input {
    border: 1px solid var(--adm-border);
    border-radius: 8px;
    padding: .6rem .8rem;
    font-size: .9rem;
    outline: none;
    background: var(--adm-surface);
    color: var(--adm-text);
}

.admin-input:focus {
    border-color: var(--adm-green);
}

.admin-btn {
    background: var(--adm-green);
    color: #fff;
    border: 0;
    border-radius: 8px;
    padding: .6rem 1rem;
    font-size: .9rem;
    font-weight: 600;
    cursor: pointer;
}

.admin-btn:disabled {
    opacity: .6;
    cursor: default;
}

/* ── Chrome ─────────────────────────────────────────────────────────────── */

.admin-topbar {
    display: flex;
    align-items: center;
    gap: 1.5rem;
    flex-wrap: wrap;
    padding: .85rem 1.5rem;
    background: var(--adm-surface);
    border-bottom: 1px solid var(--adm-border);
    position: sticky;
    top: 0;
    z-index: 10;
}

/* The brand is an <a> back to the public site. color/text-decoration are reset
   because Bootstrap and Tabler both style bare links, and the wordmark should
   read as a wordmark rather than as a link. */
.admin-brand {
    display: flex;
    align-items: baseline;
    gap: .5rem;
    color: inherit;
    text-decoration: none;
    border-radius: 8px;
    padding: .2rem .35rem;
    margin-left: -.35rem;
}

.admin-brand:hover {
    color: inherit;
    background: var(--adm-bg);
}

.admin-brand:focus-visible {
    outline: 2px solid var(--adm-green);
    outline-offset: 2px;
}

.admin-brand-mark {
    font-family: 'DM Serif Display', Georgia, serif;
    font-size: 1.15rem;
}

.admin-brand-tag {
    font-size: .68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .1em;
    color: var(--adm-green);
    background: var(--adm-green-soft);
    padding: 2px 7px;
    border-radius: 999px;
}

.admin-nav {
    display: flex;
    gap: .25rem;
    flex-wrap: wrap;
    flex: 1;
}

.admin-nav-link {
    padding: .4rem .75rem;
    border-radius: 8px;
    color: var(--adm-muted);
    text-decoration: none;
    font-weight: 500;
}

.admin-nav-link:hover {
    background: var(--adm-bg);
    color: var(--adm-text);
}

.admin-nav-link.active {
    background: var(--adm-green-soft);
    color: var(--adm-green);
    font-weight: 600;
}

.admin-whoami {
    display: flex;
    align-items: center;
    gap: .6rem;
    font-size: .85rem;
    color: var(--adm-muted);
}

.admin-role-chip {
    font-size: .68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--adm-green);
    background: var(--adm-green-soft);
    padding: 2px 8px;
    border-radius: 999px;
}

.admin-signout {
    background: none;
    border: 1px solid var(--adm-border);
    border-radius: 8px;
    padding: .3rem .7rem;
    cursor: pointer;
    color: var(--adm-muted);
    font-size: .8rem;
}

.admin-signout:hover {
    color: var(--adm-text);
    border-color: var(--adm-muted);
}

.admin-main {
    max-width: 1400px;
    margin: 0 auto;
    padding: 1.5rem;
}

/* ── Page header ────────────────────────────────────────────────────────── */

.admin-page-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1.25rem;
}

.admin-page-head h1 {
    font-size: 1.4rem;
    font-weight: 700;
    margin: 0;
}

.admin-page-sub {
    color: var(--adm-muted);
    font-size: .85rem;
    margin: .15rem 0 0;
}

.admin-head-tools {
    display: flex;
    align-items: center;
    gap: .6rem;
    flex-wrap: wrap;
}

/* ── KPI tiles ──────────────────────────────────────────────────────────── */

.admin-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: .85rem;
    margin-bottom: 1.5rem;
}

.admin-tile {
    background: var(--adm-surface);
    border: 1px solid var(--adm-border);
    border-radius: 12px;
    box-shadow: var(--adm-shadow);
    padding: 1rem 1.1rem;
}

.admin-tile-label {
    font-size: .7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--adm-muted);
}

.admin-tile-value {
    font-size: 1.75rem;
    font-weight: 700;
    line-height: 1.2;
    margin-top: .35rem;
}

.admin-tile-note {
    font-size: .78rem;
    color: var(--adm-muted);
    margin-top: .2rem;
}

/* ── Panels ─────────────────────────────────────────────────────────────── */

.admin-panels {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 1rem;
}

.admin-panel {
    background: var(--adm-surface);
    border: 1px solid var(--adm-border);
    border-radius: 12px;
    box-shadow: var(--adm-shadow);
    overflow: hidden;
}

.admin-panel-head {
    padding: .85rem 1.1rem;
    border-bottom: 1px solid var(--adm-border);
    font-weight: 600;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: .5rem;
}

.admin-panel-head small {
    color: var(--adm-muted);
    font-weight: 400;
}

.admin-panel-body {
    padding: .35rem 0;
}

.admin-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    padding: .55rem 1.1rem;
}

.admin-row + .admin-row {
    border-top: 1px solid #f2f4f7;
}

.admin-row-main {
    display: flex;
    align-items: center;
    gap: .6rem;
    min-width: 0;
}

.admin-row-title {
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.admin-avatar {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: .7rem;
    font-weight: 700;
    flex: 0 0 auto;
}

/* ── Tables ─────────────────────────────────────────────────────────────── */

.admin-table-wrap {
    background: var(--adm-surface);
    border: 1px solid var(--adm-border);
    border-radius: 12px;
    box-shadow: var(--adm-shadow);
    overflow-x: auto;
}

.admin-table {
    width: 100%;
    border-collapse: collapse;
    font-size: .875rem;
}

.admin-table thead tr {
    background: #fbfcfd;
    border-bottom: 1px solid var(--adm-border);
}

.admin-table th {
    padding: .7rem 1rem;
    text-align: left;
    font-size: .7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--adm-muted);
    white-space: nowrap;
    user-select: none;
}

.admin-table th.sortable {
    cursor: pointer;
}

.admin-table th.sortable:hover {
    color: var(--adm-green);
}

.admin-table td {
    padding: .7rem 1rem;
    border-bottom: 1px solid #f2f4f7;
    vertical-align: middle;
}

.admin-table tbody tr.clickable {
    cursor: pointer;
}

.admin-table tbody tr.clickable:hover {
    background: #fafbfc;
}

.admin-sort-icon {
    color: #b9bfc9;
    font-size: .72rem;
    margin-left: 3px;
}

.admin-num {
    font-variant-numeric: tabular-nums;
}

.admin-money {
    font-weight: 700;
    color: var(--adm-green);
    font-variant-numeric: tabular-nums;
}

.admin-muted {
    color: var(--adm-muted);
}

.admin-mono {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: .8rem;
    color: var(--adm-muted);
}

.admin-subtable-cell {
    background: #fafbfc;
    padding: 0 1rem 1rem !important;
}

.admin-subtable {
    width: 100%;
    border-collapse: collapse;
    font-size: .82rem;
}

.admin-subtable th {
    padding: .45rem .6rem;
    text-align: left;
    font-size: .68rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--adm-muted);
    border-bottom: 1px solid var(--adm-border);
}

.admin-subtable td {
    padding: .4rem .6rem;
    border-bottom: 1px solid #eef0f3;
}

.admin-table-foot {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
    margin-top: .85rem;
    font-size: .85rem;
    color: var(--adm-muted);
}

/* ── Badges ─────────────────────────────────────────────────────────────── */

.admin-badge {
    display: inline-block;
    padding: 2px 9px;
    border-radius: 999px;
    font-size: .7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    white-space: nowrap;
}

.admin-badge-neutral {
    background: #f2f4f7;
    color: #475467;
}

.admin-badge-green {
    background: var(--adm-green-soft);
    color: var(--adm-green);
}

.admin-badge-amber {
    background: var(--adm-amber-soft);
    color: var(--adm-amber);
}

.admin-badge-red {
    background: var(--adm-red-soft);
    color: var(--adm-red);
}

/* ── States ─────────────────────────────────────────────────────────────── */

.admin-state {
    text-align: center;
    padding: 3.5rem 1rem;
    color: var(--adm-muted);
}

.admin-state-error {
    color: var(--adm-red);
}

.admin-select {
    border: 1px solid var(--adm-border);
    border-radius: 8px;
    padding: .3rem .5rem;
    font-size: .82rem;
    background: var(--adm-surface);
    color: var(--adm-text);
    cursor: pointer;
}

.admin-select:disabled {
    opacity: .55;
    cursor: default;
}

.admin-search {
    border: 1px solid var(--adm-border);
    border-radius: 8px;
    padding: .45rem .8rem;
    font-size: .88rem;
    width: 260px;
    max-width: 100%;
    outline: none;
    background: var(--adm-surface);
    color: var(--adm-text);
}

.admin-search:focus {
    border-color: var(--adm-green);
}

.admin-toast {
    padding: .6rem 1rem;
    border-radius: 8px;
    font-size: .85rem;
    margin-bottom: 1rem;
}

.admin-toast-ok {
    background: var(--adm-green-soft);
    color: var(--adm-green);
}

.admin-toast-err {
    background: var(--adm-red-soft);
    color: var(--adm-red);
}

/* ── Prices page ────────────────────────────────────────────────────────────
   Added for /admin/prices. The coverage meter is the only new visual idea here:
   a fill-rate bar coloured by band, so a field that stopped being captured shows
   up as red at a glance rather than as a number you have to compare by eye. */

.admin-section-head {
    margin-top: 1.75rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--adm-border);
}

.admin-section-head .admin-page-sub {
    max-width: 62ch;
}

.admin-meter-wrap {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex-shrink: 0;
}

.admin-meter {
    width: 84px;
    height: 6px;
    border-radius: 999px;
    background: #eceff3;
    overflow: hidden;
}

.admin-meter-fill {
    height: 100%;
    border-radius: 999px;
}

.admin-meter-green {
    background: var(--adm-green);
}

.admin-meter-amber {
    background: var(--adm-amber);
}

.admin-meter-red {
    background: var(--adm-red);
}

.admin-meter-value {
    font-size: .78rem;
    color: var(--adm-muted);
    min-width: 3.2rem;
    text-align: right;
}

/* Sub-table captions inside an expanded product row. */
.admin-subhead {
    display: flex;
    align-items: center;
    gap: .6rem;
    flex-wrap: wrap;
    padding: .9rem 0 .35rem;
    font-size: .78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--adm-muted);
}

.admin-subhead .admin-muted {
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
}

/* A spread wide enough that the same product is being bought at very different
   prices — worth a second look, but not an error. */
.admin-warn {
    color: var(--adm-amber);
    font-weight: 600;
}

/* ── Charts (/admin/graphs) ─────────────────────────────────────────────────
   The chart components are pure SVG and carry no colour of their own beyond the
   validated series palette in AdminChartPalette. Everything here is chrome: the
   card, the recessive grid and axis, and the text tokens.

   Text never wears a series colour. Identity comes from the swatch beside the
   label, so a light hue (yellow, aqua) is never asked to be legible as type. */

.admin-charts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(430px, 1fr));
    gap: 1rem;
    align-items: start;
}

/* The tile row spans the grid rather than sitting in one column. */
.admin-charts > .admin-tiles {
    grid-column: 1 / -1;
    margin-bottom: 0;
}

/* Held at reduced opacity while refetching — no skeleton flash, no layout jump. */
.admin-charts-stale {
    opacity: .55;
    transition: opacity .15s ease;
}

.admin-chart-card {
    background: var(--adm-surface);
    border: 1px solid var(--adm-border);
    border-radius: 12px;
    box-shadow: var(--adm-shadow);
    padding: 1.1rem 1.2rem 1rem;
}

/* Wide charts get the full row: a stacked twelve-month column chart squeezed
   into half a grid track collides its own axis labels. */
.admin-chart-card-wide {
    grid-column: 1 / -1;
}

.admin-chart-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: .9rem;
}

.admin-chart-head h2 {
    font-size: .98rem;
    font-weight: 700;
    margin: 0;
}

.admin-chart-sub {
    color: var(--adm-muted);
    font-size: .8rem;
    margin: .2rem 0 0;
    max-width: 60ch;
}

.admin-chart-aside {
    text-align: right;
    flex-shrink: 0;
}

/* A card's headline number. Proportional figures on purpose — tabular-nums makes
   a large standalone value look loose. */
.admin-chart-figure {
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.1;
}

.admin-chart-figure-label {
    font-size: .72rem;
    color: var(--adm-muted);
}

.admin-chart {
    width: 100%;
}

.admin-chart-svg {
    width: 100%;
    height: auto;
    display: block;
    overflow: visible;
}

/* Grid and axis are hairline and solid. Dashed reads as a threshold that isn't there. */
.admin-chart-grid {
    stroke: #eef0f3;
    stroke-width: 1;
}

.admin-chart-axis-line {
    stroke: var(--adm-border);
    stroke-width: 1;
}

.admin-chart-tick,
.admin-chart-axis,
.admin-chart-rownote {
    font-size: 10.5px;
    fill: var(--adm-muted);
    font-variant-numeric: tabular-nums;
}

.admin-chart-rowlabel {
    font-size: 11.5px;
    fill: var(--adm-text);
}

.admin-chart-rownote {
    font-size: 10px;
}

/* Direct labels: sparing by design — the peak of a column chart, the tip of a bar. */
.admin-chart-value {
    font-size: 11px;
    font-weight: 600;
    fill: var(--adm-text);
    font-variant-numeric: tabular-nums;
}

.admin-chart-legend {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem .9rem;
    margin-top: .75rem;
    font-size: .78rem;
}

.admin-chart-key {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    color: var(--adm-text);
}

.admin-chart-swatch {
    width: 10px;
    height: 10px;
    border-radius: 3px;
    flex-shrink: 0;
}

/* A line series reads as a line-key rather than a block. */
.admin-chart-swatch-line {
    height: 3px;
    width: 14px;
    border-radius: 2px;
}

.admin-chart-donut {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    flex-wrap: wrap;
}

.admin-chart-donut-svg {
    width: 200px;
    height: 200px;
    flex-shrink: 0;
}

.admin-chart-donut-legend {
    display: flex;
    flex-direction: column;
    gap: .3rem;
    font-size: .8rem;
    min-width: 150px;
}

.admin-chart-donut-value {
    font-size: 21px;
    font-weight: 700;
    fill: var(--adm-text);
}

.admin-chart-donut-label {
    font-size: 10.5px;
    fill: var(--adm-muted);
}

.admin-chart-empty {
    padding: 2.5rem 1rem;
    text-align: center;
    color: var(--adm-muted);
    font-size: .85rem;
}

/* The table view. Not an extra: three series colours sit below 3:1 against this
   surface, and an exact readable equivalent is what that contrast result requires. */
.admin-chart-table {
    margin-top: .85rem;
    border-top: 1px solid var(--adm-border);
    padding-top: .5rem;
}

.admin-chart-table > summary {
    cursor: pointer;
    font-size: .78rem;
    color: var(--adm-muted);
    list-style: none;
}

.admin-chart-table > summary::-webkit-details-marker {
    display: none;
}

.admin-chart-table > summary::before {
    content: "▸ ";
}

.admin-chart-table[open] > summary::before {
    content: "▾ ";
}

.admin-chart-table > summary:hover {
    color: var(--adm-text);
}

.admin-chart-table .admin-table-wrap {
    max-height: 320px;
    overflow: auto;
    margin-top: .5rem;
}

.admin-field-label {
    font-size: .78rem;
    color: var(--adm-muted);
}

/* ── Cost (/admin/cost) ─────────────────────────────────────────────────────
   The Cost page is the one screen where an admin types into the model rather than
   only reading it, so the rate grid has to stay legible while it is being edited:
   label and field on one line, fields right-aligned and tabular so a column of
   figures reads as a column even as the values change under the cursor.
   ────────────────────────────────────────────────────────────────────────── */

.cost-rates {
    display: grid;
    grid-template-columns: 1fr 7.5rem;
    align-items: center;
    gap: .45rem .75rem;
}

/* Section heading inside the grid. Spans both tracks so it reads as a break in the
   list rather than as a label whose field went missing. */
.cost-rate-group {
    grid-column: 1 / -1;
    margin-top: .6rem;
    padding-top: .6rem;
    border-top: 1px solid var(--adm-border);
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--adm-green);
}

.cost-rate-group:first-child {
    margin-top: 0;
    padding-top: 0;
    border-top: none;
}

.cost-rate-input {
    padding: .35rem .5rem;
    font-size: .85rem;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* Explanatory copy under a panel's rows. Sized down and held to a readable measure
   so it reads as a note on the numbers above, not as another row of them. */
.cost-note {
    margin: .85rem 0 0;
    font-size: .8rem;
    line-height: 1.5;
    max-width: 62ch;
}

.cost-note code {
    font-size: .76rem;
    padding: .05rem .3rem;
    border-radius: 4px;
    background: var(--adm-bg);
    border: 1px solid var(--adm-border);
}

/* The projection row matching today's active-user count. */
.cost-row-now {
    background: var(--adm-green-soft);
}

/* Actual-vs-modelled marker. The Cost page carries both kinds of number side by side
   and they respond to different inputs, so every total that could be mistaken for the
   other kind wears one of these. Deliberately quiet — it is a qualifier on the figure
   above it, not a status worth competing with the figure for attention. */
.cost-kind {
    display: inline-block;
    margin-left: .4rem;
    padding: .05rem .35rem;
    border-radius: 4px;
    font-size: .62rem;
    font-weight: 600;
    letter-spacing: .07em;
    text-transform: uppercase;
    vertical-align: .1rem;
}

.cost-kind-actual {
    background: var(--adm-bg);
    color: var(--adm-muted);
    border: 1px solid var(--adm-border);
}

.cost-kind-model {
    background: var(--adm-green-soft);
    color: var(--adm-green);
    border: 1px solid transparent;
}

.cost-legend {
    margin-top: 1rem;
    max-width: 78ch;
}
