/* fabqueue shared app-page chrome: home + admin pages.
   Uses tokens from tokens.css. Classes are .app-* so they never collide
   with .m-* (machines.css) or .fm-* (floor-plan.css). */

.app-page {
    font-family: var(--font-stack);
    color: var(--color-text);
    background: var(--color-bg);
    min-height: 100vh;
    margin: 0;
    display: flex;
    flex-direction: column;
}

/* Centered single-card layout for pre-login + single-focus pages
   (auth, accept-invite, error pages). No nav chrome. */
.app-page-centered {
    font-family: var(--font-stack);
    color: var(--color-text);
    background: var(--color-bg);
    min-height: 100vh;
    margin: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: var(--space-6) var(--space-4);
    box-sizing: border-box;
}
.app-auth { width: 100%; max-width: 22rem; }
.app-auth-wide { max-width: 30rem; }
.app-wordmark {
    font-size: var(--type-xl);
    font-weight: 600;
    margin: 0 0 var(--space-4);
    text-align: center;
}
.app-page-centered .app-card h1 {
    font-size: var(--type-l);
    margin: 0 0 var(--space-4);
}
.app-auth-links {
    margin: var(--space-4) 0 0;
    font-size: var(--type-m);
    text-align: center;
    color: var(--color-text-muted);
}
.app-auth-links a { color: var(--color-accent); text-decoration: none; }
.app-auth-links a:hover { text-decoration: underline; }
.app-auth-links p { margin: var(--space-1) 0; }

/* ---- header ---------------------------------------------------------- */
.app-header {
    padding: var(--space-3) var(--space-4);
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    display: flex;
    gap: var(--space-4);
    align-items: center;
    flex-wrap: wrap;
}
.app-header h1 {
    font-size: var(--type-xl);
    margin: 0;
    padding-left: var(--space-2);
    border-left: 1px solid var(--color-border);
    line-height: 1;
}
.app-header h1.app-no-rule,
.app-header h1:first-child {
    /* The rule separates the h1 from a preceding back-link; drop it when the
       h1 leads the row (back-links thinned out once the nav banner landed). */
    border-left: 0;
    padding-left: 0;
}
.app-header a {
    color: var(--color-text-muted);
    text-decoration: none;
    font-size: var(--type-m);
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-s);
}
.app-header a:hover { background: var(--color-bg); color: var(--color-text); }
.app-header .app-spacer { flex: 1; }
.app-header .app-chip {
    color: var(--color-text-muted);
    font-size: var(--type-s);
}
.app-header .app-chip strong { color: var(--color-text); }

/* ---- main + cards ---------------------------------------------------- */
.app-main {
    padding: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    max-width: 960px;
    width: 100%;
    box-sizing: border-box;
    /* #189: center the column — a left-hugging 960px card on a wide monitor
       reads as half a broken page. */
    margin-inline: auto;
}
/* #189: table-heavy admin pages (edges, jobs) outgrow 960px and were silently
   clipping columns into the wrap's inner scroll on screens with room to spare.
   Capped so rows don't stretch absurd at ultrawide. */
.app-main-wide { max-width: 1600px; }
.app-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-m);
    padding: var(--space-4);
}
.app-card h2 {
    margin: 0 0 var(--space-3);
    font-size: var(--type-l);
}
.app-card h2:not(:first-child) { margin-top: var(--space-2); }
/* Single-column form cards read better capped to a comfortable width
   rather than stretching inputs across the full 960px main column. Centered
   (#189): with .app-main itself centered, a left-hugging lone card reads as
   misplaced — this matches the .app-page-centered focused-card pattern. */
.app-card-narrow { max-width: 32rem; margin-inline: auto; width: 100%; box-sizing: border-box; }

