/* ===================================================================
   Projex Mobile Stylesheet
   -------------------------------------------------------------------
   All phone overrides live here. Loaded AFTER styles.css so its rules
   win on cascade. Breakpoints (mobile-first):

   - ≤480px         phone portrait (single column, bottom nav)
   - 481–767px      phone landscape / small tablet
   - ≥768px         tablet+ (no rules here; styles.css covers it)

   Anything that must apply to ALL touch viewports (regardless of width)
   goes outside a media query but inside `body.is-touch` (set by
   mobile.js). Anything that depends ONLY on screen width uses @media.
   =================================================================== */

/* -------------------------------------------------------------------
   Safe-area variables (iOS notch / Android gesture bar)
   The viewport meta in index.html uses `viewport-fit=cover` so these
   resolve to the real inset values; on browsers without notches they
   resolve to 0.
   ------------------------------------------------------------------- */
:root {
    --safe-top: env(safe-area-inset-top, 0px);
    --safe-bottom: env(safe-area-inset-bottom, 0px);
    --safe-left: env(safe-area-inset-left, 0px);
    --safe-right: env(safe-area-inset-right, 0px);
    --mobile-bottom-nav-height: 60px;
}

/* -------------------------------------------------------------------
   Touch-target utilities — used by any element that wants to be
   tappable on mobile. Reaches the 44×44 px minimum that Apple HIG
   and WCAG 2.5.5 (AAA) require. Apply via class for opt-in clarity.
   ------------------------------------------------------------------- */
.touch-min {
    min-width: 44px;
    min-height: 44px;
}

/* On touch devices, force every interactive element to a 40px minimum
   (slightly under 44 to avoid layout disruption on dense rows).
   Excluded: items inside text content, table cells (let them stay
   table-sized), and elements explicitly opting out via .no-touch-min. */
body.is-touch button:not(.no-touch-min):not(td button):not(th button),
body.is-touch .btn:not(.no-touch-min),
body.is-touch select:not(.no-touch-min),
body.is-touch input[type="checkbox"]:not(.no-touch-min),
body.is-touch input[type="radio"]:not(.no-touch-min) {
    min-height: 40px;
}

/* -------------------------------------------------------------------
   Bottom navigation — visible only when state.viewport.isMobile.
   mobile.js injects #mobile-bottom-nav into <body> on init. Hidden
   by default; .is-mobile on body shows it.
   ------------------------------------------------------------------- */
#mobile-bottom-nav {
    display: none;
}

body.is-mobile #mobile-bottom-nav {
    display: flex;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    height: calc(var(--mobile-bottom-nav-height) + var(--safe-bottom));
    padding-bottom: var(--safe-bottom);
    padding-left: var(--safe-left);
    padding-right: var(--safe-right);
    /* Solid background so app content scrolling behind the nav is fully
       obscured — semi-transparent + backdrop-filter is too easily read
       through on light/dark themes and on phones where blur is throttled. */
    background: var(--bg-main, #0a0e1a);
    border-top: 1px solid var(--border-color, rgba(255, 255, 255, 0.08));
    /* Sits above the slide-in sidebar (1000) and its overlay scrim (999)
       so the "More" tab is still tappable while the sidebar is open.
       Below modals (2000) so dialogs cover the nav as expected. */
    z-index: 1100;
    box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.35);
}

#mobile-bottom-nav .mbn-item {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    background: transparent;
    border: none;
    color: var(--text-muted, rgba(255, 255, 255, 0.55));
    font-size: 0.65rem;
    line-height: 1;
    cursor: pointer;
    padding: 6px 4px;
    transition: color 120ms ease;
    -webkit-tap-highlight-color: transparent;
}

#mobile-bottom-nav .mbn-item.is-active {
    color: var(--accent-cyan, #38BDF8);
}

#mobile-bottom-nav .mbn-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    line-height: 1;
}
#mobile-bottom-nav .mbn-icon svg {
    width: 100%;
    height: 100%;
    display: block;
}

#mobile-bottom-nav .mbn-label {
    font-weight: 500;
    letter-spacing: 0.02em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}

/* Reserve space at the app-container level for the fixed bottom-nav.
   body is `height:100vh; overflow:hidden` (styles.css:133). Setting an
   explicit shorter height on .app-container makes every flex descendant
   (including .main-content > scroll children) compute against that
   reduced height, so the fixed nav at bottom:0 has its own gap to live
   in. `dvh` is preferred because iOS Safari's `vh` is the LARGER viewport
   (URL-bar-hidden); `vh` is the fallback for older browsers. */
body.is-mobile .app-container {
    height: calc(100vh - var(--mobile-bottom-nav-height) - var(--safe-bottom));
    height: calc(100dvh - var(--mobile-bottom-nav-height) - var(--safe-bottom));
}

