/* The product on a phone.
 *
 * Every rule below was written against something measured on a 375×812 viewport, not something
 * imagined: a page that dragged itself 600px wide because one storage path is an unbreakable
 * word, a preview bar whose height is hard-coded at the value it has only on a wide screen, a
 * chart whose axis labels came out under 4px, a slider thumb 15px across. Nothing here applies
 * above 900px, so the desktop layout is exactly what app.css says it is.
 *
 * It lives in its own file because these rules argue one case together. Scattered through
 * app.css as a dozen more media queries, each would look like a local touch-up and the case
 * would be invisible.
 */

/* Landscape on iOS otherwise inflates body text but not the boxes around it. */
html { -webkit-text-size-adjust: 100%; }

/* ------------------------------------------------------ 1. nothing scrolls sideways */

@media (max-width: 900px) {
  /* A storage path, a base64 digest and a source URL are each one unbreakable word. Inside a
     1320px frame they fit; at 375px a 44-character digest measures 400px and takes the whole
     document with it — /admin came out 601px wide, /admin/evidence 684px. A phone browser
     answers that by zooming the page out, so one path shrinks every other word on the page. */
  .kv dd, .kv dt, .mono, .secret, .breakable,
  .index-row .nm, .doc-row .name, .doc-row .sub,
  a.hit .snippet, .usermenu .panel .head span { overflow-wrap: anywhere; }

  /* Swiping a wide table sideways must not hand the gesture to the browser's back navigation
     once the table reaches its end. */
  .table-scroll, .traj-plot, .mx-basis-pick {
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
  }

  /* Three buttons in a row is common and the flex container did not wrap. */
  .form-actions { flex-wrap: wrap; }
}

/* --------------------------------------------------- 2. the bar that says PREVIEW */

@media (max-width: 900px) {
  /* The bar is fixed, and everything under it is offset by `--header-h + 39px` — the height it
     has only while it stays on one line. At 375px it wraps to three and stands 149px tall, so
     110px of every page sat underneath it, including the top of the room navigation in the open
     drawer. In flow it cannot misreport its own height. */
  .previewbar { position: static; margin-top: var(--header-h); padding: 10px 14px; }
  .main.previewing { padding-top: 0; }
  .previewbar + .sidebar, body:has(.previewbar) .sidebar { top: var(--header-h); }
  .previewbar .btn { margin-left: auto; }
}

/* ------------------------------------------------------------ 3. the menu drawer */

@media (max-width: 900px) {
  /* 236px of a 375px screen is most of it and the labels still truncate. Give the drawer room
     to hold a room name, and leave enough of the page showing that it reads as a layer over the
     page rather than as a new one. */
  .sidebar {
    width: min(304px, 84vw);
    padding: 8px 8px 20px;
    box-shadow: none;
  }
  body.nav-open .sidebar { box-shadow: var(--shadow-lift); }

  /* Reached with a thumb, walking. 35px was not. */
  .sidebar a.item { min-height: 44px; padding: 8px 12px; font-size: .92rem; }
  .sidebar .group { padding: 16px 12px 6px; }
  .sidebar .side-foot { padding: 14px 12px 2px; }

  /* A keyboard can open the drawer without the script that toggles the class: focus reaching
     the button, or any link inside the drawer, is enough. `:focus-visible` rather than `:focus`
     so a tap on the burger does not fight the toggle it just triggered. */
  body:has(.burger:focus-visible) .sidebar,
  .sidebar:focus-within { transform: none; box-shadow: var(--shadow-lift); }

  .scrim { -webkit-tap-highlight-color: transparent; }
}

/* -------------------------------------------------------- 4. controls big enough */

