/* ==========================================================================
   WPMR-MIS — design tokens and Bootstrap overrides
   ==========================================================================

   This file is loaded *after* Bootstrap so it can override Bootstrap's own
   custom properties. The approach is deliberate: a scoped token layer on top of
   stock Bootstrap, rather than a rebuilt theme. A Bootstrap upgrade then cannot
   silently undo the design, and nothing here needs a build step.

   The screen is an operations console, not a marketing page: calm, dense, and
   readable at a glance from across the room on the Smart Board. Colour is never
   the only signal for a status — every dot and ring is paired with its label.

   Sections:
     1. Tokens
     2. Base & typography
     3. Layout: sidebar, topbar, content
     4. Components: cards, tables, forms, buttons, badges
     5. Signature element: progress rings
     6. Responsive
     7. Reduced motion & print
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
    /* Six named colours. Everything else derives from --ink at low opacity
       rather than introducing new greys, which keeps the palette disciplined. */
    --ink: #152233;          /* sidebar, headings, high-emphasis text */
    --paper: #f5f6f4;        /* page background */
    --surface: #ffffff;      /* cards, table rows */
    --accent: #c97a2b;       /* primary actions, active nav, focus ring */
    --status-ok: #2f8f6d;    /* completed / on track */
    --status-warn: #b23a2e;  /* delayed / overdue */

    /* Derived neutrals — all of them --ink at an opacity. */
    --line: rgba(21, 34, 51, 0.10);
    --line-strong: rgba(21, 34, 51, 0.18);
    --muted: rgba(21, 34, 51, 0.58);
    --muted-soft: rgba(21, 34, 51, 0.38);
    --tint: rgba(21, 34, 51, 0.03);
    --accent-tint: rgba(201, 122, 43, 0.10);

    /* 8px spacing base. */
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 16px;
    --space-4: 24px;
    --space-5: 32px;

    --radius: 6px;
    --sidebar-width: 232px;
    --topbar-height: 56px;

    /* Devanagari is appended, never inserted. A browser walks this list per
       *glyph*: English characters still resolve to IBM Plex Mono and Source
       Sans 3 exactly as before, and only characters those fonts do not contain —
       ड्यासबोर्ड, कार्यहरू — fall through to a Nepali face. Adding these names
       therefore changes nothing about how the English interface renders, and
       stops Devanagari landing on whatever default the machine happens to have. */
    --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo,
                 "Noto Sans Devanagari", "Kalimati", "Mangal", monospace;
    --font-body: "Source Sans 3", -apple-system, BlinkMacSystemFont, "Segoe UI",
                 "Noto Sans Devanagari", "Kalimati", "Mangal", sans-serif;

    /* Bootstrap overrides — these are Bootstrap's own variables. */
    --bs-primary: var(--accent);
    --bs-primary-rgb: 201, 122, 43;
    --bs-body-bg: var(--paper);
    --bs-body-color: var(--ink);
    --bs-body-font-family: var(--font-body);
    --bs-border-color: var(--line);
    --bs-border-radius: var(--radius);
    --bs-link-color: var(--accent);
    --bs-link-hover-color: #a9631f;
}

/* --------------------------------------------------------------------------
   2. Base & typography
   -------------------------------------------------------------------------- */

