/* ==========================================================================
   TC-ATC PROJECT — UI polish layer
   Loaded after app.css; overrides presentation only, never structure.
   Palette: brand orange #ed6425 on a clean white surface.
   ========================================================================== */

/* Google Sans — SIL Open Font License 1.1 (see fonts/google-sans/OFL.txt).
   Variable wght 400–700, subset to Thai + Latin (~78 KB from a 5 MB source). */
@font-face {
    font-family: 'Google Sans';
    src: url('fonts/google-sans/GoogleSans-Variable.woff2?v=20261110') format('woff2-variations'),
         url('fonts/google-sans/GoogleSans-Variable.woff2?v=20261110') format('woff2');
    font-weight: 400 700;
    font-style: normal;
    font-display: swap;
}

/* Bruno Ace — SIL Open Font License 1.1 (see fonts/bruno-ace/OFL.txt).
   Display face for the Latin brand lockup and small system labels only.
   It has no Thai glyphs, so it never carries Thai text. */
@font-face {
    font-family: 'Bruno Ace';
    src: url('fonts/bruno-ace/BrunoAce-Regular.woff2?v=20261110') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0000-00FF, U+2013-2014, U+2018-201D, U+2022, U+2026, U+2192;
}

:root {
    --font-sans: 'Google Sans', 'Noto Sans Thai Looped', 'Noto Sans Thai', sans-serif;
    --font-display: 'Bruno Ace', 'Google Sans', sans-serif;
}

/* Apply site-wide: body first, then controls which do not inherit by default */
body,
button,
input,
select,
textarea,
.button {
    font-family: var(--font-sans);
}

:root {
    /* Clean white surfaces, neutral ink, brand orange accent.
       Surfaces stay white so the orange pattern reads behind them. */
    --ink: #1f242b;
    --ink-soft: #3b424c;
    --muted: #6d747f;
    --line: #e5e7ec;
    --line-strong: #d7dae1;
    --bg: #f6f7f9;
    --surface: #ffffff;
    --surface-sunken: #fafbfc;

    --orange: #ed6425;
    --orange-strong: #d85113;
    --orange-ink: #a8400f;
    --orange-wash: #fdf1e9;
    --orange-line: #f6d7c4;

    /* Elevation: warm-tinted shadows read as paper, not glass */
    --shadow-1: 0 1px 2px rgba(31, 36, 43, .05), 0 1px 1px rgba(31, 36, 43, .03);
    --shadow-2: 0 1px 3px rgba(31, 36, 43, .06), 0 6px 16px -6px rgba(31, 36, 43, .10);
    --shadow-3: 0 2px 6px rgba(31, 36, 43, .07), 0 14px 32px -12px rgba(31, 36, 43, .16);
    --shadow-focus: 0 0 0 3px rgba(237, 100, 37, .30);

    --radius-sm: 8px;
    --radius: 12px;
    --radius-lg: 16px;

    --ease: cubic-bezier(.2, .7, .3, 1);
    --fast: 140ms;
    --normal: 220ms;

    color-scheme: light;
}

/* ---------- Base rhythm ---------- */

body {
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    font-variant-numeric: proportional-nums;

    /* Site-wide graphic backdrop: orange geometric pattern over light grey.
       Pure CSS gradients, so no image request and no CSP exception is needed.
       Fixed, so it reads as one surface while the page scrolls. */
    background-color: #ffffff;
    background-image:
        /* diagonal orange hatch — the visible graphic signature */
        repeating-linear-gradient(
            135deg,
            rgba(237, 100, 37, .055) 0px,
            rgba(237, 100, 37, .055) 2px,
            rgba(237, 100, 37, 0) 2px,
            rgba(237, 100, 37, 0) 11px
        ),
        /* dot grid in neutral ink, sits under the hatch */
        radial-gradient(rgba(31, 36, 43, .07) 1px, transparent 1.4px),
        /* orange glow, top right */
        radial-gradient(64% 46% at 100% 0%, rgba(237, 100, 37, .20) 0%, rgba(237, 100, 37, 0) 66%),
        /* second orange wash, bottom left */
        radial-gradient(56% 50% at 0% 100%, rgba(237, 100, 37, .15) 0%, rgba(237, 100, 37, 0) 62%),
        /* neutral base so the middle stays quiet for reading */
        linear-gradient(180deg, #ffffff 0%, #f7f8fa 50%, #ffffff 100%);
    background-size: auto, 22px 22px, auto, auto, auto;
    background-attachment: fixed, fixed, fixed, fixed, fixed;
    background-repeat: repeat, repeat, no-repeat, no-repeat, no-repeat;
}

/* The sidebar and cards sit above the pattern; keep surfaces opaque so the
   texture only shows in the gutters. */
.card,
.chart-card,
details,
.chart-table {
    background-color: var(--surface);
}

/* The page heading sits directly on the texture — give the eyebrow a little
   more weight there so it doesn't get lost. */
.heading {
    position: relative;
}

@media (prefers-reduced-transparency: reduce) {
    body {
        background-image: linear-gradient(180deg, #ffffff 0%, #f7f8fa 100%);
    }
}

::selection {
    background: rgba(237, 100, 37, .22);
    color: var(--ink);
}

a {
    color: var(--orange-ink);
    text-underline-offset: 2px;
    text-decoration-thickness: 1px;
    transition: color var(--fast) var(--ease);
}

a:hover {
    color: var(--orange-strong);
}

:where(a, button, .button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline: 2px solid var(--orange);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

/* ---------- Sidebar: give the dark panel a material edge and an active voice ---------- */

aside {
    background: linear-gradient(180deg, #272c34 0%, #22262d 100%);
    box-shadow: inset -1px 0 0 rgba(255, 255, 255, .04), 1px 0 24px rgba(31, 36, 43, .10);
}

.wordmark {
    letter-spacing: -.6px;
    text-shadow: 0 1px 0 rgba(0, 0, 0, .18);
}

.wordmark span {
    color: #ff8a4c;
}

.department {
    border-bottom-color: rgba(255, 255, 255, .10);
}

.department img {
    box-shadow: 0 2px 10px rgba(0, 0, 0, .28);
}

nav a,
.navbutton {
    position: relative;
    border-radius: var(--radius-sm);
    transition: background var(--fast) var(--ease),
                color var(--fast) var(--ease),
                padding-left var(--fast) var(--ease);
}

nav a:hover,
.navbutton:hover {
    background: rgba(255, 255, 255, .07);
    color: #fff;
    padding-left: 15px;
}

nav a:hover::before,
.navbutton:hover::before {
    content: "";
    position: absolute;
    left: 0;
    top: 9px;
    bottom: 9px;
    width: 2px;
    border-radius: 2px;
    background: var(--orange);
}

.sidefoot {
    border-top: 1px solid rgba(255, 255, 255, .07);
    margin-top: auto;
}

/* ---------- Header: lift it off the page instead of sitting flush ---------- */

header {
    background: rgba(255, 255, 255, .92);
    backdrop-filter: saturate(140%) blur(6px);
    box-shadow: var(--shadow-1);
    border-bottom-color: var(--line);
    position: relative;
    z-index: 2;
}

.brand-text {
    letter-spacing: -.1px;
}

.brand .college-logo,
.brand .department-logo {
    filter: drop-shadow(0 1px 2px rgba(31, 36, 43, .10));
}

.account {
    color: var(--ink-soft);
    font-weight: 500;
}

.account small {
    font-weight: 400;
}

/* ---------- Page heading: tighten the eyebrow → title relationship ---------- */

.heading p {
    color: var(--orange-ink);
    letter-spacing: 2px;
}

.heading h1 {
    letter-spacing: -.5px;
    font-weight: 700;
    color: var(--ink);
}

.heading h1::after {
    content: "";
    display: block;
    /* Run almost the full content width, then fade out at the far end. */
    width: 100%;
    max-width: 100%;
    height: 3px;
    margin-top: 14px;
    border-radius: 3px;
    background: linear-gradient(90deg,
        var(--orange) 0%,
        #ef7b3e 12%,
        rgba(237, 100, 37, .45) 38%,
        rgba(237, 100, 37, .16) 68%,
        rgba(237, 100, 37, 0) 94%);
}

/* ---------- Cards: real elevation + a crisp hairline ---------- */

.card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow-2);
    transition: box-shadow var(--normal) var(--ease),
                border-color var(--normal) var(--ease);
}

.card > h2,
.card > h3 {
    letter-spacing: -.2px;
}

/* ---------- Hero: warm wash with a soft light source instead of a flat block ---------- */

.hero {
    background:
        radial-gradient(120% 140% at 100% 0%, #ffe6d5 0%, rgba(255, 230, 213, 0) 58%),
        linear-gradient(180deg, #fff6ef 0%, #fff1e6 100%);
    border: 1px solid var(--orange-line);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-2);
    position: relative;
    overflow: hidden;
}

.hero::after {
    content: "";
    position: absolute;
    right: -40px;
    top: -60px;
    width: 220px;
    height: 220px;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(237, 100, 37, .12), rgba(237, 100, 37, 0) 68%);
    pointer-events: none;
}

.hero h2 {
    letter-spacing: -.4px;
    color: var(--ink);
}

.hero p {
    color: #7d5a48;
}

.eyebrow {
    color: var(--orange-ink);
    letter-spacing: 2.2px;
}

/* ---------- Stats: every tile gets an accent, hover lifts, numbers align ---------- */

.stats {
    --stat-accent: var(--orange);
}

.stat {
    position: relative;
    background: var(--surface);
    border: 1px solid var(--line);
    border-top: 3px solid var(--stat-accent);
    border-radius: var(--radius);
    box-shadow: var(--shadow-1);
    overflow: hidden;
    transition: transform var(--normal) var(--ease),
                box-shadow var(--normal) var(--ease);
}

.stat::after {
    content: "";
    position: absolute;
    inset: auto -30% -60% auto;
    width: 150px;
    height: 150px;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(237, 100, 37, .10), rgba(237, 100, 37, 0) 70%);
    opacity: 0;
    transition: opacity var(--normal) var(--ease);
    pointer-events: none;
}

.stat:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-3);
}

.stat:hover::after {
    opacity: 1;
}

.stat b {
    font-variant-numeric: tabular-nums;
    letter-spacing: -1px;
    color: var(--ink);
}

.stat span {
    color: var(--muted);
    letter-spacing: .1px;
}

/* Alternate accents so a row of four tiles isn't monotone.
   Colour is decoration only — the label and number carry the meaning. */