@media (max-width: 900px) {
  /* Apple and Google both put the floor at 44px and 48dp. The buttons here measured 24–36px,
     which is fine with a mouse and wrong for a thumb on a moving train. Padding stays as it is
     — the height comes from a minimum, so short labels do not become square. */
  .btn { min-height: 44px; padding-top: 8px; padding-bottom: 8px; }
  .btn.small { min-height: 40px; padding: 6px 12px; font-size: .84rem; }

  .burger { width: 44px; height: 40px; }
  .usermenu > summary { min-height: 44px; }
  .usermenu .panel a { min-height: 44px; }

  details.reveal > summary { min-height: 40px; display: flex; align-items: center; }
  .refmenu > summary { min-height: 40px; }
  a.refitem { min-height: 44px; }

  a.att { min-height: 44px; }
  .stages .stage { min-height: 56px; }
  .mx-cell { min-height: 48px; }

  /* iOS zooms the whole page in when a field with type under 16px takes focus, and does not
     zoom back out afterwards. Every text control on a phone is therefore 16px. */
  input[type=text], input[type=email], input[type=password], input[type=number], input[type=tel],
  input[type=url], input[type=date], input[type=time], input[type=datetime-local], input[type=month],
  input[type=file], input[type=search],
  select, textarea, .searchbar input[type=search] { font-size: 16px; }
  input[type=text], input[type=email], input[type=password], input[type=number], input[type=tel],
  input[type=url], input[type=date], input[type=time], input[type=datetime-local], input[type=month],
  select { min-height: 44px; }
  .ui-select-trigger { min-height: 44px; font-size: 16px; }
  .ui-picker-sheet {
    border-radius: 16px;
    box-shadow: 0 24px 64px rgba(23, 32, 51, .28);
  }
  .ui-picker-sheet .ui-picker-search { padding: 12px; }
  .ui-picker-sheet .ui-picker-search input[type=text] { min-height: 44px; font-size: 16px; }
  .ui-picker-sheet .ui-picker-option { min-height: 48px; padding: 11px 12px; font-size: 16px; }
  .ui-file { min-height: 44px; }
  .check input { min-width: 22px; min-height: 22px; }
}

/* ------------------------------------------------------------- 5. dialogs as sheets */

@media (max-width: 640px) {
  /* Centred, a dialog puts its close button and its confirm button at the top of the screen,
     which is the one place a thumb cannot reach on a phone held in one hand. On the bottom edge
     both land under the thumb, and the sheet is the shape a phone user already expects. */
  dialog.dlg, dialog.dlg.wide {
    width: 100%;
    max-width: none;
    max-height: 92vh;
    margin: auto auto 0;
    border-radius: 16px 16px 0 0;
  }
  .dlg-head { padding: 18px 56px 12px 18px; }
  .dlg-body { padding: 16px 18px calc(20px + env(safe-area-inset-bottom)); }
  .dlg-close {
    top: 6px;
    right: 6px;
    width: 44px;
    height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
  }
  /* Two actions, full width, in reading order: the way out on the left, the commitment on the
     right, both hittable without shifting grip. */
  .form-actions.right { flex-wrap: nowrap; }
  .form-actions.right > .btn { flex: 1 1 0; justify-content: center; }
}

/* ------------------------------------------------------------ 6. the assistant button */

@media (max-width: 640px) {
  /* The button floats over the bottom right corner, which is exactly where the last row of a
     document list puts its Save button. The footer is the last thing in every shell, so the
     clearance goes there and every page above it ends clear of the button. */
  body:has(.asst) .foot { padding-bottom: calc(96px + env(safe-area-inset-bottom)); }
  .asst { bottom: calc(12px + env(safe-area-inset-bottom)); }
  .asst-panel { max-height: 80vh; }
  .asst-head { min-height: 52px; }
}

/* ----------------------------------------------------------------- 7. the trajectory */

/* Up to 900px, which is where the sidebar folds away and a phone in landscape lands — the case
   this page has to survive, since a chart is the one thing people turn the phone sideways for.
   Above 660px of column the minimum does nothing and only the type changes. */
