/* OurHQ — phone layer
   ==========================================================================
   Everything in this file lives inside `@media (max-width: 820px)`. Nothing
   here can reach a desktop browser, which is the point: the desktop layout was
   asked to stay exactly as it is, and a separate file that is dark above 820px
   is a stronger guarantee than remembering to scope each rule.

   820px is not arbitrary — lira.css already lifts its button by 96px below
   that width "to sit above the bottom nav". This file is the bottom nav that
   comment was waiting for.

   Three ideas, applied everywhere:

     1. Navigation belongs at the bottom. Six links in the top bar ran 133px
        off the side of a phone; Settings and Sign out were half unreachable.
     2. Any field you type into is 16px. Below that, iOS zooms the page on
        focus and leaves you scrolled sideways in a layout you did not ask for.
     3. Anything you tap is at least 44px tall.
   ========================================================================== */


/* ── Hidden everywhere except a phone ──────────────────────────────────────
   This has to sit OUTSIDE the media query below, and it is the only thing
   that does.

   The bottom bar is in the HTML of every signed-in page. All of its styling
   lived inside the phone query, so on a desktop it had no styling at all: a
   plain block, containing five <svg viewBox="0 0 24 24"> with no width or
   height, each of which then stretched to the full width of the page. The
   dashboard rendered five 1400x1400 violet icons and a document 7,583px tall.

   `display: none` here is the default state; the query below turns it back on.
   Declaring a phone-only element's resting state is not a desktop change --
   it is what stops the element being a desktop change.
   ───────────────────────────────────────────────────────────────────────── */
.mobilenav { display: none; }


/* ── The "add to home screen" offer ────────────────────────────────────────
   Outside the phone query with the same reasoning as .mobilenav above: the
   element is only ever created by assets/pwa.js, which returns early on
   anything that is not a phone -- but an element with no resting state is how
   the bottom bar came to render five 1400px icons across the dashboard. It
   gets a defined state everywhere, and its real styling inside the query.
   ───────────────────────────────────────────────────────────────────────── */
.pwa-install { display: none; }

/* The phone condition, and why it is two clauses.
 *
 *   @media (max-width: 820px), (max-height: 500px) and (pointer: coarse)
 *
 * A phone turned sideways is 844px WIDE and 390px tall. On width alone it
 * reads as a desktop, and every rule in this file switched off the moment the
 * handset rotated -- the six-link top bar came back, the fields dropped to
 * 13px, and the whole layout was the desktop one squeezed into 390px of
 * height. Measured at 844x390 that was 767 problems across the site, all of
 * them invisible from a portrait test.
 *
 * The second clause catches it by what it actually is: a short viewport with a
 * coarse pointer. `pointer: coarse` is the primary input being a finger, which
 * is false on a desktop -- including a desktop window dragged down to 460px
 * tall, and including a laptop with a touchscreen, whose primary pointer is
 * still the trackpad. So the desktop layout is as untouched as it was before.
 */