body {
    background: var(--paper);
    color: var(--ink);
    font-family: var(--font-body);
    font-size: 15px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6,
.section-label {
    font-family: var(--font-mono);
    font-weight: 500;
    letter-spacing: -0.01em;
}

h1 { font-size: 1.25rem; }
h2 { font-size: 1.1rem; }
h3 { font-size: 1rem; }

/* Alpine's x-cloak.
   Alpine strips this attribute once it has initialised. Without this rule the
   attribute does nothing, so every element Alpine is meant to hide renders
   visible until Alpine boots — and stays visible forever if it never does.
   It must be defined in a stylesheet the page loads before Alpine runs. */
[x-cloak] {
    display: none !important;
}

/* Small uppercase label above a block of content. */
.section-label {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    color: var(--muted);
    margin-bottom: var(--space-2);
}

/* Figures line up like a scoreboard. */
.figure-number {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    line-height: 1.1;
}

.text-muted-ink { color: var(--muted) !important; }

/* Every focusable thing gets a visible ring — keyboard users included. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 3px;
}

/* --------------------------------------------------------------------------
   3. Layout
   -------------------------------------------------------------------------- */

.app-shell {
    display: flex;
    min-height: 100vh;
    width: 100%;

    /* The sidebar is `position: sticky`, which pins vertically only — so if
       anything on the page overflows horizontally, the whole document scrolls
       sideways and the sidebar slides out of view with its labels clipped.
       `clip` stops that at the shell. It is used rather than `hidden` because
       `hidden` would make this a scroll container and break the sticky sidebar
       and topbar outright. Wide content still scrolls inside `.table-scroll`. */
    overflow-x: clip;
}

/* --- Sidebar ------------------------------------------------------------ */

.app-sidebar {
    width: var(--sidebar-width);
    flex: 0 0 var(--sidebar-width);
    background: var(--ink);
    color: rgba(255, 255, 255, 0.72);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
}

.app-sidebar__brand {
    padding: var(--space-3);
    border-bottom: 1px solid rgba(255, 255, 255, 0.10);
    color: #fff;
    font-family: var(--font-mono);
    font-size: 0.95rem;
    line-height: 1.3;
    text-decoration: none;
    display: block;
}

.app-sidebar__brand small {
    display: block;
    color: rgba(255, 255, 255, 0.5);
    font-size: 0.7rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    margin-top: 2px;
}

.app-sidebar__nav {
    padding: var(--space-2) 0;
    flex: 1;
}

.app-sidebar__section {
    padding: var(--space-3) var(--space-3) var(--space-1);
    font-size: 0.65rem;
    letter-spacing: 0.11em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.35);
    font-family: var(--font-mono);
}

.app-sidebar__link {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: 9px var(--space-3);
    color: rgba(255, 255, 255, 0.72);
    text-decoration: none;
    font-size: 0.9rem;
    /* Transparent border reserved so the active state does not shift the text. */
    border-left: 3px solid transparent;
}

.app-sidebar__link:hover {
    background: rgba(255, 255, 255, 0.05);
    color: #fff;
}

/* Active nav: a 3px accent rule, not a filled pill. */
.app-sidebar__link--active {
    border-left-color: var(--accent);
    background: rgba(255, 255, 255, 0.06);
    color: #fff;
}

.app-sidebar__icon {
    width: 18px;
    text-align: center;
    opacity: 0.85;
    flex: 0 0 18px;
}

/* --- Main column -------------------------------------------------------- */

.app-main {
    flex: 1 1 auto;
    min-width: 0; /* lets wide tables scroll instead of stretching the page */
    display: flex;
    flex-direction: column;
}

.app-topbar {
    height: var(--topbar-height);
    background: var(--surface);
    border-bottom: 1px solid var(--line);
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 var(--space-4);
    position: sticky;
    top: 0;
    z-index: 20;
}

.app-topbar__office {
    font-family: var(--font-mono);
    font-size: 0.9rem;
}

.app-content {
    padding: var(--space-4);
    flex: 1;
}

.page-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
    flex-wrap: wrap;
}

/* --------------------------------------------------------------------------
   4. Components
   -------------------------------------------------------------------------- */

.card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: none;
}

.card-header {
    background: transparent;
    border-bottom: 1px solid var(--line);
    padding: var(--space-3);
    font-family: var(--font-mono);
    font-size: 0.8rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--muted);
}

.card-body { padding: var(--space-3); }

/* --- Stat cards (the "today" strip) ------------------------------------- */

.stat-card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: var(--space-3);
    height: 100%;
    position: relative;
}

/* Thin left-edge bar, only when the figure is time-critical. */
.stat-card--warn { border-left: 3px solid var(--status-warn); }
.stat-card--ok { border-left: 3px solid var(--status-ok); }

.stat-card__value {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    font-size: 2rem;
    line-height: 1;
}

.stat-card__label {
    font-size: 0.78rem;
    color: var(--muted);
    margin-top: var(--space-1);
}

/* --- Status dots -------------------------------------------------------- */

