/* =============================================================================
   metta-ui.css — component layer for the 2026 redesign
   Loaded LAST, after tokens.css / app.css / pinx.css / metta-tokens.css.

   ---------------------------------------------------------------------------
   HOUSE RULES — read before adding anything
   ---------------------------------------------------------------------------
   1. ONE breakpoint. Mobile rules live in `@media (max-width: 1023.98px)` and
      nowhere else. No mobile rule may be added to app.css or pinx.css, ever.
      That single constraint is what makes desktop regression provably local.

   2. `html[data-mob="1"]` (set pre-paint, see partials/_head-assets.blade.php)
      is available INSIDE the media query when a rule must out-specify a
      selector in the 32 KB legacy app.css. Prefer a bare selector; add the
      attribute only when you actually lose a specificity fight.

   3. PREFIXES — do not mix them up:
        ds-*   NEW components from the 2026 design system. Safe to define
               freely: nothing in the app uses this prefix yet, so a view
               opts in only when it is rewritten.
        mx-*   EXISTING metta classes (mx-card ×41, mx-btn ×55, mx-btn--ghost,
               mx-btn--primary, mx-glass, mx-hover-lift), aliased to .card /
               .btn in pinx.css. NEVER redefine these here — that would
               restyle ~96 live call sites blind. They get retired in Phase 9.
        px-*   layout shell classes (sidebar, topbar, page) from layout.blade.
      Keyframes use the ds- prefix. app.css and layout.blade.php already define
      fadeUp / fadeIn / popIn / growW / growH / spin — and CSS keyframe names
      are case-sensitive, so an unprefixed `popin` would silently coexist with
      `popIn`, which is worse than a collision.

   4. METRICS — the two prototypes are deliberately different densities:
        Web App     : controls 38px, text 12.5–13px, radius 10px
        Mobile      : controls 44–52px, text 13–15px, radius 12–14px
      The "Metta Design System" file documents the MOBILE numbers (its own
      title says "Metta Mobile — დიზაინ-სისტემა"). So components are authored
      at DESKTOP density here, and scaled UP inside the media query. Never the
      other way round.

   5. Table reflow vocabulary — exactly three attributes, no more:
        data-label="სტატუსი"   labelled row in the mobile card
        data-primary            card title: larger, no label
        data-hide               dropped on mobile
      Wrapper card that must lose its border on mobile: data-tablecard
      Print-shaped tables (DPR / QA document replicas) do NOT reflow — wrap
      them in .table-scroll instead.

   6. Never shadows on glass surfaces. Translucent fill + blur + 1px border.
   ========================================================================== */


/* =============================================================================
   1. KEYFRAMES
   ========================================================================== */
@keyframes ds-fadeUp   { from { opacity:0; transform:translateY(8px) }  to { opacity:1; transform:translateY(0) } }
@keyframes ds-slideL   { from { transform:translateX(100%) }            to { transform:translateX(0) } }
@keyframes ds-sheetUp  { from { transform:translateY(100%) }            to { transform:translateY(0) } }
@keyframes ds-dimIn    { from { opacity:0 }                             to { opacity:1 } }
@keyframes ds-toastIn  { from { opacity:0; transform:translateY(12px) } to { opacity:1; transform:translateY(0) } }
@keyframes ds-popIn    { from { opacity:0; transform:translateY(-8px) scale(.98) } to { opacity:1; transform:translateY(0) scale(1) } }
@keyframes ds-thinkdot { 0%,80%,100% { opacity:.25; transform:scale(.85) } 40% { opacity:1; transform:scale(1) } }
@keyframes ds-fieldpulse { 0%,100% { border-color:rgba(0,179,122,.4) } 50% { border-color:var(--accent) } }
@keyframes ds-shimmer  { 0% { opacity:.5 } 50% { opacity:1 } 100% { opacity:.5 } }
@keyframes ds-aipulse  { 0%,100% { box-shadow:0 0 0 0 rgba(97,102,255,.35) } 50% { box-shadow:0 0 0 8px rgba(97,102,255,0) } }
@keyframes ds-ringspin { to { transform:rotate(360deg) } }

@media (prefers-reduced-motion: reduce) {
    [class*="ds-"], [class*="ds-"]::before, [class*="ds-"]::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
    }
}


/* =============================================================================
   2. COMPONENTS — authored at DESKTOP density (see house rule 4)
   Source: "Metta Web App.dc.html" + "Metta Design System.dc.html"
   Nothing in the app uses ds-* yet, so this section is inert until a view
   opts in. That is what lets Phase 1 be verified as a desktop no-op.
   ========================================================================== */

/* ── glass surface ─────────────────────────────────────────────────────────
   Translucent fill + blur + 1px border. NEVER a shadow. */
