/*
 * ============================================================================
 * DASHBOARD CARD PRESENTATION
 * ============================================================================
 * Registered as a Filament asset in AppServiceProvider, NOT compiled by Vite.
 *
 * This file is plain CSS on purpose, and that is the whole reason it exists.
 * The panel has no app-level Tailwind build feeding it: `resources/css/app.css`
 * is the Laravel starter sheet and is never loaded into the Filament panel, and
 * the panel's own stylesheet (public/css/filament/filament/app.css) is compiled
 * from FILAMENT's source, so it contains only the utilities Filament itself
 * happens to use. Checked against that file, `flex`, `flex-col`, `items-center`,
 * `gap-2`, `rounded-full`, `w-full`, `bg-success-500` and every other utility a
 * widget view might reach for are simply absent -- zero occurrences.
 *
 * That is a silent failure, which is why it is recorded here rather than left as
 * folklore: a Blade view full of Tailwind classes renders without error, returns
 * HTTP 200, and produces unstyled text. The first version of the monitor-usage
 * card was built that way. DashboardWidgetsTest now fails the build if a widget
 * view reaches for a utility class again.
 *
 * ============================================================================
 * COLOURS COME FROM FILAMENT'S OWN MECHANISM, NOT LITERALS
 * ============================================================================
 * `.fi-color-{name}` sets `--color-50 .. --color-950` from that palette, e.g.
 * `--color-500: var(--danger-500)`. So putting `fi-color-danger` on an element
 * and reading `var(--color-500)` inside it gives the themed colour, tracks any
 * future palette change, and stays correct in dark mode. A hex literal here
 * would be right once and then drift.
 *
 * The palette variables themselves (`--gray-200`, `--danger-500`) are NOT in the
 * static stylesheet -- Filament emits them per panel in a <style> block at
 * runtime. Grepping the compiled CSS for them therefore turns up nothing, which
 * is expected and not a fault.
 */

/*
 * ----------------------------------------------------------------------------
 * 1. Centre the content of every stat card, on both axes
 * ----------------------------------------------------------------------------
 * `-content` is a GRID (`display: grid; row-gap: ...`), not a flexbox, so the
 * centring properties are align-content / justify-items. `items-center` and
 * `justify-center` -- the flex equivalents -- would do nothing at all here.
 *
 * `height: 100%` is load-bearing for the vertical axis: the card already sets
 * `height: 100%` so all cards in a row match, but the content grid is only as
 * tall as its rows, so without this it sits at the top and align-content has no
 * free space to distribute.
 *
 * Vertical centring is a presentation choice with a real trade-off, recorded
 * here because an earlier version of this comment had it backwards.
 *
 * Filament's default puts the content block at the TOP of the card. Since the
 * rows are label / value / description in that order, top alignment keeps every
 * card's number at the same height and leaves the spare space at the bottom of
 * whichever cards have shorter descriptions. Centring balances the block inside
 * the card -- which is what was asked for -- at the cost that a card whose
 * description wraps to two lines now sits with its number about half a line
 * higher than its neighbours'.
 *
 * Both are defensible. This is the requested one. Deleting the two properties
 * below restores Filament's top alignment and nothing else changes.
 *
 * SPECIFICITY, deliberately: Filament's own rule is
 *   .fi-wi-stats-overview-stat .fi-wi-stats-overview-stat-content  -> (0,2,0)
 * Matching that would leave the outcome decided by which stylesheet loads last,
 * which depends on where Filament renders registered assets relative to its own
 * -- true today, not a guarantee. Adding the wrapper class makes these (0,3,0),
 * so they win on specificity and the order stops mattering. Cheaper and more
 * honest than !important.
 */
.fi-wi-stats-overview .fi-wi-stats-overview-stat > .fi-wi-stats-overview-stat-content {
    height: 100%;
    align-content: center;
    justify-items: center;
    text-align: center;
}

/* The icon+label row is a real flexbox, so here justify-content IS the property. */
.fi-wi-stats-overview .fi-wi-stats-overview-stat .fi-wi-stats-overview-stat-label-ctn {
    justify-content: center;
}

/*
 * ----------------------------------------------------------------------------
 * 2. The quota bar
 * ----------------------------------------------------------------------------
 * Filament's Stat has no progress bar and cannot grow one: its only graphical
 * option is chart(), which draws a sparkline -- a trend line over a single
 * ratio, which would invent a history that does not exist. Hence a small custom
 * card that borrows Stat's classes for its chrome and adds only the bar.
 */
