/* Breakpoints */

@media (max-width: 980px){
  .cards-row{grid-template-columns:repeat(2,1fr);}
  .mid-row{grid-template-columns:1fr;}
  /* Stacked, there is no second panel to end level with, so the cap has nothing
     to match. Lifting it also avoids a scroll area inside the page scroll, which
     on a touch screen is a trap. */
  .cat-list{max-height:none;}
  .goals-grid{grid-template-columns:1fr;}
}
@media (max-width: 760px){
  .app{grid-template-columns:1fr;}
  .sidebar{
    position:relative; height:auto; flex-direction:row; align-items:center;
    padding:14px 16px; gap:14px;
  }
  .brand{padding:0; flex:1;}
  nav.navlist{flex-direction:row; margin-top:0;}
  /* Nothing to collapse: the sidebar is already a horizontal bar at this width. */
  .sidebar-toggle{display:none;}
  /* The sidebar turns into a horizontal bar here, with no room for a footer.
     Sign out stays reachable from Settings -> Data. */
  .sidebar-foot{display:none;}
  .main{padding:20px 16px 40px;}
}
@media (max-width: 560px){
  .cards-row{grid-template-columns:1fr 1fr;}
  .topbar{flex-direction:column; align-items:flex-start;}
  .topbar-actions{width:100%;}
  .period-picker{flex:1;}
  .period-btn{width:100%; justify-content:space-between;}

  /* The panels hang off the action row, not off the buttons that open them.
     A phone is narrower than the desktop panel's 272px plus its margins, so a
     panel anchored to its own button has to take that button's width — and a
     button's width follows its label. "All Time" left too little for the twelve
     months to lay out four across, so April, August and December were clipped,
     while "2026 — full year" on the same control had room to spare. The row is
     one full-width box whatever a label reads, so a panel opens the same width
     every time and neither edge can leave the screen.

     Both pickers go static together: they share the class, so leaving one
     positioned would move only its own menu. The ids are what outrank the
     desktop width and side, which a class cannot.

     The cap is measured against the viewport rather than the row, because at
     390px the row is the wrong ruler: three controls whose labels will not wrap
     cannot fit on one line, so the row is a little wider than the screen and
     everything sized to it inherits that. 32px is .main's padding. Take the row
     overflow away and this changes nothing; leave it and the last column of
     months still lands on the screen. */
  .topbar-actions{position:relative;}
  .period-picker{position:static;}
  #periodMenu,
  #ledgerMenu{width:auto; left:0; right:0; max-width:calc(100vw - 32px);}

  /* The nav bar drops to icons.
     Four labelled items need about 458px, and with the sidebar's padding and the
     brand mark the row cannot get narrower than roughly 524px — wider than every
     phone, which is what was forcing the whole page to overflow its viewport.

     Hidden the accessible way rather than with display:none: the label IS each
     button's name, and removing it from the accessibility tree would leave four
     unlabelled buttons. Tooltips are not the answer here as they are on the
     collapsed desktop rail — a phone has no hover.

     .btn-label-wide is the second word of "Import Spreadsheet", hidden the same
     way and for a related reason: that word is unbreakable and about 88px wide,
     which is what made the action row wider than a 390px screen and set the
     whole page scrolling sideways. Reading "Import" beside a download icon
     loses nothing, and hiding it this way rather than with display:none keeps
     the button named "Import Spreadsheet" for a screen reader — the visible
     text is still contained in that name, as WCAG 2.5.3 asks. */
  .nav-label,
  .btn-label-wide{
    position:absolute;
    width:1px; height:1px;
    padding:0; margin:-1px;
    overflow:hidden;
    clip:rect(0 0 0 0);
    white-space:nowrap;
    border:0;
  }
  .nav-item{justify-content:center; padding:10px 12px;}
  nav.navlist{gap:4px;}

  /* The transactions table stops being a table.
     Six columns need roughly 670px at their narrowest and a phone gives the
     table about 300px, so it was scrolling sideways inside its own container —
     the amount and balance sat off the edge where nothing announced them.
     Each row becomes a small card instead, laid out on a two-column grid:

        Woolworths                    -R412.30
        [ Groceries v ]                  # X
        15 Sep 2026                 R99,184.22

     Nothing is dropped. Every column still has a place, including the balance,
     which drops to a muted third line. */
  table.txn-table thead{display:none;}
  table.txn-table,
  table.txn-table tbody{display:block;}

  table.txn-table tr{
    display:grid;
    grid-template-columns:minmax(0, 1fr) auto;
    grid-template-areas:
      "desc   amount"
      "cat    actions"
      "date   balance";
    gap:5px 12px;
    align-items:center;
    padding:12px 4px;
    border-bottom:1px solid var(--line-soft);
  }
  table.txn-table td{
    display:block;
    min-width:0;
    padding:0;
    border:none;
  }
  table.txn-table td:nth-child(1){grid-area:date;}
  table.txn-table td:nth-child(2){grid-area:desc; font-weight:600; overflow-wrap:anywhere;}
  table.txn-table td:nth-child(3){grid-area:cat;}
  table.txn-table td:nth-child(4){grid-area:amount; font-size:14px;}
  table.txn-table td:nth-child(5){
    grid-area:balance;
    font-size:11.5px;
    font-weight:500;
    color:var(--text-faint);
  }
  table.txn-table td:nth-child(6){grid-area:actions; justify-self:end;}

  /* The empty state is one cell spanning the old six; grid ignores colspan.
     Placed after the rules above so it wins over nth-child(1). */
  table.txn-table td[colspan]{
    grid-area:auto;
    grid-column:1 / -1;
    text-align:center;
  }

  /* A pill sized to its longest category name would push the grid wider. */
  .cat-cell{max-width:100%;}
  .cat-pill{max-width:100%;}

  .table-wrap{padding:12px 14px;}
  .txn-actions{width:auto;}
}