@media (max-width: 900px) {
  /* The chart is drawn into a 900×330 viewBox. Fitted to a 305px column that is a scale of
     0.34: the lines survive, the type does not — the axis came out at 3.6px, and the y labels
     need more room than the 22px the left padding then leaves them. Fewer labels would not help
     the y axis, which needs its scale. So the plot keeps a width at which its own labels are
     readable and scrolls inside the card, and the type is set in viewBox units chosen to land
     near 10px on the screen.

     The ceiling on the axis is not arbitrary. The chart leaves 58 viewBox units for a y label
     and one measures 4.35 units per point of type, so above 13.5pt "US$789k" starts left of the
     viewBox; the padding is what carries a minus sign in front of it on a negative line. */
  .traj-plot { overflow-x: auto; padding: 0 6px 0 8px; }
  .traj-svg { min-width: 660px; }
  .traj-svg .ax { font-size: 13.5px; }
  .traj-svg .ax.today { font-size: 12px; }
  .traj-svg .ln { stroke-width: 2.6; }
  .traj-svg .ln.band { stroke-width: 1.4; }
  .traj-svg .ln.scenario { stroke-width: 3; }
  .traj-svg .unsourced { stroke-width: 2.2; r: 4.4; }
  /* The key belongs to the whole chart, not to the part of it currently scrolled into view. */
  .traj-legend { position: sticky; left: 0; }

  /* 15px of track and a 15px thumb is a target you have to stop walking to hit. The control is
     given a thumb you can see and a 44px band you can land anywhere in. */
  .field.slider input[type=range] { height: 44px; margin: 0; }
  .field.slider input[type=range]::-webkit-slider-runnable-track { height: 6px; }
  .field.slider input[type=range]::-moz-range-track { height: 6px; }
  .field.slider input[type=range]::-webkit-slider-thumb {
    width: 26px; height: 26px; margin-top: -10px; border-width: 3px;
  }
  .field.slider input[type=range]::-moz-range-thumb {
    width: 26px; height: 26px; border-width: 3px;
  }
  /* The readout is the only feedback while a thumb covers the track, so it stays on its own
     line rather than being pushed off the end of a long label. */
  .field.slider label { flex-wrap: wrap; }
  .field.slider label .val { font-size: .9rem; }

  .traj-banner .toolbar { width: 100%; }
  .traj-banner .toolbar .btn { flex: 1 1 auto; justify-content: center; }

  /* Nine metrics wrapped to four rows put 200px of buttons between the heading and the chart.
     One swipeable row instead — they are ordinary links, so this costs nothing when the script
     never runs. */
  .traj-metrics {
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    gap: 6px;
    padding-bottom: 4px;
  }
  .traj-metrics .btn { flex: 0 0 auto; }
}

/* ------------------------------------------------- 8. matrices and the heat grid */

@media (max-width: 900px) {
  /* Scrolled two columns to the right, a matrix without a fixed row head is a grid of values
     with nothing to say which row they belong to. The investor matrix pins its dimension column
     the way the company-side one (market.css) already does. */
  .matrix { min-width: 640px; }
  .matrix th.dim {
    position: sticky;
    left: 0;
    width: 152px;
    background: var(--card);
    /* Only an edge, so the pinned column reads as a layer over the grid rather than as a
       column with a rule drawn down it. */
    box-shadow: 6px 0 7px -6px rgba(11, 29, 66, .22);
  }
  .matrix thead th.dim { z-index: 2; }
  .matrix tbody th.dim { z-index: 1; }
  .matrix .mark { padding: 8px 9px; }

  table.mx .mx-rowhead { min-width: 156px; max-width: 172px; }

  /* Same problem, same answer: the sensitivity grid's row is its salary, and scrolled right it
     was the only thing you could no longer see.

     The corner cell also has to be allowed to wrap. It names both axes on one nowrap line, and
     a table column is as wide as its widest cell — so that one label was holding the row header
     at 314px of a 620px grid, leaving 42px per figure. */
  .hm th.corner { white-space: normal; }
  .hm th[scope=row], .hm th.corner {
    position: sticky;
    left: 0;
    z-index: 1;
    width: 104px;
    background: var(--card);
    box-shadow: 6px 0 7px -6px rgba(11, 29, 66, .22);
  }

  .heat-row { grid-template-columns: 36px 1fr 84px; gap: 8px; font-size: .8rem; }
}

/* ------------------------------------------- 9. phone rules app.css never got to apply */

@media (max-width: 640px) {
  /* app.css already asks for all of this at 640px. It does not get it: its phone block sits at
     the top of the file and the base rules it means to override are declared several hundred
     lines further down, and a media query adds no specificity — later simply wins. Measured on
     a 375px screen, `.kv` was still resolving to `150px 106px`, which is what put "nobody —
     this relationship will go quiet" into three lines of a 106px column on every detail page.
     Restated here, where nothing comes after them.

     They are the original author's rules, not new ones. If app.css is ever reordered so its own
     phone block lands last, this section becomes a duplicate and should go. */
  .card { padding: 16px 14px; }
  .page-head { gap: 10px; }
  .kv { grid-template-columns: 1fr; gap: 2px 0; }
  .kv dd { margin-bottom: 10px; }
  .doc-row .meta { flex: 1 1 auto; }
  .viewer-bar { padding: 8px 12px; gap: 10px; }
  .pages { padding: 14px 10px 70px; }
  textarea.codes { font-size: .82rem; letter-spacing: 0; }
  .enrol { gap: 16px; }
}

