/* Phase 1 mobile shell. Loaded after style.css — see the <link> in header.ejs,
   login.ejs, meeting-room-guest.ejs, meeting-guest-lobby.ejs, terms.ejs, privacy.ejs,
   meeting-guest-notice.ejs.
   Overrides here beat style.css purely on source order; anywhere style.css already
   uses !important (e.g. .nav-user, .expense-filter-form's inline flex-wrap) we
   match it with !important too. */

/* Aragorn's baseline (2026-09-21) found .nav-links overflowing the viewport by
   127px at 1280px and still overflowing at 1366px — the hamburger only takes
   over at <=1200px, and the row no longer fits at common laptop widths. */
@media (min-width: 1201px) and (max-width: 1400px) {
  /* .nav-links also carries flex-shrink:0 (style.css:181) — as .nav-bottom's
     only flex child it keeps most of its unwrapped max-content width
     regardless of flex-wrap (measured: only 127px -> 82px at 1280px).
     flex-shrink:1 + max-width:100% force it to actually shrink to the
     available width so the wrap fully engages. */
  .nav-links {
    flex-wrap: wrap;
    flex-shrink: 1;
    max-width: 100%;
    justify-content: center;
  }
}

.table-wrapper {
  -webkit-overflow-scrolling: touch;
}

/* Approved-tab mobile select-all toolbar control (expenses.ejs) — the real
   #qbSelectAll lives in a <thead> that .table-cards hides at <=768px. Base
   rule hides it everywhere; the max-width:768px .table-cards block below
   switches it back on for phones. A style="display:flex" on the label used
   to force it on at all widths — style attributes outrank any plain author
   rule, including this media query, so it had to come off the element
   instead (Gandalf MEDIUM-1). */
.qb-select-all-mobile {
  display: none;
}

.table-wrapper.has-overflow {
  /* Inset shadow instead of a ::after/position:relative trick, so it can't
     shift positioning context for absolutely-positioned children on any of
     the many pages that reuse .table-wrapper. Gated behind .has-overflow
     (see footer.ejs) so it only paints when the table genuinely overflows. */
  box-shadow: inset -20px 0 16px -16px rgba(15, 27, 45, 0.15);
}

/* Login page: body.login-page is a flex box shared by the optional staging
   banner and .login-outer. In row mode (the default) the banner was a
   second flex item beside the card, so .login-page's justify-content:center
   centred the pair and overflowed narrow viewports (Aspi's phone report,
   2026-09-21). Column direction + .login-outer's flex:1/justify-content
   reproduces the old single-item centring exactly when there's no banner,
   and pins the banner as a full-width bar above the card (matching
   header.ejs) when there is one, with .login-outer centring in whatever
   space is left below it. Negative margins cancel .login-page's own
   padding (style.css) so the banner reaches the true viewport edges
   instead of sitting inset — width has to grow by the same 2rem the
   margins claw back, since .login-page's align-items:center centres the
   banner's margin box first: a plain 100% width leaves the margin box
   narrower than the available space and re-centring re-introduces the
   inset the negative margin was meant to remove. */
body.login-page {
  flex-direction: column;
}

.login-staging-banner {
  width: calc(100% + 2rem);
  flex: 0 0 auto;
  order: -1;
  margin: -1rem -1rem 1rem;
}

.login-outer {
  flex: 1 1 auto;
  justify-content: center;
}

@media (max-width: 640px) {
  /* Mirrors style.css's own .login-page padding/align-items breakpoint —
     keep this in step with that rule, not the 768/480 breakpoints used
     elsewhere in this file. */
  .login-staging-banner {
    margin-top: -2rem;
  }

  .login-outer {
    justify-content: flex-start;
  }
}