@media (max-width: 760px){
  /* Rule rows stack: keyword and category get a full line each, controls follow. */
  .rules-head{display:none;}
  .rule-row{grid-template-columns:1fr 1fr auto auto auto;}
  .rule-hits{display:none;}
  .rule-add,
  .ledger-add{grid-template-columns:1fr;}
  .settings-stack{max-width:none;}
}

/* ---------------------------------------------------------- iOS focus zoom ----
   Safari on iPhone zooms the page in whenever a form control is focused at under
   16px, and — the part that actually hurts — does not zoom back out when that
   field blurs. Every control in the app sat between 11px and 14px, so tapping
   through a form left the page magnified, and pinched out by hand once per
   field. It reads as the app zooming at random.

   Raised here rather than at each definition on purpose: 16px is a workaround
   for one browser on one class of device, not a change of mind about the type
   scale, and the desktop layout keeps the sizes it was designed at. Kept in one
   block so the reason is written once and the set stays reviewable — these rules
   live across four files and share nothing but this constraint.

   Each selector matches the specificity of the rule it overrides, which is
   enough because responsive.css loads last. The exception is #goalInput, whose
   size comes from an id that no class can outrank. A comma list carries the
   specificity of each compound selector separately, so grouping them costs
   nothing here.

   760px, not 560px: a phone in landscape lands in that band and zooms exactly
   the same. Tablets sit above it and do not auto-zoom on focus at all. Only the
   controls move — descriptions, dates, amounts and balances keep their sizes,
   which is why the rows still read as the same table.

   .cat-pill is deliberately not in this list. It is a button rather than a
   <select>, so it does not zoom at any size, and it is the one control that
   repeats on every row — at 16px it was what set the row height, costing a row
   per screenful. See js/render/categoryPicker.js. */
