/* fold.css — every screen at every size, and the fold.
   Loaded AFTER assets/unica.css, from the shell, so every route inherits it. It adds nothing to the
   vocabulary in apps/web/DESIGN.md: no new class, no new colour, no new token that a page has to
   know about. It only says how the three frames behave as the viewport narrows, widens, or arrives
   in two pieces.

   WHY THE RULES ARE KEYED TO WIDTHS AND NOT TO DEVICES. docs/unica-v4/SCREENS.md carries the
   measured viewport table, and the thing that table proves is that no device list can be the
   contract: on Android the CSS viewport is physical pixels divided by a display density the OWNER
   OF THE PHONE can change in Settings, and two reputable databases already disagree about the same
   Galaxy Z Fold6 by ninety CSS pixels for exactly that reason. A rule written against "the Fold6"
   is a rule written against one person's density setting. So the device table is evidence that the
   breakpoints below cover real widths, and the breakpoints are the contract.

   THE FOLD IS EXPRESSED IN STANDARDS, NOT IN MODEL NAMES. Three features do the work, and no
   user-agent string is read anywhere:
     horizontal-viewport-segments / vertical-viewport-segments  the window is in two pieces
     env(viewport-segment-*)                                    where the pieces are
     device-posture                                             folded, or continuous
   A browser that implements none of them gets the single-pane layout above, which is the whole
   product. Nothing here is load-bearing for a payment. */

/* ── 1. no horizontal scroll, at any width ───────────────────────────────────────────────────
   The page never scrolls sideways; a container may. Anything that can be wider than its column —
   a table, a long reference, a code block — is given its own scroller or told to break, so the
   document's own inline axis stays fixed. `overflow-x: clip` is deliberately NOT used on <body>:
   it hides the bug instead of fixing it, and it also clips position: sticky. */
img,
svg,
canvas,
video,
iframe {
  max-width: 100%;
  height: auto;
}
pre,
.evidence-json {
  overflow-x: auto;
  overflow-wrap: anywhere;
}
.hex {
  overflow-wrap: anywhere;
}
/* The one input that is asked to hold a whole payment link. It shrinks rather than pushing. */
.paylink input {
  min-width: 0;
}
.paylink,
.ctas,
.actions,
.stepper,
.assets li,
.registers li,
.product,
.order-row,
.co-lines,
.co-flow,
.co-line-what,
.pos-picks,
.pos-assets {
  min-width: 0;
}

/* ── 2. forty-four pixels, where a finger is the pointer ─────────────────────────────────────
   assets/unica.css already gives the primary controls a 44px minimum. Four smaller ones remain,
   because on a mouse they are correct at 32 to 36: the chip's inline button, its network select, a
   disclosure summary, and the colour-scheme select in assets/screens/theme.css. On a coarse pointer
   none of them is, so they grow — and only there, so the desk layout does not inflate.

   The theme control is reached with the same specificity theme.css uses and wins on order, because
   this file is loaded after it. That is the only reason this rule works, so if the shell ever moves
   fold.css above screens/, this line goes quiet and the control silently drops back to 36px. */
@media (pointer: coarse) {
  .wchip .cta,
  .wchip select,
  .fold summary {
    min-height: 44px;
  }
  .theme-pick > select {
    min-height: 44px;
  }
  .sidenav a,
  ul.nav a {
    min-height: 44px;
  }
}

/* ── 3. the three frames, narrow first ───────────────────────────────────────────────────────
   320 is the floor this product supports. The narrowest CSS viewport in SCREENS.md is 323 (the
   Galaxy Z Fold6 cover screen at its shipped density), so 320 is a real floor with three pixels
   of margin rather than a round number somebody liked. */

/* Below 30rem — every phone in SCREENS.md, and both cover screens — the frame stops spending
   width on chrome. */
@media (max-width: 29.999rem) {
  header.site,
  main,
  footer {
    padding-left: var(--s3);
    padding-right: var(--s3);
  }
  .topbar {
    padding-left: var(--s3);
    padding-right: var(--s3);
  }
  .envbar {
    padding-left: var(--s3);
    padding-right: var(--s3);
  }
  /* The signed-in menu is a top ROW, not a stack that pushes the page down: one line that scrolls
     sideways inside itself. The page's own inline axis does not move. */
  .sidenav {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: thin;
    -webkit-overflow-scrolling: touch;
  }
  .sidenav a {
    white-space: nowrap;
  }
  /* The register fills the screen: at 320 a 24rem cap would leave the keypad floating in a column
     narrower than the display above it. */
  .register {
    max-width: none;
  }
  .keypad {
    gap: var(--s2);
  }
  .keypad .key {
    min-height: calc(var(--space) * 15);
    font-size: 1.35rem;
  }
  .hero {
    padding-top: var(--s5);
  }
  .hero h1 {
    font-size: 1.75rem;
  }
  .checkout {
    padding: var(--s4);
  }
}

