/* ─────────────────────────────────────────────────────────────────────────────
   RESPONSIVE
   Responsive rules and the demo ribbon. LAST ON PURPOSE — these override.

   Part 11 of 11, cut from the 5,142-line app.css. THE ORDER OF THESE
   FILES IS LOAD-BEARING — they are one cascade, split for navigation only, and
   index.php links them in this sequence. Moving one changes which rule wins.
   ───────────────────────────────────────────────────────────────────────────── */
/* =========================================
   RESPONSIVE CONTENT — keep last in file so
   these overrides win the source-order race
   ========================================= */
@media (max-width: 900px) {
    /* view headers: title and date filter wrap instead of colliding */
    .view-controls { flex-wrap: wrap; align-items: center; gap: 12px; }

    /* overview + projects-top use an inline 3-col grid — collapse to one column */
    .overview-grid,
    .projects-top-grid { grid-template-columns: 1fr !important; }
    .overview-grid > *,
    .projects-top-grid > * { grid-column: span 1 !important; }

    /* bento boards stack full-width */
    .col-4, .col-6, .col-8 { grid-column: span 12; }
    #grid-generic { grid-template-columns: 1fr; }

    /* metric columns (Total Income / Expense / Profit) stack vertically */
    .board-grid-3, .board-grid-4, .board-grid-2 { grid-template-columns: 1fr; }
    .board-grid-col {
        border-right: none;
        border-bottom: 1px solid var(--divider);
        padding: var(--space-4) var(--space-6);
        align-items: flex-start;
    }
    .board-grid-col:last-child { border-bottom: none; }

    /* wide tables scroll inside their card instead of stretching the page */
    .board-body { overflow-x: auto; }
}

/* quick-add hub: becomes a BOTTOM SHEET on small screens — full-width, docked
   to the bottom edge, top corners rounded, sliding up like a native tray */
@media (max-width: 640px) {
    .modal-overlay { padding: 12px; }
    #modal-overlay { padding: 0; align-items: flex-end; }
    .modal-card.quick-hub {
        width: 100%;
        max-width: 100%;
        height: 92vh;
        height: min(94dvh, 720px);   /* dvh: sheet shrinks with the keyboard */
        max-height: 94vh;
        border-radius: var(--radius-lg) var(--radius-lg) 0 0;
        animation: qa-sheet-up 0.28s cubic-bezier(0.22, 1, 0.36, 1);
    }
    .quick-hub .modal-header { padding: 18px 20px 0; }
    .quick-hub:not(.show-tabs) .modal-header { padding: 20px 20px 14px; }
    .quick-hub .modal-title-single { font-size: 18px; }
    .quick-tabs { margin: 14px 20px 0; }
    .qtab { margin-right: 16px; }
    .qtab span { font-size: 12.5px; }
    .modal-intro { margin: 12px 20px 0; }
    .quick-hub #modal-form-body { padding: 16px 20px 18px; }
    .quick-hub .modal-foot { padding: 12px 20px calc(16px + env(safe-area-inset-bottom, 0px)); }

    /* footer stacks: the preference reads above, the primary sits under the thumb */
    .qa-save-row { flex-direction: column; align-items: stretch; gap: 12px; }
    .qa-keep { justify-content: center; }
    .qa-save-row .qa-save-main { width: 100%; min-width: 0; padding: 15px 18px; }

    /* one field per row — full-width tap targets */
    .quick-hub .form-grid-2 { grid-template-columns: 1fr; }
    .input-amount-huge { font-size: 40px; }
    .qa-amount-block { padding: 14px 18px 16px; margin-bottom: 18px; }
    .qa-amount-block .input-amount-huge { font-size: 38px; }
    .ai-drop { min-height: 220px; padding: 28px 20px; }

    /* AI result rows reflow to two lines: the description leads, the facts and
       controls sit under it, so nothing is squeezed into an ellipsis */
    .ai-row { flex-wrap: wrap; gap: 8px 10px; }
    .ai-row-desc { flex: 1 1 100%; order: -1; white-space: normal; }
    .ai-row-date { width: auto; }
    .ai-row .qa-select { max-width: none; flex: 1 1 140px; }
    /* whether it fits beside the amount or drops to its own line, the row CTA is
       always flush right — a wrapped button that lands left reads as a mistake */
    .ai-row-rec { margin-left: auto; }
    .ai-board { padding: 16px 16px 4px; }
    /* figures keep their own line rather than breaking mid-number */
    .ai-board-bal { margin-left: 0; width: 100%; flex-wrap: wrap; gap: 14px 20px; }
    .ai-board-bal .ai-fig-val { font-size: 15px; white-space: nowrap; }
    .ai-board-stats { grid-template-columns: repeat(2, 1fr); gap: 15px 10px; }

    /* the 5 entry types fit one row when the pills give up their min width */
    .qa-type-pills .btn-pill { min-width: 0; padding: 8px 9px; font-size: 12px; }

    /* the rail keeps the sheet's content column (no bleed — see the desktop note) */
    .qa-acc-pills { margin: 0; padding: 2px 0 6px; }
    .qa-picker-head { padding: 18px 16px 10px 22px; }
    .qa-picker-search { margin: 0 16px 10px; }

    /* charts: pie + legend stop sitting side-by-side; pie shrinks to fit */
    .chart-body { flex-direction: column !important; gap: 24px !important; }
    .chart-legend { max-width: 100% !important; }
    .donut-svg { width: 200px; }
}