@media (max-width: 760px){
  .auth-input,
  .settings-input,
  .txn-input,
  .rule-row input,
  .ledger-row input,
  .rule-add input,
  .ledger-add input,
  .txn-controls input[type="text"],
  .txn-controls select,
  .ledger-row select,
  #goalInput{
    font-size:16px;
  }

  /* The currency symbol tracks the digits it sits beside. Two reasons, and the
     second is the load-bearing one: at 13px against 16px digits it simply looked
     wrong, and --money-pad reserves room in the *input's* `ch` — so a prefix left
     behind at 13px would sit in a gap sized for a character it is not drawn in. */
  .txn-amount-prefix{font-size:16px;}
}

/* ------------------------------------------------------- iOS date fields ----
   A date input on iOS is a native control wearing a text field's clothes, and it
   sizes itself. In both dialogs it came out wider than every field above and
   below it — the transaction dialog's Date past Description and Category, the
   goal dialog's Deadline past Goal and Target amount — overrunning the dialog's
   own padding and reaching the card's edge.

   Wider by about the padding and border together, and the goal dialog's Deadline
   does it while completely empty. So this is not the control growing to fit a
   date: it is `width:100%` landing on the content box, with the padding added
   outside it, in spite of the `*{box-sizing:border-box}` in css/tokens.css.
   Turning the native appearance off is what puts the element back under the
   box model the rest of the form obeys; min-width joins it because the same
   control also carries a UA minimum that a percentage width cannot get under.

   Both properties, unprefixed second: Safari has honoured the standard
   `appearance` since 15.4, and older iOS still needs the prefix.

   760px, matching the block above, and for the same reason — this is a
   workaround for one browser on one class of device, and the desktop dialogs
   size correctly today. Verified there: in Chrome at 430px every field in the
   transaction dialog already measures 338px, date included, which is why this
   is scoped rather than applied everywhere. */
@media (max-width: 760px){
  .txn-input[type="date"]{
    -webkit-appearance:none;
    appearance:none;
    /* The percentage is already on .txn-input; these two are what let it win. */
    min-width:0;
    max-width:100%;
    /* And this is what the appearance above costs.
       Dropping the native appearance also drops the height the native control
       carried, and iOS draws nothing at all in an empty date field — no
       yyyy-mm-dd placeholder, as Chrome has. So an empty one had no content to
       stand the box up and collapsed to a thin pill, while a filled one sat at
       the same height as every other field.
       Only the goal dialog's Deadline shows it, and that is the tell rather
       than a coincidence: the transaction dialog's Date is always filled, with
       today when adding and the row's own date when editing, so it always had
       a line of text holding it open. Deadline is optional and opens empty.
       A floor rather than a height, so a filled field is still free to be
       taller: one line of text, plus the 18px of padding and 2px of border
       that .txn-input already sets. In em, so it tracks the 16px these fields
       take at this width rather than pinning a pixel count to it.
       Deliberately only a floor. Pinning line-height to match it was tried, to
       make the empty and filled heights agree to the pixel, and it cost more
       than it bought: Chrome's date field went from 40px to 42px against 38px
       neighbours, a regression in an engine that can actually be measured here,
       to chase a pixel in one that cannot. At 40px the floor is exactly what
       Chrome already draws, so it changes nothing outside WebKit. */
    min-height:calc(1.25em + 20px);
    /* Room for the glyph below: the 13px it is inset by, its own 16px, and a
       gap before any text can reach it. */
    padding-right:36px;
  }

  /* And the affordance the native control used to carry.
     With the appearance off there is nothing in an empty date field to say it
     can be tapped — iOS draws no yyyy-mm-dd — so the field read as a blank box
     you had no reason to touch. The glyph is the same one the native control
     drew, in the same place.

     The browser's own indicator goes at this width so there is exactly one:
     WebKit has none left to hide, but Chrome keeps drawing its own through
     appearance:none, and on a phone focusing the field opens the picker
     anyway. The cost lands on a desktop window narrowed below 760px, where
     the field is then typed into rather than clicked open — the trade is
     worth one icon instead of two on every Android phone. */
  .txn-input[type="date"]::-webkit-calendar-picker-indicator{display:none;}
  .txn-date-icon{display:flex;}
}