@media (max-width: 768px) {
  html {
    overflow-x: hidden;
    overflow-x: clip;
  }

  body {
    overflow-x: clip;
  }

  img,
  svg,
  video,
  canvas {
    max-width: 100%;
  }

  .container,
  .container-wide,
  .container-full {
    max-width: 100%;
    padding-left: 1rem;
    padding-right: 1rem;
  }

  .notes-container,
  .notes-container-flush {
    padding-left: 1rem;
    padding-right: 1rem;
  }

  .nav-top {
    flex-wrap: nowrap;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    min-width: 0;
  }

  .navbar-title {
    position: static;
    top: auto;
    left: auto;
    transform: none;
    font-size: 1.05rem;
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .navbar-logo {
    height: 28px;
    width: auto;
  }

  /* The notify bell is a sibling of .nav-user-dropdown inside .nav-user.
     Hiding .nav-user-dropdown (not .nav-user) keeps the bell visible next to
     the hamburger without moving it in the markup; its links move into the
     drawer's Account section instead (see header.ejs). */
  .nav-user-dropdown {
    display: none;
  }

  #meeting-notify-bell {
    min-width: 44px;
    min-height: 44px;
  }

  .navbar-hamburger {
    order: 99;
    margin-left: auto;
  }

  .hero-banner {
    padding: 1.25rem 1rem;
  }

  .hero-logo-img {
    height: auto;
    width: min(100%, 260px);
    max-width: 100%;
  }

  .card-header {
    padding: 0.9rem 1rem;
    flex-wrap: wrap;
    row-gap: 0.5rem;
  }

  .card-header > span:first-child {
    min-width: 0;
    flex-wrap: wrap;
  }

  .btn {
    min-height: 44px;
    padding: 0.65rem 1rem;
  }

  .btn-small {
    min-height: 36px;
  }

  .navbar-mobile__link {
    min-height: 44px;
  }

  /* !important: several forms set font-size inline per-field (e.g. the
     Project input in expense-form.ejs is 0.875rem inline), which otherwise
     beats an external rule and re-opens the iOS zoom-on-focus bug. */
  .form-group input,
  .form-group select,
  .form-group textarea {
    font-size: 16px !important;
  }

  .login-field input {
    font-size: 16px;
  }

  .badge {
    font-size: 0.68rem;
  }

  /* mileage.ejs sets flex-wrap: nowrap inline on .expense-filter-form, so the
     override needs !important to win (Aragorn baseline: 325px overflow here,
     the worst of the sweep). Only used on /mileage. */
  .expense-filter-form {
    flex-wrap: wrap !important;
  }

  .expense-filter-form select,
  .expense-filter-form input {
    flex: 1 1 100% !important;
    min-width: 0 !important;
    font-size: 16px !important;
  }

  .expense-filter-form .btn {
    flex: 1 1 auto !important;
  }
}

/* Phase 2a: expense tab strip becomes a horizontal scroll-snap carousel —
   style.css:4043 already sets overflow-x:auto at this breakpoint, this adds
   the snap behaviour and hides the scrollbar. Shared with mileage.ejs and
   incidents.ejs, which reuse the same .expense-tabs/.expense-tab markup. */
@media (max-width: 768px) {
  .expense-tabs {
    flex-wrap: nowrap;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    -ms-overflow-style: none;
  }

  .expense-tabs::-webkit-scrollbar {
    display: none;
  }

  .expense-tab {
    scroll-snap-align: start;
    flex: 0 0 auto;
    white-space: nowrap;
  }
}

/* Aspi E2: 769-1200px band. Seven Expenses admin tabs overflow the page at
   1000 wide (Session 106 measured 163px). Scroll horizontally to keep the
   active-tab underline intact; wrap would break style.css:3486/3495's
   border-bottom/margin-bottom:-2px overlap. Shared with mileage.ejs and
   incidents.ejs which have 2 tabs each — inert when content fits inside the
   strip. No scroll-snap here — this band is mouse/trackpad, not touch. */
@media (min-width: 769px) and (max-width: 1200px) {
  .expense-tabs {
    overflow-x: auto;
    flex-wrap: nowrap;
    scrollbar-width: none;
    -ms-overflow-style: none;
  }

  .expense-tabs::-webkit-scrollbar {
    display: none;
  }

  .expense-tab {
    flex: 0 0 auto;
    white-space: nowrap;
  }
}

/* Phase 2a: card-per-row transform for the Expenses All/Pending/Approved/
   Declined tables and the Mileage list — opt in with `.table-cards` on the
   <table> and `data-label="<th text>"` on every <td> (empty string, not a
   missing attribute, suppresses the label — see the [data-label=""] rule).
   Reconciliation/Synced/Processed Personal/Per Diem are admin desktop
   tools and keep the plain scrolling table; this block never touches them.
   `tr` is a grid, not a plain block, so `order` can promote the two
   `.tc-primary-*` cells (merchant+amount, or date+route) above the
   ordinary label/value rows without changing DOM order; `.tc-actions`
   breaks out of the label/value pattern into full-width 44px buttons. */
