/* Phone / small-tablet layout.
 *
 * Loaded last so it can override the desktop rules in layout.css, chat.css and
 * today-calendar-sidebar.css without any `!important`. Everything here is inside
 * a media query — on a desktop viewport this file contributes nothing.
 *
 * Two things the desktop CSS gets wrong on a phone, and what this fixes:
 *
 * 1. Side panels are sized as a fraction of the viewport
 *    (`--chat-panel-width: min(420px, 40vw)`), so on a 390px phone the goals /
 *    brain-dump / chat panels collapse to ~156px of unusable column. On mobile
 *    every panel becomes a full-width overlay instead, and the shell stops
 *    reserving padding for it — there is no room beside it to shift into.
 *
 * 2. The desktop topbar stacks into a column when its row does not fit
 *    (js/app-shell/topbar_fit.js), which on a phone would push the
 *    view content most of a screen down. Here it stays a compact two-row
 *    header and the tab strip scrolls horizontally instead of wrapping.
 *
 * The media query below is the SAME text as PHONE_QUERY in js/mobile/mobile.js,
 * and js/mobile/watch.py asserts they still match. A phone that gets this
 * stylesheet without the matching `is-phone` class — or the reverse — is a
 * layout that half-applies: full-screen panels with no Back button to close
 * them, or a Back press that closes a panel sitting in a desktop column.
 *
 * The second clause catches a phone in landscape (~915x412): wide enough to
 * miss a width-only test, short enough that the desktop topbar eats the screen.
 */