/* Belt-and-braces: some views set `overflow-y: auto` directly on the
   .main-content element (e.g. #overview-view, #document-view at
   styles.css:592) and skip the inner scroll-container pattern. The
   app-container height above SHOULD cover them, but iOS Safari's
   dynamic viewport + browser chrome can leak ~30–60px of content under
   the nav before the user notices. A defensive padding-bottom on those
   direct-scroll mains guarantees the last item is always above the nav.
   The padding is applied to .main-content children too so views like
   the kanban that scroll a child container still get the safety net.
   Padding (not margin) keeps the page background filling the gap. */
body.is-mobile #overview-view,
body.is-mobile #document-view,
body.is-mobile .main-content > .board-container,
body.is-mobile .main-content > .list-view-container,
body.is-mobile .main-content > .calendar-container,
body.is-mobile .main-content > .timeline-container,
body.is-mobile .main-content > .document-content,
body.is-mobile .main-content > .analytics-container,
body.is-mobile .main-content > .fin-container,
body.is-mobile #attachments-container,
body.is-mobile #my-tasks-container,
body.is-mobile #admin-view .admin-grid,
body.is-mobile #project-management-view .admin-grid {
    padding-bottom: calc(var(--mobile-bottom-nav-height) + var(--safe-bottom) + 16px);
    scrollbar-gutter: stable;
}

/* -------------------------------------------------------------------
   Global mobile fixes — anything that breaks at narrow widths before
   the per-view phases land. These are minimal — Phase 1+ will replace
   most of them with proper layouts.
   ------------------------------------------------------------------- */
@media (max-width: 767px) {
    /* Prevent every horizontal-overflow source (long pre, long URLs,
       wide tables) from forcing a horizontal scroll on the whole page. */
    html, body {
        overflow-x: hidden;
        max-width: 100vw;
    }

    /* Honor safe-area on the app shell so content doesn't slide under
       the iPhone status bar in standalone mode. */
    .app-container {
        padding-top: var(--safe-top);
    }

    /* Sidebar already slides in from the side via the existing pattern
       at styles.css:541. We just need to honor the safe-area top. */
    .sidebar {
        padding-top: calc(var(--safe-top) + 12px);
    }
}

/* Phone portrait — single column everywhere, smallest layout */
@media (max-width: 480px) {
    /* Stop top-bar buttons from wrapping awkwardly; let them scroll
       horizontally as a single row instead. Per-view phases will
       replace this with proper button-collapse / filters sheet. */
    .top-bar .controls {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        flex-wrap: nowrap;
    }
    .top-bar .controls > * {
        flex-shrink: 0;
    }

    /* Modals: full-height on phones so users can actually read them. */
    .modal .modal-content {
        max-width: 100vw !important;
        max-height: calc(100vh - var(--safe-top) - var(--safe-bottom)) !important;
        margin: 0;
        border-radius: 0;
    }
}

/* -------------------------------------------------------------------
   Standalone PWA tweaks — when the app is launched from the home
   screen, hide any in-page "Install" prompts and tighten the top
   chrome. mobile.js adds `is-standalone` to body when matchMedia
   '(display-mode: standalone)' is true.
   ------------------------------------------------------------------- */
body.is-standalone .mobile-install-prompt {
    display: none !important;
}

/* -------------------------------------------------------------------
   Redundancy removal on mobile
   The desktop top-bar carries a hamburger (`.mobile-menu-toggle`) that
   opens the sidebar — but on mobile the bottom-nav "More" tab covers
   that, so the in-page button is duplicate UI. Hide it everywhere on
   mobile so the top-bar reads cleaner.
   ------------------------------------------------------------------- */
body.is-mobile .mobile-menu-toggle {
    display: none !important;
}

/* The sidebar header has its own collapse/toggle hamburger
   (#btn-toggle-sidebar). On mobile the sidebar is opened/closed
   exclusively via the "More" bottom-nav tab, so the inside hamburger
   is redundant chrome — hide it. */
body.is-mobile #btn-toggle-sidebar {
    display: none !important;
}

/* -------------------------------------------------------------------
   Collapsible top-bar filters
   The `.controls` block in every view's top-bar (search / assignee /
   group / priority / action buttons) eats most of a phone screen above
   the actual content. mobile.js injects a `.mobile-filter-toggle` button
   before each `.controls`. Default state: filters hidden. Tap toggle:
   filters expand. Toggle button itself hidden on desktop.
   ------------------------------------------------------------------- */
.mobile-filter-toggle {
    display: none;
}