.ds-glass {
    background: var(--glass);
    -webkit-backdrop-filter: blur(var(--glass-blur));
    backdrop-filter: blur(var(--glass-blur));
    border: 1px solid var(--border);
    border-radius: 14px;
}
.ds-glass--solid { -webkit-backdrop-filter: none; backdrop-filter: none; background: var(--surface); }

/* ── card ─────────────────────────────────────────────────────────────────── */
.ds-card {
    background: var(--glass);
    -webkit-backdrop-filter: blur(var(--glass-blur));
    backdrop-filter: blur(var(--glass-blur));
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 14px;
}
.ds-card__title {
    font-family: var(--font-display), 'Lexend', sans-serif;
    font-size: 14px; font-weight: 600; color: var(--text);
    display: flex; align-items: center; gap: 8px;
}
.ds-card__sub { font-size: 12.5px; color: var(--text-2); }

/* ── buttons — 38px / r10 on desktop ─────────────────────────────────────── */
.ds-btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    height: 38px; padding: 0 14px; box-sizing: border-box;
    border-radius: 10px; border: 1px solid transparent;
    font-family: inherit; font-size: 13px; font-weight: 600; line-height: 1;
    cursor: pointer; text-decoration: none; white-space: nowrap;
    transition: background .16s ease, border-color .16s ease, opacity .16s ease;
    -webkit-tap-highlight-color: transparent; touch-action: manipulation;
}
.ds-btn:disabled, .ds-btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }
.ds-btn--primary { background: var(--accent); color: var(--accent-ink); font-weight: 700; }
.ds-btn--primary:hover { background: var(--accent-2, var(--accent)); }
.ds-btn--ghost   { background: var(--chip); border-color: var(--border); color: var(--text); }
.ds-btn--ghost:hover { background: var(--surface-hover); }
.ds-btn--ai      { background: var(--ai); color: #fff; }
.ds-btn--ai-pulse { animation: ds-aipulse 2.6s infinite; }
.ds-btn--danger  { background: var(--danger-soft); border-color: rgba(255,0,85,.4); color: var(--danger); }
.ds-btn--sm      { height: 32px; padding: 0 11px; font-size: 12px; border-radius: 8px; }
.ds-btn--block   { width: 100%; }
.ds-btn--icon    { width: 38px; padding: 0; }

/* ── form fields — 38px / r10 on desktop ─────────────────────────────────── */
.ds-field { display: flex; flex-direction: column; gap: 5px; }
.ds-field__label { font-size: 11.5px; color: var(--text-2); }
.ds-input, .ds-select, .ds-textarea {
    width: 100%; height: 38px;
    padding: 0 12px; box-sizing: border-box;
    background: var(--field); border: 1px solid var(--border);
    border-radius: 10px;
    font-family: inherit; font-size: 13px; color: var(--text);
}
.ds-textarea { height: auto; min-height: 84px; padding: 10px 12px; resize: vertical; line-height: 1.5; }
.ds-input:focus, .ds-select:focus, .ds-textarea:focus {
    outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft);
}
.ds-input::placeholder, .ds-textarea::placeholder { color: var(--text-4); }

/* ── stepper ─────────────────────────────────────────────────────────────── */
.ds-stepper {
    display: inline-flex; align-items: center;
    background: var(--field); border: 1px solid var(--border);
    border-radius: 10px; overflow: hidden;
}
.ds-stepper button {
    width: 34px; height: 38px;
    display: grid; place-items: center;
    background: none; border: 0; cursor: pointer;
    font-size: 18px; line-height: 1; color: var(--text-2);
    touch-action: manipulation;
}
.ds-stepper button:first-child { border-right: 1px solid var(--border2); }
.ds-stepper button:last-child  { border-left:  1px solid var(--border2); color: var(--accent); }
.ds-stepper__value {
    min-width: 48px; text-align: center;
    font-family: var(--font-display), 'Lexend', sans-serif;
    font-size: 14px; font-weight: 600; color: var(--text);
}

/* ── status pill ─────────────────────────────────────────────────────────── */
.ds-pill {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 5px 11px; border-radius: 999px;
    font-size: 12px; font-weight: 600; white-space: nowrap;
    background: var(--chip); border: 1px solid var(--border); color: var(--text-2);
}
.ds-pill::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.ds-pill--not-started { color: var(--st-not-started); background: rgba(124,132,141,.14); border-color: rgba(124,132,141,.4); }
.ds-pill--working     { color: var(--st-working);     background: var(--warn-soft);      border-color: rgba(255,183,0,.4); }
.ds-pill--stuck       { color: var(--st-stuck);       background: var(--danger-soft);    border-color: rgba(255,0,85,.4); }
.ds-pill--done        { color: var(--st-done);        background: var(--accent-soft);    border-color: rgba(0,224,153,.4); }