/* A 6px dot plus its label reads calmer across a dense table than a wall of
   filled pill badges. The label is always present — colour is never alone. */
.status {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.85rem;
    white-space: nowrap;
}

.status__dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex: 0 0 7px;
    background: var(--muted-soft);
}

.status--ok .status__dot { background: var(--status-ok); }
.status--warn .status__dot { background: var(--status-warn); }
.status--accent .status__dot { background: var(--accent); }
.status--muted .status__dot { background: var(--muted-soft); }

/* --- Tables ------------------------------------------------------------- */

.table {
    --bs-table-bg: var(--surface);
    --bs-table-color: var(--ink);
    margin-bottom: 0;
    font-size: 0.9rem;
}

.table > thead > tr > th {
    font-family: var(--font-mono);
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--muted);
    font-weight: 500;
    border-bottom: 1px solid var(--line-strong);
    padding: 10px var(--space-3);
    white-space: nowrap;
}

.table > tbody > tr > td {
    border-bottom: 1px solid var(--line);
    padding: 10px var(--space-3);
    vertical-align: middle;
}

.table > tbody > tr:hover > td { background: var(--tint); }

.table-numeric {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
}

/* Wide tables scroll inside their own box; the page never scrolls sideways. */
.table-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

/* --- Forms -------------------------------------------------------------- */

.form-label {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--muted);
    margin-bottom: 4px;
}

.form-control,
.form-select {
    border: 1px solid var(--line-strong);
    border-radius: var(--radius);
    font-size: 0.92rem;
    padding: 7px 10px;
    background: var(--surface);
    color: var(--ink);
}

.form-control:focus,
.form-select:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-tint);
}

.form-text { font-size: 0.78rem; color: var(--muted); }

.invalid-feedback { font-size: 0.8rem; }

.is-invalid { border-color: var(--status-warn) !important; }

/* Filter bar above an index table. */
.filter-bar {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: var(--space-3);
    margin-bottom: var(--space-3);
}

/* --- Buttons ------------------------------------------------------------ */

.btn {
    border-radius: var(--radius);
    font-size: 0.88rem;
    padding: 7px 14px;
}

.btn-primary {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

.btn-primary:hover,
.btn-primary:focus {
    background: #a9631f;
    border-color: #a9631f;
    color: #fff;
}

.btn-outline-secondary {
    border-color: var(--line-strong);
    color: var(--ink);
}

.btn-outline-secondary:hover {
    background: var(--tint);
    border-color: var(--line-strong);
    color: var(--ink);
}

.btn-danger-quiet {
    background: transparent;
    border: 1px solid var(--line-strong);
    color: var(--status-warn);
}

.btn-danger-quiet:hover {
    background: var(--status-warn);
    border-color: var(--status-warn);
    color: #fff;
}

/* --- Notifications ------------------------------------------------------ */

.notif-bell {
    position: relative;
    background: none;
    border: none;
    color: var(--ink);
    padding: 6px;
    line-height: 1;
}

.notif-badge {
    position: absolute;
    top: 0;
    right: 0;
    background: var(--status-warn);
    color: #fff;
    font-family: var(--font-mono);
    font-size: 0.6rem;
    min-width: 15px;
    height: 15px;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 3px;
}

.notif-panel {
    position: absolute;
    right: 0;
    top: calc(100% + 6px);
    /* Fixed on a laptop, but never wider than the screen it drops onto — a flat
       330px overflows a 320px phone and drags the whole page sideways. */
    width: min(330px, calc(100vw - var(--space-4)));
    max-height: 400px;
    overflow-y: auto;
    background: var(--surface);
    border: 1px solid var(--line-strong);
    border-radius: var(--radius);
    box-shadow: 0 8px 24px rgba(21, 34, 51, 0.10);
    z-index: 40;
}

.notif-item {
    display: block;
    padding: 10px var(--space-3);
    border-bottom: 1px solid var(--line);
    color: var(--ink);
    text-decoration: none;
    font-size: 0.86rem;
}

.notif-item:hover { background: var(--tint); }
.notif-item--unread { background: var(--accent-tint); }

/* --- Empty states ------------------------------------------------------- */

.empty-state {
    text-align: center;
    padding: var(--space-5) var(--space-3);
    color: var(--muted);
}

.empty-state__title {
    font-family: var(--font-mono);
    color: var(--ink);
    font-size: 0.95rem;
    margin-bottom: var(--space-1);
}

/* --------------------------------------------------------------------------
   5. Signature element: progress rings
   --------------------------------------------------------------------------
   Branch progress is shown as ring gauges rather than horizontal bars. Rings
   read faster at a distance — a Smart Board viewer three metres away can tell
   "mostly full" from "half full" instantly — and they give the KPI module a
   visual language to reuse. This is the one place the design budget is spent:
   the stat cards stay plain numbers so the ring keeps its weight.
   -------------------------------------------------------------------------- */

.ring {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3);
}