@keyframes qa-sheet-up {
    from { transform: translateY(24px); opacity: 0.4; }
    to { transform: translateY(0); opacity: 1; }
}

/* projects grid: 3 cards per row (status portal) */
#grid-projects.client-doc-grid { grid-template-columns: repeat(3, 1fr); }

/* client + team + project grids: 3 → 2 → 1 */
@media (max-width: 1200px) {
    #grid-clients.client-doc-grid,
    #grid-team.client-doc-grid,
    #grid-projects.client-doc-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 720px) {
    #grid-clients.client-doc-grid,
    #grid-team.client-doc-grid,
    #grid-projects.client-doc-grid { grid-template-columns: 1fr; }
}

/* ---- LOEWE flat bar + brand masthead (responsive) ---- */
@media (max-width: 900px) {
    .brand-masthead { width: min(430px, 60vw); margin-bottom: 26px; }
}
@media (max-width: 768px) {
    .floating-topbar.bar-flat { padding-top: 14px; padding-bottom: 10px; }
    .brand-masthead { width: min(340px, 66vw); margin-bottom: 20px; }
}
@media (max-width: 900px) {
    /* the quick-add CTA sheds its label and returns to an ink circle */
    .add-btn-label { display: none; }
    .btn-icon-add { width: 34px; padding: 0; gap: 0; border-radius: var(--radius-full); }
}

/* DOCUMENTS LIBRARY — responsive: below 980px the rail ROTATES into a
   horizontal filmstrip (filter pills scroll in one row, the item list becomes
   a snap-scrolling strip of compact cards) and the paper takes the full width.
   The arrows tuck into the canvas corners so the sheet keeps every pixel. */