.udm-quota-track {
    /* justify-self, because the parent grid now centres its items: without it
       the track would shrink to its content width, which is nothing. */
    justify-self: stretch;
    width: 100%;
    height: 0.5rem;
    overflow: hidden;
    border-radius: 9999px;
    background-color: var(--gray-200);
}

.udm-quota-track:where(.dark, .dark *) {
    background-color: var(--gray-800);
}

.udm-quota-fill {
    height: 100%;
    border-radius: inherit;
    /* Set by .fi-color-{success|warning|danger|gray} on the track. */
    background-color: var(--color-500);
    transition: width 150ms ease-out;
}

/*
 * The denominator, smaller and quieter than the numerator. em rather than rem so
 * it stays in proportion if the stat value's size ever changes.
 */
.udm-quota-limit {
    font-size: 0.6em;
    font-weight: 400;
    color: var(--gray-500);
}

.udm-quota-limit:where(.dark, .dark *) {
    color: var(--gray-400);
}

/* ===========================================================================
 * THE VERDICT BAND
 * ===========================================================================
 * One line at the top of the dashboard answering "is anything wrong?" before
 * any number has to be read. See App\Filament\Widgets\AccountVerdict.
 *
 * COLOURS COME FROM FILAMENT'S OWN CSS VARIABLES, NOT HEX VALUES.
 * var(--danger-*), var(--warning-*) and var(--gray-*) are emitted by the panel
 * at runtime from its registered palette, so this band follows a theme change
 * automatically. A hex value here would be right exactly once -- which is the
 * mistake this file already avoids for the quota bar, and the reason the accent
 * could move from amber to petrol without touching any CSS.
 *
 * There is deliberately NO tint rule for the healthy states (up, checking,
 * idle, empty): they inherit the plain surface. A band that is always coloured
 * carries no information by being coloured.
 */
.udm-verdict {
    padding: 1rem 1.25rem;
    border: 1px solid var(--gray-200);
    border-radius: 0.75rem;
    background-color: rgb(255 255 255);
}

.udm-verdict:where(.dark, .dark *) {
    border-color: var(--gray-700);
    background-color: var(--gray-900);
}

/*
 * A LEFT RULE RATHER THAN A FILLED ROW.
 * The palette rule is that status appears as a dot, a thin bar or a word, never
 * a large fill -- a full-width red row is louder than the information in it and
 * makes the surrounding text harder to read. So the tint is a 3px edge plus a
 * very light wash, and the text stays on the normal surface.
 */
.udm-verdict--down,
.udm-verdict--degraded,
.udm-verdict--stale,
.udm-verdict--unknown {
    border-left-width: 3px;
}

.udm-verdict--down {
    border-left-color: var(--danger-500);
    background-color: var(--danger-50);
}

.udm-verdict--degraded {
    border-left-color: var(--warning-500);
    background-color: var(--warning-50);
}

/*
 * STALE IS GREY, NOT AMBER, AND THAT IS THE WHOLE POINT.
 * Stale is not a third severity of "unhealthy" -- it is an absence of
 * information. Colouring it amber would file "we cannot tell you" alongside
 * "degraded", which is a claim about the customer's service rather than about
 * our own data. The left rule still marks it as needing attention.
 */
.udm-verdict--stale,
.udm-verdict--unknown {
    border-left-color: var(--gray-400);
    background-color: var(--gray-50);
}

.udm-verdict--down:where(.dark, .dark *) {
    background-color: color-mix(in srgb, var(--danger-500) 12%, var(--gray-900));
}

.udm-verdict--degraded:where(.dark, .dark *) {
    background-color: color-mix(in srgb, var(--warning-500) 12%, var(--gray-900));
}

.udm-verdict--stale:where(.dark, .dark *),
.udm-verdict--unknown:where(.dark, .dark *) {
    background-color: var(--gray-800);
}