.ring__svg {
    transform: rotate(-90deg); /* start the arc at 12 o'clock */
    flex: 0 0 auto;
}

.ring__track { stroke: var(--line); }
.ring__arc { stroke: var(--accent); stroke-linecap: butt; }
.ring__arc--ok { stroke: var(--status-ok); }
.ring__arc--warn { stroke: var(--status-warn); }

.ring__value {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-size: 0.82rem;
    font-weight: 600;
    fill: var(--ink);
}

.ring__label { font-size: 0.88rem; }
.ring__sub { font-size: 0.75rem; color: var(--muted); }

/* Slim inline bar, for places a ring would be too heavy (task rows). */
.mini-bar {
    height: 4px;
    background: var(--line);
    border-radius: 2px;
    overflow: hidden;
    min-width: 60px;
}

.mini-bar__fill {
    height: 100%;
    background: var(--accent);
    border-radius: 2px;
}

.mini-bar__fill--ok { background: var(--status-ok); }
.mini-bar__fill--warn { background: var(--status-warn); }

/* --------------------------------------------------------------------------
   6. Responsive
   --------------------------------------------------------------------------
   Under 992px the sidebar becomes an off-canvas drawer rather than a squeezed
   column — a shrunken sidebar is unusable at that width.
   -------------------------------------------------------------------------- */

@media (max-width: 991.98px) {
    .app-sidebar {
        position: fixed;
        left: 0;
        top: 0;
        z-index: 50;
        transform: translateX(-100%);
        transition: transform 0.18s ease;
        box-shadow: 0 0 40px rgba(0, 0, 0, 0.25);
    }

    .app-sidebar--open { transform: translateX(0); }

    .app-scrim {
        position: fixed;
        inset: 0;
        background: rgba(21, 34, 51, 0.45);
        z-index: 45;
    }

    .app-content { padding: var(--space-3); }
    .app-topbar { padding: 0 var(--space-3); }
}

@media (min-width: 992px) {
    .app-sidebar-toggle { display: none; }
}

/* --------------------------------------------------------------------------
   7. Reduced motion & print
   -------------------------------------------------------------------------- */

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