/* ── QA type chip ────────────────────────────────────────────────────────── */
.ds-qa {
    display: inline-flex; align-items: center;
    font-family: var(--font-display), 'Lexend', sans-serif;
    font-size: 11.5px; font-weight: 700; letter-spacing: .2px;
    padding: 3px 8px; border-radius: 6px;
}
.ds-qa--ncr { color: var(--qa-ncr); background: var(--qa-ncr-soft); }
.ds-qa--def { color: var(--qa-def); background: var(--qa-def-soft); }
.ds-qa--wir { color: var(--qa-wir); background: var(--qa-wir-soft); }
.ds-qa--maf { color: var(--qa-maf); background: var(--qa-maf-soft); }
.ds-qa--mos { color: var(--qa-mos); background: var(--qa-mos-soft); }
.ds-qa--fwa { color: var(--qa-fwa); background: var(--qa-fwa-soft); }

/* ── KPI tile ────────────────────────────────────────────────────────────── */
.ds-kpi {
    background: var(--surface-2); border: 1px solid var(--border2);
    border-left: 3px solid var(--accent);
    border-radius: 11px; padding: 10px 13px;
    display: flex; flex-direction: column; gap: 2px; min-width: 0;
}
.ds-kpi__label { font-size: 11px; color: var(--text-4); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ds-kpi__value { font-family: var(--font-display), 'Lexend', sans-serif; font-size: 22px; font-weight: 600; color: var(--text); line-height: 1.15; }
.ds-kpi--danger { border-left-color: var(--danger); }
.ds-kpi--danger .ds-kpi__value { color: var(--danger); }
.ds-kpi--warn   { border-left-color: var(--warn); }
.ds-kpi--ai     { border-left-color: var(--ai); }
.ds-kpi--muted  { border-left-color: var(--text-4); }

/* ── progress bar ────────────────────────────────────────────────────────── */
.ds-bar { height: 6px; border-radius: 99px; background: var(--track); overflow: hidden; }
.ds-bar__fill { height: 100%; border-radius: 99px; background: linear-gradient(90deg, var(--accent-2, var(--accent)), var(--accent)); transition: width .4s ease; }
.ds-bar__fill--warn   { background: var(--warn); }
.ds-bar__fill--danger { background: var(--danger); }

/* ── AI surfaces ─────────────────────────────────────────────────────────── */
.ds-ai-card {
    background: linear-gradient(135deg, var(--ai-soft), rgba(97,102,255,.06));
    border: 1px solid rgba(97,102,255,.4);
    border-radius: 14px; padding: 15px;
    -webkit-backdrop-filter: blur(var(--glass-blur));
    backdrop-filter: blur(var(--glass-blur));
    display: flex; flex-direction: column; gap: 10px;
}
.ds-ai-card__title { display: flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 600; color: var(--ai-fg); }
.ds-ai-card__body  { font-size: 12.5px; color: var(--text-2); line-height: 1.55; }
/* propose-then-confirm: the agent must never act without this being accepted */
.ds-ai-propose { background: var(--surface); border: 1px solid rgba(97,102,255,.4); border-radius: 14px; padding: 15px; display: flex; flex-direction: column; gap: 12px; }
.ds-ai-propose__actions { display: flex; gap: 9px; }
.ds-ai-propose__actions > * { flex: 1; }
.ds-thinking { display: inline-flex; gap: 4px; align-items: center; }
.ds-thinking i { width: 6px; height: 6px; border-radius: 50%; background: var(--ai-fg); animation: ds-thinkdot 1.2s infinite; }
.ds-thinking i:nth-child(2) { animation-delay: .15s; }
.ds-thinking i:nth-child(3) { animation-delay: .3s; }

/* ── banners / toast ─────────────────────────────────────────────────────── */
.ds-banner {
    border-radius: 11px; padding: 10px 14px;
    font-size: 12.5px; font-weight: 600;
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.ds-banner--warn    { background: var(--warn-soft);   border: 1px solid rgba(255,183,0,.4); color: var(--warn-ink); }
.ds-banner--success { background: var(--accent-soft); border: 1px solid rgba(0,224,153,.4); color: var(--accent-text, var(--accent)); }
.ds-banner--danger  { background: var(--danger-soft); border: 1px solid rgba(255,0,85,.4);  color: var(--danger); }
.ds-banner--offline {
    background: var(--glass2); border: 1px solid var(--border); color: var(--text-2); font-weight: 500;
    -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px);
}
.ds-banner--offline::before { content: ''; width: 8px; height: 8px; border-radius: 50%; background: var(--warn); flex-shrink: 0; }

.ds-toast {
    position: fixed; left: 50%; transform: translateX(-50%);
    bottom: calc(var(--safe-b) + 20px); z-index: 90;
    max-width: min(92vw, 420px);
    padding: 11px 16px; border-radius: 11px;
    background: var(--glass2); border: 1px solid var(--border); color: var(--text);
    -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px);
    font-size: 13px; animation: ds-toastIn .22s ease both;
}