@media (max-width: 820px), (max-height: 500px) and (pointer: coarse) {

  /* ------------------------------------------------------------ top bar --
     The brand stays (it is the way home) and Sign out stays. The six links
     move to the bottom bar below. */
  .topbar { padding: 0.6rem 0.9rem; }
  .topbar-nav a,
  .topbar-user { display: none; }
  .topbar-nav { gap: 0; }
  .topbar-brand span { font-size: 1rem; }
  .topbar-brand { min-height: 44px; }

  /* -------------------------------------------------------- bottom bar --
     Five destinations, thumb height, with the home-indicator inset honoured so
     the labels are not sitting under the gesture bar on a modern iPhone. */
  .mobilenav {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 80;
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    background: rgba(11, 15, 23, 0.94);
    backdrop-filter: blur(12px);
    border-top: 1px solid var(--line);
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  .mobilenav a {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    min-height: 54px;
    padding: 7px 2px 6px;
    color: var(--text-dim);
    font-size: 12px;
    letter-spacing: -0.005em;
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
  }
  .mobilenav a:hover { text-decoration: none; }
  .mobilenav svg { width: 21px; height: 21px; }
  .mobilenav a.is-current { color: var(--violet-hi); }
  .mobilenav a:active { background: rgba(255, 255, 255, 0.05); }

  /* Room at the foot of every page so the last row is not under the bar. */
  body.page-app { padding-bottom: calc(60px + env(safe-area-inset-bottom, 0px)); }

  /* ------------------------------------------------------ scroll padding --
     A fixed bar at the bottom of the screen covers whatever the browser
     scrolls to. Focus a field near the foot of the page -- or follow an
     in-page link, or let iOS scroll the focused input up above the keyboard --
     and it lands underneath the bar: visible, and not tappable.

     scroll-padding tells the browser those strips are spoken for, so anything
     it scrolls into view stops short of them. Without it the caret can end up
     behind the switcher and the only way out is to scroll by hand. */
  html { scroll-padding-bottom: calc(72px + env(safe-area-inset-bottom, 0px));
         scroll-padding-top: 64px; }   /* the sticky top bar */

  /* --------------------------------------------------------- page shell --
     Narrower gutters: 1.25rem of padding on a 390px screen spends 13% of the
     width on nothing. */
  .shell, .shell-wide, .shell-narrow { padding-left: 0.9rem; padding-right: 0.9rem; }
  .page-head { margin-bottom: 1.1rem; }
  .page-head h1 { font-size: 1.3rem; }
  .card, .card-wide { padding: 1.1rem 0.95rem; }

  /* ------------------------------------------------------------- fields --
     16px exactly. This is the rule that stops iOS zooming, and it applies to
     every control that takes a caret. */
  /* Named as an exclusion rather than a list of types: an <input> with no
     type attribute is a text field and would slip past `input[type="text"]`. */
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="submit"]):not([type="button"]):not([type="hidden"]),
  select, textarea, .control {
    font-size: 16px !important;
    min-height: 44px;
  }
  textarea { min-height: 88px; }
  select {
    /* A select at 16px with the platform arrow still needs room for the arrow. */
    padding-right: 2rem;
    background-position: right 0.7rem center;
  }

  /* ------------------------------------------------------------ buttons --
     44px is the smallest thing a finger hits reliably. .btn-sm exists for
     dense desktop rows; on a phone there are no dense rows. */
  .btn { min-height: 44px; padding-left: 1rem; padding-right: 1rem; }
  .btn-sm { min-height: 40px; font-size: 0.86rem; padding: 0.5rem 0.85rem; }

  /* Rows of buttons wrap instead of running off the edge. */
  .row-gap, .row-between { flex-wrap: wrap; }
  .row-between > * { min-width: 0; }

  /* --------------------------------------------------------- tool cards --
     One per row. Two columns at 390px gives each card ~180px, which is not
     enough for the description to be worth reading. */
  .tool-grid { grid-template-columns: 1fr; gap: 0.75rem; }
  .tool-card { padding: 1rem; }
  .tool-card h2 { font-size: 1.02rem; }

  /* ------------------------------------------------------------- tables --
     Wide tables scroll inside their own box rather than widening the page.
     A table that pushes the document sideways breaks every other element on
     the screen; one that scrolls on its own breaks nothing. */
  .table-wrap, .card > table.data, .subform > table.data {
    display: block;
    width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  table.data { font-size: 0.85rem; }
  table.data th, table.data td { padding: 0.6rem 0.55rem; }

  /* -------------------------------------------------- saved invoices --
     The per-client list: fixed desktop column widths become one readable
     block, and Duplicate/Delete get their own line rather than being squeezed
     into a right-aligned cell that then overflows. */
  #saved table.data th:nth-child(2), #saved table.data td:nth-child(2),
  #saved table.data th:nth-child(3), #saved table.data td:nth-child(3),
  #saved table.data th:nth-child(4), #saved table.data td:nth-child(4) {
    width: auto; padding-right: 0.5rem;
  }
  /* "Saved" (the timestamp) is the one column you never act on. */
  #saved table.data th:nth-child(4), #saved table.data td:nth-child(4) { display: none; }
  #saved table.data td:last-child { white-space: normal; }
  #saved table.data td:last-child form { margin: 0.2rem 0 0 0.35rem; }
  #saved summary { padding: 0.7rem 0; min-height: 44px; display: flex;
                   align-items: center; gap: 0.4rem; flex-wrap: wrap; }

  /* ------------------------------------------------------------- forms --
     Side-by-side label/field pairs stack. */
  .form-row, .field-row, .split { grid-template-columns: 1fr; }
  .inline-form { display: block; }
  .filters { flex-wrap: wrap; }

  /* A grid or flex item will not shrink below its min-content width unless it
     is told it may. On the settings page that floor was set by a <select>
     whose longest option is "claude-haiku-4-5-20251001": the select refused to
     be narrower than that string, so the form stayed 596px wide inside a
     359px card and pushed the whole document 237px sideways.

     min-width:0 lets the item shrink; the select rules below then keep it
     inside its parent, and the text wraps instead of demanding a wider box. */
  .stack > *, .card > *, .card-wide > *, .subform > *, .field, .field > * { min-width: 0; }
  select, .control, input, textarea { max-width: 100%; }
  select, .control { width: 100%; }
  /* Long unbroken strings -- API key hints, model ids, file paths, URLs --
     wrap rather than setting the width of the page. */
  code, .mono, .lira-opt code { overflow-wrap: anywhere; }
  .checkbox-text, label { overflow-wrap: anywhere; }

  /* --------------------------------------------------------- typography --
     Every rule in app.css that sets a size below 12px, restated at 12px and
     nothing else. Generated from the stylesheet, not written by hand: a
     blanket `.label, .sub { font-size: 12px }` also SHRINKS the variants that
     were already above the floor, which is a regression dressed as a fix.
     Matching each original selector can only raise.

     app.css sizes in rem against a 15px body, so 0.78rem is 11.7px -- fine on
     a monitor, thin on a phone held at arm's length in daylight.

     The bottom bar's own labels are exempt: see .mobilenav above. */
  .checkbox-text small                           { font-size: 12px; }   /* was 11.7px */
  .deliv-field label                             { font-size: 12px; }   /* was 11.7px */
  .err-box                                       { font-size: 12px; }   /* was 11.7px */
  .foot-note                                     { font-size: 12px; }   /* was 11.7px */
  .log-list                                      { font-size: 12px; }   /* was 11.7px */
  .pill                                          { font-size: 12px; }   /* was 10.8px */
  .reveal                                        { font-size: 12px; }   /* was 11.7px */
  .side-count                                    { font-size: 12px; }   /* was 11.1px */
  .side-title                                    { font-size: 12px; }   /* was 11.7px */
  .stat-label                                    { font-size: 12px; }   /* was 11.7px */
  .stat-note                                     { font-size: 12px; }   /* was 11.7px */
  .status, .sync, .tag                           { font-size: 12px; }   /* was 10.95px */
  button.status.is-clickable                     { font-size: 12px; }   /* was 10.95px */
  table.data th                                  { font-size: 12px; }   /* was 11.1px */
  table.invoice-list .status                     { font-size: 12px; }   /* was 10.5px */
  table.invoice-list td:first-child .mono        { font-size: 12px; }   /* was 11.7px */

  /* ------------------------------------------------------------ targets --
     Measured at 390px: the period filters on the report came back at 36px,
     the invoice-number links in the list at 14px, and the customer links at
     18px. A row you tap to open an invoice is the main thing this page is
     for -- it should not be the height of its own text. */
  .tabs a, .tabs button, .filters .btn,
  .period-tabs a { min-height: 44px; }
  .tabs a, .tabs button,
  .period-tabs a { display: inline-flex; align-items: center; }
  table.data td a, table.invoice-list td a {
    display: inline-flex; align-items: center; min-height: 40px;
  }
  .side-list a { min-height: 44px; align-items: center; }


  /* ------------------------------------------------------------- feel --
     Four things that are not layout but are most of what makes a page feel
     like an application rather than a web page being viewed on a phone.

     text-size-adjust: iOS inflates text in landscape on its own initiative,
       which undoes the type scale the moment the handset turns.

     touch-action: manipulation removes the ~300ms wait a browser spends
       deciding whether a tap was the first half of a double-tap-to-zoom.
       Buttons stop feeling laggy. Zoom by pinch is untouched.

     tap-highlight + :active: the default is a grey rectangle drawn a moment
       after the tap has already happened. A pressed state that appears at
       once reads as a response; the grey flash reads as a delay.

     overscroll-behavior: scrolling to the bottom of a drawer or a sheet
       should stop there, not hand the scroll to the page behind it. */
  html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

  a, button, .btn, .chip, summary, label, [role="button"],
  input[type="checkbox"], input[type="radio"], select {
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
  }

  .btn:active, button:active, .tool-card:active,
  .chip:active, .qa-chip:active { filter: brightness(1.25); }
  .tool-card:active { transform: scale(0.985); }
  .tool-card { transition: transform .08s ease; }

  .modal, .sidebar, .lira-panel { overscroll-behavior: contain; }
  /* A table pans sideways inside itself -- and only sideways. `contain` on
     both axes also swallowed an up-or-down swipe that started on a wide
     table, so a table filling the screen froze the page (found on Finance's
     store page, 2026-09-12; the same rule is fixed there). */
  .table-wrap { overscroll-behavior-x: contain; }

  /* Notched handsets in landscape put the camera cutout in the side gutter. */
  .topbar, .hqbar, .shell, .shell-wide, .shell-narrow {
    padding-left: max(0.9rem, env(safe-area-inset-left));
    padding-right: max(0.9rem, env(safe-area-inset-right));
  }
  /* The bars themselves stay edge to edge -- a tab bar inset by a gutter looks
     like a floating widget rather than part of the device. Only the cutout is
     avoided, and only when there is one. */
  .mobilenav, .bottomnav {
    padding-left: env(safe-area-inset-left, 0px);
    padding-right: env(safe-area-inset-right, 0px);
  }


  /* --------------------------------------------------- install the app --
     Sits above the bottom bar, not over it: this is an offer, and an offer
     that covers the navigation is a nuisance. */
  .pwa-install {
    display: flex;
    position: fixed;
    left: 8px; right: 8px;
    bottom: calc(68px + env(safe-area-inset-bottom, 0px));
    z-index: 85;
    flex-wrap: wrap;
    gap: 10px;
    align-items: center;
    justify-content: space-between;
    padding: 12px 14px;
    background: rgba(20, 26, 36, 0.97);
    border: 1px solid var(--line-strong);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    backdrop-filter: blur(10px);
  }
  .pwa-install-body { flex: 1 1 190px; min-width: 0; }
  /* Direct children only. The iOS instruction emphasises "Share" and "Add to
     Home Screen" inside its own sentence, and a blanket `strong { display:
     block }` broke that sentence onto five lines. */
  .pwa-install-body > strong { display: block; font-size: 0.95rem; }
  .pwa-install-body > span { display: block; margin-top: 2px;
                             font-size: 12px; line-height: 1.45;
                             color: var(--text-muted); }
  .pwa-install-body span strong { font-weight: 650; color: var(--text); }
  .pwa-install-actions { display: flex; gap: 8px; flex: 0 0 auto; }
  .pwa-install .btn { min-height: 40px; }
  .pwa-share { color: var(--violet-hi); font-size: 14px; }

  /* Lira's button lives at bottom-right, which is where this banner's buttons
     are. While the offer is up she moves above it -- pwa.js sets the class,
     and removes it with the banner. */
  body.pwa-offering .lira-fab {
    bottom: calc(196px + env(safe-area-inset-bottom, 0px));
    transition: bottom .15s ease;
  }

  /* --------------------------------------------------------------- misc */
  .page-head .row-between { align-items: flex-start; }
  .stat-grid { grid-template-columns: repeat(2, 1fr); }
  .muted { font-size: 0.86rem; }
  .small { font-size: 0.82rem; }

  /* The show/hide-password button sits inside the field, so it inherits the
     field's height rather than the button minimum. Match the 44px input. */
  .input-group .reveal, button.reveal { min-height: 44px; padding: 0 0.85rem; }
}

/* Installed as an app there is no browser chrome to scroll away, so the bar
   can sit tight against the bottom of the screen. */
@media (display-mode: standalone) {
  body { overscroll-behavior-y: none; }
}

/* ------------------------------------------------------------- landscape --
   Sideways, the screen is 390px tall and the chrome was about to take 124 of
   them. Everything still works; it just gets thinner, and the labels go --
   five icons in a row are recognisable on their own once you have used them
   once, and the alternative is reading an invoice through a letterbox. */
@media (max-height: 500px) and (pointer: coarse) {
  .mobilenav a { min-height: 42px; padding: 5px 2px; gap: 1px; }
  .mobilenav a span { display: none; }
  .mobilenav svg { width: 22px; height: 22px; }
  body.page-app { padding-bottom: calc(44px + env(safe-area-inset-bottom, 0px)); }
  html { scroll-padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px));
         scroll-padding-top: 52px; }
  .topbar { padding: 0.4rem 0.9rem; }
  .topbar-brand img { width: 26px; height: 26px; }
  .page-head { margin-bottom: 0.75rem; }
  /* Two across: the width is there in landscape, the height is not. */
  .tool-grid { grid-template-columns: 1fr 1fr; }
}