@media print {
    .app-sidebar,
    .app-topbar,
    .no-print { display: none !important; }

    .app-content { padding: 0; }
    .card { border: 1px solid #ccc; }
}

/* --------------------------------------------------------------------------
   8. Rich text
   --------------------------------------------------------------------------
   Descriptions are written in CKEditor and stored as HTML (sanitised on save —
   see App\Support\RichText). These rules style what comes back out, scoped to
   .rich-text so a description can never restyle the page around it.

   The allowlist in config/purifier.php admits exactly the tags styled here.
   -------------------------------------------------------------------------- */

.rich-text > *:first-child { margin-top: 0; }
.rich-text > *:last-child { margin-bottom: 0; }

.rich-text p { margin-bottom: .6rem; }

.rich-text h2 { font-size: 1rem; margin: 1rem 0 .4rem; }
.rich-text h3 { font-size: .92rem; margin: .9rem 0 .35rem; }
.rich-text h4 { font-size: .88rem; margin: .8rem 0 .3rem; }

.rich-text ul,
.rich-text ol { margin: 0 0 .6rem; padding-left: 1.3rem; }

.rich-text li { margin-bottom: .2rem; }

.rich-text blockquote {
    margin: 0 0 .6rem;
    padding-left: var(--space-3);
    border-left: 3px solid var(--line);
    color: var(--muted);
}

.rich-text a { color: var(--accent); }

.rich-text code {
    font-family: var(--font-mono);
    font-size: .85em;
    background: var(--tint);
    padding: 1px 4px;
    border-radius: 3px;
}

.rich-text pre {
    background: var(--tint);
    padding: var(--space-2);
    border-radius: var(--radius);
    overflow-x: auto;
    font-size: .85em;
}

/* --- CKEditor, matched to the design tokens ---------------------------- */

.ck.ck-editor__editable {
    min-height: 160px;
    border-color: var(--line-strong) !important;
    border-bottom-left-radius: var(--radius) !important;
    border-bottom-right-radius: var(--radius) !important;
}

.ck.ck-editor__editable.ck-focused {
    border-color: var(--accent) !important;
    box-shadow: 0 0 0 3px var(--accent-tint) !important;
}

.ck.ck-toolbar {
    border-color: var(--line-strong) !important;
    border-top-left-radius: var(--radius) !important;
    border-top-right-radius: var(--radius) !important;
    background: var(--tint) !important;
}

/* CKEditor renders into a light surface; keep it readable if the editor ever
   appears on a tinted background. */
.ck.ck-content { background: var(--surface); }

/* --------------------------------------------------------------------------
   9. Layout system
   --------------------------------------------------------------------------
   Four grids cover every screen in the application. They exist so that layout
   is decided once, here, instead of being spelled out again in col-md-* classes
   on every view — where it drifts, and where a screen nobody opened on a phone
   quietly overflows.

     .page-grid    a main column and a narrower side column
     .form-grid    fields, one/two/three columns by width
     .filter-grid  the short controls above a table
     .card-grid    a wall of equal cards

   ## Fitting every screen

   The three auto-fitting grids all size their tracks with
   `minmax(min(100%, Npx), 1fr)`. The inner `min()` is what makes them safe on a
   narrow phone: a bare `minmax(240px, 1fr)` refuses to go below 240px, so on a
   320px screen with any padding the track overflows and the whole page scrolls
   sideways. `min(100%, 240px)` lets the track shrink to the container instead.

   Extra width therefore becomes *more columns*, never wider fields — which is
   the point on an office monitor, where a stretched text input is 1400px of
   travel to read one label.
   -------------------------------------------------------------------------- */

.app-content {
    /* No cap: the content uses the screen it is given. What stops a field from
       stretching to 1400px is the column count below, not a narrower page —
       capping the container just left an empty band down one side. */
    width: 100%;
}

/* --- Main column + side column ------------------------------------------ */

.page-grid {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    gap: var(--space-3);
    align-items: start;
}

/* The narrow column first — a summary panel beside a wide table. */
.page-grid--aside-first { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); }

/* Below a laptop the side column stops being a side column and simply follows.
   Note these are classes, not inline styles: an inline grid-template-columns
   would win over this media query and leave two columns on a phone. */
@media (max-width: 991.98px) {
    .page-grid,
    .page-grid--aside-first { grid-template-columns: minmax(0, 1fr); }
}

/* An item that spans the whole row of any grid here. */
.grid-full { grid-column: 1 / -1; }

/* --- Form fields --------------------------------------------------------- */

.form-grid {
    --form-cols: 1;
    display: grid;
    grid-template-columns: repeat(var(--form-cols), minmax(0, 1fr));
    gap: var(--space-3) var(--space-4);
    align-items: start;
}

/* Fields that need the full row: rich text, checkbox grids, long notes. */
.form-grid__full { grid-column: 1 / -1; }

/* A field that wants elbow room without taking the whole row — a title, a name.
   Safe at every width: CSS Grid clamps a span to the number of columns, so on a
   one-column phone this quietly becomes a single cell. */
.form-grid__wide { grid-column: span 2; }