/* ── skeleton ────────────────────────────────────────────────────────────── */
.ds-skel { border-radius: 6px; background: var(--chip); animation: ds-shimmer 1.6s infinite; }

/* ── data table (desktop look: zebra rows, glass header) ─────────────────── */
.ds-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.ds-table thead th {
    position: sticky; top: 0; z-index: 1;
    background: var(--bg-2); color: var(--text-4);
    font-size: 11px; font-weight: 700; text-align: left;
    padding: 9px 12px; border-bottom: 1px solid var(--border);
    white-space: nowrap;
}
.ds-table tbody td { padding: 10px 12px; border-bottom: 1px solid var(--border2); color: var(--text); }
.ds-table tbody tr:nth-child(even) { background: var(--row); }
.ds-table tbody tr:hover { background: var(--surface-hover); }

/* ── hit-area expander ────────────────────────────────────────────────────
   For controls that must stay visually small (a 16px checkbox that became
   48px would look absurd). Grows the HIT AREA without changing the PAINT.
   Only active on mobile — desktop paint and hit-area stay byte-identical. */
.ds-tap { position: relative; }


/* =============================================================================
   2b. SHELL SURFACES — bottom tab bar, sheets, scrollbars.
   Declared outside the media query (so the markup can exist at any width) but
   the tab bar itself is display:none until the breakpoint, see §3.7.
   ========================================================================== */

/* Thin scrollbar used by the sidebar nav and the command palette. */
.sc::-webkit-scrollbar { width: 10px; height: 10px; }
.sc::-webkit-scrollbar-thumb { background: rgba(124,132,141,.35); border-radius: 99px; border: 3px solid transparent; background-clip: content-box; }
.sc::-webkit-scrollbar-track { background: transparent; }

.px-tabbar { display: none; }

/* Desktop / mobile exclusive blocks (tasks board renders both, CSS picks one) */
[data-mob-only] { display: none; }

/* Collapsible filter bar — the toggle itself only exists on mobile. */
.px-filter-toggle { display: none; }

/* @yield('actions') wrapper. Pages inject whole toolbars here (tasks ships a
   3-tab switcher plus three buttons ≈ 600px), which wrapped onto a second line
   inside a 60px topbar. Keep it on one line and let it scroll instead. */
.px-actions {
    display: flex; align-items: center; gap: 8px;
    flex-wrap: nowrap; min-width: 0;
    overflow-x: auto; scrollbar-width: none;
}
.px-actions::-webkit-scrollbar { display: none; }
.px-actions > * { flex-shrink: 0; }