/*
 * ============================================================================
 * THE VERDICT TEXT MUST WIN THE ROW. IT USED TO LOSE IT ENTIRELY.
 * ============================================================================
 * Reported as a design bug with a screenshot: the headline rendered as
 * "monitor" / "is" / "down" one word per line, the counts one word per line,
 * and the monitor names ONE CHARACTER per line.
 *
 * The cause was two rules working against each other:
 *
 *   .udm-verdict-action { flex: none; }   -- never shrinks
 *   .udm-verdict-text   { min-width: 0; } -- shrinks to nothing
 *
 * flex: none resolves the action block to its MAX-CONTENT width, and that block
 * holds a whole sentence ("T6 SSL expiry warn 15d - open since 3 days ago")
 * plus a button. On a 700px card that claimed almost the entire row, and
 * min-width: 0 let the text collapse into the ~50px left over. The per-character
 * wrapping was .udm-verdict-names' overflow-wrap: anywhere doing exactly what it
 * was asked to in a box narrower than one word.
 *
 * It only appears when an incident is open AND the monitor's name is long, which
 * is why it survived: the healthy states have no action block at all, and a
 * short name leaves enough room to look merely cramped.
 *
 * The fix inverts the priority. The band exists to answer "is anything wrong"
 * before any number is read, so the text gets a floor and the action shrinks --
 * and the row wraps at every width, so when there is not room for both the
 * action drops to its own line instead of squeezing the answer.
 */
.udm-verdict-row {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    /* At EVERY width, not only below 768px. The old media query wrapped only on
       a narrow viewport, so a wide screen had no escape valve and crushed the
       text instead. */
    flex-wrap: wrap;
}

.udm-verdict-icon {
    flex: none;
    /*
     * display: flex SO THE SPAN IS EXACTLY THE GLYPH WIDE.
     *
     * It is a <span> with the svg on its own indented line in the Blade, and as
     * an inline formatting context that surrounding whitespace renders as a
     * space -- about 4px of it. Measured: the row was 287px, the text floor
     * resolved to 251px, and 24 + 12 + 251 is exactly 287, so those few pixels
     * of invisible whitespace were enough to push the sum over the line and wrap
     * the icon onto a row of its own with the sentence beneath it.
     *
     * Whitespace between an element and its container is not a thing anybody
     * looks for when a layout is a few pixels out, which is the only reason this
     * is worth six lines of comment.
     */
    display: flex;
    /* Nudged to sit on the headline's cap height rather than its line box. */
    margin-top: 0.125rem;
    color: var(--gray-400);
}

.udm-verdict-icon svg {
    width: 1.5rem;
    height: 1.5rem;
}

.udm-verdict--down .udm-verdict-icon {
    color: var(--danger-500);
}

.udm-verdict--degraded .udm-verdict-icon {
    color: var(--warning-500);
}

.udm-verdict--up .udm-verdict-icon {
    /* The one place a healthy state gets colour: a 24px glyph is a dot, not a
       fill, and it is what makes the band readable at a glance rather than
       requiring the sentence to be read. */
    color: var(--success-500);
}

.udm-verdict-text {
    /*
     * A FLOOR, NOT ZERO.
     *
     * min-width: 0 was here so a long monitor name would wrap rather than force
     * the row wider than the card -- a real concern, and the reason the names
     * line carries overflow-wrap. But zero also permits the collapse described
     * above, so the floor does both jobs: names still wrap, and the column can
     * never be squeezed below something readable.
     *
     * min(...) rather than a bare 18rem, so on a card narrower than the floor the
     * text takes what there is instead of overflowing it -- the case a plain
     * min-width gets wrong, and the one that shows on a phone.
     *
     * The second term leaves room for the icon beside it -- 1.5rem of glyph, the
     * row's 0.75rem gap, and 0.75rem of slack -- so the floor does not depend on a
     * pixel tie. Subtracting the exact 2.25rem made the sum equal the line width
     * to the pixel, and a layout that turns on which way a tie falls is one that
     * breaks at a different zoom level or font.
     *
     * On a very narrow card the icon still takes a line of its own with the
     * sentence beneath it, and that is fine: nothing overflows and the sentence
     * gets the full width. Measured across 330 / 560 / 700 / 1000px, the headline
     * and the names each render on ONE line at every one of them, which is the
     * property that matters. The icon's position is not.
     */
    flex: 1 1 18rem;
    min-width: min(18rem, calc(100% - 3rem));
}

.udm-verdict-headline {
    margin: 0;
    font-size: 1.125rem;
    font-weight: 600;
    line-height: 1.4;
    color: var(--gray-950);
}

.udm-verdict-headline:where(.dark, .dark *) {
    color: rgb(255 255 255);
}

.udm-verdict-detail {
    margin: 0.125rem 0 0;
    font-size: 0.875rem;
    color: var(--gray-500);
}