/* More screen buys more columns, so a field stays a readable width instead of
   growing into one: two on a laptop, three on a desktop.

   Three is the ceiling on purpose. A fourth column makes each field narrower
   than most of the values typed into it, and a form rarely has a multiple of
   four fields — so the extra column mostly buys ragged half-empty rows. Width
   beyond that goes to the page, not to more columns. */
@media (min-width: 768px)  { .form-grid { --form-cols: 2; } }
@media (min-width: 1400px) { .form-grid { --form-cols: 3; } }

/* Opt out where a form reads better as a narrow column of long fields. */
.form-grid--pair { --form-cols: 1; }

@media (min-width: 768px) { .form-grid--pair { --form-cols: 2; } }

/* Fields stacked down a panel, evenly spaced. Used inside the two-panel forms,
   where each panel is already narrow enough that a field does not need dividing
   further — the columns come from the panels themselves. */
.form-stack {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
}

/* Kept as a hook for a form that genuinely wants to be narrow (the sign-in box).
   Ordinary forms fill the width and gain columns instead. */
.form-panel { max-width: 100%; }

/* --- Filter bars --------------------------------------------------------- */

.filter-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr));
    gap: var(--space-2) var(--space-3);
    align-items: end;
}

/* The submit button should hug its text rather than stretch across a track. */
.filter-grid__actions {
    display: flex;
    gap: var(--space-2);
    align-items: center;
}

/* --- Card walls ---------------------------------------------------------- */

/* `--card-min` is the narrowest a card may get before the grid drops a column.
   Override it per use (a checkbox needs far less room than a project card); it
   only changes the density, never whether the grid fits. */
.card-grid {
    --card-min: 300px;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--card-min)), 1fr));
    gap: var(--space-3);
    align-items: start;
}

/* Figures are short, so they pack tighter than cards do. */
.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr));
    gap: var(--space-3);
}

/* --- Definition lists in a side panel ------------------------------------ */

.detail-list { margin: 0; font-size: .9rem; }
.detail-list dt { margin-bottom: 2px; }
.detail-list dd { margin-bottom: var(--space-3); }
.detail-list dd:last-child { margin-bottom: 0; }

/* --------------------------------------------------------------------------
   10. Settings panels: icon fields and image uploads
   -------------------------------------------------------------------------- */

/* Small uppercase field label, for the settings-style panels. */
.form-label--caps {
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 5px;
}

/* The required marker. Red carries the meaning, the asterisk carries it again
   for anyone who cannot see the colour. */
.req {
    color: var(--status-warn);
    margin-left: 2px;
}

/* --- Inputs with a leading icon ---------------------------------------- */

.input-group > .input-group-text {
    background: var(--tint);
    border-color: var(--line-strong);
    color: var(--muted);
    padding-inline: 10px;
}

/* Bootstrap draws the focus ring on the input alone, which leaves the icon
   sitting outside a half-highlighted control. Lift it to the whole group. */
.input-group:focus-within > .input-group-text {
    border-color: var(--accent);
    color: var(--accent);
}

.input-group:focus-within > .form-control {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-tint);
}

/* A BS date beside its time. The time box only needs enough room for HH:MM,
   so it takes its own width and the date takes the rest. */
.datetime-pair {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--space-2);
}

/* --- Image upload ------------------------------------------------------- */

.upload-field + .upload-field {
    margin-top: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px solid var(--line);
}

/* Fixed height, so the panel does not jump as images are added or removed. */
.upload-preview {
    height: 132px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-2);
    margin-bottom: var(--space-2);
    background: var(--tint);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    overflow: hidden;
}

.upload-preview img {
    max-height: 116px;
    max-width: 100%;
    object-fit: contain;
}

.upload-preview__empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    color: var(--muted-soft);
    font-size: .78rem;
}

/* --- A note at the foot of a panel -------------------------------------- */

.panel-note {
    display: flex;
    gap: var(--space-2);
    align-items: flex-start;
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: 1px solid var(--line);
    color: var(--muted);
    font-size: .82rem;
}

.panel-note .icon { flex: 0 0 auto; margin-top: 2px; }

/* Icons sit on the text baseline rather than the box's. */
.icon { vertical-align: -0.15em; }


