/* ─────────────────────────────────────────────────────────────────────────
   Module summary panels (2026-09-09)

   The landing dashboard is now a stack of these, and every module page can
   render the same panel at the top of itself. Everything here is scoped under
   .cx-mod* or .cx-dashboard so it can never leak into another surface.

   Deliberately built ON the existing vocabulary rather than beside it: the KPI
   chips are the app's own .kt-stat-chip family, the table is .kt-table
   .sb-table, and the phone treatment is the app's established
   .kt-table-wrap / .kt-mobile-cards swap at 860px. There is no new colour
   language here, only layout.
   ───────────────────────────────────────────────────────────────────────── */

/* ── The page: header, sticky period bar, panel grid ─────────────────────── */

.cx-dashboard {
    display: grid;
    gap: 1rem;
}

.cx-dash-bar {
    align-items: center;
    background: color-mix(in srgb, var(--card) 92%, transparent);
    backdrop-filter: blur(8px);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    display: flex;
    flex-wrap: wrap;
    gap: .75rem 1rem;
    justify-content: space-between;
    padding: .7rem .9rem;
    position: sticky;
    /* Clears the app's own utility bar, which is itself sticky. */
    top: .5rem;
    z-index: 30;
}

.cx-dash-bar-label {
    color: var(--muted-foreground);
    font-size: var(--text-xs);
    letter-spacing: .04em;
    text-transform: uppercase;
}

.cx-dash-periods {
    display: flex;
    flex-wrap: wrap;
    gap: .3rem;
}

.cx-dash-period {
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 999px;
    color: var(--muted-foreground);
    cursor: pointer;
    font-size: var(--text-2sm);
    font-weight: var(--font-weight-medium);
    padding: .34rem .8rem;
    transition: background .12s ease, color .12s ease, border-color .12s ease;
}

.cx-dash-period:hover,
.cx-dash-period:focus-visible {
    border-color: color-mix(in srgb, var(--primary) 45%, var(--border));
    color: var(--foreground);
}

.cx-dash-period.active {
    background: var(--primary);
    border-color: var(--primary);
    color: #fff;
}

.cx-mod-more { display: none; }

.cx-dash-note {
    color: var(--muted-foreground);
    font-size: var(--text-xs);
}