body.is-mobile .mobile-filter-toggle {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    align-self: flex-start;
    padding: 8px 14px;
    font-size: 0.85rem;
    font-weight: 500;
    background: transparent;
    color: var(--text-secondary);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

body.is-mobile .mobile-filter-toggle .mft-icon,
body.is-mobile .mobile-filter-toggle .mft-chevron {
    display: inline-flex;
    width: 16px;
    height: 16px;
}
body.is-mobile .mobile-filter-toggle .mft-icon svg,
body.is-mobile .mobile-filter-toggle .mft-chevron svg {
    width: 100%;
    height: 100%;
}
body.is-mobile .mobile-filter-toggle .mft-chevron {
    transition: transform 180ms ease;
}
body.is-mobile .mobile-filter-toggle.is-open .mft-chevron {
    transform: rotate(180deg);
}
body.is-mobile .mobile-filter-toggle.is-open {
    color: var(--text-primary);
    border-color: var(--accent-cyan, #38BDF8);
}

/* Hide the controls block by default on mobile. mobile.js toggles
   .is-open on it via the filter-toggle button. Covers both the static
   `.controls` blocks (kanban/list/calendar/timeline/analytics) and the
   dynamically-rendered `.ov-controls` block in the overview view. */
body.is-mobile .top-bar .controls,
body.is-mobile .top-bar .ov-controls {
    display: none;
}
body.is-mobile .top-bar .controls.is-open {
    display: flex;
}
body.is-mobile .top-bar .ov-controls.is-open {
    /* Preserve the overview's native flex/grid layout; only flip visibility. */
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* -------------------------------------------------------------------
   Calendar — drop the leading/trailing month-padding cells on mobile.
   On desktop those cells preserve weekday alignment in the 7-col grid,
   but on a 1-col mobile layout they render as huge blank rows above /
   below the actual month. Just skip them on phones; the heading already
   tells the user what month they're looking at.
   ------------------------------------------------------------------- */
body.is-mobile .calendar-day-pad {
    display: none;
}

/* -------------------------------------------------------------------
   Calendar — mobile month switcher and Options panel.
   By default `body.is-mobile .top-bar .controls` is `display: none`
   (mobile.js shows it via `.is-open`). For the calendar we keep the
   container itself visible so the month nav lives above the collapsed
   Options panel — month navigation is primary and shouldn't be hidden
   behind a tap. Other children only render when the Options toggle is
   open. Override the global rule with #-prefix specificity.
   ------------------------------------------------------------------- */
body.is-mobile #calendar-controls {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 8px 0 0;
    width: 100%;
}
body.is-mobile #calendar-controls > * {
    display: none;
}
body.is-mobile #calendar-controls > .calendar-month-nav {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    gap: 8px;
}
body.is-mobile #calendar-controls.is-open > * {
    /* When the Options panel is open, reveal every control as a block-flex.
       Block-flex matches the column layout the children expect. */
    display: flex;
}
/* Bigger, easier to tap month-nav buttons on phones. */
body.is-mobile .calendar-month-nav-btn {
    min-width: 44px;
    min-height: 40px;
    padding: 8px 14px;
    font-size: 1rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
body.is-mobile .calendar-month-nav .calendar-month-label {
    flex: 1 1 auto;
    text-align: center;
    min-width: 0;
    font-size: 1rem;
    letter-spacing: 0;
}

/* -------------------------------------------------------------------
   Workflow columns (kanban-style multi-column grids inside My Tasks,
   project board, etc.) — on desktop columns sit side-by-side with a
   horizontal-scroll fallback. On mobile they currently overflow the
   page horizontally because the inline `grid-template-columns:
   repeat(N, minmax(260px, 1fr))` style wins over the CSS rule. Force
   a vertical stack so columns flow down the screen instead.
   `!important` is required to beat the inline style; a per-controller
   mobile branch would be cleaner but is out of scope for Phase 0.
   The swimlane-content scroll container is no longer needed once
   columns stack, so disable its overflow trapping too.
   ------------------------------------------------------------------- */
body.is-mobile .workflow-columns {
    grid-template-columns: 1fr !important;
    gap: 10px;
}

body.is-mobile .swimlane-content {
    overflow-x: visible;
    flex-direction: column;
    align-items: stretch;
}

body.is-mobile .column {
    min-width: 0 !important;
    width: 100%;
}

/* -------------------------------------------------------------------
   Fixed-position elements need to lift above the bottom-nav, not sit
   under it.
   ------------------------------------------------------------------- */
body.is-mobile .bulk-bar {
    bottom: calc(var(--mobile-bottom-nav-height) + var(--safe-bottom) + 14px);
}

/* -------------------------------------------------------------------
   Gantt / Timeline mobile layout
   At desktop the timeline reserves min 240px for the label column and
   gives the rest to the bar track. On a 360px phone that leaves ~120px
   for the bars — they collapse into unreadable strips.
   Strategy: shrink the label column, set a usable min-width on the
   chart wrapper so the track always has room for a meaningful range,
   and let users scroll the chart horizontally. Vertical scrolling stays
   inside `.timeline-body` as before.
   ------------------------------------------------------------------- */
body.is-mobile .timeline-chart-wrapper {
    --timeline-label-width: 110px;
    /* Override the desktop `overflow: hidden` so horizontal panning is
       possible; vertical scrolling still lives inside `.timeline-body`. */
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
}

/* The header row and every chart row need to share the same min-width so
   they scroll horizontally as a unit and the bars stay aligned with the
   header date range. 640px gives ~530px of track after the label column,
   which is comfortable for a 30-day window. */
body.is-mobile .timeline-header-row,
body.is-mobile .timeline-row {
    min-width: 640px;
}

/* Tighten bar typography so labels stay readable inside the now-narrower
   bars without forcing wider min-widths on the chart. */
body.is-mobile .timeline-bar {
    font-size: 0.62rem;
    padding: 0 5px;
}

/* The timeline controls row (prev/next/today/zoom/project-filter) is
   essential nav, not optional filters — keep it visible on mobile but
   let buttons wrap and shrink so they don't bust out of the viewport. */
body.is-mobile .timeline-controls {
    flex-wrap: wrap;
    gap: 6px;
    padding: 8px;
}
body.is-mobile .timeline-controls .glass-btn-sm {
    padding: 6px 8px;
    font-size: 0.75rem;
}
body.is-mobile .timeline-filter-label {
    flex-basis: 100%;
    display: flex;
    align-items: center;
    gap: 6px;
}
body.is-mobile .timeline-filter-label select {
    flex: 1;
}
/* The spacer is a desktop "push everything right" trick — neutralize it
   so wrapped rows pack tight together instead of leaving a gap. */
body.is-mobile .timeline-controls-spacer {
    display: none;
}

/* -------------------------------------------------------------------
   Overview (Projects view) — stack project header vertically on mobile
   The desktop layout puts the project title block beside a 180px-wide
   aside that carries the progress bar. On a 360px screen that aside
   eats half the row, squeezing the title down to ~180px and forcing
   it to wrap or truncate. Flip the header to column flex so the
   progress bar moves to its own row below the title.
   ------------------------------------------------------------------- */
body.is-mobile .ov-project-head {
    flex-direction: column;
    gap: 10px;
}
body.is-mobile .ov-project-head-aside {
    min-width: 0;
    width: 100%;
    align-items: stretch;
}
body.is-mobile .ov-project-pbar {
    width: 100%;
}

/* When a project is expanded its task list renders as a 6-column flex
   row on desktop (title / assignee / planned / realized / progress /
   actions). On mobile that compresses each cell to ~45px and breaks
   the layout. Stack everything into a card per row instead: title +
   actions on top, metadata rows below, progress bar at the bottom.
   Hide the desktop column-header row entirely — without per-row labels
   it's just dead weight on mobile. */
body.is-mobile .ov-task-table-head {
    display: none;
}

body.is-mobile .ov-task-row {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas:
        "title    actions"
        "assignee assignee"
        "planned  planned"
        "realized realized"
        "progress progress";
    column-gap: 8px;
    row-gap: 4px;
    padding: 12px;
    align-items: start;
}
body.is-mobile .ov-task-title    { grid-area: title;    min-width: 0; flex: none; }
body.is-mobile .ov-task-actions  { grid-area: actions;  flex: none; }
body.is-mobile .ov-task-assignee { grid-area: assignee; flex: none; }
body.is-mobile .ov-task-planned  { grid-area: planned;  flex: none; }
body.is-mobile .ov-task-realized { grid-area: realized; flex: none; }
body.is-mobile .ov-task-progress { grid-area: progress; flex: none; width: 100%; }

/* Hide the metadata cells when they're empty so the row collapses
   gracefully (a task with no assignee or no planned-date shouldn't
   leave a blank grid track). */
body.is-mobile .ov-task-row .ov-task-assignee:empty,
body.is-mobile .ov-task-row .ov-task-planned:empty,
body.is-mobile .ov-task-row .ov-task-realized:empty {
    display: none;
}

/* Subtask rows stay inset but use the same stacked layout. */
body.is-mobile .ov-task-row-subtask {
    padding-left: 22px;
}

/* -------------------------------------------------------------------
   Phase 1+ rules will be added below this line. Each phase appends
   a new commented section so blame stays useful.
   =================================================================== */