.udm-verdict-detail:where(.dark, .dark *) {
    color: var(--gray-400);
}

.udm-verdict-age {
    /* Quieter than the counts beside it: it qualifies them rather than being
       one of them. */
    color: var(--gray-400);
}

.udm-verdict-names {
    margin: 0.375rem 0 0;
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--gray-700);
    overflow-wrap: anywhere;
}

.udm-verdict-names:where(.dark, .dark *) {
    color: var(--gray-300);
}

.udm-verdict-action {
    /*
     * flex: 0 1 auto -- may SHRINK, was flex: none.
     *
     * This single keyword was the bug. `none` is shorthand for `0 0 auto`, and
     * the zero shrink factor is what let a sentence-plus-button block hold its
     * max-content width against a column whose whole purpose is to be read.
     */
    flex: 0 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    /* So the button drops under the incident line rather than the pair of them
       forcing the row wider. */
    flex-wrap: wrap;
}

/* The Acknowledge button itself does not shrink -- a squashed button with a
   clipped label is worse than one that wraps to the next line. */
.udm-verdict-action .fi-btn {
    flex: none;
}

.udm-verdict-incident {
    font-size: 0.8125rem;
    color: var(--gray-500);
    /* min-width: 0 so this sentence can wrap inside the action block instead of
       setting its max-content width; overflow-wrap for the same reason the names
       line has it -- a monitor name is customer-supplied and can be one long
       unbroken token. */
    min-width: 0;
    overflow-wrap: anywhere;
}

.udm-verdict-incident:where(.dark, .dark *) {
    color: var(--gray-400);
}

/*
 * Below Filament's own 768px breakpoint for this grid, the action block takes
 * the whole line so the button sits under the incident sentence at the left
 * margin rather than trailing it.
 *
 * The flex-wrap declarations that used to live here have moved into the base
 * rules: wrapping only on a narrow viewport was what left a wide screen with no
 * escape valve, and a wide screen is where the bug was reported.
 */
@media (max-width: 768px) {
    .udm-verdict-action {
        width: 100%;
    }
}

/* ==========================================================================
 * THE LOGIN LOGO IS A HERO. THE SIDEBAR LOGO IS FURNITURE.
 * ==========================================================================
 * Filament has ONE setting for both: brandLogoHeight() emits an inline
 * style="height: ..." on every .fi-logo it renders. A height that suits the
 * sidebar, where the logo sits in a 3rem-tall bar next to the nav, is far too
 * small on the sign-in card, where the logo is the only thing above the form
 * and is doing the work of identifying the deployment.
 *
 * Reported the direct way: "on login screen logo is very small". At 2.5rem a
 * 724x306 wordmark renders about 76px wide, so the lettering is present and
 * unreadable.
 *
 * SCOPED TO .fi-simple-header, which is the auth layout's own header -- the
 * sign-in, password-reset and email-verification pages. The panel sidebar uses
 * a different wrapper, so it keeps the configured height and is untouched.
 *
 * !important IS REQUIRED HERE AND IS NOT LAZINESS. The height Filament applies
 * is an INLINE style attribute on the img, and inline styles outrank any
 * selector in a stylesheet regardless of specificity. Without !important this
 * rule is simply ignored, which is the failure mode that makes people conclude
 * the stylesheet is not loading at all.
 *
 * height:auto rather than a fixed height, capped by max-height and max-width,
 * so a tall square mark and a wide wordmark both come out sensibly and neither
 * can overflow the card on a narrow viewport.
 * ========================================================================== */
.fi-simple-header .fi-logo {
    height: auto !important;
    max-height: 7rem;
    max-width: 100%;
    width: auto;
    margin-inline: auto;
}

/* A phone gets less, because the card itself is narrower and the form below is
 * what the visitor came for. */
@media (max-width: 640px) {
    .fi-simple-header .fi-logo {
        max-height: 4.5rem;
    }
}