.stat:nth-child(2) { --stat-accent: #2f8f5b; }
.stat:nth-child(3) { --stat-accent: #2f6ea5; }
.stat:nth-child(4) { --stat-accent: #b07a12; }

.stat:nth-child(2)::after { background: radial-gradient(circle, rgba(47, 143, 91, .10), rgba(47, 143, 91, 0) 70%); }
.stat:nth-child(3)::after { background: radial-gradient(circle, rgba(47, 110, 165, .10), rgba(47, 110, 165, 0) 70%); }
.stat:nth-child(4)::after { background: radial-gradient(circle, rgba(176, 122, 18, .10), rgba(176, 122, 18, 0) 70%); }

/* ---------- Buttons: pressable, not printed ---------- */

button,
.button {
    /* Brand orange as the fill, near-black text: #2b1608 on #ed6425 is
       4.9:1, so small action buttons stay legible without dulling the brand. */
    background: linear-gradient(180deg, #f57a41 0%, #ed6425 52%, #e25a1b 100%);
    color: #2b1608;
    text-shadow: 0 1px 0 rgba(255, 255, 255, .18);
    box-shadow: 0 1px 2px rgba(150, 60, 14, .28), 0 2px 10px -2px rgba(150, 60, 14, .22);
    transition: transform var(--fast) var(--ease),
                box-shadow var(--fast) var(--ease),
                background var(--fast) var(--ease);
    font-weight: 700;
    letter-spacing: .1px;
}

button:hover,
.button:hover {
    background: linear-gradient(180deg, #ff8549 0%, #f26a2b 52%, #e85f1e 100%);
    color: #241206;
    box-shadow: 0 2px 4px rgba(150, 60, 14, .30), 0 10px 20px -8px rgba(150, 60, 14, .38);
    text-decoration: none;
}

button:active,
.button:active {
    transform: translateY(1px);
    box-shadow: 0 1px 2px rgba(150, 60, 14, .30);
}

button.secondary,
.button.secondary {
    background: var(--surface);
    border: 1px solid var(--line-strong);
    box-shadow: var(--shadow-1);
    color: var(--ink);
}

button.secondary:hover,
.button.secondary:hover {
    background: #fff;
    border-color: #c9ced6;
    box-shadow: var(--shadow-2);
}

/* ---------- Inputs: focus reads as a state, not an outline ---------- */

input,
select,
textarea {
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-sm);
    background: var(--surface);
    transition: border-color var(--fast) var(--ease),
                box-shadow var(--fast) var(--ease),
                background var(--fast) var(--ease);
}

input:hover,
select:hover,
textarea:hover {
    border-color: #c3c9d2;
}

input:focus,
select:focus,
textarea:focus {
    outline: none;
    border-color: var(--orange);
    background: #fffdfb;
    box-shadow: var(--shadow-focus);
}

input::placeholder,
textarea::placeholder {
    color: #9aa0a9;
}

.field {
    color: var(--ink-soft);
}

/* ---------- Tabs: hover affordance + a stronger active marker ---------- */

.tabs {
    border-bottom-color: var(--line-strong);
    gap: 2px;
}

.tabs a {
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    transition: color var(--fast) var(--ease),
                background var(--fast) var(--ease);
}

.tabs a:hover {
    color: var(--ink);
    background: var(--surface-sunken);
    text-decoration: none;
}

.tabs a.active {
    color: var(--orange-ink);
    border-bottom-width: 3px;
    background: var(--orange-wash);
}

/* ---------- Badges: pill-er, with a hairline so pale fills still read ---------- */

.badge {
    border-radius: 999px;
    padding: 4px 11px;
    letter-spacing: .2px;
    border: 1px solid rgba(31, 36, 43, .06);
    /* The original #747982 on #f0f1f4 measured 3.87:1; darken to clear AA */
    background: #eef0f3;
    color: #5b616b;
}

.passed,
.issued {
    background: #e6f6ed;
    color: #1d6845;
    border-color: #c9e9d6;
}

.submitted,
.requested,
.correction {
    background: #fff1e3;
    color: #a24f0d;
    border-color: #f7dcc2;
}

.conditional {
    background: #fff6d8;
    color: #82620f;
    border-color: #f2e2ac;
}

.failed {
    background: #fdeceb;
    color: #a72f2f;
    border-color: #f6d2d0;
}

/* ---------- Notices: keep the accent bar, add calm surface ---------- */

.notice {
    background: var(--orange-wash);
    border-left-width: 3px;
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-1);
    color: var(--ink-soft);
}

.notice.error {
    background: #fdeeee;
    color: #8c2b2b;
}

/* ---------- Tables: scanning aid via hover + quieter rules ---------- */

table {
    font-variant-numeric: tabular-nums;
}

th {
    background: var(--surface-sunken);
    border-bottom: 1px solid var(--line-strong);
    letter-spacing: .2px;
    text-transform: none;
}

th,
td {
    border-bottom-color: var(--line);
}

tbody tr {
    transition: background var(--fast) var(--ease);
}

tbody tr:hover {
    background: #fbfbfd;
}

td a {
    color: var(--orange-ink);
}

/* ---------- Progress bars: rounded, with a soft inner track ---------- */

.summary-bar progress {
    height: 10px;
    background: #eceef2;
    box-shadow: inset 0 1px 2px rgba(31, 36, 43, .06);
}

progress::-webkit-progress-value {
    background: linear-gradient(90deg, var(--orange), #f89a63);
    border-radius: 9px;
}

progress::-moz-progress-bar {
    background: linear-gradient(90deg, var(--orange), #f89a63);
    border-radius: 9px;
}

.summary-bar strong {
    font-variant-numeric: tabular-nums;
    color: var(--ink);
}

/* ---------- Steps, details, misc surfaces ---------- */

.stepnum {
    background: var(--orange-wash);
    border: 1px solid var(--orange-line);
    color: var(--orange-ink);
    font-weight: 700;
}

details {
    border-color: var(--line);
    border-radius: var(--radius-sm);
    background: var(--surface);
    transition: box-shadow var(--normal) var(--ease);
}

details[open] {
    box-shadow: var(--shadow-1);
}

summary {
    font-weight: 600;
    color: var(--ink);
}

summary::marker {
    color: var(--orange);
}

.empty h3 {
    letter-spacing: -.2px;
}

.deadline {
    color: var(--orange-ink);
    font-weight: 600;
}

footer {
    /* 10px text at #9aa0a9 on the page background was 2.42:1 — bump to 4.6:1 */
    color: #6b7178;
    border-top-color: var(--line);
}

.login {
    box-shadow: var(--shadow-3);
    border-radius: var(--radius-lg);
}

.login h2 {
    letter-spacing: -.5px;
}

.login > .eyebrow {
    display: block;
    margin-bottom: 18px;
    line-height: 1.6;
}

section.card.login > h2 {
    display: flex;
    width: fit-content;
    margin-top: 0;
    margin-bottom: 16px;
    line-height: 1.5;
}

/* ---------- Motion: only where it clarifies, never for decoration overload ---------- */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
        scroll-behavior: auto !important;
    }

    .stat:hover {
        transform: none;
    }
}

/* ---------- Responsive: mirror app.css breakpoints for the properties changed here ---------- */

@media (max-width: 1100px) {
    .stat:first-child { border-top-width: 3px; }
}

@media (max-width: 720px) {
    aside {
        background: #24282f;
        box-shadow: 0 2px 12px rgba(31, 36, 43, .14);
    }

    nav a:hover,
    .navbutton:hover {
        padding-left: 12px;
    }

    nav a:hover::before,
    .navbutton:hover::before {
        left: 2px;
    }

    .heading h1::after {
        margin-top: 10px;
        width: 32px;
        height: 2px;
    }

    .hero::after {
        width: 150px;
        height: 150px;
        right: -30px;
        top: -40px;
    }
}
/* ==========================================================================
   Dashboard charts
   One hue for magnitude (brand orange), 2px surface gaps, 4px rounded
   data-ends, recessive tracks. Text always wears text tokens, never the
   series colour.
   ========================================================================== */

.chart-card {
    --chart-ink: var(--ink);
    --chart-muted: var(--muted);
    --chart-track: #eef0f4;
    --chart-series: #d2560f;
    --chart-series-2: #2f6ea5;
}

.chart-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 18px;
    margin-bottom: 20px;
}

.chart-head h2 {
    margin-bottom: 4px;
}

.chart-head p {
    margin: 0;
}

/* ---------- Ranked horizontal bars ---------- */

.chart-bars {
    display: grid;
    gap: 14px;
}

.chart-row {
    display: grid;
    grid-template-columns: minmax(96px, 168px) minmax(0, 1fr) auto;
    align-items: center;
    gap: 14px;
    border-radius: var(--radius-sm);
    padding: 3px 4px;
    transition: background var(--fast) var(--ease);
}

.chart-row:hover,
.chart-row:focus-visible {
    background: var(--surface-sunken);
}

.chart-row-label {
    font-size: 13px;
    color: var(--chart-ink);
    line-height: 1.4;
    overflow-wrap: anywhere;
}

.chart-row-track {
    position: relative;
    display: block;
    height: 14px;
    border-radius: 4px;
    background: var(--chart-track);
    overflow: hidden;
}

.chart-row-fill {
    position: absolute;
    inset: 0 auto 0 0;
    width: 0;
    min-width: 3px;
    border-radius: 4px;
    background: var(--chart-series);
    transition: width 420ms var(--ease);
}

/* Zero-length bars read as an empty track, not a stray dot */
.chart-row-fill.is-zero {
    min-width: 0;
}

.chart-row-value {
    font-size: 13px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--chart-ink);
    text-align: right;
    min-width: 42px;
}

.chart-row-value small {
    font-weight: 400;
    font-size: 11px;
    color: var(--chart-muted);
}

/* ---------- Tall segmented bar (one whole in parts) ---------- */

.segbar {
    display: flex;
    gap: 2px; /* the surface gap that separates parts — never a border */
    height: 28px;
    border-radius: 4px;
    overflow: hidden;
    background: var(--chart-track);
    margin-bottom: 16px;
}

.segbar-part {
    position: relative;
    display: flex;
    align-items: center;
    width: 0;
    min-width: 2px;
    transition: width 420ms var(--ease), filter var(--fast) var(--ease);
}

.segbar-part:hover {
    filter: brightness(1.06);
}

.segbar-part.seg-1 { background: var(--chart-series); }
.segbar-part.seg-2 { background: var(--chart-series-2); }

.segbar-text {
    padding-left: 10px;
    font-size: 11px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: #fff;
    text-shadow: 0 1px 1px rgba(0, 0, 0, .18);
}

.segbar-legend {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 8px 22px;
    margin: 0;
    padding: 0;
    font-size: 13px;
    color: var(--chart-ink);
}

.segbar-legend li {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.legend-swatch {
    width: 11px;
    height: 11px;
    border-radius: 3px;
    flex: 0 0 auto;
}

.legend-swatch.seg-1 { background: var(--chart-series); }
.legend-swatch.seg-2 { background: var(--chart-series-2); }

/* ---------- Empty state: intentional, not a blank hole ---------- */

.chart-empty {
    border: 1px dashed var(--line-strong);
    border-radius: var(--radius-sm);
    padding: 26px 20px;
    margin: 0;
    text-align: center;
    font-size: 13px;
    color: var(--chart-muted);
    background: var(--surface-sunken);
}

/* ---------- Table view ---------- */

.chart-table {
    margin-bottom: 22px;
    background: var(--surface);
}

.chart-table table {
    font-size: 13px;
}

.chart-table caption {
    text-align: left;
    padding-bottom: 10px;
}

/* ---------- Tooltip (progressive enhancement, see assets/charts.js) ---------- */

.chart-tip {
    position: fixed;
    z-index: 30;
    pointer-events: none;
    padding: 7px 11px;
    border-radius: 8px;
    background: #1f242b;
    color: #fff;
    font-size: 12px;
    line-height: 1.45;
    box-shadow: var(--shadow-3);
    opacity: 0;
    transform: translateY(3px);
    transition: opacity 120ms var(--ease), transform 120ms var(--ease);
    max-width: 240px;
}

.chart-tip[data-open="1"] {
    opacity: 1;
    transform: translateY(0);
}

.chart-tip strong {
    font-variant-numeric: tabular-nums;
}

@media (max-width: 720px) {
    .chart-row {
        grid-template-columns: minmax(84px, 120px) minmax(0, 1fr) auto;
        gap: 10px;
    }

    .chart-row-label {
        font-size: 12px;
    }

    .segbar {
        height: 24px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .chart-row-fill,
    .segbar-part {
        transition: none;
    }
}

/* ---------- Bar widths, quantised to 1% so no inline style is needed
   (the page CSP sets style-src 'self' and blocks style attributes) ---------- */
.chart-row-fill.w0, .segbar-part.w0 { width: 0%; }
.chart-row-fill.w1, .segbar-part.w1 { width: 1%; }
.chart-row-fill.w2, .segbar-part.w2 { width: 2%; }
.chart-row-fill.w3, .segbar-part.w3 { width: 3%; }
.chart-row-fill.w4, .segbar-part.w4 { width: 4%; }
.chart-row-fill.w5, .segbar-part.w5 { width: 5%; }
.chart-row-fill.w6, .segbar-part.w6 { width: 6%; }
.chart-row-fill.w7, .segbar-part.w7 { width: 7%; }
.chart-row-fill.w8, .segbar-part.w8 { width: 8%; }
.chart-row-fill.w9, .segbar-part.w9 { width: 9%; }
.chart-row-fill.w10, .segbar-part.w10 { width: 10%; }
.chart-row-fill.w11, .segbar-part.w11 { width: 11%; }
.chart-row-fill.w12, .segbar-part.w12 { width: 12%; }
.chart-row-fill.w13, .segbar-part.w13 { width: 13%; }
.chart-row-fill.w14, .segbar-part.w14 { width: 14%; }
.chart-row-fill.w15, .segbar-part.w15 { width: 15%; }
.chart-row-fill.w16, .segbar-part.w16 { width: 16%; }
.chart-row-fill.w17, .segbar-part.w17 { width: 17%; }
.chart-row-fill.w18, .segbar-part.w18 { width: 18%; }
.chart-row-fill.w19, .segbar-part.w19 { width: 19%; }
.chart-row-fill.w20, .segbar-part.w20 { width: 20%; }
.chart-row-fill.w21, .segbar-part.w21 { width: 21%; }
.chart-row-fill.w22, .segbar-part.w22 { width: 22%; }
.chart-row-fill.w23, .segbar-part.w23 { width: 23%; }
.chart-row-fill.w24, .segbar-part.w24 { width: 24%; }
.chart-row-fill.w25, .segbar-part.w25 { width: 25%; }
.chart-row-fill.w26, .segbar-part.w26 { width: 26%; }
.chart-row-fill.w27, .segbar-part.w27 { width: 27%; }
.chart-row-fill.w28, .segbar-part.w28 { width: 28%; }
.chart-row-fill.w29, .segbar-part.w29 { width: 29%; }
.chart-row-fill.w30, .segbar-part.w30 { width: 30%; }
.chart-row-fill.w31, .segbar-part.w31 { width: 31%; }
.chart-row-fill.w32, .segbar-part.w32 { width: 32%; }
.chart-row-fill.w33, .segbar-part.w33 { width: 33%; }
.chart-row-fill.w34, .segbar-part.w34 { width: 34%; }
.chart-row-fill.w35, .segbar-part.w35 { width: 35%; }
.chart-row-fill.w36, .segbar-part.w36 { width: 36%; }
.chart-row-fill.w37, .segbar-part.w37 { width: 37%; }
.chart-row-fill.w38, .segbar-part.w38 { width: 38%; }
.chart-row-fill.w39, .segbar-part.w39 { width: 39%; }
.chart-row-fill.w40, .segbar-part.w40 { width: 40%; }
.chart-row-fill.w41, .segbar-part.w41 { width: 41%; }
.chart-row-fill.w42, .segbar-part.w42 { width: 42%; }
.chart-row-fill.w43, .segbar-part.w43 { width: 43%; }
.chart-row-fill.w44, .segbar-part.w44 { width: 44%; }
.chart-row-fill.w45, .segbar-part.w45 { width: 45%; }
.chart-row-fill.w46, .segbar-part.w46 { width: 46%; }
.chart-row-fill.w47, .segbar-part.w47 { width: 47%; }
.chart-row-fill.w48, .segbar-part.w48 { width: 48%; }
.chart-row-fill.w49, .segbar-part.w49 { width: 49%; }
.chart-row-fill.w50, .segbar-part.w50 { width: 50%; }
.chart-row-fill.w51, .segbar-part.w51 { width: 51%; }
.chart-row-fill.w52, .segbar-part.w52 { width: 52%; }
.chart-row-fill.w53, .segbar-part.w53 { width: 53%; }
.chart-row-fill.w54, .segbar-part.w54 { width: 54%; }
.chart-row-fill.w55, .segbar-part.w55 { width: 55%; }
.chart-row-fill.w56, .segbar-part.w56 { width: 56%; }
.chart-row-fill.w57, .segbar-part.w57 { width: 57%; }
.chart-row-fill.w58, .segbar-part.w58 { width: 58%; }
.chart-row-fill.w59, .segbar-part.w59 { width: 59%; }
.chart-row-fill.w60, .segbar-part.w60 { width: 60%; }
.chart-row-fill.w61, .segbar-part.w61 { width: 61%; }
.chart-row-fill.w62, .segbar-part.w62 { width: 62%; }
.chart-row-fill.w63, .segbar-part.w63 { width: 63%; }
.chart-row-fill.w64, .segbar-part.w64 { width: 64%; }
.chart-row-fill.w65, .segbar-part.w65 { width: 65%; }
.chart-row-fill.w66, .segbar-part.w66 { width: 66%; }
.chart-row-fill.w67, .segbar-part.w67 { width: 67%; }
.chart-row-fill.w68, .segbar-part.w68 { width: 68%; }
.chart-row-fill.w69, .segbar-part.w69 { width: 69%; }
.chart-row-fill.w70, .segbar-part.w70 { width: 70%; }
.chart-row-fill.w71, .segbar-part.w71 { width: 71%; }
.chart-row-fill.w72, .segbar-part.w72 { width: 72%; }
.chart-row-fill.w73, .segbar-part.w73 { width: 73%; }
.chart-row-fill.w74, .segbar-part.w74 { width: 74%; }
.chart-row-fill.w75, .segbar-part.w75 { width: 75%; }
.chart-row-fill.w76, .segbar-part.w76 { width: 76%; }
.chart-row-fill.w77, .segbar-part.w77 { width: 77%; }
.chart-row-fill.w78, .segbar-part.w78 { width: 78%; }
.chart-row-fill.w79, .segbar-part.w79 { width: 79%; }
.chart-row-fill.w80, .segbar-part.w80 { width: 80%; }
.chart-row-fill.w81, .segbar-part.w81 { width: 81%; }
.chart-row-fill.w82, .segbar-part.w82 { width: 82%; }
.chart-row-fill.w83, .segbar-part.w83 { width: 83%; }
.chart-row-fill.w84, .segbar-part.w84 { width: 84%; }
.chart-row-fill.w85, .segbar-part.w85 { width: 85%; }
.chart-row-fill.w86, .segbar-part.w86 { width: 86%; }
.chart-row-fill.w87, .segbar-part.w87 { width: 87%; }
.chart-row-fill.w88, .segbar-part.w88 { width: 88%; }
.chart-row-fill.w89, .segbar-part.w89 { width: 89%; }
.chart-row-fill.w90, .segbar-part.w90 { width: 90%; }
.chart-row-fill.w91, .segbar-part.w91 { width: 91%; }
.chart-row-fill.w92, .segbar-part.w92 { width: 92%; }
.chart-row-fill.w93, .segbar-part.w93 { width: 93%; }
.chart-row-fill.w94, .segbar-part.w94 { width: 94%; }
.chart-row-fill.w95, .segbar-part.w95 { width: 95%; }
.chart-row-fill.w96, .segbar-part.w96 { width: 96%; }
.chart-row-fill.w97, .segbar-part.w97 { width: 97%; }
.chart-row-fill.w98, .segbar-part.w98 { width: 98%; }
.chart-row-fill.w99, .segbar-part.w99 { width: 99%; }
.chart-row-fill.w100, .segbar-part.w100 { width: 100%; }

/* ==========================================================================
   Bento layout for the dashboard analytics
   Lead card spans two columns and carries the headline number; the rest
   fill the grid. Collapses to one column below 1100px.
   ========================================================================== */

.bento {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 18px;
    margin-bottom: 22px;
}

.bento > .chart-card {
    margin-bottom: 0;
    display: flex;
    flex-direction: column;
}

.bento-lead {
    grid-column: span 2;
}

/* ---------- Lead figure: the number the page leads with ---------- */

.lead-figure {
    display: flex;
    align-items: baseline;
    gap: 16px;
    flex-wrap: wrap;
    margin: 4px 0 22px;
}

.lead-number {
    font-size: 56px;
    line-height: 1;
    font-weight: 700;
    letter-spacing: -2px;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
}

.lead-unit {
    font-size: 22px;
    font-weight: 500;
    letter-spacing: -.4px;
    color: var(--muted);
}

.lead-caption {
    margin: 0;
    font-size: 13px;
    color: var(--muted);
    max-width: 34ch;
}

.lead-caption strong {
    color: var(--ink);
}

/* Proportional strip: draft / in progress / done, 2px surface gaps */
.lead-meter {
    display: flex;
    gap: 2px;
    height: 12px;
    border-radius: 4px;
    overflow: hidden;
    background: var(--chart-track);
    margin-bottom: 16px;
}

.lead-meter-part {
    display: block;
    min-width: 2px;
    transition: width 420ms var(--ease), filter var(--fast) var(--ease);
}

/* The width comes from the shared .w0-.w100 classes; those rules are declared
   above this block, so restate them here at higher specificity. */
.bento .lead-meter-part.w0 { width: 0%; }

.lead-meter-part.is-zero { min-width: 0; }

.lm-draft { background: #c9ccd4; }
.lm-active { background: var(--orange); }
.lm-conditional { background: #e8a13a; }
.lm-done { background: #2f8f5b; }
.lm-failed { background: #c75b54; }

.lead-legend {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 8px 20px;
    margin: 0;
    padding: 0;
    font-size: 12px;
    color: var(--ink-soft);
}

.lead-legend li {
    display: inline-flex;
    align-items: center;
    gap: 7px;
}

.lead-legend strong {
    font-variant-numeric: tabular-nums;
    color: var(--ink);
}

.lead-note {
    margin: 12px 0 0;
    font-size: 12px;
    color: var(--orange-ink);
}

/* ---------- Donut (pure CSS, conic-gradient via width classes) ---------- */

.donut-wrap {
    display: flex;
    align-items: center;
    gap: 22px;
    flex-wrap: wrap;
    margin-top: 4px;
}

.chart-card[aria-labelledby="chart-level-title"] {
    --chart-series: var(--orange);
    --chart-series-2: #2f8f5b;
}

.donut {
    position: relative;
    width: 118px;
    height: 118px;
    flex: 0 0 auto;
}

.donut-ring {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: conic-gradient(var(--chart-series) 0 50%, var(--chart-series-2) 50% 100%);
    -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 14px), #000 calc(100% - 13px));
    mask: radial-gradient(farthest-side, transparent calc(100% - 14px), #000 calc(100% - 13px));
}

/* Share of the first slice drives the split point; see .donut-a## classes */
.donut-hole {
    position: absolute;
    inset: 0;
    display: grid;
    place-content: center;
    text-align: center;
    line-height: 1.1;
}

.donut-hole span {
    font-size: 24px;
    font-weight: 700;
    letter-spacing: -.6px;
    font-variant-numeric: tabular-nums;
}

.donut-hole small {
    display: block;
    font-size: 10px;
    color: var(--muted);
    letter-spacing: .2px;
}

.donut-legend {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 10px;
    font-size: 13px;
    min-width: 0;
    flex: 1 1 140px;
}

.donut-legend li {
    display: grid;
    grid-template-columns: auto 1fr auto auto;
    align-items: center;
    gap: 8px;
}

.donut-legend-name {
    overflow-wrap: anywhere;
}

.donut-legend strong {
    font-variant-numeric: tabular-nums;
    color: var(--ink);
}

/* ---------- Chapter steps ---------- */

.chapter-steps {
    display: grid;
    gap: 2px;
}

.chapter-step {
    display: grid;
    grid-template-columns: 26px 1fr auto;
    align-items: center;
    gap: 12px;
    padding: 8px 4px;
    border-radius: var(--radius-sm);
    transition: background var(--fast) var(--ease);
}

.chapter-step:hover,
.chapter-step:focus-visible {
    background: var(--surface-sunken);
}

.chapter-dot {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    font-size: 11px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    background: var(--orange-wash);
    color: var(--orange-ink);
    border: 1px solid var(--orange-line);
}

.chapter-dot.is-empty {
    background: #f2f3f6;
    color: #9aa0a9;
    border-color: var(--line);
}

.chapter-label {
    font-size: 13px;
    color: var(--ink);
}

.chapter-count {
    font-size: 13px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--ink);
}

.chapter-count small {
    font-weight: 400;
    font-size: 11px;
    color: var(--muted);
}

/* ---------- Empty state glyph ---------- */

.chart-empty {
    display: grid;
    place-items: center;
    gap: 10px;
    text-align: center;
}

.chart-empty p {
    margin: 0;
    max-width: 32ch;
}

.empty-glyph {
    width: 34px;
    height: 34px;
    border-radius: 10px;
    border: 1.5px dashed var(--line-strong);
    display: block;
}

/* ---------- Responsive ---------- */

@media (max-width: 1100px) {
    .bento {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .bento-lead {
        grid-column: span 2;
    }

    .lead-number {
        font-size: 46px;
    }
}

@media (max-width: 720px) {
    .bento {
        grid-template-columns: 1fr;
        gap: 14px;
    }

    .bento-lead {
        grid-column: span 1;
    }

    .lead-number {
        font-size: 40px;
        letter-spacing: -1.4px;
    }

    .donut {
        width: 96px;
        height: 96px;
    }

    .donut-hole span {
        font-size: 20px;
    }
}

/* Donut split points (CSP blocks inline style, so the angle is a class) */
.donut-ring.donut-a0 { background: conic-gradient(var(--chart-series) 0 0%, var(--chart-series-2) 0% 100%); }
.donut-ring.donut-a1 { background: conic-gradient(var(--chart-series) 0 1%, var(--chart-series-2) 1% 100%); }
.donut-ring.donut-a2 { background: conic-gradient(var(--chart-series) 0 2%, var(--chart-series-2) 2% 100%); }
.donut-ring.donut-a3 { background: conic-gradient(var(--chart-series) 0 3%, var(--chart-series-2) 3% 100%); }
.donut-ring.donut-a4 { background: conic-gradient(var(--chart-series) 0 4%, var(--chart-series-2) 4% 100%); }
.donut-ring.donut-a5 { background: conic-gradient(var(--chart-series) 0 5%, var(--chart-series-2) 5% 100%); }
.donut-ring.donut-a6 { background: conic-gradient(var(--chart-series) 0 6%, var(--chart-series-2) 6% 100%); }
.donut-ring.donut-a7 { background: conic-gradient(var(--chart-series) 0 7%, var(--chart-series-2) 7% 100%); }
.donut-ring.donut-a8 { background: conic-gradient(var(--chart-series) 0 8%, var(--chart-series-2) 8% 100%); }
.donut-ring.donut-a9 { background: conic-gradient(var(--chart-series) 0 9%, var(--chart-series-2) 9% 100%); }
.donut-ring.donut-a10 { background: conic-gradient(var(--chart-series) 0 10%, var(--chart-series-2) 10% 100%); }
.donut-ring.donut-a11 { background: conic-gradient(var(--chart-series) 0 11%, var(--chart-series-2) 11% 100%); }
.donut-ring.donut-a12 { background: conic-gradient(var(--chart-series) 0 12%, var(--chart-series-2) 12% 100%); }
.donut-ring.donut-a13 { background: conic-gradient(var(--chart-series) 0 13%, var(--chart-series-2) 13% 100%); }
.donut-ring.donut-a14 { background: conic-gradient(var(--chart-series) 0 14%, var(--chart-series-2) 14% 100%); }
.donut-ring.donut-a15 { background: conic-gradient(var(--chart-series) 0 15%, var(--chart-series-2) 15% 100%); }
.donut-ring.donut-a16 { background: conic-gradient(var(--chart-series) 0 16%, var(--chart-series-2) 16% 100%); }
.donut-ring.donut-a17 { background: conic-gradient(var(--chart-series) 0 17%, var(--chart-series-2) 17% 100%); }
.donut-ring.donut-a18 { background: conic-gradient(var(--chart-series) 0 18%, var(--chart-series-2) 18% 100%); }
.donut-ring.donut-a19 { background: conic-gradient(var(--chart-series) 0 19%, var(--chart-series-2) 19% 100%); }
.donut-ring.donut-a20 { background: conic-gradient(var(--chart-series) 0 20%, var(--chart-series-2) 20% 100%); }
.donut-ring.donut-a21 { background: conic-gradient(var(--chart-series) 0 21%, var(--chart-series-2) 21% 100%); }
.donut-ring.donut-a22 { background: conic-gradient(var(--chart-series) 0 22%, var(--chart-series-2) 22% 100%); }
.donut-ring.donut-a23 { background: conic-gradient(var(--chart-series) 0 23%, var(--chart-series-2) 23% 100%); }
.donut-ring.donut-a24 { background: conic-gradient(var(--chart-series) 0 24%, var(--chart-series-2) 24% 100%); }
.donut-ring.donut-a25 { background: conic-gradient(var(--chart-series) 0 25%, var(--chart-series-2) 25% 100%); }
.donut-ring.donut-a26 { background: conic-gradient(var(--chart-series) 0 26%, var(--chart-series-2) 26% 100%); }
.donut-ring.donut-a27 { background: conic-gradient(var(--chart-series) 0 27%, var(--chart-series-2) 27% 100%); }
.donut-ring.donut-a28 { background: conic-gradient(var(--chart-series) 0 28%, var(--chart-series-2) 28% 100%); }
.donut-ring.donut-a29 { background: conic-gradient(var(--chart-series) 0 29%, var(--chart-series-2) 29% 100%); }
.donut-ring.donut-a30 { background: conic-gradient(var(--chart-series) 0 30%, var(--chart-series-2) 30% 100%); }
.donut-ring.donut-a31 { background: conic-gradient(var(--chart-series) 0 31%, var(--chart-series-2) 31% 100%); }
.donut-ring.donut-a32 { background: conic-gradient(var(--chart-series) 0 32%, var(--chart-series-2) 32% 100%); }
.donut-ring.donut-a33 { background: conic-gradient(var(--chart-series) 0 33%, var(--chart-series-2) 33% 100%); }
.donut-ring.donut-a34 { background: conic-gradient(var(--chart-series) 0 34%, var(--chart-series-2) 34% 100%); }
.donut-ring.donut-a35 { background: conic-gradient(var(--chart-series) 0 35%, var(--chart-series-2) 35% 100%); }
.donut-ring.donut-a36 { background: conic-gradient(var(--chart-series) 0 36%, var(--chart-series-2) 36% 100%); }
.donut-ring.donut-a37 { background: conic-gradient(var(--chart-series) 0 37%, var(--chart-series-2) 37% 100%); }
.donut-ring.donut-a38 { background: conic-gradient(var(--chart-series) 0 38%, var(--chart-series-2) 38% 100%); }
.donut-ring.donut-a39 { background: conic-gradient(var(--chart-series) 0 39%, var(--chart-series-2) 39% 100%); }
.donut-ring.donut-a40 { background: conic-gradient(var(--chart-series) 0 40%, var(--chart-series-2) 40% 100%); }
.donut-ring.donut-a41 { background: conic-gradient(var(--chart-series) 0 41%, var(--chart-series-2) 41% 100%); }
.donut-ring.donut-a42 { background: conic-gradient(var(--chart-series) 0 42%, var(--chart-series-2) 42% 100%); }
.donut-ring.donut-a43 { background: conic-gradient(var(--chart-series) 0 43%, var(--chart-series-2) 43% 100%); }
.donut-ring.donut-a44 { background: conic-gradient(var(--chart-series) 0 44%, var(--chart-series-2) 44% 100%); }
.donut-ring.donut-a45 { background: conic-gradient(var(--chart-series) 0 45%, var(--chart-series-2) 45% 100%); }
.donut-ring.donut-a46 { background: conic-gradient(var(--chart-series) 0 46%, var(--chart-series-2) 46% 100%); }
.donut-ring.donut-a47 { background: conic-gradient(var(--chart-series) 0 47%, var(--chart-series-2) 47% 100%); }
.donut-ring.donut-a48 { background: conic-gradient(var(--chart-series) 0 48%, var(--chart-series-2) 48% 100%); }
.donut-ring.donut-a49 { background: conic-gradient(var(--chart-series) 0 49%, var(--chart-series-2) 49% 100%); }
.donut-ring.donut-a50 { background: conic-gradient(var(--chart-series) 0 50%, var(--chart-series-2) 50% 100%); }
.donut-ring.donut-a51 { background: conic-gradient(var(--chart-series) 0 51%, var(--chart-series-2) 51% 100%); }
.donut-ring.donut-a52 { background: conic-gradient(var(--chart-series) 0 52%, var(--chart-series-2) 52% 100%); }
.donut-ring.donut-a53 { background: conic-gradient(var(--chart-series) 0 53%, var(--chart-series-2) 53% 100%); }
.donut-ring.donut-a54 { background: conic-gradient(var(--chart-series) 0 54%, var(--chart-series-2) 54% 100%); }
.donut-ring.donut-a55 { background: conic-gradient(var(--chart-series) 0 55%, var(--chart-series-2) 55% 100%); }
.donut-ring.donut-a56 { background: conic-gradient(var(--chart-series) 0 56%, var(--chart-series-2) 56% 100%); }
.donut-ring.donut-a57 { background: conic-gradient(var(--chart-series) 0 57%, var(--chart-series-2) 57% 100%); }
.donut-ring.donut-a58 { background: conic-gradient(var(--chart-series) 0 58%, var(--chart-series-2) 58% 100%); }
.donut-ring.donut-a59 { background: conic-gradient(var(--chart-series) 0 59%, var(--chart-series-2) 59% 100%); }
.donut-ring.donut-a60 { background: conic-gradient(var(--chart-series) 0 60%, var(--chart-series-2) 60% 100%); }
.donut-ring.donut-a61 { background: conic-gradient(var(--chart-series) 0 61%, var(--chart-series-2) 61% 100%); }
.donut-ring.donut-a62 { background: conic-gradient(var(--chart-series) 0 62%, var(--chart-series-2) 62% 100%); }
.donut-ring.donut-a63 { background: conic-gradient(var(--chart-series) 0 63%, var(--chart-series-2) 63% 100%); }
.donut-ring.donut-a64 { background: conic-gradient(var(--chart-series) 0 64%, var(--chart-series-2) 64% 100%); }
.donut-ring.donut-a65 { background: conic-gradient(var(--chart-series) 0 65%, var(--chart-series-2) 65% 100%); }
.donut-ring.donut-a66 { background: conic-gradient(var(--chart-series) 0 66%, var(--chart-series-2) 66% 100%); }
.donut-ring.donut-a67 { background: conic-gradient(var(--chart-series) 0 67%, var(--chart-series-2) 67% 100%); }
.donut-ring.donut-a68 { background: conic-gradient(var(--chart-series) 0 68%, var(--chart-series-2) 68% 100%); }
.donut-ring.donut-a69 { background: conic-gradient(var(--chart-series) 0 69%, var(--chart-series-2) 69% 100%); }
.donut-ring.donut-a70 { background: conic-gradient(var(--chart-series) 0 70%, var(--chart-series-2) 70% 100%); }
.donut-ring.donut-a71 { background: conic-gradient(var(--chart-series) 0 71%, var(--chart-series-2) 71% 100%); }
.donut-ring.donut-a72 { background: conic-gradient(var(--chart-series) 0 72%, var(--chart-series-2) 72% 100%); }
.donut-ring.donut-a73 { background: conic-gradient(var(--chart-series) 0 73%, var(--chart-series-2) 73% 100%); }
.donut-ring.donut-a74 { background: conic-gradient(var(--chart-series) 0 74%, var(--chart-series-2) 74% 100%); }
.donut-ring.donut-a75 { background: conic-gradient(var(--chart-series) 0 75%, var(--chart-series-2) 75% 100%); }
.donut-ring.donut-a76 { background: conic-gradient(var(--chart-series) 0 76%, var(--chart-series-2) 76% 100%); }
.donut-ring.donut-a77 { background: conic-gradient(var(--chart-series) 0 77%, var(--chart-series-2) 77% 100%); }
.donut-ring.donut-a78 { background: conic-gradient(var(--chart-series) 0 78%, var(--chart-series-2) 78% 100%); }
.donut-ring.donut-a79 { background: conic-gradient(var(--chart-series) 0 79%, var(--chart-series-2) 79% 100%); }
.donut-ring.donut-a80 { background: conic-gradient(var(--chart-series) 0 80%, var(--chart-series-2) 80% 100%); }
.donut-ring.donut-a81 { background: conic-gradient(var(--chart-series) 0 81%, var(--chart-series-2) 81% 100%); }
.donut-ring.donut-a82 { background: conic-gradient(var(--chart-series) 0 82%, var(--chart-series-2) 82% 100%); }
.donut-ring.donut-a83 { background: conic-gradient(var(--chart-series) 0 83%, var(--chart-series-2) 83% 100%); }
.donut-ring.donut-a84 { background: conic-gradient(var(--chart-series) 0 84%, var(--chart-series-2) 84% 100%); }
.donut-ring.donut-a85 { background: conic-gradient(var(--chart-series) 0 85%, var(--chart-series-2) 85% 100%); }
.donut-ring.donut-a86 { background: conic-gradient(var(--chart-series) 0 86%, var(--chart-series-2) 86% 100%); }
.donut-ring.donut-a87 { background: conic-gradient(var(--chart-series) 0 87%, var(--chart-series-2) 87% 100%); }
.donut-ring.donut-a88 { background: conic-gradient(var(--chart-series) 0 88%, var(--chart-series-2) 88% 100%); }
.donut-ring.donut-a89 { background: conic-gradient(var(--chart-series) 0 89%, var(--chart-series-2) 89% 100%); }
.donut-ring.donut-a90 { background: conic-gradient(var(--chart-series) 0 90%, var(--chart-series-2) 90% 100%); }
.donut-ring.donut-a91 { background: conic-gradient(var(--chart-series) 0 91%, var(--chart-series-2) 91% 100%); }
.donut-ring.donut-a92 { background: conic-gradient(var(--chart-series) 0 92%, var(--chart-series-2) 92% 100%); }
.donut-ring.donut-a93 { background: conic-gradient(var(--chart-series) 0 93%, var(--chart-series-2) 93% 100%); }
.donut-ring.donut-a94 { background: conic-gradient(var(--chart-series) 0 94%, var(--chart-series-2) 94% 100%); }
.donut-ring.donut-a95 { background: conic-gradient(var(--chart-series) 0 95%, var(--chart-series-2) 95% 100%); }
.donut-ring.donut-a96 { background: conic-gradient(var(--chart-series) 0 96%, var(--chart-series-2) 96% 100%); }
.donut-ring.donut-a97 { background: conic-gradient(var(--chart-series) 0 97%, var(--chart-series-2) 97% 100%); }
.donut-ring.donut-a98 { background: conic-gradient(var(--chart-series) 0 98%, var(--chart-series-2) 98% 100%); }
.donut-ring.donut-a99 { background: conic-gradient(var(--chart-series) 0 99%, var(--chart-series-2) 99% 100%); }
.donut-ring.donut-a100 { background: conic-gradient(var(--chart-series) 0 100%, var(--chart-series-2) 100% 100%); }

/* Width classes for the lead meter, declared last so they win over the base rule */
.bento .lead-meter-part.w0 { width: 0%; }
.bento .lead-meter-part.w1 { width: 1%; }
.bento .lead-meter-part.w2 { width: 2%; }
.bento .lead-meter-part.w3 { width: 3%; }
.bento .lead-meter-part.w4 { width: 4%; }
.bento .lead-meter-part.w5 { width: 5%; }
.bento .lead-meter-part.w6 { width: 6%; }
.bento .lead-meter-part.w7 { width: 7%; }
.bento .lead-meter-part.w8 { width: 8%; }
.bento .lead-meter-part.w9 { width: 9%; }
.bento .lead-meter-part.w10 { width: 10%; }
.bento .lead-meter-part.w11 { width: 11%; }
.bento .lead-meter-part.w12 { width: 12%; }
.bento .lead-meter-part.w13 { width: 13%; }
.bento .lead-meter-part.w14 { width: 14%; }
.bento .lead-meter-part.w15 { width: 15%; }
.bento .lead-meter-part.w16 { width: 16%; }
.bento .lead-meter-part.w17 { width: 17%; }
.bento .lead-meter-part.w18 { width: 18%; }
.bento .lead-meter-part.w19 { width: 19%; }
.bento .lead-meter-part.w20 { width: 20%; }
.bento .lead-meter-part.w21 { width: 21%; }
.bento .lead-meter-part.w22 { width: 22%; }
.bento .lead-meter-part.w23 { width: 23%; }
.bento .lead-meter-part.w24 { width: 24%; }
.bento .lead-meter-part.w25 { width: 25%; }
.bento .lead-meter-part.w26 { width: 26%; }
.bento .lead-meter-part.w27 { width: 27%; }
.bento .lead-meter-part.w28 { width: 28%; }
.bento .lead-meter-part.w29 { width: 29%; }
.bento .lead-meter-part.w30 { width: 30%; }
.bento .lead-meter-part.w31 { width: 31%; }
.bento .lead-meter-part.w32 { width: 32%; }
.bento .lead-meter-part.w33 { width: 33%; }
.bento .lead-meter-part.w34 { width: 34%; }
.bento .lead-meter-part.w35 { width: 35%; }
.bento .lead-meter-part.w36 { width: 36%; }
.bento .lead-meter-part.w37 { width: 37%; }
.bento .lead-meter-part.w38 { width: 38%; }
.bento .lead-meter-part.w39 { width: 39%; }
.bento .lead-meter-part.w40 { width: 40%; }
.bento .lead-meter-part.w41 { width: 41%; }
.bento .lead-meter-part.w42 { width: 42%; }
.bento .lead-meter-part.w43 { width: 43%; }
.bento .lead-meter-part.w44 { width: 44%; }
.bento .lead-meter-part.w45 { width: 45%; }
.bento .lead-meter-part.w46 { width: 46%; }
.bento .lead-meter-part.w47 { width: 47%; }
.bento .lead-meter-part.w48 { width: 48%; }
.bento .lead-meter-part.w49 { width: 49%; }
.bento .lead-meter-part.w50 { width: 50%; }
.bento .lead-meter-part.w51 { width: 51%; }
.bento .lead-meter-part.w52 { width: 52%; }
.bento .lead-meter-part.w53 { width: 53%; }
.bento .lead-meter-part.w54 { width: 54%; }
.bento .lead-meter-part.w55 { width: 55%; }
.bento .lead-meter-part.w56 { width: 56%; }
.bento .lead-meter-part.w57 { width: 57%; }
.bento .lead-meter-part.w58 { width: 58%; }
.bento .lead-meter-part.w59 { width: 59%; }
.bento .lead-meter-part.w60 { width: 60%; }
.bento .lead-meter-part.w61 { width: 61%; }
.bento .lead-meter-part.w62 { width: 62%; }
.bento .lead-meter-part.w63 { width: 63%; }
.bento .lead-meter-part.w64 { width: 64%; }
.bento .lead-meter-part.w65 { width: 65%; }
.bento .lead-meter-part.w66 { width: 66%; }
.bento .lead-meter-part.w67 { width: 67%; }
.bento .lead-meter-part.w68 { width: 68%; }
.bento .lead-meter-part.w69 { width: 69%; }
.bento .lead-meter-part.w70 { width: 70%; }
.bento .lead-meter-part.w71 { width: 71%; }
.bento .lead-meter-part.w72 { width: 72%; }
.bento .lead-meter-part.w73 { width: 73%; }
.bento .lead-meter-part.w74 { width: 74%; }
.bento .lead-meter-part.w75 { width: 75%; }
.bento .lead-meter-part.w76 { width: 76%; }
.bento .lead-meter-part.w77 { width: 77%; }
.bento .lead-meter-part.w78 { width: 78%; }
.bento .lead-meter-part.w79 { width: 79%; }
.bento .lead-meter-part.w80 { width: 80%; }
.bento .lead-meter-part.w81 { width: 81%; }
.bento .lead-meter-part.w82 { width: 82%; }
.bento .lead-meter-part.w83 { width: 83%; }
.bento .lead-meter-part.w84 { width: 84%; }
.bento .lead-meter-part.w85 { width: 85%; }
.bento .lead-meter-part.w86 { width: 86%; }
.bento .lead-meter-part.w87 { width: 87%; }
.bento .lead-meter-part.w88 { width: 88%; }
.bento .lead-meter-part.w89 { width: 89%; }
.bento .lead-meter-part.w90 { width: 90%; }
.bento .lead-meter-part.w91 { width: 91%; }
.bento .lead-meter-part.w92 { width: 92%; }
.bento .lead-meter-part.w93 { width: 93%; }
.bento .lead-meter-part.w94 { width: 94%; }
.bento .lead-meter-part.w95 { width: 95%; }
.bento .lead-meter-part.w96 { width: 96%; }
.bento .lead-meter-part.w97 { width: 97%; }
.bento .lead-meter-part.w98 { width: 98%; }
.bento .lead-meter-part.w99 { width: 99%; }
.bento .lead-meter-part.w100 { width: 100%; }

/* ==========================================================================
   Bruno Ace — display face for Latin-only brand text
   Bruno Ace is wide and geometric, so it needs tighter tracking and a
   slightly smaller size than the sans it replaces. It carries no Thai, and
   every element below is English-only by design.
   ========================================================================== */

/* Sidebar lockup: TC-ATC PROJECT */
.wordmark {
    font-family: var(--font-display);
    font-weight: 400;
    font-size: 17px;
    letter-spacing: .5px;
    line-height: 1.35;
    text-shadow: none;
}

.wordmark span {
    color: #ff8a4c;
}

/* Header department name: "TC-ATC PROJECT" sits inside .brand-text before the
   Thai line, so scope the display face to the first line only. */
.brand-text {
    font-family: var(--font-sans);
}

/* Eyebrow labels (all English: "PROJECT CALENDAR", "TC-ATC PROJECT / ...").
   Bruno Ace is wide and has small x-height at tiny sizes, so these run at
   11px with generous tracking rather than the 10px used by the sans face. */
.eyebrow,
.heading > p {
    font-family: var(--font-display);
    font-weight: 400;
    letter-spacing: 1.6px;
    text-transform: none;
}

.heading > p {
    font-size: 11px;
    letter-spacing: 1.8px;
    color: var(--orange-ink);
    line-height: 1.6;
}

/* The hero eyebrow sits on the warm wash; same treatment, slightly larger */
.hero .eyebrow {
    font-size: 11px;
    letter-spacing: 1.8px;
}

/* Bruno Ace is much wider: keep the sidebar lockup from wrapping at narrow
   widths by trimming tracking and size. */
@media (max-width: 1100px) {
    .wordmark {
        font-size: 15px;
        letter-spacing: .3px;
    }
}

@media (max-width: 720px) {
    .wordmark {
        font-size: 15px;
    }

    .heading > p {
        font-size: 9px;
        letter-spacing: 1.2px;
        line-height: 1.7;
    }
}

/* ==========================================================================
   Header — orange graphic treatment + a tidier account zone
   Pure CSS so no markup changes and no CSP exception is needed.
   ========================================================================== */

header {
    position: relative;
    isolation: isolate;
    background-color: #ffffff;
    background-image:
        /* fine diagonal hatch, the same signature as the page backdrop */
        repeating-linear-gradient(
            135deg,
            rgba(237, 100, 37, .07) 0px,
            rgba(237, 100, 37, .07) 1.5px,
            rgba(237, 100, 37, 0) 1.5px,
            rgba(237, 100, 37, 0) 9px
        ),
        /* warm glow behind the account zone on the right */
        radial-gradient(42% 160% at 100% 50%, rgba(237, 100, 37, .16) 0%, rgba(237, 100, 37, 0) 70%),
        /* soft cream lift from the logotype side */
        linear-gradient(90deg, #fffdfb 0%, #ffffff 46%, #fff8f3 100%);
    background-size: auto, auto, auto;
    background-repeat: repeat, no-repeat, no-repeat;
    border-bottom: 1px solid var(--line);
    box-shadow: var(--shadow-1);
}

/* Gradient hairline along the bottom edge, fading out toward the right */
header::after {
    content: "";
    position: absolute;
    inset: auto 0 0 0;
    height: 3px;
    background: linear-gradient(90deg, var(--orange) 0%, #f7a273 26%, rgba(237, 100, 37, .25) 58%, rgba(237, 100, 37, 0) 88%);
    pointer-events: none;
    z-index: 1;
}

/* Logos sit on their own plate so the hatch never touches them */
.brand-logos {
    padding-right: 20px;
    border-right: 1px solid var(--line-strong);
}

.brand .college-logo,
.brand .department-logo {
    border-radius: 10px;
    background: #fff;
    filter: none;
    box-shadow: 0 1px 2px rgba(31, 36, 43, .08);
}

.brand .college-logo {
    padding: 3px;
}

.department-logo {
    padding: 2px;
}

/* ---------- Account zone: a calm pill holding status, then the action ---------- */

.header-account {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: flex-end;
    gap: 14px;
    flex-wrap: wrap;
    min-width: 0;
}

.online-header {
    order: 1;
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0 9px;
    padding: 7px 14px;
    border-radius: 999px;
    background: rgba(255, 255, 255, .86);
    border: 1px solid var(--orange-line);
    box-shadow: 0 1px 2px rgba(31, 36, 43, .05);
    color: var(--ink-soft);
    font-size: 11px;
    line-height: 1.5;
    max-width: 100%;
}

.online-label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-weight: 600;
    color: var(--ink-soft);
    white-space: nowrap;
}

/* Pulse the live dot so "online" reads as live, not static */
.online-dot {
    width: 7px;
    height: 7px;
    background: #2f9e5f;
    box-shadow: 0 0 0 0 rgba(47, 158, 95, .45);
    animation: online-pulse 2.4s var(--ease) infinite;
}

@keyframes online-pulse {
    0%   { box-shadow: 0 0 0 0 rgba(47, 158, 95, .40); }
    70%  { box-shadow: 0 0 0 6px rgba(47, 158, 95, 0); }
    100% { box-shadow: 0 0 0 0 rgba(47, 158, 95, 0); }
}

.online-count strong {
    color: var(--orange-ink);
    font-weight: 700;
}

.online-divider {
    /* A hairline rule reads tidier than a floating middle dot */
    display: inline-block;
    width: 1px;
    height: 12px;
    background: var(--line-strong);
    color: transparent;
    overflow: hidden;
    font-size: 0;
    line-height: 0;
    flex: 0 0 auto;
}

.header-account .login-link {
    order: 0;
    align-self: center;
    white-space: nowrap;
    padding: 10px 18px;
    font-size: 13px;
}

/* Signed-in account block: name on one line, role badges on the next.
   Right-aligned so the block hangs off the same edge as the online pill. */
.header-account .account {
    order: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 6px;
    text-align: right;
    max-width: 360px;
    padding: 2px 18px 2px 4px;
    border-right: 1px solid var(--line-strong);
    color: var(--ink);
    font-weight: 600;
    font-size: 13.5px;
    line-height: 1.3;
    letter-spacing: -.1px;
}

.header-account .account small {
    display: block;
    margin: 0;
    color: var(--muted);
    font-weight: 400;
}

@media (prefers-reduced-motion: reduce) {
    .online-dot {
        animation: none;
    }
}

/* ---------- Responsive ---------- */

@media (max-width: 1100px) {
    header {
        gap: 16px;
    }

    .online-header {
        font-size: 10.5px;
        padding: 6px 11px;
    }
}

@media (max-width: 720px) {
    header {
        background-image:
            repeating-linear-gradient(
                135deg,
                rgba(237, 100, 37, .06) 0px,
                rgba(237, 100, 37, .06) 1.5px,
                rgba(237, 100, 37, 0) 1.5px,
                rgba(237, 100, 37, 0) 9px
            ),
            linear-gradient(180deg, #ffffff 0%, #fffaf7 100%);
        padding-bottom: 14px;
    }

    .header-account {
        flex-basis: 100%;
        width: 100%;
        justify-content: space-between;
        gap: 10px;
    }

    .online-header {
        order: 1;
        flex: 1 1 auto;
        justify-content: flex-start;
        border-radius: 10px;
        font-size: 10.5px;
        padding: 6px 10px;
    }

    .header-account .login-link {
        order: 0;
        flex: 0 0 auto;
    }

    .header-account .account {
        order: 0;
        border-right: 0;
        padding-right: 0;
        text-align: left;
        flex: 1 1 100%;
    }

    .brand-logos {
        padding-right: 14px;
    }
}

@media (max-width: 420px) {
    .online-header {
        gap: 3px 6px;
    }

    .header-account {
        gap: 8px;
    }
}

/* ==========================================================================
   Sidebar active state
   The nav marks the current page with .active + aria-current="page"
   (see nav_link() in core.php). The marker is a solid orange rail plus a
   tinted plate, so the current section reads at a glance.
   ========================================================================== */

nav a.active,
.navbutton.active {
    /* A .16 orange tint over #272c34 reads muddy brown; a brighter, more
       saturated plate keeps the brand hue legible on the dark rail. */
    background: rgba(237, 100, 37, .26);
    color: #fff;
    font-weight: 600;
    border-radius: var(--radius-sm);
    position: relative;
}

nav a.active::before {
    content: "";
    position: absolute;
    left: 0;
    top: 8px;
    bottom: 8px;
    width: 3px;
    border-radius: 0 3px 3px 0;
    background: var(--orange);
}

nav a.active:hover {
    background: rgba(237, 100, 37, .34);
    color: #fff;
    padding-left: 12px;
}

nav a.active:hover::before {
    background: #ff9a63;
}

/* Keep the plain hover rail from doubling up on the active item */
nav a.active:hover::before {
    content: "";
    width: 3px;
}

/* ---------- Role badges in the header account block ---------- */

.header-account .account {
    max-width: 360px;
}

.role-badges {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    align-items: center;
    gap: 5px;
    margin: 0;
    padding: 0;
    line-height: 1;
}

.role-badge {
    /* One fixed height for every badge so a row of four never looks ragged */
    display: inline-flex;
    align-items: center;
    height: 21px;
    padding: 0 9px;
    border-radius: 999px;
    background: var(--orange-wash);
    border: 1px solid var(--orange-line);
    color: var(--orange-ink);
    font-size: 10px;
    font-weight: 600;
    white-space: nowrap;
    letter-spacing: .1px;
    line-height: 1;
}

/* Below 720px the account block re-aligns left, so the badges do too */
@media (max-width: 720px) {
    .role-badges {
        justify-content: flex-start;
    }
}

/* Mobile: the nav becomes a horizontal strip, so the active marker has to
   sit on the bottom edge instead of the left. */
@media (max-width: 720px) {
    nav a.active {
        background: rgba(237, 100, 37, .18);
        box-shadow: inset 0 -3px 0 var(--orange);
    }

    nav a.active::before {
        display: none;
    }

    nav a.active:hover {
        padding-left: 8px;
    }
}

/* ==========================================================================
   Developer credit badge (header + footer)
   The department name is long; the badge keeps it on one visual token while
   the "พัฒนาโดย" label stays quiet so the badge is what the eye lands on.
   ========================================================================== */

.brand-text small.brand-credit {
    /* app.css sets `.brand-text small { display: block }`, which beat a bare
       `.brand-credit` rule. Qualify it and force a single flex row. */
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    gap: 5px;
    margin-top: 6px;
    font-size: 11px;
    line-height: 1.5;
    min-width: 0;
    max-width: 100%;
}

.credit-label {
    color: var(--muted);
    font-weight: 400;
    letter-spacing: .2px;
    flex: 0 0 auto;
    white-space: nowrap;
}

.credit-badge {
    display: inline-block;
    padding: 2px 9px;
    border-radius: 999px;
    background: linear-gradient(180deg, #fff4ec 0%, #fdeade 100%);
    border: 1px solid var(--orange-line);
    color: var(--orange-ink);
    /* Shrinks to fit the row; the full name stays available via title text
       in the footer, where there is room to wrap. */
    font-size: 10px;
    font-weight: 600;
    line-height: 1.7;
    letter-spacing: 0;
    white-space: nowrap;
    min-width: 0;
    flex: 0 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ==========================================================================
   Footer — three-band layout: identity / credit / meta
   ========================================================================== */

.site-footer {
    margin-top: 8px;
    padding: 22px 38px 26px;
    border-top: 1px solid var(--line);
    background:
        repeating-linear-gradient(
            135deg,
            rgba(237, 100, 37, .05) 0px,
            rgba(237, 100, 37, .05) 1.5px,
            rgba(237, 100, 37, 0) 1.5px,
            rgba(237, 100, 37, 0) 9px
        ),
        linear-gradient(180deg, #ffffff 0%, #fdfaf7 100%);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px 26px;
    position: relative;
}

/* Gradient hairline on top, mirroring the header's bottom rule */
.site-footer::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 3px;
    background: linear-gradient(90deg, rgba(237, 100, 37, 0) 0%, rgba(237, 100, 37, .28) 55%, var(--orange) 100%);
    pointer-events: none;
}

.footer-brand {
    display: flex;
    align-items: baseline;
    gap: 10px;
    min-width: 0;
}

.footer-mark {
    font-family: var(--font-display);
    font-size: 13px;
    letter-spacing: .6px;
    color: var(--ink);
}

.footer-version {
    font-size: 10px;
    color: var(--muted);
    padding: 1px 7px;
    border-radius: 999px;
    border: 1px solid var(--line);
    background: var(--surface);
    white-space: nowrap;
}

.footer-credit {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 11px;
    min-width: 0;
}

.footer-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    font-size: 10.5px;
    color: var(--muted);
    margin-left: auto;
}

.footer-sep {
    color: var(--line-strong);
}

/* ---------- Responsive ---------- */

@media (max-width: 1100px) {
    .site-footer {
        padding: 20px 22px 24px;
        gap: 12px 20px;
    }

    .footer-meta {
        margin-left: 0;
        flex-basis: 100%;
    }
}

@media (max-width: 720px) {
    .site-footer {
        padding: 18px 20px 22px;
        flex-direction: column;
        align-items: flex-start;
        gap: 10px;
    }

    .footer-meta {
        flex-basis: auto;
    }

    .credit-badge {
        white-space: normal;
    }
}

/* ==========================================================================
   Wordmark — tech circuit graphic behind the TC-ATC PROJECT lockup
   Built from layered CSS gradients: a circuit-board trace pattern, a soft
   orange glow, and a faint grid. Purely decorative, so it is aria-hidden by
   being a pseudo-element, and it never intercepts pointer events.
   ========================================================================== */

.wordmark {
    position: relative;
    display: inline-block;
    padding: 8px 12px 9px;
    margin: -8px -12px 0;
    border-radius: 10px;
    z-index: 0;
    isolation: isolate;
}

/* Backdrop: one clean accent, not a lattice. A soft orange wash with a
   single diagonal sweep and a thin baseline — enough to lift the lockup off
   the dark rail without competing with the letters. */
.wordmark::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    z-index: -1;
    background-image:
        /* Diagonal sweep pushed to the trailing edge, clear of the letters */
        linear-gradient(115deg, rgba(237, 100, 37, 0) 0%, rgba(237, 100, 37, 0) 74%, rgba(237, 100, 37, .34) 76%, rgba(237, 100, 37, 0) 78%),
        /* warm corner light */
        radial-gradient(120% 130% at 6% 0%, rgba(237, 100, 37, .22) 0%, rgba(237, 100, 37, 0) 62%);
    background-size: auto, auto;
    background-repeat: no-repeat, no-repeat;
    pointer-events: none;
}

/* A brighter corner notch so the lockup reads as an illuminated panel */
.wordmark::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    z-index: -1;
    border: 1px solid rgba(237, 100, 37, .22);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .03);
    pointer-events: none;
}

/* Text sits above the graphic and keeps its own contrast */
.wordmark span,
.wordmark {
    position: relative;
}

@media (max-width: 720px) {
    .wordmark {
        /* Negative side margins pushed the box past the viewport at 390px;
           use symmetric padding and let the box stay inside the rail. */
        padding: 6px 10px 7px;
        margin: 0;
        max-width: 100%;
        font-size: 14px;
        letter-spacing: .2px;
    }
}



/* ==========================================================================
   Dashboard filter — equal control heights
   The year control is a bare <select> while the department control is a
   .field-wrapped select, so their boxes and baselines drift apart. Give the
   bare control the same label row and margin.
   ========================================================================== */

.filter-form {
    align-items: flex-end;
}

.filter-form > label {
    display: block;
    font-size: 13px;
    font-weight: 500;
    line-height: 1.35;
    color: var(--ink-soft);
    margin: 0 0 0 0;
    padding-bottom: 0;
}

.filter-form > select,
.filter-form > .field {
    /* same vertical rhythm: label line + control */
    margin-bottom: 0;
}

.filter-form > select {
    display: block;
    height: 42px;
    padding: 0 12px;
    margin-top: 6px;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--ink);
    font-size: inherit;
    line-height: 40px;
    box-sizing: border-box;
    /* keep the native arrow but reserve room so text never sits under it */
    padding-right: 32px;
}

.filter-form .field {
    margin-bottom: 0;
    line-height: 1.35;
}

.filter-form .field select {
    height: 42px;
    padding: 0 32px 0 12px;
    margin-top: 6px;
    box-sizing: border-box;
}

.filter-form > button,
.filter-form button.secondary {
    height: 42px;
    padding: 0 20px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    white-space: nowrap;
}

@media (max-width: 520px) {
    .filter-form > select {
        flex: 1 1 100%;
        width: 100%;
    }

    .filter-form > button {
        flex: 0 0 auto;
    }
}

/* ==========================================================================
   Journey flow — the project lifecycle as a connected step sequence
   Horizontal on desktop (numbered nodes on a rail), vertical on mobile.
   ========================================================================== */

.journey-flow {
    list-style: none;
    margin: 22px 0 4px;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0;
    counter-reset: step;
}

.journey-step {
    position: relative;
    padding: 0 18px 0 0;
    min-width: 0;
}

/* connector rail between nodes */
.journey-step:not(:last-child)::after {
    content: "";
    position: absolute;
    top: 15px;
    left: 34px;
    right: 6px;
    height: 2px;
    background: linear-gradient(90deg, var(--orange-line) 0%, var(--orange-line) 55%, rgba(246, 215, 196, .25) 100%);
    border-radius: 2px;
}

.journey-num {
    position: relative;
    z-index: 1;
    display: grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--surface);
    border: 2px solid var(--orange);
    color: var(--orange-ink);
    font-size: 13px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    margin-bottom: 14px;
    box-shadow: 0 1px 2px rgba(31, 36, 43, .06);
}

.journey-body .eyebrow {
    display: block;
    margin-bottom: 4px;
    font-size: 10px;
    letter-spacing: 1.2px;
}

.journey-body h3 {
    margin: 0 0 5px;
    font-size: 15px;
    letter-spacing: -.1px;
    color: var(--ink);
}

.journey-body p {
    margin: 0;
    font-size: 12px;
    line-height: 1.6;
}

/* last step gets a filled node so the terminus reads as the goal */
.journey-step:last-child .journey-num {
    background: var(--orange);
    border-color: var(--orange);
    color: #2b1608;
}

@media (max-width: 1100px) {
    .journey-flow {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        row-gap: 26px;
    }

    .journey-step:nth-child(2n)::after {
        display: none;
    }
}

@media (max-width: 640px) {
    .journey-flow {
        grid-template-columns: 1fr;
        row-gap: 0;
    }

    .journey-step {
        display: grid;
        grid-template-columns: 32px 1fr;
        gap: 0 14px;
        padding: 0 0 22px 0;
    }

    /* vertical rail between stacked nodes */
    .journey-step:not(:last-child)::after {
        top: 32px;
        left: 15px;
        right: auto;
        bottom: 0;
        width: 2px;
        height: auto;
        background: linear-gradient(180deg, var(--orange-line) 0%, rgba(246, 215, 196, .25) 100%);
    }

    .journey-step:last-child {
        padding-bottom: 0;
    }

    .journey-num {
        margin-bottom: 0;
    }

    .journey-body {
        padding-top: 2px;
    }
}

@media (prefers-reduced-motion: no-preference) {
    .journey-step {
        animation: journey-in 420ms var(--ease) both;
    }

    .journey-step:nth-child(2) { animation-delay: 60ms; }
    .journey-step:nth-child(3) { animation-delay: 120ms; }
    .journey-step:nth-child(4) { animation-delay: 180ms; }

    @keyframes journey-in {
        from { opacity: 0; transform: translateY(6px); }
        to   { opacity: 1; transform: none; }
    }
}

/* ==========================================================================
   Heading ornaments — a soft orange plate behind section titles so each
   reads as a heading rather than as grey text on a white card.
   Applied to card h2 and the page h1 area; the background is deliberately
   low-contrast so body copy stays the loudest thing on screen.
   ========================================================================== */

.dashboard-section-title,
.card > h2,
.chart-card > h2,
section.card > h2,
.card .row > h2,
section.card .row > h2 {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 9px;
    margin: 0 0 14px;
    padding: 7px 14px 7px 12px;
    border-radius: 9px;
    background:
        linear-gradient(90deg, rgba(237, 100, 37, .13) 0%, rgba(237, 100, 37, .05) 62%, rgba(237, 100, 37, 0) 100%);
    font-size: 18px;
    letter-spacing: -.2px;
    color: var(--ink);
}

/* A short solid tab on the leading edge anchors the title */
.dashboard-section-title::before,
.card > h2::before,
.chart-card > h2::before,
section.card > h2::before,
.card .row > h2::before,
section.card .row > h2::before {
    content: "";
    width: 4px;
    height: 17px;
    border-radius: 3px;
    background: var(--orange);
    flex: 0 0 auto;
}

/* Titles that live in a flex row (e.g. "รายชื่อโครงงาน" + count) must not
   stretch the row. */
.row > h2 {
    margin-bottom: 0;
    /* keep the pill tight to the text inside the flex row */
    align-self: center;
}

/* ---------- Table view inside the chart block ---------- */

.chart-table {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    padding: 0;
    overflow: hidden;
    box-shadow: var(--shadow-1);
}

.chart-table > summary {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px 18px;
    font-size: 13px;
    font-weight: 600;
    color: var(--ink);
    background: linear-gradient(90deg, rgba(237, 100, 37, .08) 0%, rgba(237, 100, 37, 0) 70%);
    list-style: none;
    cursor: pointer;
    transition: background var(--fast) var(--ease);
}

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

.chart-table > summary:hover {
    background: linear-gradient(90deg, rgba(237, 100, 37, .13) 0%, rgba(237, 100, 37, .03) 70%);
}

/* Chevron that rotates when open */
.chart-table > summary::after {
    content: "";
    margin-left: auto;
    width: 8px;
    height: 8px;
    border-right: 2px solid var(--orange-ink);
    border-bottom: 2px solid var(--orange-ink);
    transform: rotate(45deg) translateY(-2px);
    transition: transform var(--fast) var(--ease);
}

.chart-table[open] > summary::after {
    transform: rotate(-135deg) translateY(-2px);
}

.chart-table[open] > summary {
    border-bottom: 1px solid var(--line);
}

.chart-table .tablewrap {
    padding: 0;
    overflow-x: auto;
}

.chart-table table {
    margin: 0;
}



/* Zebra + header for the chart table specifically: `.chart-table table`
   outranks `.tablewrap tbody tr`, so restate the stripes at matching depth. */
.chart-table tbody tr:nth-child(odd) {
    background: #ffffff;
}

.chart-table tbody tr:nth-child(even) {
    background: #fdf4ee;
}

.chart-table tbody tr:hover {
    background: #fbe9dd;
}

.chart-table thead th {
    background: linear-gradient(180deg, #fdf6f1 0%, #faeee4 100%);
    color: var(--ink-soft);
    font-weight: 600;
    font-size: 11.5px;
}

.chart-table tbody th[scope="row"] {
    font-weight: 500;
    color: var(--ink);
}

.chart-table tbody td {
    font-variant-numeric: tabular-nums;
    color: var(--ink-soft);
}

.chart-table tbody td:last-child {
    font-weight: 600;
    color: var(--orange-ink);
}

/* ==========================================================================
   Data tables — zebra striping in brand tones, sticky header, aligned numerics
   ========================================================================== */

.tablewrap table {
    border-collapse: separate;
    border-spacing: 0;
    font-size: 13px;
}

.tablewrap thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: linear-gradient(180deg, #fbf7f3 0%, #f7f2ec 100%);
    color: var(--ink-soft);
    font-weight: 600;
    font-size: 11.5px;
    letter-spacing: .2px;
    border-bottom: 1px solid var(--line-strong);
    white-space: nowrap;
}

.tablewrap tbody tr:nth-child(odd) {
    background: #ffffff;
}

.tablewrap tbody tr:nth-child(even) {
    background: #fdf8f4;
}

.tablewrap tbody tr:hover {
    background: #fdf1e9;
}

.tablewrap tbody tr {
    transition: background var(--fast) var(--ease);
}

.tablewrap tbody td {
    border-bottom: 1px solid rgba(229, 231, 236, .7);
    color: var(--ink-soft);
}

.tablewrap tbody tr:last-child td {
    border-bottom: 0;
}

/* Numeric columns line up: right-align cells whose content is only digits */
.tablewrap td:nth-child(n) {
    font-variant-numeric: tabular-nums;
}

.tablewrap caption {
    caption-side: top;
    text-align: left;
    padding: 0 0 12px;
    font-size: 12px;
    color: var(--muted);
}

/* First column gets a subtle leading rule so the eye can track the row */
.tablewrap tbody th,
.tablewrap tbody td:first-child {
    font-weight: 500;
    color: var(--ink);
}

@media (max-width: 720px) {
    .card > h2,
    .chart-card > h2,
    section.card > h2,
    .card .row > h2 {
        font-size: 16px;
        padding: 6px 11px 6px 10px;
    }

    .chart-table > summary {
        padding: 12px 14px;
        font-size: 12px;
    }
}

/* ==========================================================================
   Logout — icon button at the right edge of the header
   ========================================================================== */

.logout-form {
    display: inline-flex;
    margin: 0;
    order: 2;
}

.logout-button {
    display: inline-grid;
    place-items: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border-radius: 10px;
    background: linear-gradient(180deg, #f57a41 0%, #ed6425 52%, #e25a1b 100%);
    color: #2b1608;
    border: 0;
    box-shadow: 0 1px 2px rgba(150, 60, 14, .28), 0 2px 8px -2px rgba(150, 60, 14, .22);
    cursor: pointer;
    transition: transform var(--fast) var(--ease),
                box-shadow var(--fast) var(--ease),
                background var(--fast) var(--ease);
}

.logout-button:hover {
    background: linear-gradient(180deg, #ff8549 0%, #f26a2b 52%, #e85f1e 100%);
    box-shadow: 0 2px 4px rgba(150, 60, 14, .30), 0 8px 16px -6px rgba(150, 60, 14, .38);
}

.logout-button:active {
    transform: translateY(1px);
}

.logout-button svg {
    display: block;
}

@media (max-width: 720px) {
    .logout-form {
        order: 2;
    }

    .logout-button {
        width: 32px;
        height: 32px;
    }
}


/* ==========================================================================
   Chart table caption — inset to match the cells
   Declared last and qualified with .tablewrap so it beats `.tablewrap caption`.
   ========================================================================== */

.chart-table .tablewrap caption,
.tablewrap .chart-table caption,
.chart-table caption {
    padding: 14px 16px 12px;
    text-align: left;
    font-size: 12px;
    color: var(--muted);
    background: var(--surface);
    border-bottom: 1px solid var(--line);
    caption-side: top;
}

/* ==========================================================================
   Pagination + soft orange buttons
   The primary button treatment is intentionally light here: these are
   navigational, not the page's main action, so a tinted ghost reads calmer
   than a solid saturated fill.
   ========================================================================== */

.pagination {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 6px;
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--line);
}

/* Page numbers */
.pagination-page,
.pagination-arrow,
.pagination-gap {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 34px;
    height: 34px;
    padding: 0 11px;
    border-radius: 9px;
    font-size: 13px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    line-height: 1;
    text-decoration: none;
    transition: background var(--fast) var(--ease),
                color var(--fast) var(--ease),
                border-color var(--fast) var(--ease),
                box-shadow var(--fast) var(--ease);
}

.pagination-page {
    color: var(--orange-ink);
    background: linear-gradient(180deg, #fff8f4 0%, #fdefe6 100%);
    border: 1px solid var(--orange-line);
    box-shadow: 0 1px 1px rgba(31, 36, 43, .03);
}

.pagination-page:hover {
    background: linear-gradient(180deg, #fff2e9 0%, #fbe4d5 100%);
    border-color: #eec3aa;
    color: var(--orange-strong);
    text-decoration: none;
    box-shadow: 0 1px 3px rgba(150, 60, 14, .12);
}

/* Current page: solid, but a softer ramp than the primary CTA */
.pagination-page.is-current {
    background: linear-gradient(180deg, #f58a55 0%, #ed6425 55%, #e05f22 100%);
    border-color: #df5f22;
    color: #2b1608;
    box-shadow: 0 1px 2px rgba(150, 60, 14, .22), 0 3px 10px -4px rgba(150, 60, 14, .30);
    cursor: default;
}

/* Prev / next */
.pagination-arrow {
    color: var(--ink-soft);
    background: var(--surface);
    border: 1px solid var(--line-strong);
    padding: 0 14px;
}

.pagination-arrow:hover {
    background: var(--surface-sunken);
    border-color: #c9ced6;
    color: var(--ink);
    text-decoration: none;
}

.pagination-arrow.is-disabled {
    color: #b6bac1;
    background: var(--surface-sunken);
    border-color: var(--line);
    cursor: not-allowed;
    opacity: .75;
}

.pagination-gap {
    color: var(--muted);
    min-width: 22px;
    padding: 0 4px;
    letter-spacing: .5px;
}

/* ---------- Soften the solid primary buttons site-wide ---------- */

button,
.button {
    /* Lighter ramp + lighter text contrast than the earlier build */
    background: linear-gradient(180deg, #f8996a 0%, #f07840 52%, #e86f37 100%);
    color: #2b1608;
    box-shadow: 0 1px 2px rgba(150, 60, 14, .20), 0 2px 8px -3px rgba(150, 60, 14, .22);
}

button:hover,
.button:hover {
    background: linear-gradient(180deg, #ffa87c 0%, #f5854d 52%, #ec7840 100%);
    box-shadow: 0 2px 4px rgba(150, 60, 14, .22), 0 8px 18px -6px rgba(150, 60, 14, .28);
}

/* Secondary buttons stay as a quiet outline */
button.secondary,
.button.secondary {
    background: var(--surface);
    border: 1px solid var(--line-strong);
    color: var(--ink);
    box-shadow: var(--shadow-1);
}

button.secondary:hover,
.button.secondary:hover {
    background: var(--surface-sunken);
    border-color: #c9ced6;
}

@media (max-width: 520px) {
    .pagination {
        gap: 5px;
    }

    .pagination-page,
    .pagination-arrow {
        min-width: 32px;
        height: 32px;
        padding: 0 9px;
        font-size: 12px;
    }
}


/* ==========================================================================
   Pagination reset — app.css sets `nav a { display:block; width:100% }` for the
   sidebar. The pagination is also a <nav>, so every link inherited that and
   stacked vertically. Scope the reset to this nav only.
   ========================================================================== */

nav.pagination a.pagination-page,
nav.pagination a.pagination-arrow,
.pagination .pagination-page,
.pagination .pagination-arrow,
.pagination .pagination-gap {
    display: inline-flex;
    width: auto;
    margin: 0;
    text-align: center;
    white-space: nowrap;
}

nav.pagination {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 6px;
    width: auto;
    overflow: visible;
}


/* ==========================================================================
   Filter controls — matching text size
   The year control inherits 15px from <body>, while the department control
   sits inside .field (13px) and inherits that. Force one size on both, and
   on the labels, so the two controls read as a pair.
   ========================================================================== */

.filter-form > label,
.filter-form .field,
.filter-form > select,
.filter-form .field select {
    font-size: 13px;
    line-height: 1.35;
}

.filter-form > select,
.filter-form .field select {
    font-family: var(--font-sans);
    font-size: 13px;
    font-weight: 400;
    color: var(--ink);
    height: 42px;
    padding: 0 32px 0 12px;
    margin-top: 6px;
    box-sizing: border-box;
    vertical-align: middle;
}

/* Keep the labels the same weight and colour so the row looks deliberate */
.filter-form > label {
    color: var(--ink-soft);
    font-weight: 500;
}


/* ==========================================================================
   Filter form — label above control, both columns aligned
   The year label sat beside the select (app.css sets white-space:nowrap on
   .filter-form label), which pushed it under the box. Make every control a
   two-row column: label, then the field.
   ========================================================================== */

.filter-form {
    display: flex;
    align-items: flex-end;
    gap: 10px;
    flex-wrap: wrap;
}

/* Year control: wrap the bare label+select into a column without markup change */
.filter-form > label {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    margin: 0;
    white-space: normal;
    font-size: 13px;
    font-weight: 500;
    line-height: 1.35;
    color: var(--ink-soft);
}

.filter-form > label select {
    margin-top: 6px;
}

/* Department control: <label class="field">แผนกวิชา<select>…</select></label>
   The label text and the select are siblings, so flex-column stacks them. */
.filter-form label.field {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    gap: 0;
    margin: 0;
    font-size: 13px;
    font-weight: 500;
    line-height: 1.35;
    color: var(--ink-soft);
    white-space: normal;
}

.filter-form .field > select {
    margin-top: 6px;
}

/* Give both selects identical box metrics */
.filter-form > label > select,
.filter-form .field > select {
    height: 42px;
    padding: 0 32px 0 12px;
    font-size: 13px;
    font-weight: 400;
    box-sizing: border-box;
}

/* The submit button lines up with the controls, not the labels */
.filter-form > button {
    height: 42px;
    margin: 0 0 0 2px;
}


/* Both filter columns must start at the same y. `.dashboard-filter` is a
   flex row; align it to the top of the form and let each column size itself. */
.dashboard-filter {
    align-items: flex-start;
}

.dashboard-filter > div {
    flex: 1 1 auto;
    min-width: 0;
}

.dashboard-filter .filter-form {
    align-items: flex-start;
    flex: 0 0 auto;
}

/* Strip the default label margins so both rows start level */
.filter-form > label,
.filter-form label.field {
    padding: 0;
    margin: 0;
}

/* The year <label> and the department <label class="field"> must share a
   baseline for their text, so give both the same line box. */
.filter-form > label,
.filter-form label.field {
    min-height: 17.5px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
}


/* ==========================================================================
   Filter form — one row, three aligned control groups
   The bare year <label> + <select> are siblings, so making the form a flex
   row puts them side by side and wraps the rest. Wrap each pair in its own
   flex item using display:contents on the label.
   ========================================================================== */

.filter-form {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: flex-end;
    gap: 10px;
}

/* Year pair: label above its select, both shrink-wrapped into one column */
.filter-form > label[for="academic-year"] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-end;
    gap: 0;
    margin: 0;
    white-space: normal;
    font-size: 13px;
    font-weight: 500;
    color: var(--ink-soft);
    line-height: 1.35;
}

/* Department pair: <label class="field">text<select></label> */
.filter-form > label.field {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-end;
    gap: 0;
    margin: 0;
    white-space: normal;
    font-size: 13px;
    font-weight: 500;
    color: var(--ink-soft);
    line-height: 1.35;
}

/* Both selects share the same box, and both sit on the same bottom line */
.filter-form > label[for="academic-year"] > select,
.filter-form > label.field > select {
    height: 42px;
    margin-top: 6px;
    padding: 0 32px 0 12px;
    font-size: 13px;
    font-weight: 400;
    box-sizing: border-box;
}

.filter-form > button {
    height: 42px;
    margin: 0;
    flex: 0 0 auto;
}

@media (max-width: 900px) {
    .filter-form {
        flex-wrap: wrap;
        width: 100%;
    }

    .filter-form > label[for="academic-year"],
    .filter-form > label.field {
        flex: 1 1 150px;
    }

    .filter-form > label[for="academic-year"] > select,
    .filter-form > label.field > select {
        width: 100%;
    }
}


/* Keep the three controls inside the card: the department list is long, so
   cap the two selects and let them shrink before the button is pushed out. */
.filter-form {
    flex-wrap: nowrap;
    min-width: 0;
    max-width: 100%;
}

.filter-form > label.field {
    flex: 0 1 190px;
    min-width: 120px;
    max-width: 220px;
}

.filter-form > label.field > select {
    width: 100%;
    min-width: 0;
}

.filter-form > button {
    flex: 0 0 auto;
    margin-left: 4px;
}

@media (max-width: 1180px) {
    .filter-form {
        flex-wrap: wrap;
        justify-content: flex-start;
        width: 100%;
    }

    .filter-form > label.field {
        /* Share the row evenly and let the button keep its natural size; the
           sum must not exceed 100% or the last item overflows the card. */
        flex: 1 1 0;
        max-width: none;
        min-width: 0;
    }

    .dashboard-filter .filter-form {
        margin-top: 12px;
        flex: 1 1 100%;
        width: 100%;
        max-width: 100%;
        justify-content: flex-start;
    }

    .dashboard-filter > div {
        flex: 1 1 100%;
    }
}


/* ==========================================================================
   Filter form — authoritative rules (kept last so earlier passes cannot win)
   Goal: two labelled selects and the submit button share one baseline.
   ========================================================================== */

.dashboard-filter .filter-form {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    /* bottom-align so the button's box lines up with the select boxes,
       not with the labels above them */
    align-items: flex-end;
    gap: 10px;
    min-width: 0;
    max-width: 100%;
}

.dashboard-filter .filter-form > label.field {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-end;
    gap: 0;
    margin: 0;
    padding: 0;
    flex: 0 1 200px;
    min-width: 130px;
    max-width: 230px;
    font-size: 13px;
    font-weight: 500;
    line-height: 1.35;
    color: var(--ink-soft);
    white-space: normal;
}

.dashboard-filter .filter-form > label.field > select {
    display: block;
    width: 100%;
    height: 42px;
    margin: 6px 0 0;
    padding: 0 32px 0 12px;
    font-family: var(--font-sans);
    font-size: 13px;
    font-weight: 400;
    line-height: 40px;
    color: var(--ink);
    box-sizing: border-box;
}

.dashboard-filter .filter-form > button,
.dashboard-filter .filter-form > button.secondary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 42px;
    margin: 0;
    padding: 0 20px;
    flex: 0 0 auto;
    align-self: flex-end;
    white-space: nowrap;
    font-size: 13px;
}

@media (max-width: 1180px) {
    .dashboard-filter .filter-form {
        flex-wrap: wrap;
        width: 100%;
        max-width: 100%;
        margin-top: 12px;
    }

    .dashboard-filter .filter-form > label.field {
        flex: 1 1 0;
        min-width: 0;
        max-width: none;
    }
}


/* ==========================================================================
   Table stripes — unmistakably warm
   The earlier #fdf8f4 read as a cool/greenish grey on some displays because
   the orange component was only +5 over green. Push the hue properly warm so
   the stripe is recognisably the brand tone, not a grey.
   ========================================================================== */

.tablewrap tbody tr:nth-child(even) {
    background: #fdf2ea;
}

.tablewrap tbody tr:nth-child(odd) {
    background: #ffffff;
}

.tablewrap tbody tr:hover {
    background: #fbe7da;
}

/* Chart table mirrors it at higher specificity */
.chart-table tbody tr:nth-child(even) {
    background: #fdf2ea;
}

.chart-table tbody tr:nth-child(odd) {
    background: #ffffff;
}

.chart-table tbody tr:hover {
    background: #fbe7da;
}

/* Header row: a clearer orange wash rather than a beige grey */
.tablewrap thead th {
    background: linear-gradient(180deg, #fdf4ed 0%, #f9e9dc 100%);
    color: var(--ink-soft);
}

.chart-table thead th {
    background: linear-gradient(180deg, #fdf4ed 0%, #f9e9dc 100%);
    color: var(--ink-soft);
}


/* ==========================================================================
   Table header — orange rule under the header row
   Replaces the neutral grey hairline so the header reads as part of the
   brand palette. 2px keeps it visible above the zebra stripes without
   turning the table into a heavy grid.
   ========================================================================== */

.tablewrap thead th,
.chart-table thead th {
    border-bottom: 2px solid var(--orange);
}

/* The last body row keeps its soft hairline; only the header carries the
   orange rule so the accent stays a single, intentional marker. */
.tablewrap tbody tr:last-child td,
.chart-table tbody tr:last-child td {
    border-bottom: 0;
}

/* ==========================================================================
   Stat cards — brand-toned, with a decorative icon watermark
   Each card carries a small icon next to the label and a large, very low
   opacity watermark of the same icon behind the number. The watermark is
   position-only decoration: it never overlaps the value, and the label
   always states the metric in words.
   ========================================================================== */

.stats {
    --stat-accent: var(--orange);
}

.stat {
    position: relative;
    overflow: hidden;
    isolation: isolate;
    background:
        linear-gradient(180deg, #ffffff 0%, #fffaf7 100%);
    border: 1px solid var(--line);
    border-top: 3px solid var(--stat-accent);
    border-radius: var(--radius);
    box-shadow: var(--shadow-1);
    padding: 20px 20px 18px;
    transition: transform var(--normal) var(--ease),
                box-shadow var(--normal) var(--ease),
                border-color var(--normal) var(--ease);
}

/* Warm wash behind each card, tinted by its own accent */
.stat::before {
    content: "";
    position: absolute;
    inset: auto -34% -52% auto;
    width: 190px;
    height: 190px;
    border-radius: 50%;
    background: radial-gradient(circle, var(--stat-wash, rgba(237, 100, 37, .16)) 0%, rgba(255, 255, 255, 0) 68%);
    z-index: -1;
    pointer-events: none;
}

.stat:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-3);
    border-color: var(--orange-line);
}

/* Small inline icon, sitting left of the label */
.stat-icon {
    display: block;
    width: 18px;
    height: 18px;
    color: var(--stat-accent);
    margin-bottom: 10px;
    opacity: .95;
}

.stat b {
    position: relative;
    z-index: 1;
    display: block;
    font-size: 34px;
    line-height: 1.15;
    font-weight: 700;
    letter-spacing: -1px;
    font-variant-numeric: tabular-nums;
    color: var(--ink);
}

.stat span {
    display: block;
    margin-bottom: 6px;
    font-size: 12px;
    line-height: 1.45;
    color: var(--ink-soft);
    font-weight: 500;
}

.stat small {
    position: relative;
    z-index: 1;
    display: block;
    margin-top: 2px;
    font-size: 11px;
    color: var(--muted);
}

/* ---------- Per-metric accent + watermark ---------- */

.stat[data-stat="total"]     { --stat-accent: #c15a1c; --stat-wash: rgba(237, 100, 37, .18); }
.stat[data-stat="waiting"]   { --stat-accent: #c98a12; --stat-wash: rgba(230, 165, 40, .18); }
.stat[data-stat="passed"]    { --stat-accent: #2f8f5b; --stat-wash: rgba(47, 143, 91, .15); }
.stat[data-stat="completed"] { --stat-accent: #2f6ea5; --stat-wash: rgba(47, 110, 165, .15); }

.stat[data-stat="staff"]      { --stat-accent: #7a5ea8; --stat-wash: rgba(122, 94, 168, .15); }
.stat[data-stat="vocational"] { --stat-accent: #2f6ea5; --stat-wash: rgba(47, 110, 165, .15); }
.stat[data-stat="higher"]     { --stat-accent: #2f8f5b; --stat-wash: rgba(47, 143, 91, .15); }
.stat[data-stat="classes"]    { --stat-accent: #c15a1c; --stat-wash: rgba(237, 100, 37, .18); }

/* Watermark: the same icon, huge and faint, in the lower-right corner */
.stat::after {
    content: "";
    position: absolute;
    right: -6px;
    bottom: -14px;
    width: 92px;
    height: 92px;
    z-index: 0;
    opacity: .09;
    background-color: var(--stat-accent);
    background-repeat: no-repeat;
    background-position: center;
    background-size: contain;
    -webkit-mask-image: var(--stat-glyph);
    mask-image: var(--stat-glyph);
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    pointer-events: none;
    transition: opacity var(--normal) var(--ease);
}

.stat:hover::after {
    opacity: .14;
}

/* The glyph is supplied per metric as a data-URI SVG (a mask, so it inherits
   the accent colour rather than carrying its own fill). */
.stat[data-stat="total"]::after {
    --stat-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 5.5A1.5 1.5 0 0 1 5.5 4h4A1.5 1.5 0 0 1 11 5.5v4A1.5 1.5 0 0 1 9.5 11h-4A1.5 1.5 0 0 1 4 9.5z'/%3E%3Cpath d='M13 5.5A1.5 1.5 0 0 1 14.5 4h4A1.5 1.5 0 0 1 20 5.5v4A1.5 1.5 0 0 1 18.5 11h-4A1.5 1.5 0 0 1 13 9.5z'/%3E%3Cpath d='M4 14.5A1.5 1.5 0 0 1 5.5 13h4A1.5 1.5 0 0 1 11 14.5v4A1.5 1.5 0 0 1 9.5 20h-4A1.5 1.5 0 0 1 4 18.5z'/%3E%3Cpath d='M13 14.5A1.5 1.5 0 0 1 14.5 13h4A1.5 1.5 0 0 1 20 14.5v4A1.5 1.5 0 0 1 18.5 20h-4A1.5 1.5 0 0 1 13 18.5z'/%3E%3C/svg%3E");
}

.stat[data-stat="waiting"]::after {
    --stat-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.5'/%3E%3Cpath d='M12 7.5V12l3 1.8'/%3E%3C/svg%3E");
}

.stat[data-stat="passed"]::after {
    --stat-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.5'/%3E%3Cpath d='m8.5 12.2 2.4 2.4 4.6-4.9'/%3E%3C/svg%3E");
}

.stat[data-stat="completed"]::after {
    --stat-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 4.5h9.5L19 9v10.5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-14a1 1 0 0 1 1-1z'/%3E%3Cpath d='M14 4.5V9h4.5'/%3E%3Cpath d='m8 14.5 1.6 1.6 3.1-3.3'/%3E%3C/svg%3E");
}

.stat[data-stat="staff"]::after {
    --stat-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='8.5' r='3.2'/%3E%3Cpath d='M5.5 20a6.5 6.5 0 0 1 13 0'/%3E%3C/svg%3E");
}

.stat[data-stat="vocational"]::after {
    --stat-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.5 21 8l-9 4.5L3 8z'/%3E%3Cpath d='M6.5 10.3V15c0 1.7 2.5 3 5.5 3s5.5-1.3 5.5-3v-4.7'/%3E%3C/svg%3E");
}

.stat[data-stat="higher"]::after {
    --stat-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 20h18'/%3E%3Cpath d='M6 20V9l4-3 4 3v11'/%3E%3Cpath d='M14 20V12l4-2 3 2v8'/%3E%3C/svg%3E");
}

.stat[data-stat="classes"]::after {
    --stat-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3.5' y='5' width='17' height='14' rx='1.6'/%3E%3Cpath d='M8 3.5v3M16 3.5v3M3.5 10h17'/%3E%3C/svg%3E");
}

@media (max-width: 720px) {
    .stat {
        padding: 16px 16px 14px;
    }

    .stat b {
        font-size: 28px;
    }

    .stat::after {
        width: 74px;
        height: 74px;
        right: -8px;
        bottom: -16px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .stat:hover {
        transform: none;
    }
}


/* ==========================================================================
   Fixes: pagination hover rail, card top border, button rhythm
   ========================================================================== */

/* `nav a:hover::before` was written for the sidebar; the pagination is also a
   <nav>, so its links grew an orange left rail on hover. Remove it there. */
nav.pagination a:hover::before,
nav.pagination a::before,
.pagination a::before,
.pagination a:hover::before {
    content: none;
    display: none;
}

/* ---------- Card: no accent line on the top edge ---------- */
.card,
.chart-card,
.stat {
    border-top-width: 1px;
    border-top-color: var(--line);
}

.stat {
    border-top: 1px solid var(--line);
}

/* ---------- Button rhythm: one height, one radius, consistent gaps ---------- */

button,
.button,
input[type="submit"],
input[type="button"] {
    --btn-h: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    min-height: var(--btn-h);
    padding: 0 18px;
    border-radius: 9px;
    font-size: 13px;
    font-weight: 600;
    line-height: 1.2;
    box-sizing: border-box;
    vertical-align: middle;
    white-space: nowrap;
}

/* Small buttons used inside table rows / action clusters */
.actions button,
.actions .button,
td button,
td .button {
    --btn-h: 34px;
    padding: 0 14px;
    font-size: 12px;
}

/* Every action cluster gets the same breathing room above it, so a button row
   never sits flush against the heading or the field above it. */
.actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin: 18px 0 4px;
}

.actions form {
    display: inline-flex;
    margin: 0;
}

/* Filter actions specifically: keep clear of the select above and the table
   below. */
.filter-form + .actions,
.actions.actions-inline {
    margin-top: 18px;
    margin-bottom: 18px;
}

/* A button that directly follows a heading or a form field needs air above */
.card > h2 + .actions,
.card > h3 + .actions,
.card > .field + .actions,
.card > form > .actions:first-child {
    margin-top: 16px;
}

/* Headings that sit right above a button row */
.card h2 + button,
.card h2 + .button,
.card h3 + button,
.card h3 + .button {
    margin-top: 14px;
}


/* Hard override: the earlier `.stat { border-top: 3px solid var(--stat-accent) }`
   sits in the same layer, so restate with element + attribute specificity. */
.stats .stat,
.stats .stat[data-stat] {
    border-top: 1px solid var(--line);
    border-top-width: 1px;
    border-top-color: var(--line);
}


/* One button height everywhere, including the filter submit. The filter rule
   pinned 42px; fold it into the shared 40px rhythm so nothing looks off. */
.dashboard-filter .filter-form > button,
.dashboard-filter .filter-form > button.secondary,
.filter-form > button {
    height: 40px;
    min-height: 40px;
    padding: 0 18px;
}

/* Keep the selects matched to the button height next to them */
.dashboard-filter .filter-form > label.field > select,
.filter-form > label.field > select,
.filter-form > label[for="academic-year"] > select {
    height: 40px;
    line-height: 38px;
}

/* ==========================================================================
   Stat card polish pass 2
   ========================================================================== */

/* Missing accent for the "โครงงานในความรับผิดชอบ" card (dashboard page) */
.stat[data-stat="assigned"] {
    --stat-accent: #c15a1c;
    --stat-wash: rgba(237, 100, 37, .18);
}

.stat[data-stat="assigned"]::after {
    --stat-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 5.5A1.5 1.5 0 0 1 5.5 4h4A1.5 1.5 0 0 1 11 5.5v4A1.5 1.5 0 0 1 9.5 11h-4A1.5 1.5 0 0 1 4 9.5z'/%3E%3Cpath d='M13 5.5A1.5 1.5 0 0 1 14.5 4h4A1.5 1.5 0 0 1 20 5.5v4A1.5 1.5 0 0 1 18.5 11h-4A1.5 1.5 0 0 1 13 9.5z'/%3E%3Cpath d='M4 14.5A1.5 1.5 0 0 1 5.5 13h4A1.5 1.5 0 0 1 11 14.5v4A1.5 1.5 0 0 1 9.5 20h-4A1.5 1.5 0 0 1 4 18.5z'/%3E%3Cpath d='M13 14.5A1.5 1.5 0 0 1 14.5 13h4A1.5 1.5 0 0 1 20 14.5v4A1.5 1.5 0 0 1 18.5 20h-4A1.5 1.5 0 0 1 13 18.5z'/%3E%3C/svg%3E");
}


/* Keep the inline icon away from the card edges: a little more top air and a
   clear gap before the label. */
.stat .stat-icon {
    margin: 2px 0 12px;
    width: 20px;
    height: 20px;
    opacity: 1;
}

/* The watermark sat too close to the bottom edge; lift and shrink it so the
   number never competes with it. */
.stat::after {
    right: -4px;
    bottom: -10px;
    width: 84px;
    height: 84px;
    opacity: .08;
}

.stat:hover::after {
    opacity: .12;
}

/* Cards without a metric key (older markup) still get a default accent */
.stat:not([data-stat]) {
    --stat-accent: var(--orange);
}


/* ==========================================================================
   Stat watermark — final placement
   The glyph now lifts off the bottom edge and shrinks so it reads as a
   backdrop, not a second icon. `assigned` gets its own glyph so it no longer
   duplicates the "total" grid icon.
   ========================================================================== */

.stat::after {
    right: -2px;
    bottom: 4px;
    width: 76px;
    height: 76px;
    opacity: .07;
}

.stat:hover::after {
    opacity: .11;
}

/* Distinct glyph for the dashboard's "โครงงานในความรับผิดชอบ" card */
.stat[data-stat="assigned"]::after {
    --stat-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 4.5h6a1.5 1.5 0 0 1 1.5 1.5v.5H16a1 1 0 0 0 0 2h.5V18a1.5 1.5 0 0 1-1.5 1.5H9A1.5 1.5 0 0 1 7.5 18V6A1.5 1.5 0 0 1 9 4.5z'/%3E%3Cpath d='M10 10h4M10 13.5h4'/%3E%3C/svg%3E");
}

/* ==========================================================================
   Stat border — kill the legacy first-child accent
   app.css has `.stat:first-child { border-top: 3px solid var(--orange) }`,
   which painted an orange edge on whichever card happened to be first — on
   the catalog page that was "ระดับ ปวช.". No stat card should carry it.
   ========================================================================== */

.stat:first-child,
.card.stat,
section.card.stat,
.stats .stat:first-child,
.grid .stat:first-child {
    border-top: 1px solid var(--line);
    border-top-width: 1px;
}

/* Cards that use the .card + .stat combination need the stat layout too */
.card.stat {
    position: relative;
    overflow: hidden;
    display: block;
    padding: 20px 20px 18px;
    background: linear-gradient(180deg, #ffffff 0%, #fffaf7 100%);
    box-shadow: var(--shadow-1);
}

.card.stat b {
    display: block;
    font-size: 34px;
    line-height: 1.15;
    font-weight: 700;
    letter-spacing: -1px;
    font-variant-numeric: tabular-nums;
    color: var(--ink);
}

.card.stat span {
    display: block;
    margin-bottom: 6px;
    font-size: 12px;
    font-weight: 500;
    color: var(--ink-soft);
}

.card.stat small {
    display: block;
    margin-top: 2px;
    font-size: 11px;
    color: var(--muted);
}

.card.stat .stat-icon {
    margin: 2px 0 12px;
}


/* ==========================================================================
   Stat accents — per-metric colours, declared last so nothing resets them
   ========================================================================== */

.stat[data-stat] {
    /* fallback only; per-key rules below override it */
    --stat-accent: var(--orange);
    --stat-wash: rgba(237, 100, 37, .16);
}

.stat[data-stat="total"],
.stat[data-stat="classes"],
.stat[data-stat="assigned"] {
    --stat-accent: #c15a1c;
    --stat-wash: rgba(237, 100, 37, .18);
}

.stat[data-stat="waiting"] {
    --stat-accent: #b8791a;
    --stat-wash: rgba(230, 165, 40, .20);
}

.stat[data-stat="passed"],
.stat[data-stat="higher"] {
    --stat-accent: #2f8f5b;
    --stat-wash: rgba(47, 143, 91, .16);
}

.stat[data-stat="completed"],
.stat[data-stat="vocational"] {
    --stat-accent: #2f6ea5;
    --stat-wash: rgba(47, 110, 165, .16);
}

.stat[data-stat="staff"] {
    --stat-accent: #7a5ea8;
    --stat-wash: rgba(122, 94, 168, .16);
}


/* ==========================================================================
   Stat watermark — corner placement, fully inside the card
   Previously right:-2px / bottom:4px pushed the glyph past the right edge and
   pinned it to the bottom. Sit it in the lower-right corner with a matching
   inset on both sides, clear of the card's border.
   ========================================================================== */

.stat::after {
    right: 10px;
    bottom: 10px;
    width: 78px;
    height: 78px;
    opacity: .10;
}

.stat:hover::after {
    opacity: .15;
}

/* On narrow cards the value can reach the corner; shrink the glyph so it
   stays a backdrop rather than colliding with the digits. */
@media (max-width: 720px) {
    .stat::after {
        right: 8px;
        bottom: 8px;
        width: 60px;
        height: 60px;
    }
}


/* Align the watermark's inset with the card's own 20px padding so it sits on
   the same optical grid as the icon and the number. */
.stat::after {
    right: 18px;
    bottom: 16px;
    width: 72px;
    height: 72px;
    opacity: .11;
}

.stat:hover::after {
    opacity: .16;
}


/* ==========================================================================
   Stat watermark — restore the mask fill
   The `background:` shorthand on `.stat` / `.card.stat` cascaded into the
   ::after pseudo-element and wiped its background-color, so the mask had
   nothing to cut and only the first card (which had an explicit colour)
   rendered. Re-declare the fill last, keyed to each card's accent.
   ========================================================================== */

.stat::after,
.card.stat::after,
.stats .stat::after {
    background-color: var(--stat-accent, var(--orange));
    background-image: none;
    -webkit-mask-image: var(--stat-glyph);
    mask-image: var(--stat-glyph);
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-size: contain;
    mask-size: contain;
}

/* ==========================================================================
   Week status card — "where are we now" banner on the dashboard
   Sits directly under the calendar hero. Reads as an alert: week number,
   term progress, and the next thing to do.
   ========================================================================== */

.week-card {
    position: relative;
    overflow: hidden;
    margin-bottom: 22px;
    padding: 20px 24px 18px;
    border-radius: var(--radius-lg);
    border: 1px solid var(--orange-line);
    background:
        radial-gradient(90% 140% at 100% 0%, rgba(237, 100, 37, .14) 0%, rgba(237, 100, 37, 0) 62%),
        linear-gradient(180deg, #fffaf6 0%, #fdf2ea 100%);
    box-shadow: var(--shadow-2);
}

.week-head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px 14px;
    margin-bottom: 14px;
}

.week-head h2 {
    margin: 0;
    font-size: 17px;
    font-weight: 600;
    letter-spacing: -.2px;
    color: var(--ink);
}

.week-chip {
    display: inline-flex;
    align-items: baseline;
    gap: 4px;
    padding: 4px 12px;
    border-radius: 999px;
    background: linear-gradient(180deg, #f8996a 0%, #ef7439 100%);
    color: #2b1608;
    font-size: 12px;
    font-weight: 700;
    white-space: nowrap;
    box-shadow: 0 1px 2px rgba(150, 60, 14, .18);
}

.week-chip-total {
    font-weight: 500;
    opacity: .78;
}

/* Term progress rail */
.week-progress {
    position: relative;
    height: 8px;
    border-radius: 6px;
    background: #f0e2d7;
    overflow: hidden;
    margin-bottom: 18px;
}

.week-progress-fill {
    display: block;
    height: 100%;
    border-radius: 6px;
    background: linear-gradient(90deg, #f8a273 0%, var(--orange) 100%);
    transition: width 420ms var(--ease);
}

.week-body {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 20px;
    flex-wrap: wrap;
}

.week-next {
    min-width: 0;
    flex: 1 1 320px;
}

.week-next-kind {
    display: inline-block;
    margin-bottom: 5px;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--orange-ink);
}

.week-next h3 {
    margin: 0 0 4px;
    font-size: 15px;
    font-weight: 600;
    line-height: 1.45;
    color: var(--ink);
    overflow-wrap: anywhere;
}

.week-next p {
    margin: 0;
    font-size: 12px;
}

.week-next.is-done .week-next-kind,
.week-next.is-idle .week-next-kind {
    color: var(--muted);
}

.week-next.is-done h3,
.week-next.is-idle h3 {
    font-size: 14px;
    font-weight: 500;
    color: var(--ink-soft);
}

/* Per-class week list (staff / multi-group view) */
.week-classes {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 0;
    padding: 0;
    flex: 0 1 auto;
}

.week-classes li {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: 999px;
    background: rgba(255, 255, 255, .8);
    border: 1px solid var(--orange-line);
    font-size: 11px;
    color: var(--ink-soft);
    white-space: nowrap;
}

.week-class-code {
    font-weight: 600;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
}

.week-class-level {
    color: var(--muted);
}

.week-class-week {
    color: var(--orange-ink);
    font-weight: 600;
}

.week-link {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin-top: 14px;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--orange-ink);
    text-decoration: none;
}

.week-link:hover {
    color: var(--orange-strong);
    text-decoration: underline;
    text-underline-offset: 3px;
}

@media (max-width: 720px) {
    .week-card {
        padding: 16px 16px 14px 18px;
    }

    .week-head h2 {
        font-size: 15px;
    }

    .week-body {
        gap: 14px;
    }

    .week-classes {
        flex-basis: 100%;
    }
}

@media (prefers-reduced-motion: reduce) {
    .week-progress-fill {
        transition: none;
    }
}

/* Width classes for the week progress bar (shares the .w0-.w100 scale) */
.week-progress-fill.w0 { width: 0%; }
.week-progress-fill.w1 { width: 1%; }
.week-progress-fill.w2 { width: 2%; }
.week-progress-fill.w3 { width: 3%; }
.week-progress-fill.w4 { width: 4%; }
.week-progress-fill.w5 { width: 5%; }
.week-progress-fill.w6 { width: 6%; }
.week-progress-fill.w7 { width: 7%; }
.week-progress-fill.w8 { width: 8%; }
.week-progress-fill.w9 { width: 9%; }
.week-progress-fill.w10 { width: 10%; }
.week-progress-fill.w11 { width: 11%; }
.week-progress-fill.w12 { width: 12%; }
.week-progress-fill.w13 { width: 13%; }
.week-progress-fill.w14 { width: 14%; }
.week-progress-fill.w15 { width: 15%; }
.week-progress-fill.w16 { width: 16%; }
.week-progress-fill.w17 { width: 17%; }
.week-progress-fill.w18 { width: 18%; }
.week-progress-fill.w19 { width: 19%; }
.week-progress-fill.w20 { width: 20%; }
.week-progress-fill.w21 { width: 21%; }
.week-progress-fill.w22 { width: 22%; }
.week-progress-fill.w23 { width: 23%; }
.week-progress-fill.w24 { width: 24%; }
.week-progress-fill.w25 { width: 25%; }
.week-progress-fill.w26 { width: 26%; }
.week-progress-fill.w27 { width: 27%; }
.week-progress-fill.w28 { width: 28%; }
.week-progress-fill.w29 { width: 29%; }
.week-progress-fill.w30 { width: 30%; }
.week-progress-fill.w31 { width: 31%; }
.week-progress-fill.w32 { width: 32%; }
.week-progress-fill.w33 { width: 33%; }
.week-progress-fill.w34 { width: 34%; }
.week-progress-fill.w35 { width: 35%; }
.week-progress-fill.w36 { width: 36%; }
.week-progress-fill.w37 { width: 37%; }
.week-progress-fill.w38 { width: 38%; }
.week-progress-fill.w39 { width: 39%; }
.week-progress-fill.w40 { width: 40%; }
.week-progress-fill.w41 { width: 41%; }
.week-progress-fill.w42 { width: 42%; }
.week-progress-fill.w43 { width: 43%; }
.week-progress-fill.w44 { width: 44%; }
.week-progress-fill.w45 { width: 45%; }
.week-progress-fill.w46 { width: 46%; }
.week-progress-fill.w47 { width: 47%; }
.week-progress-fill.w48 { width: 48%; }
.week-progress-fill.w49 { width: 49%; }
.week-progress-fill.w50 { width: 50%; }
.week-progress-fill.w51 { width: 51%; }
.week-progress-fill.w52 { width: 52%; }
.week-progress-fill.w53 { width: 53%; }
.week-progress-fill.w54 { width: 54%; }
.week-progress-fill.w55 { width: 55%; }
.week-progress-fill.w56 { width: 56%; }
.week-progress-fill.w57 { width: 57%; }
.week-progress-fill.w58 { width: 58%; }
.week-progress-fill.w59 { width: 59%; }
.week-progress-fill.w60 { width: 60%; }
.week-progress-fill.w61 { width: 61%; }
.week-progress-fill.w62 { width: 62%; }
.week-progress-fill.w63 { width: 63%; }
.week-progress-fill.w64 { width: 64%; }
.week-progress-fill.w65 { width: 65%; }
.week-progress-fill.w66 { width: 66%; }
.week-progress-fill.w67 { width: 67%; }
.week-progress-fill.w68 { width: 68%; }
.week-progress-fill.w69 { width: 69%; }
.week-progress-fill.w70 { width: 70%; }
.week-progress-fill.w71 { width: 71%; }
.week-progress-fill.w72 { width: 72%; }
.week-progress-fill.w73 { width: 73%; }
.week-progress-fill.w74 { width: 74%; }
.week-progress-fill.w75 { width: 75%; }
.week-progress-fill.w76 { width: 76%; }
.week-progress-fill.w77 { width: 77%; }
.week-progress-fill.w78 { width: 78%; }
.week-progress-fill.w79 { width: 79%; }
.week-progress-fill.w80 { width: 80%; }
.week-progress-fill.w81 { width: 81%; }
.week-progress-fill.w82 { width: 82%; }
.week-progress-fill.w83 { width: 83%; }
.week-progress-fill.w84 { width: 84%; }
.week-progress-fill.w85 { width: 85%; }
.week-progress-fill.w86 { width: 86%; }
.week-progress-fill.w87 { width: 87%; }
.week-progress-fill.w88 { width: 88%; }
.week-progress-fill.w89 { width: 89%; }
.week-progress-fill.w90 { width: 90%; }
.week-progress-fill.w91 { width: 91%; }
.week-progress-fill.w92 { width: 92%; }
.week-progress-fill.w93 { width: 93%; }
.week-progress-fill.w94 { width: 94%; }
.week-progress-fill.w95 { width: 95%; }
.week-progress-fill.w96 { width: 96%; }
.week-progress-fill.w97 { width: 97%; }
.week-progress-fill.w98 { width: 98%; }
.week-progress-fill.w99 { width: 99%; }
.week-progress-fill.w100 { width: 100%; }

/* ==========================================================================
   Week card — event detail disclosure
   Exam briefings run 500+ characters. Show a two-line preview and let the
   reader open the rest, so the card never becomes a wall of text.
   ========================================================================== */

.week-due {
    margin: 2px 0 12px;
    font-size: 12px;
    line-height: 1.6;
    color: var(--ink-soft);
    font-variant-numeric: tabular-nums;
}

/* One text block that clamps when collapsed and expands in place.
   No wrapper box inside a wrapper box. */
.week-detail {
    margin: 0;
    padding: 0;
    border: 0;
    background: none;
    box-shadow: none;
}

.week-detail > summary {
    display: block;
    padding: 0;
    margin: 0;
    border: 0;
    background: none;
    cursor: pointer;
    list-style: none;
}

.week-detail > summary::-webkit-details-marker {
    display: none;
}

.week-detail-text {
    display: block;
    margin: 0;
    padding: 0;
    font-size: 12px;
    line-height: 1.75;
    color: var(--ink-soft);
    overflow-wrap: anywhere;
}

/* Collapsed: two lines, no box, just text with a fade at the cut */
.week-detail:not([open]) .week-detail-text {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.week-detail-toggle {
    display: inline-flex;
    align-items: center;
    margin-top: 6px;
}

.week-detail-more {
    font-size: 11.5px;
    font-weight: 600;
    color: var(--orange-ink);
    letter-spacing: .1px;
}

.week-detail-more::after {
    content: " ▾";
    font-size: 9px;
    line-height: 1;
}

.week-detail[open] .week-detail-more::after {
    content: " ▴";
}

/* Plain (short) detail: same typography, no disclosure affordance */
p.week-detail-text {
    margin: 0 0 4px;
}
}

/* ==========================================================================
   Week card — second upcoming item
   The extra row was unstyled, so its inline spans overlapped the primary
   column. Give it its own block with a divider above.
   ========================================================================== */

.week-next-second {
    margin-top: 12px;
    padding-top: 11px;
    border-top: 1px dashed var(--orange-line);
    display: block;
    width: 100%;
    min-width: 0;
}

.week-next-second .week-next-kind {
    display: block;
    margin-bottom: 3px;
    color: var(--muted);
    letter-spacing: .8px;
}

.week-next-line {
    display: block;
    font-size: 12px;
    line-height: 1.6;
    color: var(--ink-soft);
    overflow-wrap: anywhere;
}

.week-next-line strong {
    font-weight: 600;
    color: var(--ink);
}

/* The primary column should not stretch under the class chips; keep the body
   a two-column row where the second column only holds the chips. */
.week-body {
    align-items: flex-start;
}

.week-next {
    flex: 1 1 100%;
    max-width: 100%;
}

.week-classes {
    order: 2;
    flex: 0 0 auto;
}

@media (min-width: 900px) {
    .week-next {
        flex: 1 1 auto;
        max-width: calc(100% - 300px);
    }
}


/* The class chips were forced onto one line (white-space:nowrap inherited
   into a 4-chip row) and overflowed a 360px card by 300px. Let them wrap and
   cap the row width on small screens. */
.week-classes {
    flex-wrap: wrap;
    max-width: 100%;
    min-width: 0;
}

.week-classes li {
    max-width: 100%;
    min-width: 0;
}

@media (max-width: 720px) {
    .week-classes {
        gap: 5px;
    }

    .week-classes li {
        font-size: 10.5px;
        padding: 3px 8px;
        white-space: normal;
    }

    .week-class-code {
        font-size: 10.5px;
    }
}


/* ==========================================================================
   Week card — vertical rhythm
   The body was a flex row, so the primary column, the second event and the
   class chips all competed for the same line and landed at mismatched
   positions. Stack them in reading order instead.
   ========================================================================== */

.week-body {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
}

.week-next {
    flex: 0 0 auto;
    max-width: 100%;
    min-width: 0;
}

.week-next-second {
    margin-top: 14px;
    padding-top: 12px;
}

.week-classes {
    margin-top: 14px;
    order: 0;
    flex: 0 0 auto;
}

/* Tighter, uniform spacing between the stacked blocks */
.week-next h3 {
    margin: 0 0 5px;
}

.week-due {
    margin: 0 0 10px;
}

.week-detail,
p.week-detail-text {
    margin: 0;
}

.week-link {
    margin-top: 16px;
}


/* ==========================================================================
   Week card — detail panel
   The full briefing belongs inside the disclosure, in a white panel, not
   sitting open beneath the summary. Collapsed shows only the toggle.
   ========================================================================== */

.week-detail > summary {
    display: inline-flex;
    align-items: center;
    padding: 0;
    margin: 0;
    border: 0;
    background: none;
    cursor: pointer;
    list-style: none;
}

.week-detail-panel {
    margin-top: 10px;
    padding: 14px 16px;
    border-radius: 10px;
    background: #ffffff;
    border: 1px solid var(--line);
    box-shadow: 0 1px 2px rgba(31, 36, 43, .04);
    max-width: 100%;
}

.week-detail-panel > p {
    margin: 0;
    font-size: 12px;
    line-height: 1.8;
    color: var(--ink-soft);
    overflow-wrap: anywhere;
}

/* A long briefing should scroll rather than push the whole card down */
.week-detail-panel {
    max-height: 300px;
    overflow-y: auto;
}

.week-detail-panel::-webkit-scrollbar {
    width: 8px;
}

.week-detail-panel::-webkit-scrollbar-thumb {
    background: #ded6cd;
    border-radius: 8px;
}

.week-detail-panel::-webkit-scrollbar-track {
    background: transparent;
}

@media (max-width: 720px) {
    .week-detail-panel {
        padding: 12px 13px;
        max-height: 240px;
    }

    .week-detail-panel > p {
        font-size: 11.5px;
        line-height: 1.75;
    }
}


/* `<details>` hides its body via content-visibility, not display:none. Setting
   `display` on the panel made it visible while collapsed. Only style it when
   the details element is actually open. */
.week-detail:not([open]) .week-detail-panel {
    display: none;
}

.week-detail[open] .week-detail-panel {
    display: block;
}

/* Let the panel size to its content up to the cap rather than a fixed box */
.week-detail-panel {
    max-height: none;
    overflow: visible;
}

.week-detail[open] .week-detail-panel {
    max-height: 320px;
    overflow-y: auto;
}

/* ==========================================================================
   Week card — meta badges
   "กำหนดสอบ / อีก 3 วัน" and "ถัดไป / ติดตามความก้าวหน้า" read as labels, so
   they wear badge chips rather than plain uppercase text.
   ========================================================================== */

.week-next-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-bottom: 8px;
}

.week-badge {
    display: inline-flex;
    align-items: center;
    height: 21px;
    padding: 0 10px;
    border-radius: 999px;
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: .2px;
    line-height: 1;
    white-space: nowrap;
}

/* Kind: the brand accent — this is what the item IS */
.week-badge-kind {
    background: linear-gradient(180deg, #fff2e8 0%, #fde4d4 100%);
    border: 1px solid var(--orange-line);
    color: var(--orange-ink);
}

/* When: urgency, sits quieter than the kind */
.week-badge-when {
    background: #ffffff;
    border: 1px solid var(--line-strong);
    color: var(--ink-soft);
    font-weight: 500;
}

/* Secondary/contextual chips (ถัดไป, ล่าสุด, ยังไม่มีกำหนดการ) */
.week-badge-muted {
    background: #f3f4f6;
    border: 1px solid var(--line);
    color: var(--muted);
    font-weight: 500;
}

/* The old uppercase label is no longer used; keep the selector harmless */
.week-next-kind {
    display: none;
}

/* Second item's badges sit above its one-line summary */
.week-next-second .week-next-meta {
    margin-bottom: 5px;
}

/* ==========================================================================
   Week card — calendar buttons and corner watermark
   ========================================================================== */

/* The CTA is now a real button, so drop the old link styling and give it the
   same rhythm as the rest of the button system. */
.week-card .week-cta {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 38px;
    min-height: 38px;
    margin-top: 16px;
    padding: 0 16px;
    font-size: 12.5px;
    font-weight: 600;
}

.btn-icon {
    display: block;
    flex: 0 0 auto;
    transition: transform var(--fast) var(--ease);
}

.button:hover .btn-icon {
    transform: translateX(2px);
}

/* Retirement of the old text-link rule */
.week-link {
    display: none;
}

/* ---------- Calendar watermark, right side ---------- */

.week-card::after {
    content: "";
    position: absolute;
    right: 22px;
    top: 50%;
    transform: translateY(-50%);
    width: 118px;
    height: 118px;
    z-index: 0;
    opacity: .08;
    background-color: var(--orange);
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4.5' width='18' height='16' rx='2.2'/%3E%3Cpath d='M8 2.5v4M16 2.5v4M3 10h18'/%3E%3Cpath d='M7.5 13.5h2M11 13.5h2M14.5 13.5h2M7.5 17h2M11 17h2'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4.5' width='18' height='16' rx='2.2'/%3E%3Cpath d='M8 2.5v4M16 2.5v4M3 10h18'/%3E%3Cpath d='M7.5 13.5h2M11 13.5h2M14.5 13.5h2M7.5 17h2M11 17h2'/%3E%3C/svg%3E");
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-position: center;
    mask-position: center;
    pointer-events: none;
}

/* Keep content above the watermark */
.week-head,
.week-progress,
.week-body {
    position: relative;
    z-index: 1;
}

/* On narrow screens the glyph would sit behind the text; shrink and fade it */
@media (max-width: 1100px) {
    .week-card::after {
        width: 92px;
        height: 92px;
        right: 16px;
        opacity: .06;
    }
}

@media (max-width: 720px) {
    .week-card::after {
        width: 74px;
        height: 74px;
        right: 12px;
        top: 64px;
        transform: none;
        opacity: .05;
    }
}


/* Watermark readability: .08 was nearly invisible against the warm card.
   Lift it and anchor it to the upper-right, clear of the chips below. */
.week-card::after {
    right: 26px;
    top: 54px;
    transform: none;
    width: 112px;
    height: 112px;
    opacity: .16;
    background-color: #c15a1c;
}

@media (max-width: 1100px) {
    .week-card::after {
        width: 92px;
        height: 92px;
        right: 18px;
        top: 48px;
        opacity: .13;
    }
}

@media (max-width: 720px) {
    .week-card::after {
        width: 70px;
        height: 70px;
        right: 12px;
        top: 46px;
        opacity: .11;
    }
}


/* Watermark +30% as requested: 112px -> 146px (and the responsive steps scale
   with it so the proportion stays the same at every width). */
.week-card::after {
    width: 146px;
    height: 146px;
    right: 24px;
    top: 46px;
    opacity: .15;
}

@media (max-width: 1100px) {
    .week-card::after {
        width: 120px;
        height: 120px;
        right: 18px;
        top: 44px;
        opacity: .13;
    }
}

@media (max-width: 720px) {
    .week-card::after {
        width: 92px;
        height: 92px;
        right: 12px;
        top: 42px;
        opacity: .11;
    }
}


/* Watermark: larger again and anchored to the lower-right of the card. */
.week-card::after {
    width: 190px;
    height: 190px;
    right: 18px;
    top: auto;
    bottom: -18px;
    opacity: .15;
}

@media (max-width: 1100px) {
    .week-card::after {
        width: 150px;
        height: 150px;
        right: 14px;
        bottom: -14px;
        opacity: .13;
    }
}

@media (max-width: 720px) {
    .week-card::after {
        width: 112px;
        height: 112px;
        right: 10px;
        bottom: -10px;
        opacity: .11;
    }
}


/* Keep the enlarged glyph fully inside the card's rounded corner instead of
   straddling the bottom edge. */
.week-card::after {
    right: 20px;
    bottom: 6px;
    width: 190px;
    height: 190px;
}

@media (max-width: 1100px) {
    .week-card::after {
        width: 150px;
        height: 150px;
        right: 16px;
        bottom: 6px;
    }
}

@media (max-width: 720px) {
    .week-card::after {
        width: 108px;
        height: 108px;
        right: 12px;
        bottom: 6px;
    }
}


/* ==========================================================================
   Pagination — shared presentation, centred
   The markup now comes from pagination() in core.php, so one rule set styles
   every page: dashboard, admin lists, follow-up and any future pager.
   ========================================================================== */

.pagination-wrap {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    margin-top: 20px;
    padding-top: 16px;
    border-top: 1px solid var(--line);
    text-align: center;
}

.pagination-summary {
    margin: 0;
    font-size: 12px;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

.pagination {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 6px;
    margin: 0;
    padding: 0;
    width: auto;
    overflow: visible;
}

/* ==========================================================================
   Week card — tighter detail gap, divider before the next item
   ========================================================================== */

.week-detail {
    margin-top: 0;
}

.week-detail > summary {
    margin: 0 0 0 0;
}

.week-detail-panel {
    margin-top: 6px;   /* was 10px — sits closer to its own trigger */
    padding: 12px 14px;
}

/* A visible rule separates "now" from "next", matching the second-item block */
.week-next-second {
    margin-top: 16px;
    padding-top: 14px;
    border-top: 1px solid var(--orange-line);
}

/* ==========================================================================
   Form spacing — one rhythm site-wide
   Cards were stacking a heading, a form and a table with ad-hoc margins.
   ========================================================================== */

.card > form,
.card > .filter-form,
.card > .grid {
    margin-top: 4px;
}

.card > .field,
.card > label.field {
    margin-bottom: 14px;
}

.card > .actions,
.card > form + .actions,
.card > .tablewrap {
    margin-top: 18px;
}

/* The actions row that follows a filter form needs air before the table */
.actions + .tablewrap,
.actions + table {
    margin-top: 18px;
}

/* ==========================================================================
   Collapsible blocks — one standard
   details elements across the app (status, audit trail, add-user, password
   reset) had browser-default styling. Give them all the same shape.
   ========================================================================== */

.card details,
details:not([class]) {
    border: 1px solid var(--line);
    border-radius: 10px;
    background: var(--surface);
    padding: 0;
    margin: 12px 0;
    overflow: hidden;
    transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}

.card details:hover,
details:not([class]):hover {
    border-color: var(--line-strong);
}

.card details > summary,
details:not([class]) > summary {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 14px;
    font-size: 13px;
    font-weight: 600;
    color: var(--ink);
    cursor: pointer;
    list-style: none;
    background: linear-gradient(90deg, rgba(237, 100, 37, .055) 0%, rgba(237, 100, 37, 0) 72%);
    transition: background var(--fast) var(--ease);
}

.card details > summary::-webkit-details-marker,
details:not([class]) > summary::-webkit-details-marker {
    display: none;
}

.card details > summary:hover,
details:not([class]) > summary:hover {
    background: linear-gradient(90deg, rgba(237, 100, 37, .10) 0%, rgba(237, 100, 37, .02) 72%);
}

/* Chevron on the right, rotates when open */
.card details > summary::after,
details:not([class]) > summary::after {
    content: "";
    margin-left: auto;
    width: 7px;
    height: 7px;
    flex: 0 0 auto;
    border-right: 2px solid var(--orange-ink);
    border-bottom: 2px solid var(--orange-ink);
    transform: rotate(45deg) translateY(-2px);
    transition: transform var(--fast) var(--ease);
}

.card details[open] > summary::after,
details:not([class])[open] > summary::after {
    transform: rotate(-135deg) translateY(-2px);
}

.card details[open] > summary,
details:not([class])[open] > summary {
    border-bottom: 1px solid var(--line);
    margin-bottom: 0;
}

/* Body padding: the content is always wrapped in something after summary */
.card details > summary ~ *,
details:not([class]) > summary ~ * {
    margin-left: 14px;
    margin-right: 14px;
}

.card details > summary ~ *:last-child,
details:not([class]) > summary ~ *:last-child {
    margin-bottom: 14px;
}

.card details > summary ~ *:first-of-type,
details:not([class]) > summary ~ *:first-of-type {
    margin-top: 14px;
}

/* The week-card detail keeps its own minimal look */
.week-detail {
    border: 0 !important;
    background: none !important;
    border-radius: 0 !important;
    margin: 0 !important;
    overflow: visible !important;
}

.week-detail > summary {
    padding: 0 !important;
    background: none !important;
    font-size: 11.5px;
    color: var(--orange-ink);
}

.week-detail > summary::after {
    content: none !important;
}


/* ==========================================================================
   Header icon buttons — password (key) and sign-out
   Same size and rhythm, different colour so the destructive action reads
   apart from the routine one.
   ========================================================================== */

.icon-button,
.logout-button {
    display: inline-grid;
    place-items: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border-radius: 10px;
    border: 1px solid transparent;
    cursor: pointer;
    transition: transform var(--fast) var(--ease),
                box-shadow var(--fast) var(--ease),
                background var(--fast) var(--ease),
                border-color var(--fast) var(--ease);
    text-decoration: none;
}

/* Key — routine action, quiet orange tint */
.icon-button {
    background: var(--orange-wash);
    border-color: var(--orange-line);
    color: var(--orange-ink);
    box-shadow: 0 1px 2px rgba(31, 36, 43, .05);
}

.icon-button:hover {
    background: #fbe4d7;
    border-color: #eec3aa;
    color: var(--orange-strong);
    box-shadow: 0 2px 6px -1px rgba(150, 60, 14, .18);
    text-decoration: none;
}

/* Sign out — a different hue so it is not mistaken for the key */
.logout-button {
    background: #c94141;
    border-color: #b93636;
    color: #ffffff;
    box-shadow: 0 1px 2px rgba(31, 36, 43, .18);
}

.logout-button:hover {
    background: #b33232;
    box-shadow: 0 2px 6px -1px rgba(31, 36, 43, .24);
}

.icon-button:active,
.logout-button:active {
    transform: translateY(1px);
}

.icon-button:focus-visible,
.logout-button:focus-visible {
    outline: 2px solid var(--orange);
    outline-offset: 2px;
}

/* Group the two icons with a small gap */
.header-account {
    gap: 12px;
}

.header-account .header-session-actions {
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;
    order: 2;
    gap: 8px;
}

.header-session-actions .logout-form { margin: 0; }
.header-session-actions .icon-button,
.header-session-actions .logout-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    min-height: 38px;
    margin: 0;
    padding: 0;
    border-radius: 10px;
    flex: 0 0 38px;
}

.actions .invention-edit { background: #fff0e5; border-color: #efcdb7; color: #a1491d; }
.actions .invention-edit:hover { background: #fce0cd; }
td form > button.education-type-save { background: var(--orange); color: #fff; border: 1px solid var(--orange); }
td form > button.education-type-save:hover { background: #d85116; border-color: #d85116; }
.actions .invention-toggle--close { background: #fdefee; border-color: #edc5c3; color: #a23d3b; }
.actions .invention-toggle--close:hover { background: #f9dddb; }
.actions .invention-toggle--open { background: #e7f5ec; border-color: #bdddc9; color: #28754e; }
.actions .invention-toggle--open:hover { background: #d4eddf; }

@media (max-width: 720px) {
    .icon-button,
    .logout-button {
        width: 32px;
        height: 32px;
    }
}

/* Compact buttons for in-table actions: same shape, smaller footprint so a
   row of them never dominates the data. */
.button.button-compact {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 32px;
    min-height: 32px;
    padding: 0 12px;
    font-size: 12px;
    font-weight: 600;
    border-radius: 8px;
    white-space: nowrap;
}

.button.button-compact .btn-icon {
    width: 12px;
    height: 12px;
}

/* ---- One button style across every page ---- */

/* Links that used to act like buttons inside tables */
td > a:not(.button):not(.badge) {
    font-weight: 500;
}

/* Keep calendar + projector CTAs visually identical to the week-card CTA */
.hero .button,
.calendar-hero .button {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 40px;
    min-height: 40px;
    padding: 0 18px;
    font-size: 13px;
    font-weight: 600;
}


/* ==========================================================================
   Pagination — remove the separators
   Two rules each drew a top border: the old standalone `.pagination` block and
   the newer `.pagination-wrap`. Together they read as a doubled line above the
   pager. The table already ends with its own rule, so neither is needed.
   ========================================================================== */

.pagination-wrap {
    border-top: 0;
    padding-top: 0;
    margin-top: 18px;
}

.pagination {
    border-top: 0;
    padding-top: 0;
    margin-top: 0;
}

/* ==========================================================================
   Form field rhythm — the calendar filter is the reference
   Every field: label with no bottom margin, control 6px below it.
   ========================================================================== */

.field {
    display: block;
    margin: 0 0 0 0;
    font-size: 13px;
    font-weight: 500;
    line-height: 1.35;
    color: var(--ink-soft);
}

.field > input,
.field > select,
.field > textarea,
.field > .dropzone {
    margin-top: 6px;
}

/* Fields stack with one consistent gap */
form > .field + .field,
form > .field + .field {
    margin-top: 14px;
}

/* Reset the old blanket rule that added bottom margins */
.card > .field,
.card > label.field {
    margin-bottom: 0;
}

/* Buttons that close a form sit further down */
form > button:last-child,
form > .actions:last-child {
    margin-top: 18px;
}

/* Standard control height everywhere, matching the calendar filter */
.field > input:not([type="checkbox"]):not([type="radio"]),
.field > select,
.filter-form > label.field > select,
input[type="text"],
input[type="search"],
input[type="password"],
input[type="email"],
input[type="date"],
input[type="number"],
select,
textarea {
    height: 40px;
    box-sizing: border-box;
    font-size: 13px;
}

textarea {
    height: auto;
    min-height: 96px;
}

/* ==========================================================================
   Dropzone — drag & drop file field
   ========================================================================== */

.dropzone {
    position: relative;
    display: block;
    border-radius: 12px;
    border: 1.5px dashed var(--line-strong);
    background: linear-gradient(180deg, #fffdfb 0%, #fdf7f2 100%);
    transition: border-color var(--fast) var(--ease),
                background var(--fast) var(--ease),
                box-shadow var(--fast) var(--ease);
}

.dropzone:hover {
    border-color: var(--orange-line);
    background: linear-gradient(180deg, #fffaf6 0%, #fdf2ea 100%);
}

/* Drag-over state: unmistakable, but no layout shift */
.dropzone.is-dragover {
    border-color: var(--orange);
    border-style: solid;
    background: linear-gradient(180deg, #fff5ee 0%, #fdeade 100%);
    box-shadow: 0 0 0 4px rgba(237, 100, 37, .12);
}

/* The native control stays focusable but visually replaced by the label */
.dropzone-input {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

.dropzone-input:focus-visible + .dropzone-body {
    outline: 2px solid var(--orange);
    outline-offset: 3px;
    border-radius: 10px;
}

.dropzone-body {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 7px;
    padding: 26px 22px;
    text-align: center;
    cursor: pointer;
    border-radius: 12px;
}

.dropzone-icon {
    width: 30px;
    height: 30px;
    color: var(--orange);
    opacity: .85;
    transition: transform var(--fast) var(--ease), opacity var(--fast) var(--ease);
}

.dropzone:hover .dropzone-icon,
.dropzone.is-dragover .dropzone-icon {
    transform: translateY(-2px);
    opacity: 1;
}

.dropzone-title {
    font-size: 13px;
    font-weight: 600;
    color: var(--ink);
}

.dropzone-hint {
    font-size: 12px;
    color: var(--muted);
    line-height: 1.5;
}

.dropzone-browse {
    color: var(--orange-ink);
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 2px;
}

.dropzone-file {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 4px;
    padding: 5px 12px;
    border-radius: 999px;
    background: var(--orange-wash);
    border: 1px solid var(--orange-line);
    color: var(--orange-ink);
    font-size: 11.5px;
    font-weight: 600;
    overflow-wrap: anywhere;
    text-align: center;
}

.dropzone-file[hidden] {
    display: none;
}

.dropzone.has-file {
    border-color: var(--orange-line);
    border-style: solid;
    background: linear-gradient(180deg, #fffaf6 0%, #fdf2ea 100%);
}

@media (max-width: 720px) {
    .dropzone-body {
        padding: 22px 16px;
    }

    .dropzone-icon {
        width: 26px;
        height: 26px;
    }
}

/* Calendar page: the "เปิดปฏิทิน" submit should match the primary buttons
   elsewhere, not the quiet secondary outline. */
form button.secondary:not(.actions button):not(td button) {
    background: linear-gradient(180deg, #f8996a 0%, #f07840 52%, #e86f37 100%);
    border: 0;
    color: #2b1608;
    box-shadow: 0 1px 2px rgba(150, 60, 14, .20), 0 2px 8px -3px rgba(150, 60, 14, .22);
}

form button.secondary:not(.actions button):not(td button):hover {
    background: linear-gradient(180deg, #ffa87c 0%, #f5854d 52%, #ec7840 100%);
}


/* The dashed border was a 1px hairline in --line-strong, which read as almost
   invisible against the warm surface. Make it a clear 2px dash. */
.dropzone {
    border: 2px dashed #ddc9b8;
    background: linear-gradient(180deg, #fffdfb 0%, #fdf7f1 100%);
}

.dropzone:hover {
    border-color: var(--orange-line);
}

.dropzone.is-dragover {
    border-color: var(--orange);
    border-style: solid;
}

.dropzone.has-file {
    border-style: solid;
    border-color: var(--orange-line);
}


/* ==========================================================================
   Form submit spacing
   The submit button sat only 10px under the last select — visually glued.
   Give it the same 20px step used between fields, and a little more when it
   closes a filter form.
   ========================================================================== */

form > button:last-of-type,
form > .field:last-of-type + button,
form > label.field + button,
form > .field + button {
    margin-top: 20px;
}

/* Filter forms that end in a submit button */
.filter-form > button,
.calendar-filter button,
form button[type="submit"] {
    margin-top: 20px;
}

/* But not when the button already sits in an actions row (that row owns its
   own spacing). */
.actions button,
.filter-form > button.filter-apply {
    margin-top: 0;
}

/* Calendar page: the submit follows six stacked selects */
#projectCalendar button,
.calendar-filter-form > button {
    margin-top: 22px;
}


/* ==========================================================================
   Dropzone spacing
   It had no margin of its own, so it hugged whatever preceded it (the class
   select on the import page). Give it the same 16px step used between fields.
   ========================================================================== */

.dropzone {
    margin-top: 16px;
    margin-bottom: 0;
}

/* When a dropzone follows a field directly, keep the label-to-control step
   consistent with every other field (6px is too tight for a large target). */
.field + .dropzone,
.field + .dropzone-body {
    margin-top: 16px;
}

/* Inside a .field wrapper the control step still applies */
.field > .dropzone {
    margin-top: 6px;
}

@media (max-width: 720px) {
    .dropzone {
        margin-top: 14px;
    }
}


/* The class select sits in a .field which now has margin-bottom:0, so the
   dropzone was the only thing creating separation. Add a clear step below any
   field that precedes a dropzone, matching the field-to-field rhythm. */
form > .field {
    margin-bottom: 14px;
}

form > .field:last-of-type {
    margin-bottom: 0;
}

/* Restore a consistent step between stacked fields inside forms */
form > .field + .field,
form > .field + .dropzone {
    margin-top: 14px;
}

/* The dropzone's own top margin then collapses with that step rather than
   doubling it. */
form > .field + .dropzone {
    margin-top: 16px;
}


/* ==========================================================================
   Section spacing after button rows
   An `.actions` row sat 4px above the next heading, so the buttons looked
   glued to "รายชื่อนักเรียนและนักศึกษา". Give every block that follows an
   action row a real step.
   ========================================================================== */

.actions {
    margin: 18px 0 20px;
}

.actions + h2,
.actions + h3,
.actions + .row,
.actions + p,
.actions + .tablewrap,
.actions + table,
.actions + section {
    margin-top: 22px;
}

/* Headings inside cards already carry their own top padding; make sure the
   actions row above them does not creep up. */
.actions + .muted {
    margin-top: 14px;
}

/* ==========================================================================
   Secondary/utility buttons in content — the "ดาวน์โหลดแม่แบบ CSV" case
   A lone `.button.secondary` inside a paragraph looked unlike every other
   button because it kept the old 9px radius and inline line-height.
   ========================================================================== */

.card p > .button,
.card p > a.button {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 36px;
    min-height: 36px;
    padding: 0 14px;
    margin: 2px 0;
    font-size: 12.5px;
    font-weight: 600;
    vertical-align: middle;
}

/* Give the paragraph that holds a download button breathing room below it */
.card > p:has(> .button) {
    margin-bottom: 18px;
}

/* Fallback for browsers without :has() */
.card > p + p + .dropzone {
    margin-top: 16px;
}

/* Keep the class select clear of the download button above it */
form > .field:first-of-type,
form > label.field:first-of-type {
    margin-top: 18px;
}


/* The p element inside the form (usage note) added its own margin on top of
   the field gap, producing 44px between the class select and the dropzone.
   Tame the note paragraphs inside forms. */
form > p {
    margin: 12px 0;
    font-size: 12px;
    line-height: 1.65;
    color: var(--muted);
}

form > p + .field,
form > p + label.field {
    margin-top: 12px;
}

form > .field + p {
    margin-top: 10px;
}

/* A note sitting between the field and the dropzone should not inflate the gap */
form > .field + p + .dropzone {
    margin-top: 12px;
}


/* Field bottom margins now duplicate the paragraph margins inside forms.
   One step only: the field keeps no bottom margin, the note provides the gap. */
form > .field,
form > label.field {
    margin-bottom: 0;
}

form > .field + p {
    margin-top: 8px;
}

form > .field + .dropzone,
form > .field + p + .dropzone {
    margin-top: 14px;
}


/* ==========================================================================
   Buttons inside .actions — zero out stray margins
   The form-submit rule added `margin-top: 20px` to every <button>, while
   <a class="button"> siblings kept margin 0. Inside an .actions row that made
   a button sit 10px lower than the link beside it. The row owns the spacing,
   so its children must carry none.
   ========================================================================== */

.actions > button,
.actions > a,
.actions > a.button,
.actions > .button,
.actions > form,
.actions > form > button,
.actions > span {
    margin: 0;
    flex: 0 0 auto;
    align-self: center;
}

/* Keep the row itself the single source of vertical rhythm */
.actions {
    align-items: center;
}

/* Same guarantee for inline button clusters outside .actions */
td > button,
td > a.button,
.row > button,
.row > a.button {
    margin: 0;
    vertical-align: middle;
}


/* ==========================================================================
   Final: a button inside .actions never carries its own top margin.
   The submit-spacing rules above are broad (`form > .field + button`); this
   one is scoped and declared last so it always wins.
   ========================================================================== */

.actions button,
.actions a.button,
.actions .button,
.actions form button,
.card .actions button,
.card .actions a.button,
section .actions button,
section .actions a.button {
    margin-top: 0 !important;
    margin-bottom: 0 !important;
}

/* Pending advisor requests need attention on the teacher dashboard. */
#advisor-requests.advisor-requests-pending {
    background: #fff5f5;
    border-color: #f3c5c5;
}

#advisor-requests.advisor-requests-pending > h2 {
    color: #9f303d;
    background: linear-gradient(90deg, #fbe0e3, #fff5f5);
    gap: 10px;
    line-height: 1.6;
}

#advisor-requests.advisor-requests-pending > h2::before {
    display: none;
}

#advisor-requests .advisor-request-alert {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 36px;
    width: 36px;
    height: 36px;
    border: 1px solid #efb9bf;
    border-radius: 50%;
    background: #fff0f1;
    color: #b53949;
}

#advisor-requests.advisor-requests-pending .tablewrap {
    border-color: #f3c5c5;
}

#advisor-requests.advisor-requests-pending thead th {
    background: #fce9eb;
    color: #853441;
}

#advisor-requests .advisor-request-badges {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    max-width: 320px;
}

#advisor-requests .advisor-request-badges .badge {
    max-width: 100%;
    white-space: normal;
    overflow-wrap: anywhere;
    background: #fce9eb;
    border-color: #f3c5cb;
    color: #9f303d;
}

#advisor-requests .advisor-request-semester {
    font-weight: 600;
}

#advisor-requests .advisor-request-submitted {
    margin-top: 8px;
    font-size: 12px;
    color: #636873;
}

#advisor-requests .advisor-request-submitted > span,
#advisor-requests .advisor-request-submitted > time {
    display: block;
}

#advisor-requests .button.button-compact {
    background: #b53949;
    border-color: #b53949;
    color: #fff;
    box-shadow: 0 3px 8px rgba(181, 57, 73, .16);
}

#advisor-requests .button.button-compact:hover {
    background: #982d3b;
    border-color: #982d3b;
}

#advisor-requests .button.button-compact:focus-visible {
    outline: 2px solid #b53949;
    outline-offset: 3px;
}

/* Personal project table: project identity, review status and chapter progress. */
.dashboard-projects .project-search {
    width: min(100%, 320px);
    margin: 0;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 8px;
    align-items: end;
}

.dashboard-projects .project-search .field {
    margin: 0;
}

.dashboard-projects .project-search button {
    margin: 0;
}

.dashboard-projects .project-title {
    display: block;
    min-width: 180px;
    max-width: 360px;
    font-size: 14px;
    overflow-wrap: anywhere;
    color: var(--ink);
}

.dashboard-projects .project-code {
    display: block;
    margin-top: 5px;
    color: #636873;
    font-size: 11px;
    letter-spacing: .4px;
}

.dashboard-projects .project-class-badge {
    background: #fff0e5;
    border-color: #f5d4be;
    color: #99401a;
}

.dashboard-projects .project-status-list {
    display: grid;
    gap: 10px;
    margin: 0;
    min-width: 205px;
}

.dashboard-projects .project-status-item {
    display: grid;
    grid-template-columns: 54px minmax(0, 1fr);
    gap: 8px;
    align-items: start;
}

.dashboard-projects .project-status-item dt,
.dashboard-projects .project-binding > span:first-child {
    color: #636873;
    font-size: 11px;
    padding-top: 4px;
}

.dashboard-projects .project-status-item dd {
    margin: 0;
}

.dashboard-projects .badge {
    white-space: normal;
    overflow-wrap: anywhere;
}

.dashboard-projects .badge.correction {
    background: #fde9eb;
    border-color: #f3c5cb;
    color: #9f303d;
}

.dashboard-projects .project-review-count {
    display: block;
    margin-top: 5px;
    color: #636873;
    font-size: 11px;
}

.dashboard-projects .project-progress {
    min-width: 150px;
    font-size: 12px;
    font-weight: 600;
}

.dashboard-projects progress {
    display: block;
    width: 100%;
    height: 7px;
    margin: 8px 0 12px;
    border: 0;
    border-radius: 999px;
    overflow: hidden;
    background: #eef0f3;
    accent-color: #28754e;
}

.dashboard-projects progress::-webkit-progress-bar {
    background: #eef0f3;
    border-radius: 999px;
}

.dashboard-projects progress::-webkit-progress-value {
    background: #28754e;
    border-radius: 999px;
}

.dashboard-projects progress::-moz-progress-bar {
    background: #28754e;
    border-radius: 999px;
}

.dashboard-projects .project-binding {
    display: grid;
    justify-items: start;
    gap: 4px;
}

.dashboard-projects .project-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

@media (max-width: 720px) {
    .dashboard-projects > .row {
        align-items: stretch;
    }

    .dashboard-projects .project-search {
        width: 100%;
    }

    .dashboard-projects .tablewrap {
        overflow: visible;
    }

    :is(#projects,.other-projects-table),
    :is(#projects,.other-projects-table) tbody,
    :is(#projects,.other-projects-table) tbody tr,
    :is(#projects,.other-projects-table) tbody td {
        display: block;
        width: 100%;
        min-width: 0;
    }

    :is(#projects,.other-projects-table) thead {
        display: none;
    }

    :is(#projects,.other-projects-table) tbody tr {
        padding: 16px;
        margin-bottom: 14px;
        border: 1px solid var(--line);
        border-radius: 12px;
        background: #fff;
    }

    :is(#projects,.other-projects-table) tbody tr[hidden] {
        display: none;
    }

    :is(#projects,.other-projects-table) tbody td {
        padding: 0 0 14px;
        border: 0;
    }

    :is(#projects,.other-projects-table) tbody td[data-label]:not(:first-child)::before {
        content: attr(data-label);
        display: block;
        margin-bottom: 7px;
        color: var(--ink);
        font-size: 12px;
        font-weight: 600;
    }

    :is(#projects,.other-projects-table) .project-title {
        min-width: 0;
        max-width: none;
    }

    :is(#projects,.other-projects-table) .project-action {
        padding-bottom: 0;
    }

    :is(#projects,.other-projects-table) .project-action .button {
        width: 100%;
        justify-content: center;
    }
}

/* The shared pager exposes page size only for project lists. */
.pagination-with-size {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    align-items: center;
    gap: 12px 16px;
    text-align: center;
}

.pagination-with-size .pagination-size {
    grid-column: 1;
    grid-row: 2;
    justify-content: flex-start;
}

.pagination-with-size .pagination {
    grid-column: 2;
    grid-row: 2;
    justify-content: center;
}

.pagination-with-size .pagination-summary {
    grid-column: 1 / -1;
    grid-row: 1;
}

.pagination-size {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 8px;
    margin: 0;
    color: #636873;
    font-size: 12px;
}

.pagination-size select {
    width: 72px;
    margin: 0;
    padding: 6px 10px;
}

.pagination-size button.secondary {
    margin: 0;
    padding: 6px 12px;
    min-height: 36px;
    font-size: 12px;
}

@media (max-width: 1100px) {
    .pagination-with-size {
        grid-template-columns: minmax(0, 1fr);
    }

    .pagination-with-size .pagination-size {
        grid-column: 1;
        grid-row: 2;
    }

    .pagination-with-size .pagination {
        grid-column: 1;
        grid-row: 3;
        justify-self: center;
    }
}

/* Dashboard context: keep calendar accessible without pushing KPIs down. */
.dashboard-calendar {
    margin-bottom: 20px;
    border: 1px solid var(--orange-line);
    border-radius: var(--radius-lg);
    background: #fffaf6;
}
.dashboard-calendar > summary {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 20px;
    cursor: pointer;
    list-style: none;
}
.dashboard-calendar > summary::-webkit-details-marker { display: none; }
.dashboard-calendar > summary::after {
    content: "+";
    margin-left: auto;
    color: var(--orange-ink);
    font-size: 24px;
}
.dashboard-calendar[open] > summary::after { content: "−"; }
.dashboard-calendar > summary strong { display: block; color: var(--ink); }
.dashboard-calendar > summary .dashboard-section-title { margin-bottom: 2px; }
.dashboard-calendar > summary small { display: block; color: var(--muted); margin-top: 2px; }
.dashboard-calendar > summary:focus-visible { outline: 2px solid var(--orange); outline-offset: 3px; }
.dashboard-calendar-content { padding: 0 16px 16px; }
.dashboard-calendar .calendar-hero { padding: 18px 20px; margin-bottom: 12px; }
.dashboard-calendar .calendar-hero h2 { font-size: 19px; }
.dashboard-calendar .week-card { margin-bottom: 0; box-shadow: none; }
.dashboard-member-heading { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; }
.dashboard-member-heading h2 { margin-bottom: 0; }
.dashboard-scope { padding: 3px 10px; border-radius: 999px; background: #f0f2f5; color: var(--ink-soft); font-size: 12px; }
.dashboard-member-note { font-size: 12px; }
@media (max-width: 720px) {
    .dashboard-calendar > summary { padding: 12px 14px; }
    .dashboard-calendar-content { padding: 0 10px 10px; }
    .dashboard-calendar .calendar-hero { padding: 16px; }
}

/* Budget details shared by proposal readers and committee assessment. */
.budget-summary { white-space: normal; }
.budget-align-left { text-align: left; }
.budget-align-center { text-align: center; }
.budget-align-right { text-align: right; font-variant-numeric: tabular-nums; }