@media (max-width: 768px) {
  /* .table-wrapper.expense-sticky-wrap (style.css ~3653) is also two classes
     and loads first; matching its specificity here and relying on mobile.css
     loading second (header.ejs) is what wins the cascade — an !important on
     overflow/max-height would just invite the next specificity war. */
  .table-wrapper.table-cards-wrapper {
    overflow: visible;
    max-height: none;
  }

  .table-cards thead {
    display: none;
  }

  .table-cards,
  .table-cards tbody {
    display: block;
    width: 100%;
  }

  .table-cards tr {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 0.75rem;
    row-gap: 0.2rem;
    background: var(--card, #fff);
    border: 1px solid var(--border, #e2e8f0);
    border-radius: var(--radius-lg, 10px);
    padding: 0.75rem 0.875rem;
    margin-bottom: 0.75rem;
    box-shadow: var(--shadow-sm, 0 1px 2px rgba(15, 27, 45, 0.08));
    /* Legolas: median measured card height on Expenses All (337 rows) is
       ~295px (range 256-351px) — 290px keeps the off-screen placeholder
       close to real size. `auto` remembers the real height once a row has
       rendered once, so this only affects unvisited rows. */
    content-visibility: auto;
    contain-intrinsic-size: auto 290px;
  }

  .table-cards tbody tr:last-child {
    margin-bottom: 0;
  }

  /* The description/edit-history "sub-rows" (colspan on desktop) read as a
     note attached to the card above rather than a card of their own. */
  .table-cards tr.expense-desc-row,
  .table-cards tr.expense-edit-history-row {
    margin-top: -0.6rem;
    padding-top: 0.5rem;
    border-top: none;
    border-top-left-radius: 0;
    border-top-right-radius: 0;
    background: var(--bg-light, #f8fafc);
    box-shadow: none;
  }

  .table-cards tr.expense-desc-row td,
  .table-cards tr.expense-edit-history-row td {
    grid-column: 1 / -1;
    padding: 0;
  }

  .table-cards td {
    display: flex;
    align-items: flex-start;
    flex-wrap: wrap;
    column-gap: 0.4rem;
    row-gap: 0.1rem;
    padding: 0.3rem 0;
    border: none;
    font-size: 0.8125rem;
    min-width: 0;
    /* style.css:743 sets `table tbody tr { white-space: nowrap }` for the
       desktop scrolling-table layout, inherited into every cell; several
       desktop <td>s also carry an inline nowrap. Both need beating so long
       merchant/description/route text wraps inside the card instead of
       overflowing the viewport. */
    white-space: normal !important;
  }

  .table-cards td::before {
    content: attr(data-label);
    font-weight: 600;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--text-mid, #64748b);
    margin-right: auto;
    flex-shrink: 0;
  }

  .table-cards td[data-label=""]::before {
    content: none;
  }

  /* A <td> with no data-label attribute at all (missed when a table was
     opted into .table-cards) would otherwise render an empty ::before box
     via attr(data-label) resolving to "" — content: none suppresses it. */
  .table-cards td:not([data-label])::before {
    content: none;
  }

  .table-cards td.tc-primary-1,
  .table-cards td.tc-primary-2,
  .table-cards td.tc-actions {
    grid-column: 1 / -1;
  }

  .table-cards td.tc-primary-1,
  .table-cards td.tc-primary-2 {
    display: block;
    padding: 0 0 0.3rem;
    font-weight: 700;
    font-size: 0.9375rem;
    color: var(--text, #0f1b2d);
  }

  .table-cards td.tc-primary-1::before,
  .table-cards td.tc-primary-2::before {
    content: none;
  }

  .table-cards td.tc-primary-1 {
    order: -2;
  }

  .table-cards td.tc-primary-2 {
    order: -1;
  }

  .table-cards td.tc-amount {
    text-align: right;
    color: var(--accent, #2563eb);
  }

  .table-cards td.tc-actions {
    display: block;
    margin-top: 0.4rem;
    padding-top: 0.6rem;
    border-top: 1px solid var(--border-light, #f1f5f9);
  }

  .table-cards td.tc-actions::before {
    display: block;
    margin-bottom: 0.5rem;
  }

  .table-cards td.tc-actions form,
  .table-cards td.tc-actions > a,
  .table-cards td.tc-actions > button,
  .table-cards td.tc-actions > div {
    display: block;
    width: 100%;
    margin: 0 0 0.5rem;
    box-sizing: border-box;
  }

  .table-cards td.tc-actions form:last-child,
  .table-cards td.tc-actions > a:last-child,
  .table-cards td.tc-actions > button:last-child,
  .table-cards td.tc-actions > div:last-child {
    margin-bottom: 0;
  }

  .table-cards td.tc-actions a.btn-small,
  .table-cards td.tc-actions button.btn-small,
  .table-cards td.tc-actions form button,
  .table-cards td.tc-actions > select {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: 44px;
    box-sizing: border-box;
  }

  /* task-row.ejs's status <select> carries an inline font-size:0.8rem that
     triggers iOS Safari's zoom-on-focus below 16px. !important is needed to
     beat the inline style without stripping it (that would change desktop
     sizing too). */
  .table-cards td.tc-actions select {
    font-size: 16px !important;
  }

  .qb-select-all-mobile {
    display: flex;
    align-items: center;
    gap: 0.375rem;
  }
}

/* dvh progressive-enhancement: iOS Safari's collapsing toolbar shortens
   100vh on scroll; browsers without dvh ignore the second line */
@media (max-width: 768px) {
  .eve-modal {
    max-height: calc(100vh - 2rem);
    max-height: calc(100dvh - 2rem);
  }
  .tracking-sidebar {
    max-height: 40vh;
    max-height: 40dvh;
  }
  .tracking-map {
    height: 60vh;
    height: 60dvh;
  }
}

@media (max-width: 480px) {
  .navbar-title {
    display: none;
  }

  .card-header .btn {
    width: 100%;
    justify-content: center;
  }

  .modal .modal-content,
  .confirm-modal,
  .eve-modal,
  .ra-modal-content,
  .qb-error-modal {
    width: 100%;
    max-width: 100%;
    max-height: calc(100vh - 1.5rem);
    max-height: calc(100dvh - 1.5rem);
  }

  .confirm-modal {
    overflow-y: auto;
  }

  .ra-modal {
    padding: 1rem;
  }
}

@media print {
  .navbar-mobile-overlay,
  .navbar-hamburger {
    display: none !important;
  }
}