/* ---- buttons --------------------------------------------------------- */
.app-btn,
button.app-btn {
    display: inline-block;
    background: var(--color-accent);
    color: white;
    text-decoration: none;
    font: inherit;
    font-size: var(--type-m);
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-s);
    border: 1px solid var(--color-accent);
    cursor: pointer;
}
.app-btn:hover { filter: brightness(1.1); color: white; }
.app-btn-secondary,
button.app-btn-secondary {
    background: var(--color-surface);
    color: var(--color-text);
    border: 1px solid var(--color-border);
}
.app-btn-secondary:hover {
    background: var(--color-bg);
    color: var(--color-text);
    filter: none;
}
.app-btn-row { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* A <button> that renders as an inline text link — for scripted actions that
   should not be <a href="javascript:…"> (keyboard/AT semantics + CSP-safety). */
.app-linkbtn {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    color: var(--color-accent);
    text-decoration: underline;
    cursor: pointer;
}

/* ---- forms ----------------------------------------------------------- */
.app-form {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
.app-form label {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    font-size: var(--type-s);
    color: var(--color-text-muted);
}
.app-form input[type="text"],
.app-form input[type="email"],
.app-form input[type="password"],
.app-form input[type="number"],
.app-form select {
    font: inherit;
    font-size: var(--type-m);
    color: var(--color-text);
    padding: var(--space-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-s);
    background: var(--color-surface);
    width: 100%;
    box-sizing: border-box;
}
.app-form small { color: var(--color-text-muted); }
/* #186: checkbox rows. The stacked column layout above is for text inputs
   (label text as a heading over a full-width field); a checkbox's caption IS
   its label and belongs beside the box, not orphaned underneath it. */
.app-form label.app-check {
    flex-direction: row;
    align-items: flex-start;
    gap: var(--space-2);
}
.app-form label.app-check input[type="checkbox"] {
    flex-shrink: 0;
    margin: 0.15em 0 0;
}

/* Inline form: fields laid out in a row (qty/min/target + button on one line).
   Unlike .app-form, inputs keep their natural/explicit width instead of 100%. */
.app-form-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-3);
    margin: 0;
}
.app-form-row label {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    font-size: var(--type-s);
    color: var(--color-text-muted);
}
.app-form-row input,
.app-form-row select {
    font: inherit;
    font-size: var(--type-m);
    color: var(--color-text);
    padding: var(--space-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-s);
    background: var(--color-surface);
    box-sizing: border-box;
}
.app-form-row .app-form-static { align-self: center; }

/* Vertical stack with consistent spacing — e.g. alert(s) above a form. */
.app-stack { display: flex; flex-direction: column; gap: var(--space-3); }

/* Muted helper paragraph under a section heading. */
.app-hint {
    color: var(--color-text-muted);
    font-size: var(--type-s);
    margin: 0 0 var(--space-3);
}
/* Inside table cells the hint is a compact annotation under a badge/value —
   the form-context bottom margin just inflates the row. */
.app-table .app-hint { margin: 0; }