/* ----------------------------------------------------------------- 10. the frame */

@media (max-width: 640px) {
  /* Home indicator on a notched phone, and the two edges a landscape notch eats. */
  .wrap { padding-left: max(14px, env(safe-area-inset-left)); padding-right: max(14px, env(safe-area-inset-right)); }
  .topbar { padding-left: max(10px, env(safe-area-inset-left)); padding-right: max(10px, env(safe-area-inset-right)); }
  .foot { padding-bottom: calc(40px + env(safe-area-inset-bottom)); }

  /* A page title that is a company name plus a round is two lines on a phone; it should not be
     two lines of 24px. */
  h1 { font-size: 1.32rem; }
  .page-head { margin-bottom: 16px; }
  .page-head .grow { min-width: 0; }

  /* The two-up card grid has a 320px minimum, which at 305px of column produced one card per
     row anyway — say so, rather than relying on the fallback. */
  .grid.two, .grid.three { grid-template-columns: 1fr; }
  .grid.four { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }

  .card-head { gap: 8px; }
  .card-head .toolbar { width: 100%; }

  /* The viewer's own bar carries a back link, a title, a page counter and up to two controls. */
  .viewer-bar .btn.small { flex: 0 0 auto; }
  .viewer-bar .title { order: -1; width: 100%; font-size: .95rem; }

  .funnel .step { min-width: 92px; }
  .stages .stage { min-width: 96px; }

  /* Assumption editors: three number columns at 375px leaves 70px each, which is not a field. */
  .assump-grid { grid-template-columns: 1fr 1fr; }
  .mod-form .field { min-width: 100%; }
}

/* ------------------------------------------------------ tables become lists

   A table is a grid because the columns line up; on a phone they cannot, and a table that scrolls
   sideways inside a card is a table nobody reads the right-hand half of. So below the breakpoint a
   marked table stacks into one card per row, and each value carries the name of its column — a
   stacked table without labels is a column of orphan values: "97", "PDF", "1.1 MB", and nothing
   saying which is which.

   Only tables whose cells carry `data-label` do this. A matrix or a heatmap has no such labels and
   keeps scrolling, because stacking a grid destroys the comparison it exists to make. */
@media (max-width: 720px) {
  .table-scroll:has(table.listable) { overflow-x: visible; }

  table.listable, table.listable tbody, table.listable tr, table.listable td { display: block; }
  /* The scroll container gives every table a minimum width so its columns are not crushed. A
     stacked table has no columns to crush, and keeping it would leave the page scrolling
     sideways with nothing out there to see. */
  .table-scroll > table.listable { min-width: 0; width: 100%; }
  table.listable thead { display: none; }
  table.listable { border: 0; }

  table.listable tr {
    border: 1px solid var(--line);
    border-radius: 10px;
    background: #fff;
    padding: 12px 14px;
    margin-bottom: 10px;
  }
  table.listable tr:last-child { margin-bottom: 0; }

  table.listable td {
    display: flex;
    gap: 12px;
    align-items: baseline;
    justify-content: space-between;
    border: 0;
    padding: 5px 0;
    text-align: left;
  }
  table.listable td::before {
    content: attr(data-label);
    flex: none;
    color: var(--muted);
    font-size: .74rem;
    letter-spacing: .02em;
    text-transform: uppercase;
    padding-top: 2px;
  }
  table.listable td[data-label=""]::before { content: none; }
  table.listable td > * { min-width: 0; }

  /* The row's name is the card's heading. Where a row has no name column, the first cell is the
     nearest thing to one. */
  table.listable td[data-label="Name"],
  table.listable td[data-label="Person"],
  table.listable td[data-label="Organisation"],
  table.listable td[data-label="Investor"],
  table.listable td[data-label="Document"],
  table.listable td[data-label="Project"],
  table.listable tr:not(:has(td[data-label="Name"], td[data-label="Person"],
                             td[data-label="Organisation"], td[data-label="Investor"],
                             td[data-label="Document"], td[data-label="Project"])) td:first-child {
    display: block;
    font-size: .98rem;
    padding: 0 0 6px;
    border-bottom: 1px solid var(--line);
    margin-bottom: 6px;
  }
  table.listable td[data-label="Name"]::before,
  table.listable td[data-label="Person"]::before,
  table.listable td[data-label="Organisation"]::before,
  table.listable td[data-label="Investor"]::before,
  table.listable td[data-label="Document"]::before,
  table.listable td[data-label="Project"]::before,
  table.listable tr:not(:has(td[data-label="Name"], td[data-label="Person"],
                             td[data-label="Organisation"], td[data-label="Investor"],
                             td[data-label="Document"], td[data-label="Project"])) td:first-child::before {
    content: none;
  }
  /* A heading that is not the first cell still reads first. */
  table.listable td[data-label="Name"],
  table.listable td[data-label="Person"],
  table.listable td[data-label="Organisation"],
  table.listable td[data-label="Investor"],
  table.listable td[data-label="Document"],
  table.listable td[data-label="Project"] { order: -1; }
  table.listable tr { display: flex; flex-direction: column; }
  /* Stacked, there is room for the whole name — clipping it here would hide it for good, since
     a phone has no hover to reveal the rest. */
  table.listable td .clip { white-space: normal; max-width: none; }

  /* An empty state spans the row and should not pretend to be a card. */
  table.listable td[colspan] { border: 0; padding: 6px 0; }
  table.listable tr:has(td[colspan]) { border: 0; background: none; padding: 0; }

  /* Actions sit under the card rather than crowding the last line. */
  table.listable td.right { justify-content: flex-start; flex-wrap: wrap; }
}