/* ── mobile board cards (tasks/_board_cards.blade.php) ─────────────────── */
.mbc-tabs {
    display: flex; gap: 7px; overflow-x: auto; scrollbar-width: none;
    padding: 2px 0 10px; margin: 0 -2px;
}
.mbc-tabs::-webkit-scrollbar { display: none; }
.mbc-tab {
    display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0;
    height: 36px; padding: 0 13px; border-radius: 999px;
    background: var(--chip); border: 1px solid var(--border2);
    color: var(--text-2); font-family: inherit; font-size: 12.5px; font-weight: 600;
    cursor: pointer; white-space: nowrap;
}
.mbc-tab.is-active { background: var(--accent-soft); border-color: rgba(0,224,153,.4); color: var(--accent-text, var(--accent)); }
.mbc-tab__dot { width: 7px; height: 7px; border-radius: 50%; background: var(--tab-color, var(--text-4)); flex-shrink: 0; }
.mbc-tab__n {
    font-family: var(--font-display), 'Lexend', sans-serif; font-size: 11px; font-weight: 700;
    color: var(--text-4); background: var(--surface); border-radius: 999px; padding: 1px 6px;
}
.mbc-list { display: flex; flex-direction: column; gap: 10px; }
.mbc-card {
    background: var(--surface); border: 1px solid var(--border);
    border-radius: 14px; padding: 13px 14px;
    display: flex; flex-direction: column; gap: 10px;
}
.mbc-card__main { display: flex; align-items: flex-start; gap: 10px; text-decoration: none; color: var(--text); }
.mbc-card__dot { width: 8px; height: 8px; border-radius: 50%; margin-top: 6px; flex-shrink: 0; }
.mbc-card__title { flex: 1; min-width: 0; font-size: 14.5px; font-weight: 600; line-height: 1.4; }
.mbc-card__av {
    width: 30px; height: 30px; flex-shrink: 0; border-radius: 50%;
    background: var(--chip); color: var(--text-2);
    display: grid; place-items: center; font-size: 12px; font-weight: 700;
}
.mbc-card__meta { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.mbc-chip { font-size: 12px; color: var(--text-2); background: var(--chip); padding: 4px 10px; border-radius: 8px; }
.mbc-dim { font-size: 12px; color: var(--text-4); }
.mbc-over { font-size: 12px; font-weight: 700; color: var(--danger); }
.mbc-card__bar { display: flex; align-items: center; gap: 10px; }
.mbc-pct { font-size: 12px; font-weight: 700; flex-shrink: 0; min-width: 34px; text-align: right; }
.mbc-card__foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.mbc-status {
    background: none; border: 0; padding: 6px 0 6px 6px; margin: -6px 0;
    font-family: inherit; font-size: 12px; font-weight: 700; cursor: pointer;
    min-height: 44px; display: inline-flex; align-items: center;
}
.mbc-empty { padding: 30px 12px; text-align: center; font-size: 13px; color: var(--text-4); }

/* Command palette overlay.
   display MUST live in a class, not an inline style: Alpine's x-show clears
   el.style.display when it shows an element, so an inline `display:flex`
   silently degrades to `block` and justify-content stops applying. */
.px-palette-scrim {
    position: fixed; inset: 0; z-index: 95;
    background: rgba(0,0,0,.5);
    -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
    display: flex; justify-content: center; align-items: flex-start;
    padding: 12vh 16px 16px;
    animation: ds-dimIn .15s ease-out;
}
.px-palette {
    width: min(94vw, 600px); max-height: 70vh;
    display: flex; flex-direction: column;
    background: var(--glass2);
    -webkit-backdrop-filter: blur(30px) saturate(1.4); backdrop-filter: blur(30px) saturate(1.4);
    border: 1px solid var(--border); border-radius: 16px; overflow: hidden;
    animation: ds-popIn .16s ease-out;
}
.px-palette__row {
    display: flex; align-items: center; gap: 11px;
    height: 46px; padding: 0 12px; border-radius: 10px;
    text-decoration: none; color: var(--text);
}
.px-palette__row:hover { background: var(--chip); }

/* Bottom sheet (capture menu, and any future sheet) */
.px-sheet-scrim {
    position: fixed; inset: 0; z-index: 88;
    background: rgba(0,0,0,.5);
    -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
    display: flex; align-items: flex-end; justify-content: center;
    animation: ds-dimIn .18s ease-out;
}
.px-sheet {
    width: 100%; max-width: 560px; max-height: 82dvh; overflow-y: auto;
    background: var(--glass2);
    -webkit-backdrop-filter: blur(30px) saturate(1.4); backdrop-filter: blur(30px) saturate(1.4);
    border: 1px solid var(--border); border-bottom: 0;
    border-radius: 18px 18px 0 0;
    padding: 8px 14px calc(18px + var(--safe-b));
    animation: ds-sheetUp .24s cubic-bezier(.2,.8,.2,1);
}
.px-sheet__handle { width: 40px; height: 4px; border-radius: 99px; background: var(--border-strong); margin: 4px auto 14px; cursor: grab; }
.px-sheet__item {
    display: flex; align-items: center; gap: 13px;
    padding: 11px 8px; border-radius: 12px;
    text-decoration: none; color: var(--text);
}
.px-sheet__item:hover, .px-sheet__item:active { background: var(--chip); }
.px-sheet__item b { display: block; font-size: 14.5px; font-weight: 600; }
.px-sheet__item small { display: block; font-size: 11.5px; color: var(--text-4); margin-top: 1px; }
.px-sheet__ic {
    width: 44px; height: 44px; flex-shrink: 0;
    display: grid; place-items: center; border-radius: 12px; font-size: 20px;
}

/* ── delays: slide-over form ─────────────────────────────────────────────
   Desktop slides in from the right, mobile rises from the bottom (the
   .px-sheet-scrim it reuses is already bottom-aligned). */
.dly-scrim { align-items: stretch; justify-content: flex-end; }
.dly-panel {
    width: min(560px, 100%); max-height: 100dvh; overflow-y: auto;
    background: var(--glass2);
    -webkit-backdrop-filter: blur(30px) saturate(1.4); backdrop-filter: blur(30px) saturate(1.4);
    border-left: 1px solid var(--border);
    padding: 18px 18px calc(18px + var(--safe-b));
    animation: ds-slideL .24s cubic-bezier(.2,.8,.2,1);
}
.dly-panel .px-sheet__handle { display: none; }
.dly-picker {
    max-height: 260px; overflow-y: auto;
    border: 1px solid var(--border2); border-radius: 12px; padding: 4px;
}
.dly-pick {
    display: flex; align-items: center; gap: 10px;
    padding: 8px 10px; border-radius: 9px; cursor: pointer;
}
.dly-pick:hover { background: var(--chip); }

/* Row actions. .px-iconbtn is display:grid, i.e. block-level, so a plain
   sequence of inline <form>s stacked one per line. */
.dly-actions { display: flex; align-items: center; justify-content: flex-end; gap: 6px; }
.dly-actions form { margin: 0; display: flex; }

@media (max-width: 1023.98px) {
    .dly-scrim { align-items: flex-end; justify-content: center; }
    /* In card mode the actions cell is the card's last row — left-align it
       with the rest of the card instead of hugging the right edge. */
    .table[data-cards] .dly-actions { justify-content: flex-start; }
    .dly-panel {
        width: 100%; max-width: 560px; max-height: 88dvh;
        border-left: 0; border-top: 1px solid var(--border);
        border-radius: 18px 18px 0 0;
        padding: 8px 14px calc(18px + var(--safe-b));
        animation: ds-sheetUp .24s cubic-bezier(.2,.8,.2,1);
    }
    .dly-panel .px-sheet__handle { display: block; }
}


/* =============================================================================
   3. MOBILE  —  the ONE breakpoint. Nothing below this line affects desktop.
   ========================================================================== */
@media (max-width: 1023.98px) {

    /* ── 3.7 shell ───────────────────────────────────────────────────────
       The sidebar is off-canvas below this width (layout.blade.php owns that
       rule), so navigation moves to a bottom tab bar and the project switcher
       moves to the topbar chip. */
    .px-tabbar {
        position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
        display: flex; align-items: flex-end; justify-content: space-around;
        height: var(--tabbar-total); padding-bottom: var(--safe-b);
        /* Deliberately SOLID, not glass: stacking a blurred fixed bar over the
           blurred fixed topbar causes repaint jank and transparent-black
           artifacts on iOS Safari. */
        background: var(--bg-2);
        border-top: 1px solid var(--border);
    }
    .px-tab {
        flex: 1 1 0; min-width: 0;
        display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
        height: var(--tabbar-h); padding: 0 2px;
        background: none; border: 0; cursor: pointer;
        color: var(--text-4); text-decoration: none;
        font-size: 10px; font-weight: 600; font-family: inherit;
        -webkit-tap-highlight-color: transparent;
    }
    .px-tab span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
    .px-tab.is-active { color: var(--accent); }
    .px-tab--fab { color: var(--accent); justify-content: flex-end; }
    .px-fab {
        width: 56px; height: 56px; border-radius: 50%;
        background: linear-gradient(160deg, var(--accent), var(--accent-2, var(--accent)));
        border: 4px solid var(--bg);
        display: grid; place-items: center;
        margin-top: -22px; margin-bottom: 1px;
        box-shadow: 0 6px 20px rgba(0,224,153,.35);
    }

    /* Content must clear the bar. */
    .px-page, .page { padding-bottom: calc(var(--tabbar-total) + 20px) !important; }

    /* Topbar: the date, the section crumb and the preview-role label are all
       .px-hide-sm. What remains is burger · context chip · AI · bell · theme. */
    .px-topbar { height: 56px; padding: 0 10px; gap: 7px; }
    /* The chip is the only way to change project on a phone (the sidebar is
       off-canvas), so it gets the leftover width rather than a fixed size. */
    .px-ctx { flex: 1 1 auto; max-width: none; min-width: 96px; padding: 0 12px; }
    .px-ai-btn { padding: 0; width: 38px; justify-content: center; }

    /* @section('actions') is up to four controls wide on some pages (tasks
       injects a 300px tab switcher plus three buttons). Relocate it to its own
       horizontally-scrollable rail under the topbar rather than letting it
       overflow a 56px non-wrapping flex line. */
    /* Height is derived from --tap so the rail and the padding that clears it
       can never drift apart: controls inside are forced to --tap by §3.4. */
    .px-actions {
        --actionrail-h: calc(var(--tap) + 17px);
        position: fixed; top: 56px; left: 0; right: 0; z-index: 39;
        height: var(--actionrail-h); box-sizing: border-box;
        display: flex; align-items: center; gap: 8px;
        padding: 8px 12px; margin: 0;
        overflow-x: auto; overflow-y: hidden; scrollbar-width: none;
        background: var(--bg-2); border-bottom: 1px solid var(--border2);
    }
    .px-actions::-webkit-scrollbar { display: none; }
    .px-actions > * { flex-shrink: 0; }
    /* Push the page down by the rail's height when one is present. */
    body:has(.px-actions) .px-page,
    body:has(.px-actions) .page { padding-top: calc(var(--tap) + 25px); }

    /* The sidebar drawer keeps its own width on a phone; 248px of 390 is fine. */
    .px-sidebar { width: 264px; }

    /* ── 3.1 viewport plumbing ───────────────────────────────────────────
       viewport-fit=cover makes 100vh wrong under the iOS URL bar and lets a
       fixed bottom bar sit beneath the home indicator. dvh + safe areas fix
       both. Fallback line first for browsers without dvh. */
    html[data-mob="1"] .px-shell,
    html[data-mob="1"] .fs-shell { height: 100vh; height: 100dvh; }

    /* ── 3.2 iOS focus-zoom ──────────────────────────────────────────────
       Safari zooms on focus for any field under 16px COMPUTED font-size.
       ~200 fields are sized by inline styles, which beat stylesheets — this
       is the one place !important is the correct tool rather than a smell.
       .fs-fieldinput is excluded: those are %-positioned PDF overlays that
       would burst their box at 16px (handled separately in Phase 2). */
    input:not([type=checkbox]):not([type=radio]):not([type=range]):not(.fs-fieldinput),
    select,
    textarea {
        font-size: 16px !important;
    }
    input:not([type=checkbox]):not([type=radio]):not([type=range]):not(.fs-fieldinput),
    select,
    textarea {
        min-height: 48px;
    }

    /* ── 3.3 components scale up to the mobile spec ──────────────────────
       Design System: buttons 52/r14, fields 52/r12, text 15, touch 48. */
    .ds-btn        { height: 52px; padding: 0 20px; font-size: 15px; border-radius: 14px; gap: 8px; }
    .ds-btn--sm    { height: 44px; padding: 0 15px; font-size: 13.5px; border-radius: 11px; }
    .ds-btn--icon  { width: 52px; }
    .ds-input, .ds-select, .ds-textarea { height: 52px; padding: 0 16px; font-size: 15px; border-radius: 12px; }
    .ds-textarea   { height: auto; min-height: 96px; padding: 12px 16px; }
    .ds-field__label { font-size: 12px; }
    .ds-card       { padding: 16px; border-radius: 16px; }
    .ds-card__title { font-size: 17px; }
    .ds-pill       { padding: 7px 14px; font-size: 13px; }
    .ds-pill::before { width: 8px; height: 8px; }
    .ds-kpi__value { font-size: 24px; }
    /* Two per row on a phone leaves ~150px: Georgian labels are long enough
       that ellipsis eats the meaning ("სულ დაკარგული დ…"). Let them wrap. */
    .ds-kpi__label { white-space: normal; overflow: visible; line-height: 1.3; }
    .ds-bar        { height: 8px; }
    .ds-stepper button { width: var(--tap); height: var(--tap); font-size: 20px; }
    .ds-stepper__value { min-width: 56px; font-size: 17px; }

    /* ── 3.4 touch targets ───────────────────────────────────────────────
       Tier 1: class-level, zero Blade edits. Covers the systemic offenders
       (px-iconbtn 32×32, btn, tabs__item, theme-toggle, sidebar rows). */
    .px-iconbtn, .btn, .btn--icon, .mx-btn, .fs-btn, .tabs__item,
    .mfile-ic, .mboard-sub, .mstatus-pill, .theme-toggle,
    .px-nav, .px-proj, .row, .nav__item {
        min-width: var(--tap);
        min-height: var(--tap);
    }
    .px-iconbtn, .btn--icon, .theme-toggle { display: inline-grid; place-items: center; }

    /* The headcount stepper in reports/edit is the one control a supervisor
       taps repeatedly with gloves on. 34×38 → --tap. */
    .stepper > button { width: var(--tap) !important; height: var(--tap) !important; font-size: 22px; }
    .stepper > input  { min-height: var(--tap); font-weight: 700; }

    /* Photo grids: minmax(200px) leaves a single column with dead space at
       360px. Two thumbs per row reads far better when reviewing captures. */
    [style*="minmax(200px"], [style*="minmax(160px"] { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }

    /* Tier 2: hit-area expander for controls that must stay visually small. */
    .ds-tap::after {
        content: ''; position: absolute; top: 50%; left: 50%;
        transform: translate(-50%, -50%);
        width: max(100%, var(--tap)); height: max(100%, var(--tap));
    }

    a, button, [role="button"], input, select, textarea, summary, label {
        touch-action: manipulation;
        -webkit-tap-highlight-color: transparent;
    }

    /* ── 3.5 layout — migrated out of layout.blade.php's 640/420 blocks ── */
    .px-topbar { padding: 0 12px; height: 54px; gap: 6px; }
    .px-page   { padding: 14px 12px calc(44px + var(--safe-b)); }
    .px-hide-sm { display: none !important; }
    /* minmax(0,…), not 1fr: a grid item defaults to min-width:auto, so one long
       unbreakable string (a task title) widens the track past the viewport and
       the whole page scrolls sideways. The child min-width:0 does the same for
       flex rows nested inside. */
    .grid-resp { grid-template-columns: minmax(0, 1fr) !important; }
    .grid-resp > *, .kpi-grid > *, .grid-2 > *, .grid-3 > * { min-width: 0; }
    .mx-card, .card { max-width: 100%; }

    /* Fixed multi-column grids that would each get ~90px at 360px wide.
       Cheaper and far more reliable than tagging ~45 call sites by hand. */
    .kpi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
    .grid-2, .grid-3 { grid-template-columns: minmax(0, 1fr) !important; }

    /* ── 3.6 tables → cards ──────────────────────────────────────────────
       See house rule 5.

       OPT-IN: reflow only fires on `table.table[data-cards]`. A table without
       labels would reflow into a stack of bare values with no column context —
       WORSE than scrolling. So a table converts only once its cells carry
       data-label / data-primary / data-hide (Phase 4), and until then it
       simply scrolls. `thead` stays in the DOM (visually hidden) so screen
       readers keep the column semantics. */
    table.table[data-cards] { display: block; width: 100%; min-width: 0; }
    table.table[data-cards] thead {
        position: absolute; width: 1px; height: 1px;
        overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
    }
    table.table[data-cards] tbody,
    table.table[data-cards] tbody tr,
    table.table[data-cards] tbody td { display: block; }
    table.table[data-cards] tbody tr {
        border: 1px solid var(--border); border-radius: var(--r-3, 8px);
        background: var(--surface); margin: 0 0 10px; padding: 10px 12px;
    }
    table.table[data-cards] tbody td {
        display: flex; align-items: center; justify-content: space-between; gap: 10px;
        border: 0; padding: 6px 0; min-height: 44px; text-align: left !important;
        white-space: normal;
    }
    table.table[data-cards] tbody td::before {
        content: attr(data-label);
        flex: 0 0 40%; font-size: 11.5px; font-weight: 700; color: var(--text-3);
    }
    table.table[data-cards] tbody td:not([data-label])::before { display: none; }
    table.table[data-cards] tbody td[data-primary] { font-size: 15px; font-weight: 700; display: block; }
    table.table[data-cards] tbody td[data-primary]::before { display: none; }
    table.table[data-cards] tbody td[data-hide] { display: none; }

    /* Not yet converted → must at least SCROLL. Ten of the eleven table views
       sit inside a card with overflow:hidden, which is what clipped them. */
    .card:has(table.table:not([data-cards])),
    .mx-card:has(table.table:not([data-cards])),
    [data-tablecard]:has(table.table:not([data-cards])) {
        overflow-x: auto !important;
        -webkit-overflow-scrolling: touch;
    }

    /* ── 3.8 desktop/mobile exclusive blocks ────────────────────────────── */
    [data-mob-only] { display: block; }
    [data-desk-only] { display: none !important; }

    /* Filter bar collapses behind a toggle. It opens automatically when a
       filter is already applied, so an active filter is never invisible. */
    .px-filter-toggle {
        display: inline-flex; align-items: center; gap: 8px;
        height: 44px; padding: 0 15px; margin-bottom: 12px;
        border-radius: 12px; background: var(--chip); border: 1px solid var(--border2);
        color: var(--text-2); font-family: inherit; font-size: 13px; font-weight: 600;
        cursor: pointer;
    }
    .px-filter-toggle__n {
        font-family: var(--font-display), 'Lexend', sans-serif; font-size: 11px; font-weight: 700;
        color: var(--accent-ink); background: var(--accent); border-radius: 999px; padding: 1px 7px;
    }
    .filterbar { display: none !important; }
    .filterbar[data-open] { display: grid !important; grid-template-columns: 1fr !important; gap: 10px; }

    /* ── 3.9 remaining screens ──────────────────────────────────────────── */

    /* AI assistant: a 330px fixed rail next to the chat left ~44px for the
       conversation at 390px. Stack them; the rail carries settings, so it goes
       BELOW the chat rather than pushing it off the first screen. */
    .ai-shell { flex-direction: column; height: auto !important; min-height: 0 !important; }
    .ai-rail  { width: 100% !important; order: 2; max-height: 60dvh; }

    /* Dashboard donut + week bars are fixed-size flex children. */
    [style*="width:150px"][style*="height:150px"] { width: 128px !important; height: 128px !important; }
    [style*="height:150px"][style*="align-items:flex-end"] { height: 120px !important; }

    /* Embedded PDF preview: 640px is most of a phone screen before any chrome. */
    object[style*="height:640px"], iframe[style*="height:640px"] { height: 58dvh !important; }

    /* Tree view indents its leaf rows by 96px, which eats a quarter of a
       360px screen before any content. Cards carry no hierarchy of their own,
       so the indent is pure loss on mobile. */
    .tree-leaf { padding-left: 0 !important; max-width: none !important; }
    .tree--depth-1, .tree--depth-2, .tree--depth-3 { padding-left: 8px !important; }

    /* The card wrapper would otherwise double-border every reflowed row. */
    [data-tablecard] {
        border: 0 !important; background: transparent !important;
        overflow: visible !important; padding: 0 !important;
    }

    /* Print-shaped tables (DPR / QA document replicas) scroll, never reflow. */
    .table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
    .table-scroll > table { min-width: 640px; }
}