/* ---- alerts ---------------------------------------------------------- */
.app-alert-error,
.app-alert-success,
.app-alert-warn,
.app-alert-info {
    border-radius: var(--radius-s);
    padding: var(--space-2) var(--space-3);
    margin: 0;
    font-size: var(--type-m);
}
.app-alert-error   { background: #fdecea; color: #8a1f11; border: 1px solid #f5b3ab; }
.app-alert-success { background: #e9f7ec; color: #1a7f37; border: 1px solid #aed8b8; }
.app-alert-warn    { background: #fff4e0; color: #8a5a00; border: 1px solid #f0d08a; }
.app-alert-info    { background: #e8f0fe; color: #1356b8; border: 1px solid #b8cdf0; }

/* ---- tables ---------------------------------------------------------- */
.app-table {
    width: 100%;
    border-collapse: collapse;
    background: var(--color-surface);
}
.app-table th, .app-table td {
    padding: var(--space-2) var(--space-3);
    text-align: left;
    border-bottom: 1px solid var(--color-border);
    font-size: var(--type-m);
}
.app-table thead th {
    background: var(--color-bg);
    font-weight: 600;
    color: var(--color-text-muted);
    font-size: var(--type-s);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.app-table tbody tr:last-child td { border-bottom: 0; }
.app-table a { color: var(--color-accent); text-decoration: none; }
.app-table a:hover { text-decoration: underline; }
/* table inside a card: keep the card's border, drop the table's outer one */
.app-card .app-table { background: transparent; }
.app-card > .app-table-wrap { margin: calc(-1 * var(--space-4)); }
.app-table-wrap {
    overflow-x: auto;
    border-radius: var(--radius-m);
}
/* #189: when the wrap really does scroll (narrow viewport), fade the right
   edge so hidden columns are discoverable — the clip otherwise lands on a
   column boundary and reads as "that's the whole table". Scroll-driven
   animation keyed to the wrap's own x-scroll: fade while more content hides
   to the right, gone at scroll end; browsers without support (or with no
   overflow, where the timeline is inert) just get the plain scroller. */
@supports (animation-timeline: scroll(self x)) {
    .app-table-wrap {
        animation: app-scroll-hint linear both;
        animation-timeline: scroll(self x);
        /* Two mask layers: the animated fade covers the content area only,
           while a constant bottom strip keeps the wrap's own classic
           horizontal scrollbar (Linux/Windows) out of the fade — masking the
           scroller masks its scrollbar too, and a dissolving scrollbar end
           looks broken. Overlay-scrollbar platforms just get a 16px sliver
           of unfaded last-row edge, invisible in practice. */
        mask-repeat: no-repeat;
        mask-position: left top, left bottom;
        mask-size: 100% calc(100% - 16px), 100% 16px;
    }
    @keyframes app-scroll-hint {
        0%, 70% {
            mask-image:
                linear-gradient(to right,
                    #000 calc(100% - var(--space-8)), transparent 100%),
                linear-gradient(#000, #000);
        }
        /* Same gradient shape as the 0% frame (stops interpolate) so the
           fade ramps out smoothly instead of popping off. */
        100% {
            mask-image:
                linear-gradient(to right,
                    #000 calc(100% - 0px), transparent 100%),
                linear-gradient(#000, #000);
        }
    }
}
/* #189: row-action cluster in a table cell — wraps instead of forcing the
   whole table wide with white-space: nowrap. */
.app-cell-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    min-width: 16rem;
}

/* ---- nav list (home page) -------------------------------------------- */
.app-nav-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    list-style: none;
    padding: 0;
    margin: 0;
}
.app-nav-list li { margin: 0; }
.app-nav-list a {
    display: block;
    padding: var(--space-3);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-s);
    color: var(--color-text);
    text-decoration: none;
    font-size: var(--type-m);
}
.app-nav-list a:hover { background: var(--color-bg); }
.app-nav-list .app-nav-meta {
    color: var(--color-text-muted);
    font-size: var(--type-s);
    margin-left: var(--space-2);
}
/* Attention badges (nav item 11): errors / failures / offline. Muted amber,
   not alarm-red — the hub stays calm, the count carries the signal. */
.app-nav-list .app-nav-meta-warn { color: #8a5a00; }

/* ---- "Get set up" checklist (home, admin-only) ------------------------ */
.app-setup-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}
.app-setup-list li { display: flex; align-items: baseline; gap: var(--space-2); }
.app-setup-list .app-setup-mark { color: var(--color-text-muted); }
.app-setup-list li.done .app-setup-mark { color: #1a7f37; }
.app-setup-list li.done a {
    color: var(--color-text-muted);
    text-decoration: line-through;
}

/* Tight, bullet-less list for inline cell content (e.g. linked items). */
.app-list-tight {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

/* ---- badges ---------------------------------------------------------- */
.app-badge {
    display: inline-block;
    padding: 1px var(--space-2);
    border-radius: var(--radius-s);
    font-size: var(--type-s);
    font-weight: 600;
    line-height: 1.5;
}
/* #150: tinted (white-on-green failed AA at this size). */
.app-badge-current { background: #e9f7ec; color: #1a7f37; border: 1px solid #aed8b8; }
.app-badge-info    { background: #e3f0ff; color: #1364c4; }
.app-badge-muted {
    background: var(--color-bg);
    color: var(--color-text-muted);
    border: 1px solid var(--color-border);
}
/* Status badges for table cells. Same palette as the app-alert-* banners, but
   badge-sized and inline-block — an inline span with the alert classes' large
   padding paints its background outside the line box and overlaps adjacent
   table rows (the /admin/edges "clipped Revoked" glitch). Use these in cells;
   alerts are for block-level page messages only. */
.app-badge-success { background: #e9f7ec; color: #1a7f37; border: 1px solid #aed8b8; }
.app-badge-warn    { background: #fff4e0; color: #8a5a00; border: 1px solid #f0d08a; }
.app-badge-error   { background: #fdecea; color: #8a1f11; border: 1px solid #f5b3ab; }

/* ---- filter chips (/jobs state row) ---------------------------------- */
/* The machines-page m-chip look, but as plain GET links — no JS. */
.app-filter-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1);
}
.app-filter-chips .app-chip-label {
    color: var(--color-text-muted);
    font-size: var(--type-s);
    margin-right: var(--space-1);
}
a.app-filter-chip {
    display: inline-flex;
    align-items: center;
    padding: var(--space-1) var(--space-3);
    border-radius: 999px;
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    color: var(--color-text);
    text-decoration: none;
    font-size: var(--type-s);
}
a.app-filter-chip:hover { border-color: var(--color-text-muted); }
a.app-filter-chip.selected { font-weight: 600; background: var(--color-bg); }

/* ---- empty state ----------------------------------------------------- */
.app-muted { color: var(--color-text-muted); }
.app-empty {
    color: var(--color-text-muted);
    font-style: italic;
    padding: var(--space-4);
    text-align: center;
}

/* ---- mobile ---------------------------------------------------------- */
@media (max-width: 640px) {
    .app-header h1 { font-size: var(--type-l); }
    .app-main { padding: var(--space-3); }
    .app-card { padding: var(--space-3); }
}