@media (max-width: 980px) {
    .doclib { grid-template-columns: 1fr; gap: 16px; }
    .doclib-rail { position: static; top: auto; padding: 12px; gap: 12px; }
    .doclib-filters { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
    .doclib-filters::-webkit-scrollbar { display: none; }
    .doclib-pill { white-space: nowrap; flex: 0 0 auto; }
    .doclib-list {
        flex-direction: row; max-height: none; overflow-x: auto; overflow-y: hidden;
        gap: 8px; padding: 2px 2px 8px; scroll-snap-type: x proximity;
        -webkit-overflow-scrolling: touch;
    }
    .doclib-group { display: none; }   /* group headers don't read in a strip */
    .doclib-item { flex: 0 0 auto; width: 210px; scroll-snap-align: start; }
    .doclib-item-meta { display: none; }
    .doclib-sortrow { max-width: 340px; }
}
@media (max-width: 760px) {
    /* the workflow CTA drops its label — icon-only ink pill, tooltip carries the words */
    .doclib-actions .lst-cta span { display: none; }
    .doclib-actions .lst-cta { padding: 8px 10px; margin-right: 2px; }
}
@media (max-width: 640px) {
    /* the floating bar compacts: meta shrinks, tools stay one row */
    .doclib-bar { top: 70px; gap: 8px; padding: 8px 8px 8px 14px; }
    .doclib-meta b { font-size: 12.5px; }
    .doclib-meta span { display: none; }
    .doclib-pageind { margin-right: 2px; }
    .doclib-sheets { gap: 16px; }
    .doclib-item { width: 180px; }
    .doclib-actions .doclib-bar-sep { display: none; }
}

/* ═══════════════════════════════════════════════ LIVE-DEMO PILL
   The read-only frame around a public demo session (index.php, $isDemo). It had no
   styles at all and rendered as bare text with default blue links, sitting in the
   flow above the greeting and pushing the page down.

   FIXED, BOTTOM CENTRE, OUTSIDE THE SHELL. It belongs to the frame, not to the page:
   it takes no layout from the app, does not move with the content, and is reachable
   from every view without scrolling. Below the modal layer (1000) on purpose — a
   dialog is the thing you are doing; this is only the thing you are in. */
.demo-ribbon {
    position: fixed; left: 50%; bottom: 20px; transform: translateX(-50%);
    z-index: 900;
    display: flex; align-items: center; gap: 10px;
    max-width: calc(100vw - 32px);
    padding: 7px 7px 7px 15px;
    border-radius: var(--radius-pill);
    background: var(--bg-glass-panel);
    -webkit-backdrop-filter: blur(20px) saturate(1.6);
    backdrop-filter: blur(20px) saturate(1.6);
    border: 1px solid var(--divider);
    box-shadow: var(--shadow-3);
    font-size: 12.5px; line-height: 1;
}
/* the only thing on the pill that moves — "live", said once and quietly */
.demo-ribbon-dot {
    flex: 0 0 auto; width: 7px; height: 7px; border-radius: 50%;
    background: var(--success-green);
    animation: demoPulse 2.4s ease-out infinite;
}
@keyframes demoPulse {
    0%   { box-shadow: 0 0 0 0 rgba(1, 235, 114, 0.5); }
    70%  { box-shadow: 0 0 0 7px rgba(1, 235, 114, 0); }
    100% { box-shadow: 0 0 0 0 rgba(1, 235, 114, 0); }
}
.demo-ribbon-label {
    min-width: 0;
    color: var(--text-muted); white-space: nowrap;
    overflow: hidden; text-overflow: ellipsis;
}
/* the way out, and the only control here — ink on the pill, so it reads as the
   button it is rather than as another word in the sentence */
.demo-ribbon-btn {
    flex: 0 0 auto;
    padding: 7px 15px; border-radius: var(--radius-pill);
    background: var(--text-main); color: var(--bg-card);
    font-size: 12px; font-weight: var(--fw-semibold); letter-spacing: 0;
    text-decoration: none; white-space: nowrap;
    transition: opacity 0.14s ease;
}
.demo-ribbon-btn:hover, .demo-ribbon-btn:focus-visible { opacity: 0.82; outline: none; }
@media (prefers-reduced-motion: reduce) { .demo-ribbon-dot { animation: none; } }
@media (max-width: 520px) { .demo-ribbon { bottom: 14px; padding-left: 13px; } }

/* ── FORECAST SWITCHER on the live-demo pill ──────────────────────────────────
   The house segmented control (.toggle-group, so pill-slider.js glides the pill
   for free) shrunk to ribbon scale. The settings-panel size is built around a
   44px header pill; inside a 12.5px ribbon it would dwarf the Exit button and
   push the whole thing off a phone.

   A divider rule separates it from the sentence to its left, because "Live demo
   — read-only" is a statement and this is a control, and they should not read as
   one run of words. */
.demo-ribbon-scen {
    flex: 0 1 auto; min-width: 0;
    gap: 1px;
    padding-left: 9px;
    margin-left: 1px;
    border-left: 1px solid var(--divider-strong);
}
.demo-ribbon-scen .toggle-btn {
    padding: 5px 9px;
    font-size: 11.5px;
    letter-spacing: 0.01em;
    text-decoration: none;
    border-radius: var(--radius-pill);
}
/* the glider is sized from the active segment, so it inherits the smaller box */
.demo-ribbon-scen .pill-glider { border-radius: var(--radius-pill); }

/* HOW BIG THE FORECAST IS. The segment names the scenario, this names its size —
   together they read "growth · 500 accounts" without the ribbon having to say the
   word twice. Muted: it is a caption on the control, not a second control. */
.demo-ribbon-count {
    flex: 0 0 auto;
    font-size: 11.5px;
    color: var(--text-muted);
    white-space: nowrap;
    padding-left: 9px;
    border-left: 1px solid var(--divider-strong);
}

/* NARROW SCREENS. The sentence is the first thing to go: a visitor on a phone can
   see the pulsing dot and the Exit button, and the switcher is the only part that
   stops working if it is squeezed. Below 720px the label goes; below 480px the
   segments tighten rather than wrap, because a wrapped ribbon stops being a pill. */
@media (max-width: 720px) {
    .demo-ribbon-label { display: none; }
    .demo-ribbon-scen { padding-left: 0; margin-left: 0; border-left: 0; }
}
@media (max-width: 560px) {
    /* the count goes before the slider is squeezed — the pilled segment still names
       the scenario, which is the part that must never disappear */
    .demo-ribbon-count { display: none; }
}
@media (max-width: 480px) {
    .demo-ribbon-scen .toggle-btn { padding: 5px 7px; font-size: 11px; }
    .demo-ribbon-btn { padding: 7px 12px; }
}