/* Regula Modern shell alignment.  Kept last because this file intentionally owns the final
   narrow-screen cascade.  Behaviour remains the existing native drawer and bottom-sheet flow. */
@media (max-width: 1023px) {
  .auth-shell { display: block; }
  .auth-masthead { display: none; }
  .auth-stage {
    display: grid;
    min-height: 100vh;
    min-height: 100dvh;
    grid-template-rows: auto 1fr;
    align-items: stretch;
    padding: 22px 24px 52px;
  }
  .auth-stage-top {
    position: static;
    width: 100%;
    max-width: 440px;
    justify-self: center;
    justify-content: space-between;
    margin-bottom: 34px;
  }
  .auth-frame {
    align-self: center;
    justify-self: center;
  }
  .auth-mobile-brand { display: inline-flex; }
}

@media (max-width: 900px) {
  .topbar {
    left: 0;
    border-bottom-color: var(--line);
    background: rgba(255, 255, 255, .94);
    color: var(--ink);
  }
  .sidebar {
    top: var(--header-h);
    width: min(320px, 88vw);
    padding: 0 8px 20px;
    background: rgba(251, 252, 255, .99);
  }
  .sidebar-brand { margin: 0 -8px; padding-inline: 14px; }
  .sidebar-nav { padding-top: 10px; }
  .sidebar a.item { border-radius: var(--control-radius); }
  body.nav-open .scrim { inset: var(--header-h) 0 0; }
}

@media (max-width: 640px) {
  .auth-stage { padding: 16px 14px 36px; }
  .auth-stage-top {
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 28px;
  }
  .auth-test-mark,
  .auth-switch { min-height: 38px; padding-inline: 9px; }
  .auth-stage-top .auth-switch { margin-left: auto; }
  .auth-mobile-brand { margin-bottom: 34px; }
  .auth-intro { padding-left: 16px; }
  .auth-intro h1 { font-size: 1.72rem; }
  .auth-panel { margin-top: 28px; padding: 20px 17px; border-radius: 13px; }
  .auth-panel .form-actions { grid-template-columns: 1fr; }

  .topbar { gap: 4px; }
  .shell-topbar > .brand { display: none; }
  .topbar .brand .wordmark { display: none; }
  .internal-test-mark {
    width: min(132px, 38vw);
    max-width: none;
    font-size: .7rem;
    line-height: 1.05;
    letter-spacing: .04em;
    text-align: center;
    white-space: normal;
  }
  .shell-topbar > .preview-link { display: none; }
  .topbar .top-link { min-width: 32px; padding-inline: 8px; }
  .topbar .usermenu > summary .ic { display: none; }
  .topbar .usermenu > summary { width: 44px; justify-content: center; }
  table.listable tr { border-radius: 13px; background: var(--card); }
}