/* --------------------------------------------------------------------------
   11. Calendar
   --------------------------------------------------------------------------
   The grid is laid out in Bikram Sambat months, so each cell carries two dates:
   the BS day as the figure you read, and the Gregorian one small beside it.
   -------------------------------------------------------------------------- */

/* --- Type filters ------------------------------------------------------- */

.cal-filters {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

.cal-filter {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 6px 13px;
    border: 1px solid var(--line-strong);
    border-radius: 100px;
    background: var(--surface);
    color: var(--ink);
    font-size: .85rem;
    text-decoration: none;
    white-space: nowrap;
}

.cal-filter:hover {
    border-color: var(--muted-soft);
    background: var(--tint);
    color: var(--ink);
}

/* The chosen filter is filled, so "which of these is on" survives a glance —
   a pill that differed only by border weight would not. */
.cal-filter--on {
    background: var(--ink);
    border-color: var(--ink);
    color: #fff;
}

.cal-filter__dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--muted-soft);
    flex: 0 0 8px;
}

.cal-filter--ok .cal-filter__dot { background: var(--status-ok); }
.cal-filter--warn .cal-filter__dot { background: var(--status-warn); }
.cal-filter--accent .cal-filter__dot { background: var(--accent); }

/* --- The grid ----------------------------------------------------------- */

.cal-grid {
    display: grid;
    /* Seven columns always — a week does not reflow. The minimum keeps a day
       legible; below that the grid scrolls inside .table-scroll rather than
       crushing the cells. */
    grid-template-columns: repeat(7, minmax(112px, 1fr));
    gap: 1px;
    background: var(--line);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    overflow: hidden;
}

.cal-grid__head {
    background: var(--tint);
    padding: 8px;
    text-align: center;
    font-family: var(--font-mono);
    font-size: .68rem;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--muted);
}

.cal-day {
    background: var(--surface);
    min-height: 104px;
    padding: 7px;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

/* Padding days from the neighbouring month: present, so the grid keeps its
   shape, but visibly not part of what you are reading. */
.cal-day--muted { background: var(--tint); }
.cal-day--muted .cal-day__bs { color: var(--muted-soft); }

.cal-day--today { box-shadow: inset 0 0 0 2px var(--accent); }

/* Saturday is the weekly holiday in Nepal, not Sunday. */
.cal-day--holiday .cal-day__bs { color: var(--status-warn); }

.cal-day__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 4px;
    margin-bottom: 2px;
}

.cal-day__bs {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-size: 1rem;
    font-weight: 600;
    line-height: 1;
}

.cal-day--today .cal-day__bs { color: var(--accent); }

.cal-day__ad {
    font-size: .66rem;
    color: var(--muted-soft);
    white-space: nowrap;
}

.cal-event {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: .74rem;
    line-height: 1.25;
    color: var(--ink);
    text-decoration: none;
    padding: 2px 4px;
    border-radius: 3px;
    background: var(--tint);
}

.cal-event:hover { background: var(--accent-tint); color: var(--ink); }

.cal-event__dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    flex: 0 0 6px;
    background: var(--muted-soft);
}

.cal-event--ok .cal-event__dot { background: var(--status-ok); }
.cal-event--warn .cal-event__dot { background: var(--status-warn); }
.cal-event--accent .cal-event__dot { background: var(--accent); }

/* One line per event: a long title must not push the cell taller than its
   neighbours and ripple the whole row. */