.cx-dash-grid {
    display: grid;
    gap: 1rem;
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* ── The panel ───────────────────────────────────────────────────────────── */

.cx-mod {
    /* A grid item's default min-width is auto, so a wide table inside would
       push the CARD past its column instead of being contained - measured
       2026-09-09: a 530px Supervisor panel with a 771px scrollWidth painted
       its KPI chips straight over the Advisor panel beside it. */
    min-width: 0;
    overflow: hidden;
}

.cx-mod--full { grid-column: 1 / -1; }

.cx-mod-head {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: .5rem .9rem;
    justify-content: space-between;
}

.cx-mod-id {
    align-items: baseline;
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    min-width: 0;
}

.cx-mod-name {
    font-size: 1rem;
    font-weight: var(--font-weight-semibold);
    margin: 0;
}

.cx-mod-scope {
    color: var(--muted-foreground);
    font-size: var(--text-xs);
}

.cx-mod-dot {
    align-self: center;
    border-radius: 50%;
    flex: 0 0 auto;
    height: 8px;
    width: 8px;
}

.cx-mod-dot--ok   { background: var(--kt-pattern-green, #4ade80); }
.cx-mod-dot--warn { background: var(--kt-pattern-orange, #ffad5b); }
.cx-mod-dot--bad  { background: var(--destructive-readable); }
.cx-mod-dot--idle { background: var(--muted-foreground); }

.cx-mod-body {
    display: grid;
    gap: .75rem;
    min-width: 0;
    transition: opacity .12s ease;
}

.cx-mod-body.is-loading { opacity: .45; }

/* The one plain-English sentence. It is the only thing on the panel a human
   can read without decoding a number, so it gets real type, not fine print. */
.cx-mod-line {
    color: var(--foreground);
    font-size: var(--text-sm);
    line-height: 1.5;
    margin: 0;
}

.cx-mod-foot {
    color: var(--muted-foreground);
    font-size: var(--text-xs);
    line-height: 1.45;
    margin: 0;
}

/* ── KPI band ────────────────────────────────────────────────────────────── */

.cx-mod-kpis {
    /* auto-fit rather than a fixed six: a panel with four figures spreads them
       across the width instead of leaving two empty tracks on the right. */
    display: grid;
    gap: .5rem;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}

.cx-mod--half .cx-mod-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }

.cx-mod-kpi {
    align-items: flex-start;
    display: flex;
    flex-direction: column;
    gap: .1rem;
    min-width: 0;
    padding: .5rem .65rem;
    text-decoration: none;
    /* The chip family is built for an inline strip and sizes to its content;
       inside this grid each chip owns a whole cell, so they must all be the
       same width AND the same height, or a chip whose label wraps to two lines
       leaves its neighbour looking clipped. */
    height: 100%;
    width: 100%;
}

a.cx-mod-kpi:hover { border-color: color-mix(in srgb, var(--kt-stat-color) 45%, var(--border)); }

.cx-mod-kpi .kt-stat-label {
    /* Labels wrap to a second line rather than truncating. "Listings monitored
       now" ellipsised to "LISTINGS MONITORED N", which is not a label. */
    line-height: 1.25;
    white-space: normal;
    width: 100%;
    word-break: normal;
    overflow-wrap: anywhere;
}

.cx-mod-kpi .kt-stat-value { font-size: 1.4rem; line-height: 1.15; }

.cx-mod-kpi-note {
    color: var(--muted-foreground);
    font-size: var(--text-xs);
    line-height: 1.3;
}

.kt-stat-chip--muted { --kt-stat-color: var(--muted-foreground); }

/* ── Table + cells ───────────────────────────────────────────────────────── */

.cx-mod-table {
    max-width: 100%;
    /* Never a sideways scroll on the page itself; if a table genuinely cannot
       fit, it scrolls inside its own box - and below 860px it is replaced by
       stacked records instead. */
    overflow-x: auto;
}

/* Fixed layout so the metric columns cannot be widened by one long company
   name. The first column absorbs the slack and truncates; the rest split what
   is left evenly, which works for both the four and six column panels. */
.cx-mod-table .sb-table {
    table-layout: fixed;
    width: 100%;
}

.cx-mod-table .sb-table th,
.cx-mod-table .sb-table td {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cx-mod-table .sb-table th:first-child,
.cx-mod-table .sb-table td:first-child { width: 34%; }

/* The name is the column a human reads first. It may run to a second line
   rather than truncate to "New category to consi...". */
.cx-mod-table .sb-table td:first-child,
.cx-mod-table .sb-table td:first-child .cx-cell {
    white-space: normal;
}

.cx-mod-table .sb-table td:first-child .cx-cell {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-height: 1.25;
    overflow: hidden;
}

/* A half-width panel has half the room, and the name is the column a human
   reads first - it gets the extra, not the metric columns. */
.cx-mod--half .sb-table th:first-child,
.cx-mod--half .sb-table td:first-child { width: 40%; }

/* Five columns now (what / how often / where / since / action), so the
   sentence gives some width back. */
.cx-mod--alerts .sb-table th:first-child,
.cx-mod--alerts .sb-table td:first-child { width: 44%; }

.cx-mod--alerts .sb-table th:last-child,
.cx-mod--alerts .sb-table td:last-child { width: 5rem; }

/* The last column is where a panel explains itself ("Watch - spend pacing
   high"). It is the one cell allowed to run to a second line. */
.cx-mod-table .sb-table td:last-child,
.cx-mod-table .sb-table td:last-child .cx-cell,
.cx-mod-table .sb-table td:last-child .cx-cell-sub {
    white-space: normal;
}

/* The state cell is a word, not a measurement - it must never read "Healt...". */
.cx-mod-table .sb-table td:last-child .cx-cell {
    display: inline;
    overflow: visible;
}

.cx-mod-table .sb-table td:last-child .cx-cell-sub {
    line-height: 1.25;
    overflow: hidden;
}

.cx-mod-table .sb-table thead th {
    color: var(--muted-foreground);
    font-size: var(--text-2sm);
    font-weight: var(--font-weight-medium);
    /* Headers wrap rather than truncate. A column headed "Listin..." is not
       labelled at all, which is worse than a two-line header. */
    line-height: 1.2;
    padding: .45rem .6rem;
    white-space: normal;
}

.cx-mod-table .sb-table tbody td {
    padding: .45rem .6rem;
    vertical-align: middle;
}

/* Zebra. Half the value of a dense table is being able to track one row
   across six columns without a ruler, so the step has to be visible - a 45%
   mix over a near-black card read as no stripe at all. */
.cx-mod-table .sb-table tbody tr:nth-child(odd) td {
    background: color-mix(in srgb, var(--muted) 85%, transparent);
}

/* Numbers left, bare counts centred - the house rule, applied per cell by the
   summary class rather than guessed from the value. */
.cx-al-left   { text-align: left; }
.cx-al-center { text-align: center; }

.cx-cell {
    display: inline-block;
    font-size: var(--text-sm);
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: bottom;
    white-space: nowrap;
}

.cx-cell--strong { font-weight: var(--font-weight-semibold); }
.cx-cell--link { color: inherit; text-decoration: none; }
.cx-cell--link:hover { text-decoration: underline; }

.cx-cell--primary { color: var(--kt-pattern-blue, #57a6ff); }
.cx-cell--info    { color: var(--kt-pattern-cyan, #45d5e7); }
.cx-cell--accent  { color: var(--kt-pattern-violet, #a98bff); }
.cx-cell--success { color: var(--kt-pattern-green, #4ade80); }
.cx-cell--warn    { color: var(--kt-pattern-orange, #ffad5b); }
.cx-cell--danger  { color: var(--destructive-readable); }
.cx-cell--muted   { color: var(--muted-foreground); }

.cx-cell-sub {
    /* One step up from --muted-foreground: this is the line that explains a
       row ("spend pacing high"), and it was measured too faint to read at
       12px on the card tint. */
    color: color-mix(in srgb, var(--foreground) 62%, var(--muted-foreground));
    display: block;
    font-size: var(--text-xs);
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cx-mod-empty {
    color: var(--muted-foreground);
    font-size: var(--text-sm);
    margin: 0;
    padding: .8rem .6rem;
    text-align: center;
}

/* ── The alerts strip ────────────────────────────────────────────────────── */

.cx-mod--alerts { border-color: color-mix(in srgb, var(--destructive-readable) 35%, var(--border)); }

.cx-mod--alerts .cx-mod-line {
    font-size: 1rem;
    font-weight: var(--font-weight-semibold);
}

/* A clean board should read as calm, not as an empty table. */
.cx-mod--alerts .cx-mod-dot--ok ~ .cx-mod-name { color: var(--foreground); }

/* ── Phone cards ─────────────────────────────────────────────────────────── */

.cx-mod-cards { display: none; }

.cx-mod-card {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    display: grid;
    gap: .25rem;
    padding: .6rem .7rem;
}

.cx-mod-card-head {
    font-size: var(--text-sm);
    font-weight: var(--font-weight-semibold);
}

.cx-mod-card-field {
    align-items: baseline;
    display: flex;
    gap: .4rem;
    justify-content: space-between;
}

.cx-mod-card-field .lbl {
    color: var(--muted-foreground);
    font-size: var(--text-xs);
}

.cx-mod-card-field .cx-cell { text-align: right; }

/* ── Responsive ──────────────────────────────────────────────────────────── */

@media (max-width: 1280px) {
    .cx-mod-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 1024px) {
    .cx-dash-grid { grid-template-columns: minmax(0, 1fr); }
    .cx-mod--half .cx-mod-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 860px) {
    /* The app-wide swap: the table goes, the stacked records arrive. Declared
       here as well as in patterns.css because these panels bring their own
       wrapper classes and must not depend on selector order between sheets. */
    .cx-mod-table { display: none; }
    .cx-mod-cards { display: grid; gap: .5rem; padding: 0; }
    .cx-mod-cards .cx-mod-card:nth-child(odd) {
        background: color-mix(in srgb, var(--muted) 70%, var(--card));
    }

    /* A phone gets the top THREE records per module, not all six. Twelve
       panels at six records each measured 13,600px tall, which is not a
       dashboard, it is a scroll. The "Open <module>" button above is how you
       see the rest. */
    .cx-mod-cards .cx-mod-card:nth-child(n+4) { display: none; }

    .cx-mod-more {
        color: var(--muted-foreground);
        display: block;
        font-size: var(--text-xs);
        margin: 0;
        padding-top: .1rem;
    }

    /* Nothing in a record may run past its own card - but break-word, not
       anywhere: "Watch" was being split into "Wat" and "ch". Only a token with
       no break opportunity at all is allowed to break. */
    .cx-mod-card-head,
    .cx-mod-card .cx-cell,
    .cx-mod-card .cx-cell-sub {
        overflow-wrap: break-word;
        white-space: normal;
        word-break: normal;
    }

    /* Label left, value right, on ONE line. Stacking them was tried and cost
       2,400px of page height across twelve panels for no legibility gain - the
       broken "Wat/ch" was overflow-wrap:anywhere, fixed above, not the row. */
    .cx-mod-card-field {
        align-items: baseline;
        gap: .75rem;
    }

    .cx-mod-card-field .lbl { flex: 0 0 auto; }
    .cx-mod-card-field .cx-cell { text-align: right; }

    .cx-mod-card .cx-cell {
        -webkit-line-clamp: none;
        display: inline;
        overflow: visible;
    }



    /* 12px is the floor for anything a human has to read on a phone. */
    .cx-cell-sub,
    .cx-mod-foot,
    .cx-mod-card-field .lbl { font-size: 12px; }
}

@media (max-width: 620px) {
    .cx-dash-bar {
        align-items: stretch;
        flex-direction: column;
        gap: .5rem;
        position: static;
    }

    /* Six pills in a wrapping row become six thin slivers. On a phone they
       become an even 3 by 2 grid with a real touch target each - a native
       select was tried first and rendered as a row of chevrons in the panel's
       own chrome. */
    .cx-dash-periods {
        display: grid;
        gap: .35rem;
        grid-template-columns: repeat(3, minmax(0, 1fr));
        width: 100%;
    }

    .cx-dash-period {
        min-height: 42px;
        padding: .5rem .4rem;
    }

    .cx-mod-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .cx-mod--half .cx-mod-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .cx-mod-kpi .kt-stat-value { font-size: 1.25rem; }

    .cx-mod-head { align-items: flex-start; flex-direction: column; }
    .cx-mod-open { width: 100%; }
}

/* ── Phone jump list ─────────────────────────────────────────────────────────
   The stacked page is eleven thousand pixels tall on a phone, which is fine to
   read top to bottom and useless to navigate. This is the index: one chip per
   panel, in the same reading order, right under the period control. Desktop
   has the sidebar and does not need it. */

.cx-dash-jump { display: none; }

@media (max-width: 860px) {
    .cx-dash-jump {
        display: flex;
        flex-wrap: wrap;
        gap: .3rem;
        margin: 0;
        padding: 0;
        width: 100%;
    }

    .cx-dash-jump a {
        border: 1px solid var(--border);
        border-radius: 999px;
        color: var(--muted-foreground);
        font-size: 12px;
        padding: .35rem .6rem;
        text-decoration: none;
    }

    .cx-dash-jump a:active { color: var(--foreground); }
}