/* The checkout card: capped and centred at every width, so the thing a customer is about to pay
   for is the same shape on a phone, a tablet and a desk. 28rem is the cap; the column around it
   may be wider, the card is not. */
.checkout {
  max-width: 28rem;
  margin-inline: auto;
}
.lay-checkout main > .checkout,
.lay-checkout .checkout {
  margin-inline: auto;
}

/* 30rem and up: the keypad has room to be a comfortable block rather than the whole width. */
@media (min-width: 30rem) {
  .register {
    max-width: 24rem;
  }
}

/* The sidebar collapse boundary is 52rem, and it is DECLARED here as well as inherited, because a
   builder reading this file must be able to see the number without opening the other one.
   assets/unica.css turns .appframe into `14rem minmax(0, 1fr)` at (min-width: 52rem); below that
   it is a single column and .sidebar is a top row with a bottom border. This block does not move
   the boundary — it only makes the collapsed row behave like a row. */
@media (max-width: 51.999rem) {
  .appframe {
    grid-template-columns: minmax(0, 1fr);
  }
  .sidebar {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--paper);
  }
  .lay-app main,
  .lay-app footer {
    max-width: none;
  }
}

/* Tablet and small laptop: 744 (iPad in a narrow split), 820 (iPad portrait), 1024. */
@media (min-width: 46.5rem) {
  .kpis {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
@media (min-width: 64rem) {
  .lay-app main {
    max-width: 58rem;
  }
  .pagehead {
    align-items: center;
  }
}
/* 1280 and 1440: the measure stops growing. A line of body text is not more readable at 1100px
   wide, so the extra width becomes margin. */
@media (min-width: 80rem) {
  .lay-marketing header.site,
  .lay-marketing main,
  .lay-marketing footer {
    max-width: 64rem;
  }
  .lay-app .appframe {
    max-width: 80rem;
    margin-inline: auto;
  }
}

/* ── 4. two segments, side by side ───────────────────────────────────────────────────────────
   The window is reported in two pieces with a gap between them. The gap is not guessed and not
   measured from a device list: it is the distance between the right edge of segment (0,0) and the
   left edge of segment (1,0), which is exactly what the two env() functions below return. The
   fallbacks make the declaration harmless on a browser that knows the media feature but not the
   variables — the frame simply keeps a normal gutter.

   The assumption this makes, stated so it can be checked: .appframe spans the viewport's inline
   axis from its origin, so segment (0,0)'s right edge is also the left pane's width. <body> carries
   only the safe-area insets, which are zero on the segmented layouts in SCREENS.md. */
@media (horizontal-viewport-segments: 2) {
  :root {
    --seg-a-end: env(viewport-segment-right 0 0, 50%);
    --seg-b-start: env(viewport-segment-left 1 0, 50%);
    --hinge: calc(var(--seg-b-start) - var(--seg-a-end));
  }

  /* app — the sidebar takes the left pane, the content takes the right, the hinge is the gutter
     and holds nothing. Neither pane's content is ever cut by the seam. */
  .appframe {
    display: grid;
    grid-template-columns: var(--seg-a-end) minmax(0, 1fr);
    column-gap: var(--hinge);
  }
  .sidebar {
    border-bottom: 0;
    border-right: 1px solid var(--line);
    min-height: 60vh;
    position: static;
  }
  .sidenav {
    display: block;
    flex-wrap: wrap;
    overflow-x: visible;
  }
  .sidenav li + li {
    margin-top: var(--s1);
  }
  .lay-app main {
    max-width: none;
  }

  /* checkout — the card stays whole inside the left pane. A total and the button under it must
     never sit on opposite sides of a seam. */
  .lay-checkout header.site,
  .lay-checkout main,
  .lay-checkout footer {
    max-width: var(--seg-a-end);
    margin-inline: 0 auto;
  }

  /* marketing — one measure, inside one pane, so no line of text crosses the gap. */
  .lay-marketing header.site,
  .lay-marketing main,
  .lay-marketing footer {
    max-width: var(--seg-a-end);
    margin-inline: 0 auto;
  }
}

/* ── 5. two segments, stacked ────────────────────────────────────────────────────────────────
   The same idea on the block axis: the gap is the distance between the bottom of segment (0,0) and
   the top of segment (0,1). The frame stacks and the seam becomes the row gap, so nothing lands
   half in each half. */
@media (vertical-viewport-segments: 2) {
  :root {
    --seg-a-end-block: env(viewport-segment-bottom 0 0, 50%);
    --seg-b-start-block: env(viewport-segment-top 0 1, 50%);
    --hinge-block: calc(var(--seg-b-start-block) - var(--seg-a-end-block));
  }
  .appframe {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--hinge-block);
  }
  .sidebar {
    border-right: 0;
    border-bottom: 1px solid var(--line);
    min-height: 0;
    position: static;
  }
  .sidenav {
    display: flex;
    flex-wrap: wrap;
  }
  /* A control the customer is reaching for should not be scrolled to rest under the seam. */
  main {
    scroll-padding-block-end: var(--hinge-block);
  }
  .checkout,
  .register {
    scroll-margin-block-end: var(--hinge-block);
  }
}

/* ── 6. posture ──────────────────────────────────────────────────────────────────────────────
   The web platform exposes POSTURE, not angle: `folded` or `continuous`, and nothing between them.
   So this is a transition between two states when the device changes posture, never an animation
   driven by how far open the hinge is — docs/unica-v4/SCREENS.md says the same in prose, because
   somebody will eventually ask for the per-degree version and the answer has to be findable.

   Two ways in, on purpose. The media feature is the standard; `data-posture` on <html> is what
   assets/fold.js writes from the DevicePosture API, for the browsers that ship the object but not
   the media feature (and it is the only thing that file does). Either one is enough. */
:root {
  --frame-panel: var(--paper);
  --frame-quiet: var(--surface);
  --frame-glass: none;
  --frame-panel-line: var(--line);
}

.topbar,
.card,
.checkout,
.empty {
  background-color: var(--frame-panel);
  backdrop-filter: var(--frame-glass);
  -webkit-backdrop-filter: var(--frame-glass);
  transition:
    background-color 240ms ease,
    border-color 240ms ease,
    backdrop-filter 240ms ease,
    -webkit-backdrop-filter 240ms ease;
}
.envbar,
.status {
  background-color: var(--frame-quiet);
  backdrop-filter: var(--frame-glass);
  -webkit-backdrop-filter: var(--frame-glass);
  transition:
    background-color 240ms ease,
    backdrop-filter 240ms ease,
    -webkit-backdrop-filter 240ms ease;
}

/* The folded state. The panels go translucent and, where the browser can, blur what is behind
   them, so the frame reads as glass while the device is closing and as solid when it is open.

   THE CONTRAST WAS COMPUTED, NOT EYEBALLED. At 62% the panel composites over whatever page surface
   is behind it. The worst pairing in either scheme is body ink over a panel sitting on --line:
   14.69:1 in the dark scheme, 15.74:1 in the light one; the quietest text, --muted, bottoms out at
   5.15:1 (light, over --line). apps/web/tests/fold.test.mjs recomputes all of it from the hex in
   assets/unica.css and this alpha, and fails below 4.5:1 — with a control proving the arithmetic
   can fail. */
@media (device-posture: folded) {
  :root {
    --frame-panel: color-mix(in srgb, var(--paper) 62%, transparent);
    --frame-quiet: color-mix(in srgb, var(--surface) 62%, transparent);
    --frame-panel-line: color-mix(in srgb, var(--ink) 22%, transparent);
  }
  .topbar,
  .card,
  .checkout,
  .empty {
    border-color: var(--frame-panel-line);
  }
}
:root[data-posture="folded"] {
  --frame-panel: color-mix(in srgb, var(--paper) 62%, transparent);
  --frame-quiet: color-mix(in srgb, var(--surface) 62%, transparent);
  --frame-panel-line: color-mix(in srgb, var(--ink) 22%, transparent);
}
:root[data-posture="folded"] .topbar,
:root[data-posture="folded"] .card,
:root[data-posture="folded"] .checkout,
:root[data-posture="folded"] .empty {
  border-color: var(--frame-panel-line);
}

/* The blur is an enhancement, not the effect: without it the panels are still translucent. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  @media (device-posture: folded) {
    :root {
      --frame-glass: blur(12px) saturate(1.08);
    }
  }
  :root[data-posture="folded"] {
    --frame-glass: blur(12px) saturate(1.08);
  }
}

/* `continuous` is the solid state, and it is written down rather than left to the absence of the
   folded rule, so a posture that arrives late still puts the frame back. */
:root[data-posture="continuous"] {
  --frame-panel: var(--paper);
  --frame-quiet: var(--surface);
  --frame-glass: none;
  --frame-panel-line: var(--line);
}

/* Reduced motion: the state still changes, the change is just not animated. assets/unica.css
   already carries a blanket rule; this one is here so that THIS file is correct on its own, and so
   the test that reads the emitted stylesheet is reading a guarantee rather than a coincidence. */
@media (prefers-reduced-motion: reduce) {
  .topbar,
  .card,
  .checkout,
  .empty,
  .envbar,
  .status {
    transition: none;
  }
}

/* ── 7. the same rules, reaching the blocks the product renders TODAY ────────────────────────
   Sections 1–6 are written against apps/web/DESIGN.md, which names the checkout card `.checkout`
   and the counter `.register`. Those are the contract and they stay. But the screens that exist on
   this branch right now render `.co-card` inside `.lay-checkout`, and `.pos` inside `.lay-app` —
   different names for the same two things. A rule that reaches only the contract name is correct on
   paper and absent from the screen, and "the checkout card is capped at 28rem" would then be a
   claim about a stylesheet rather than about anything a customer sees. So this section bridges the
   two, and it is kept separate rather than merged into the selector lists above so that the day the
   screens are rebuilt on the contract names, the whole bridge can be deleted in one piece.

   SPECIFICITY HERE IS LOAD-BEARING, AND IT IS NOT TASTE. assets/fold.css is linked in <head>;
   a route's own assets/screens/*.css is linked inside <main>, which is LATER IN DOCUMENT ORDER. At
   equal specificity the route stylesheet therefore wins. So every selector below is prefixed with
   its layout class to reach (0,2,0), and the prefix is doing two different jobs:

     REQUIRED TODAY, for the glass. screens/checkout.css declares `.co-card { background: ... }` at
     (0,1,0), and `background` is a shorthand that sets `background-color`. Unprefixed, the folded
     panel's translucency is overwritten and the whole see-through treatment silently does nothing
     on the only checkout that exists. This was verified by removing the prefix and watching the
     test go red, not by reading the cascade and believing it.

     DEFENSIVE, for the 28rem cap. screens/checkout.css caps `.co`, not `.co-card`, so at present
     an unprefixed cap would apply. The prefix costs nothing and stops that from depending on the
     other file never adding a width — which is exactly the sort of thing it would be entitled to
     add, since `.co-card` is its block.

   Either way, removing a prefix fails SILENTLY: nothing turns red, the page just keeps the other
   file's value. apps/web/tests/fold.test.mjs compares every rule in this file against all three
   route stylesheets, expanding shorthands, and fails on any rule that would be beaten. */

/* The cap the owner asked for, on the card that is actually on screen. The COLUMN around it may
   stay wider — assets/screens/checkout.css puts `.co` at 34rem and that is its business — but the
   card a customer reads a total off is the same 28rem on a phone, a tablet and a desk. */
.lay-checkout .co-card {
  max-width: 28rem;
  margin-inline: auto;
}

/* Below 30rem the card spends its width on the total and the button, not on padding, matching what
   section 3 does for `.checkout`. */
@media (max-width: 29.999rem) {
  .lay-checkout .co-card {
    padding: var(--s4);
  }
  /* The till fills the screen. assets/screens/pos.css is already one column below 52rem, so this
     only tightens the gap between the keypad and the sale so both fit above the fold at 320. */
  .lay-app .pos {
    gap: var(--s4);
  }
}

/* Posture, section 6, reaching the same two blocks. `.co-card` sits on --paper exactly as
   `.checkout` does, so the contrast arithmetic in apps/web/tests/fold.test.mjs covers it without a
   second computation — the panel colour and the alpha are the same two values. */
.lay-checkout .co-card,
.lay-app .pos-sale {
  background-color: var(--frame-panel);
  backdrop-filter: var(--frame-glass);
  -webkit-backdrop-filter: var(--frame-glass);
  transition:
    background-color 240ms ease,
    border-color 240ms ease,
    backdrop-filter 240ms ease,
    -webkit-backdrop-filter 240ms ease;
}

@media (device-posture: folded) {
  .lay-checkout .co-card,
  .lay-app .pos-sale {
    border-color: var(--frame-panel-line);
  }
}
:root[data-posture="folded"] .lay-checkout .co-card,
:root[data-posture="folded"] .lay-app .pos-sale {
  border-color: var(--frame-panel-line);
}

/* Two segments: the checkout card and the till stay whole inside one pane. A total and the button
   under it on opposite sides of a seam is the single worst thing this file could allow. */
@media (horizontal-viewport-segments: 2) {
  .lay-checkout .co {
    max-width: none;
  }
  .lay-app .pos {
    grid-template-columns: minmax(0, 1fr);
  }
}
@media (vertical-viewport-segments: 2) {
  .lay-checkout .co-card,
  .lay-app .pos-pad {
    scroll-margin-block-end: var(--hinge-block);
  }
  /* Sticky positioning and a seam disagree: a keypad pinned to the top of the lower segment sits
     against the hinge. It scrolls with the page instead. */
  .lay-app .pos-pad {
    position: static;
  }
}

@media (prefers-reduced-motion: reduce) {
  .lay-checkout .co-card,
  .lay-app .pos-sale {
    transition: none;
  }
}