.cal-event__title {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cal-day__more {
    font-size: .7rem;
    color: var(--muted);
    text-decoration: none;
    margin-top: auto;
}

.cal-day__more:hover { color: var(--accent); }

/* --------------------------------------------------------------------------
   12. Nepali
   --------------------------------------------------------------------------
   Two adjustments for Devanagari, both scoped with `:lang(ne)` — which matches
   through the `lang` attribute the layout already sets from `app()->getLocale()`.
   Nothing here can affect the English interface.

   `text-transform: uppercase` is left alone: Devanagari has no case, so it is
   simply inert on Nepali text and still does its job on English.
   -------------------------------------------------------------------------- */

/* Letter-spacing pulls conjuncts apart — ड्या renders as three loose pieces
   rather than one glyph — so the tracking on the small caps labels is dropped
   for Nepali. The size, weight and colour stay exactly as they are. */
:lang(ne) .app-sidebar__section,
:lang(ne) .section-label,
:lang(ne) .form-label--caps,
:lang(ne) .app-sidebar__brand small,
:lang(ne) .card-header,
:lang(ne) .table > thead > tr > th {
    letter-spacing: normal;
}

/* Devanagari sits taller than Latin: matras hang above the line and below it.
   A little extra leading stops them colliding in the sidebar's tight rows,
   without moving anything on the English side. */
:lang(ne) .app-sidebar__link,
:lang(ne) .app-sidebar__section {
    line-height: 1.6;
}

/* --------------------------------------------------------------------------
   13. Dashboard scope note
   --------------------------------------------------------------------------
   Says whose figures are on the page. Deliberately quiet — it is context for
   the numbers, not a heading competing with them.
   -------------------------------------------------------------------------- */

.scope-note {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
    margin-bottom: var(--space-3);
}

.scope-note__chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 11px;
    border-radius: 100px;
    background: var(--accent-tint);
    color: var(--accent);
    font-size: .82rem;
    font-weight: 600;
    white-space: nowrap;
}

.scope-note__text {
    color: var(--muted);
    font-size: .82rem;
}

/* On a phone the sentence goes; the chip alone still answers the question. */
@media (max-width: 575.98px) {
    .scope-note__text { display: none; }
}

/* --------------------------------------------------------------------------
   14. Assignee picker
   --------------------------------------------------------------------------
   The task form's "assign to" list. Checkboxes rather than a multi-select,
   because a list of twenty names is far easier to scan as rows than as a
   scrolling box — and ticking is a clearer gesture than ctrl-clicking.
   -------------------------------------------------------------------------- */

.assignee-picker {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
    gap: 2px 12px;
    max-height: 240px;
    overflow-y: auto;
    padding: var(--space-2);
    border: 1px solid var(--line-strong);
    border-radius: var(--radius);
    background: var(--surface);
}

.assignee {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    padding: 6px 8px;
    border-radius: var(--radius);
    cursor: pointer;
    font-size: .88rem;
}

.assignee:hover { background: var(--tint); }

/* The whole row is the label, so the click target is the name, not just the
   7px box beside it. */
.assignee input { margin-top: 3px; flex: 0 0 auto; }

.assignee__name { display: block; }

.assignee__role {
    display: block;
    font-size: .74rem;
    color: var(--muted);
}

/* A ticked row stands out from the list without needing a second colour. */
.assignee:has(input:checked) {
    background: var(--accent-tint);
}

.assignee:has(input:checked) .assignee__name {
    font-weight: 600;
}

/* ------------------------------------------------------------------ *
 * 15. Tick-off rows — the to-do list
 * ------------------------------------------------------------------ */

/* Narrow enough that the checkbox reads as furniture beside the serial
   number rather than as a column of its own. */
.todo-check-col {
    width: 2.5rem;
    text-align: center;
}

.todo-check {
    display: inline-flex;
    margin: 0;
}

.todo-check input {
    cursor: pointer;
    width: 1.05rem;
    height: 1.05rem;
    accent-color: var(--status-ok);
}

/* A finished item stays on the list, struck through, until the page is
   next loaded. Dropping it the instant it is ticked would take the row out
   from under the reader's cursor and lose the confirmation that anything
   happened. */
.todo-row--done .todo-row__title {
    text-decoration: line-through;
    color: var(--muted);
}

.todo-row--done {
    opacity: .72;
}

/* Not a transition on `opacity` alone: the strike-through should land at the
   same moment, and a reader with reduced-motion set gets neither animated. */
.todo-row {
    transition: opacity .15s ease;
}

@media (prefers-reduced-motion: reduce) {
    .todo-row { transition: none; }
}

/* The date picker appends its calendar to <body>, so Bootstrap's modal —
   z-index 1050 — used to cover it: the calendar was there but invisible.
   Lifting it above every modal keeps the BS date box usable inside the to-do
   and task dialogs without touching the vendor file. */
.ndp-container {
    z-index: 2000;
}