/* ==========================================================================
 * 3. THE STAT CARDS ARE SMALLER THAN FILAMENT MAKES THEM
 * ==========================================================================
 * Asked for directly: "widgets can be smaller and 4 in a row". The row count is
 * not here -- it is App\Filament\Widgets\MonitorStatusOverview::$columns, because
 * it is a property of the widget rather than of its appearance. This file only
 * does the size.
 *
 * Filament's own values, read from the compiled panel stylesheet rather than
 * assumed, are padding 1.5rem, a 0.5rem row gap and a 1.875rem value. Six cards
 * at that size fill most of a laptop viewport before the chart below them begins,
 * and four to a row makes each one narrower, so the large number is also the thing
 * most likely to wrap.
 *
 * SPECIFICITY IS LOAD-BEARING, as it is for the centring rules above. Filament
 * declares these on single classes -- .fi-wi-stats-overview-stat (0,1,0) and
 * .fi-wi-stats-overview-stat-value (0,1,0) -- so two and three class selectors
 * win outright and the outcome does not depend on which stylesheet the panel
 * happens to emit last. That ordering is true today and is not a guarantee, which
 * is the whole reason not to rely on it.
 *
 * ONE SELECTOR, NOT TWO, AND THAT IS A RECENT CHANGE. The quota card used to be its
 * own widget, which put it OUTSIDE .fi-wi-stats-overview, so every rule here and in
 * section 1 carried a second `.udm-quota-card.fi-wi-stats-overview-stat` selector to
 * reach it. It is now a Stat inside that same grid (see
 * MonitorStatusOverview::quotaCard), so the first selector already matches it and the
 * second matched nothing. Kept "just in case" it would have been dead rules with an
 * excuse attached, which is how a stylesheet stops being readable.
 *
 * .udm-quota-card stays on the element, but not because anything here styles it: the
 * bar rules in section 2 are keyed on .udm-quota-track and .udm-quota-fill, and no
 * rule in this file now matches .udm-quota-card at all. It is kept as the card's name
 * in the markup -- what DashboardWidgetsTest looks for, and what makes the element
 * findable among Filament-generated class names. If that stops being true, delete it
 * from the Blade rather than invent a rule to justify it.
 */
.fi-wi-stats-overview .fi-wi-stats-overview-stat {
    padding: 1rem;
}

.fi-wi-stats-overview .fi-wi-stats-overview-stat > .fi-wi-stats-overview-stat-content {
    row-gap: 0.25rem;
}

/*
 * 1.5rem, down from 1.875rem. Still by far the largest thing on the card, which is
 * the property that matters: the number is what the card exists to show, and the
 * label above it stays at Filament's 0.875rem so the ratio between them is wider
 * than before rather than narrower.
 */
.fi-wi-stats-overview .fi-wi-stats-overview-stat .fi-wi-stats-overview-stat-value {
    font-size: 1.5rem;
    line-height: 1.25;
}

/* ==========================================================================
 * 4. BROWSER SESSIONS, ON THE PROFILE PAGE
 * ==========================================================================
 * The list of devices signed in to an account. Plain CSS for the reason at the
 * top of this file: a Tailwind utility here would render as nothing at all.
 *
 * Colours come from Filament's runtime palette variables rather than literals,
 * so this follows a theme change and works in both light and dark without a
 * second block. --gray-* are emitted per panel at runtime, which is why grepping
 * the compiled stylesheet for them finds nothing.
 */
.udm-session-list {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.udm-session {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.udm-session-icon {
    /* display:flex so the span is exactly the glyph wide -- the same whitespace
       trap the verdict band's icon documents further up this file. */
    display: flex;
    flex: none;
    color: var(--gray-400);
}

.udm-session-icon svg {
    width: 1.5rem;
    height: 1.5rem;
}

.udm-session-detail {
    display: flex;
    flex-direction: column;
    /* So a long unrecognised user agent wraps inside the row instead of setting
       the row's width. BrowserSessions truncates it, but a 60-character token
       with no spaces still has to be allowed to break. */
    min-width: 0;
    overflow-wrap: anywhere;
}

.udm-session-agent {
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--gray-950);
}

.udm-session-agent:where(.dark, .dark *) {
    color: rgb(255 255 255);
}

.udm-session-meta {
    font-size: 0.75rem;
    color: var(--gray-500);
}

.udm-session-meta:where(.dark, .dark *) {
    color: var(--gray-400);
}

/*
 * THE ONLY COLOURED THING IN THE LIST, and it is the accent rather than a status
 * colour. "This device" is not a state of the customer's service, it is which row
 * you are reading from -- so it takes the interactive hue, and the palette rule
 * that status colours mean status stays intact.
 */
.udm-session-current {
    font-weight: 600;
    color: var(--primary-600);
}

.udm-session-note {
    margin: 0;
    font-size: 0.875rem;
    color: var(--gray-500);
}

.udm-session-note:where(.dark, .dark *) {
    color: var(--gray-400);
}