@media (max-width: 900px), (pointer: coarse) and (max-height: 520px) {
  /* ── Topbar ─────────────────────────────────────────────────────────────
     Never the desktop column stack; a phone needs the header short, not tall. */
  .topbar {
    flex-direction: row;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    padding-top: max(8px, env(safe-area-inset-top));
  }

  .topbar-left {
    flex: 1 1 100%;
    gap: 4px;
    overflow-x: auto;
    scrollbar-width: none;
  }

  .topbar-left::-webkit-scrollbar {
    display: none;
  }

  .topbar-actions {
    flex: 1 1 100%;
    justify-content: flex-start;
    gap: 6px;
  }

  /* The tab strip scrolls sideways rather than wrapping to three rows. */
  .tab-group {
    display: flex;
    flex: 1 1 100%;
    max-width: 100%;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }

  .tab-group::-webkit-scrollbar {
    display: none;
  }

  /* Tabs and icon buttons grow to a thumb-sized target (~40px tall). */
  .tab {
    flex: 0 0 auto;
    padding: 9px 12px;
    font-size: 13px;
  }

  .nav-icon-button {
    width: 36px;
    height: 36px;
  }

  .nav-icon-button--labeled {
    width: auto;
    height: 36px;
  }

  .topbar-views-summary {
    padding: 8px 12px;
  }

  .topbar-week-label {
    padding: 6px 4px;
  }

  /* Dropdowns are anchored to a topbar button, so at phone width they hang off
     the edge of the screen. Pin them to the viewport instead. */
  .topbar-views-panel,
  .topbar-goal-view-panel {
    left: 0;
    right: auto;
    min-width: 0;
    width: calc(100vw - 20px);
    max-width: calc(100vw - 20px);
    max-height: 70vh;
    overflow-y: auto;
  }

  /* The Days dropdown is anchored mid-topbar rather than at its left edge, so
     the pin above would push it off the RIGHT instead. It is a short list of
     short labels — hang it from the trigger's right edge and let it be as wide
     as it needs to be. `computeMaxDays()` answers 1 on a phone whatever is
     picked here, so this menu states a preference for the next desktop/landscape
     session; that is why it is not hidden outright. */
  .topbar-days-wrap .topbar-days-menu {
    left: auto;
    right: 0;
    min-width: 0;
    max-width: calc(100vw - 20px);
    max-height: 70vh;
    overflow-y: auto;
  }

  /* ── Topbar surfaces that moved into the drawer ─────────────────────────
     `.topbar-actions` is the panel-opening strip, and it is the whole reason the
     phone topbar used to be 203px tall — wrapped flex rows, each
     `flex: 1 1 100%`. Every destination in it is a row in the nav drawer
     (js/app-shell/nav_drawer.js builds them from the same constants), so showing
     it here as well would be two controls for one thing, stacked, on the
     smallest screen the app runs on.

     What stays in the phone topbar: the hamburger, the week label, the
     prev/next/Today period navigation, and the four cycle tabs. */
  .topbar-actions {
    display: none;
  }

  /* ⚠️ `#primary-navigation` USED to be hidden here, alongside the line above,
     and for the same reason: it was a strip of six DESTINATIONS, every one of
     which the drawer also lists.

     It is the Envision · Plan · Do · Reflect cycle now, and the cycle is what the
     app is for — the drawer's rows are horizons and destinations, not steps, and
     it cannot express "the same view, reflecting" without inventing a second way
     to say it. Hiding this would make Reflect unreachable on a phone, i.e. in the
     whole Android app, with nothing to show for it: four short tabs are one row
     that scrolls sideways (see `.tab-group` above).

     (`#primary-navigation` rather than `.tab-group`, whichever way this rule
     goes: the auth screen's `#guest-tabs` shares that class and is the only
     navigation on a page the drawer does not exist on.) */
  #primary-navigation {
    /* Its own row, and wide enough to hit with a thumb. */
    flex: 1 1 100%;
    justify-content: center;
  }

  /* `#views-toggle-wrap` (the "Views" dropdown) is deliberately NOT hidden. It
     is a control for the view currently on screen, not global navigation, so it
     belongs with the period label and the prev/next/Today buttons that stay
     here. Only the surfaces that move you *between* views leave the phone
     topbar — those are what the drawer is for.

     It was hidden briefly on 2026-07-29 and restored the same day. If you hide
     it again, note that it needs `!important`: `router.js` writes
     `style.display` on this element directly, and an inline style outranks an
     ID selector, so the obvious rule silently does nothing. */

  /* Exactly one hamburger — the two halves of that rule are here.

     Two adjacent three-line icons that open different things is the confusing
     outcome this avoids, so the swap is all-or-nothing: whichever one is shown,
     the other is hidden.

     Desktop: my calendars (its panel opens beside the view, which is a desktop
     interaction) and no drawer — nav-drawer.css hides the drawer toggle.
     Phone: the drawer (it carries the whole topbar navigation the rules above
     hide) and my calendars becomes a row inside it.

     `.nav-icon-button.mobile-nav-drawer-toggle` doubled to match the specificity
     of the rule it overrides; a single class would lose the tie and the phone
     would have no hamburger at all. */
  .my-calendars-toggle {
    display: none;
  }

  .nav-icon-button.mobile-nav-drawer-toggle {
    display: inline-flex;
  }

  /* ── Side panels become full-screen overlays ────────────────────────────
     The width is a viewport fraction that goes unusable on a phone. My
     calendars is a `.chat-panel` since 2026-08-09, so it is covered by these
     rules rather than by a second set of its own. */
  .app-shell {
    --chat-panel-width: 100vw;
    padding-bottom: env(safe-area-inset-bottom);
  }

  .chat-panel {
    width: 100vw;
    max-width: 100vw;
    border-left: 0;
    border-right: 0;
  }

  /* An overlay covers the shell, so the shell must not also indent for it —
     that would push the content out from under a panel that is already on top
     of it. */
  .app-shell-chat-open {
    padding-right: 0;
  }

  .chat-panel-header {
    padding-top: max(12px, env(safe-area-inset-top));
  }

  /* Close buttons are the only way back out of a full-screen panel. */
  .chat-panel-close {
    font-size: 26px;
    padding: 6px 12px;
  }

  /* The Brain Dump's cards wire no drag at this breakpoint at all — the gesture
     drops onto the Calendar's time grid, which a full-screen panel is sitting on
     top of. `brain_dump_outline.js` passes `onDrag: null` here, and the board
     card has no grip element to hide, so nothing is needed on this side any
     more. (Until 2026-08-08 this hid `.pbd-grip` and re-declared the row's grid
     columns to close the gap it left.) */

  /* `grab` on a card that no longer drags. Harmless on touch, but this
     breakpoint also catches a narrow desktop window, where the cursor is real
     and would be promising a gesture that is wired off. */
  .bds-row {
    cursor: default;
  }

  /* The dump's words at phone reading size. Also the iOS rule: a contenteditable
     under 16px zooms the page on focus and never zooms back. Same selector as the
     desktop rule in brain-dump-sidebar.css — this file loads later, so it wins
     the tie without `!important`. */
  .bds-list .bds-row.gb-card .ltg-text {
    font-size: 17px;
  }

  /* ── View content ──────────────────────────────────────────────────────── */
  .guest-banner-inner {
    padding: 8px 10px;
  }

  /* The desktop backdrop blur is a full-viewport filter that costs real frames
     on a phone GPU while sitting behind opaque cards. */
  .backdrop {
    filter: blur(20px);
  }

  /* ── Multi-column goal grids collapse to a single column ────────────────
     These are the app's real source of horizontal overflow on a phone: the
     period grids are laid out at a per-column *minimum* (200-220px), so four
     quarters demand ~800px and the seven-day grid ~1260px. Below that width the
     grid does not shrink — the page scrolls sideways and the topbar, which is
     only 100vw wide, detaches from the content under it.

     `!important` is load-bearing here and is the one place this file needs it.
     `period_view_dom.js` and `weekly_long_term_goals_embed.js` write
     `gridTemplateColumns` as an *inline style* (it varies with the number of
     periods in view), and an inline style outranks any stylesheet selector
     regardless of specificity. Without `!important` these rules silently do
     nothing. Do not "clean them up". */
  .wlg-grid,
  .qlg-quarter-grid,
  .dlg-view .wlg-grid.dlg-grid {
    grid-template-columns: minmax(0, 1fr) !important;
  }

  /* The month overview keeps all seven columns — a month grid folded into one
     column stops being a month. Only the 120px floor has to go so the week
     fits the viewport instead of overflowing it. */
  .month-grid {
    grid-template-columns: repeat(7, minmax(0, 1fr));
  }

  .month-grid .month-cell,
  .month-grid .month-day {
    min-width: 0;
  }

  /* ── Week calendar ──────────────────────────────────────────────────────
     The day columns are already `minmax(0, 1fr)`, so they shrink rather than
     overflow — but the 90px time axis eats a quarter of a phone screen before
     the first day starts. Narrowing it hands that width back to the days.

     This is a mitigation, not a phone week view: seven columns on a 390px
     screen is still ~48px per day. A real one means rendering fewer days
     (`render.js` already drives column count off `--dn-week-days`, and already
     sets it to 1 for the day view), which is a JS + product change, not CSS. */
  .intentional-calendar-x-root .dn__calendar-wrapper,
  .intentional-calendar-x-root .dn__calendar,
  .intentional-calendar-x-root .dn__view-container,
  .intentional-calendar-x-root .dn__week-wrapper {
    --dn-week-time-axis-width: 52px;
  }

  /* ── Full-height shells ─────────────────────────────────────────────────
     `100vh` on Android is the viewport with the URL bar HIDDEN — the largest
     the screen ever gets. Every `min-height: 100vh` shell is therefore taller
     than the visible page on load, which adds a scrollbar's worth of dead space
     to a screen that has none to spare and makes the page bounce as the URL bar
     slides away.

     `--dn-viewport-height` is js/mobile/mobile.js tracking `visualViewport`,
     which is the height actually on screen right now — URL bar and software
     keyboard included. `100dvh` is the fallback for the first paint, before
     that module has run.

     `.chat-panel` is deliberately not in this list: it is `position: fixed`
     with `top: 0; bottom: 0`, which the `interactive-widget=resizes-content`
     in index.html's viewport meta already resizes for the keyboard. */
  body,
  .app-shell,
  .auth-shell {
    min-height: var(--dn-viewport-height, 100dvh);
  }

  .auth-page-stack {
    min-height: calc(var(--dn-viewport-height, 100dvh) - 120px);
  }

  .auth-hero-grid,
  .auth-card-wrap {
    min-height: auto;
  }

  /* ── Auth screen ────────────────────────────────────────────────────────
     The side padding is already tuned down from its 70px desktop value by
     auth.css's own 1200px and 680px rules — do not restate it here, this file
     loads later and would silently win. The one thing those rules predate is
     the notch: in landscape, `viewport-fit=cover` runs the shell under it.
     `max()` keeps whichever is larger, so on a phone with no inset this
     changes nothing. */
  .auth-shell {
    padding-left: max(14px, env(safe-area-inset-left));
    padding-right: max(14px, env(safe-area-inset-right));
  }

  /* ── Form inputs ────────────────────────────────────────────────────────
     iOS Safari auto-zooms the viewport on focus for any input whose font is
     under 16px, and never zooms back out — which on the auth screen leaves a
     first-time user stranded on a magnified, half-offscreen form. 16px is the
     threshold, not a style preference. */
  input,
  textarea,
  select,
  .auth-input {
    font-size: 16px;
  }
}
