/* layouts.css — THE page frames. Split out of global.css so every layout a page can
   wear is in one file, readable end to end, instead of interleaved with typography
   and component chrome.

   WHAT LIVES HERE — exactly one thing: the layout a page wears on its <main>, plus
   the column system those frames provide and the page-level responsive rules that
   govern them (the desktop left gutter, the phone full-bleed block, the 960px
   stack). A template picks ONE frame; the classes are global, so a new page reuses
   an existing frame by naming it rather than inventing a width.

   THE FRAMES, all of them — FOUR, and that is the whole list. Each carries its own
   width, so a page names exactly ONE class on its <main>: never two together, never a
   grid nested inside another frame. Reuse one; don't mint a width:

     .single-column-grid   720px centred column of cards,   tx, address, asset,
                           plus a side track an <order-     monitor, DEX fill,
                           panel> can take (0 wide until    mn_tx, mn_address
                           opened; drops under the column
                           below 960px)
     .split-grid           1020px centred, 12 columns       dex-volume, home (its
                           (.main-col 7 / .side-col 5),     hero wears it too, so
                           one column below 960px           the two widths match)
     .fullpage-grid        the SAME 12 columns at the       chart (7/5 split),
                           full viewport, 8px right         profile pages + connect
                           gutter                           (no columns, just width)
     .wide-column-grid     1200px centred — THE default     dapps (+ sub-pages),
                           wide frame                       components

   …plus ONE that cannot live here, listed so the set is complete:

     three-columns-grid    12 tracks, each card spanning 4  components — declared in
                           (→ 6 tablet → full width phone)  that page's SHADOW

   WHAT DOES NOT — anything INSIDE the frame. Content grids (.utxo-cols, .tx-meta),
   flex rows (.hash-row, .section-head), headings and every component's chrome stay
   in global.css / the component's own shadow. The line is "does <main> wear it".

   NO PAGE-SPECIFIC FRAMES. A frame describes a SHAPE — a width, a column count, a
   split — and knows nothing about which page wears it or what that page is for. So it
   is named for its shape — every name above says how wide it is and how many columns
   it has, and nothing else. Never for a page or a feature: `.tx-layout`, `.addr-grid`,
   `.mn-main`, `.chart-grid`, `.asset-grid`, `.monitor-main`, `.portfolio-main`,
   `.events-main` and the anonymous `.container` were all exactly that and are all
   gone. A frame also carries no business logic — no rule that only makes sense for
   transactions, orders, the chart or a profile. Page names are how near-duplicates
   breed: SEVEN classes all meaning some flavour of "a centred readable column" existed
   at once, each named after its page rather than its shape, so nobody could see they
   were the same thing — they are now ONE. The one concession is a shape that needs a
   slot for a specific ELEMENT (the side track an <order-panel> can occupy) — express
   it as a track any page could fill, and say so in the comment.

   PAGES DO NOT CUSTOMISE THE FRAME. A template picks a frame by NAME and stops there:
   no width/padding/margin/grid override on the <main> from a page's own <style> block,
   no `.some-page .split-grid { … }` refinement, no per-page media query re-doing the
   breakpoints, and no page component reaching out to restyle its container. The frame
   is the contract — every page that names it gets the same geometry, which is the only
   reason the site has one rhythm rather than N. If a page seems to need something the
   frame does not give, there are exactly three honest answers: wear a different frame,
   change the frame HERE for everyone that wears it, or lay the page's own content out
   INSIDE its component (which is where content, unlike frames, belongs — see
   <portfolio-page> and <components-page>, both of which build their internal grid in
   their own shadow). Adding a fourth answer in the page is what produced the seven
   near-duplicate frames named above. The same goes for HOOKING onto a frame: page CSS
   selects its own content (`.vault { … }`), never `.wide-column-grid .vault`, or the
   page breaks the day it wears a different frame.

   LOAD ORDER: this file is linked BEFORE global.css in every template, so the two
   keep the declaration order they had when they were one file. Nothing should
   DEPEND on that: a frame here and a rule there must not set the same property on
   the same element. The one pair that came close — a frame's `margin: 0 auto` vs
   `.hero`'s vertical margin — was made disjoint (`.hero` uses `margin-block`)
   rather than left to the cascade. Keep it that way.

   Spacing is the --space-* scale (defined in global.css :root); custom properties
   resolve at computed-value time, so the token definitions loading second is fine.
   Add a step to the scale rather than hand-picking a gutter.

   A frame added here also gets a row in js/components-catalog.js (LAYOUTS), which
   is what the /components page lists. */

/* ── The 12-column system ──────────────────────────────────────────────────────
   TWO frames provide columns, and they differ in ONE property — their width:

     .split-grid      1020px centred   home, /dapps/dex-volume
     .fullpage-grid   the viewport     chart, profile pages, connect

   So the column mechanics are declared ONCE for both and each frame then sets only
   its own width. A page wears exactly ONE of them: they are alternatives, not a base
   plus a modifier. (`.split-grid.fullpage-grid` used to be how the chart got a
   full-width split — two frame classes on one element, which reads as a nested grid
   and forced every reader to work out which width won on source order.)

   A page that wants columns fills `.main-col` (7) and `.side-col` (5); below 960px
   both span the full width and stack in source order. A page that just wants the
   width puts its content straight in — a bare child spans all 12 (see below), so the
   profile pages stack a breadcrumb and one component with no columns at all. */
.split-grid,
.fullpage-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--space-2);
  align-items: start;
}
.split-grid { max-width: 1020px; margin: 0 auto; padding: var(--space-2); }

/* The full-page width: the whole viewport (no max-width cap → no auto side margins),
   with an 8px right gutter here — its own 0 left is lifted to 8px on desktop by the
   universal `body > main[class]` rule below, so it still shares the page-wide left
   gutter — and a little vertical padding, so the content has all the room there is.
   Mobile drops all gutters (the phone block below). Worn by the chart (a candle chart
   uses every pixel it is given), and by the profile + connect pages, which lay their
   own content out inside a component's shadow. It replaced `.portfolio-main`, which
   was the same thing under a page's name. */
.fullpage-grid { max-width: none; padding: var(--space-2) var(--space-2) var(--space-2) 0; }

:is(.split-grid, .fullpage-grid) .main-col,
:is(.split-grid, .fullpage-grid) .side-col {
  min-width: 0;               /* let the chart/tables shrink inside the column */
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
:is(.split-grid, .fullpage-grid) .main-col { grid-column: span 7; }
:is(.split-grid, .fullpage-grid) .side-col { grid-column: span 5; }
/* Any other direct child — a breadcrumb, a page heading, a whole page component —
   spans the row, so a page can put chrome above the columns, or skip the columns
   entirely, without wrapping anything in a second frame. Frames are never nested and
   never combined: one <main>, one frame class. */
:is(.split-grid, .fullpage-grid) > *:not(.main-col):not(.side-col) { grid-column: 1 / -1; }
/* Cards in a gap-based column are spaced by the column's `gap`, so drop their own
   bottom margin (<app-card> reads this custom property through the shadow boundary)
   — otherwise a stacked pair gets gap + margin = double the intended spacing. */
:is(.split-grid, .fullpage-grid) .main-col > *,
:is(.split-grid, .fullpage-grid) .side-col > * { --card-margin: 0; }

@media (max-width: 960px) {
  :is(.split-grid, .fullpage-grid) .main-col,
  :is(.split-grid, .fullpage-grid) .side-col { grid-column: 1 / -1; }
}

/* THE default wide frame: a 1200px centred column, wider than the readable column
   because the content wants the room — the dapps feed holds a row of event badges per
   line, and the component gallery lays its cards out on its own 12-column grid.
   Tables scroll inside their own box below that width. Worn by dapps (+ its
   sub-pages) and components — reach for this one, or `.single-column-grid`, before
   adding a new frame. (It was `.events-main`, named for the page it started on.) */
.wide-column-grid { max-width: 1200px; margin: 0 auto; padding: var(--space-2); }

/* THE single centred column — ONE frame for every page that is just a stack of cards
   in a readable column: /tx, /address, /asset, /monitor, the DEX fill page, /mn_tx and
   /mn_address. It replaced `.container`, `.tx-layout`, `.addr-grid`, `.asset-grid`,
   the 960px `.mn-main` and the 1400px `.monitor-main`, so "a readable column" is ONE
   width on this site instead of six near-identical ones. The pages that were wider
   keep working because a table wider than the column scrolls inside its own card
   (<app-table> already does; the Midnight pages' hand-rolled tables were given the
   same `overflow-x`) — which is the site-wide rule for wide content anyway, and a
   better answer than a page-shaped width: at 1400px the monitor table simply pushed
   the rest of the page around.

   It is a GRID rather than a plain block for ONE reason: a page may hang an
   <order-panel> to the LEFT of the column, taking no room at all until a fill's order
   link is clicked (/tx is the one that does). So the frame declares two tracks —
   [panel] [column]; every child lands in the column track and stacks in source order,
   and the panel is the single exception that takes track 1. A page with no panel
   leaves that track empty at zero width and is simply a centred column. Cards space
   themselves by <app-card>'s own bottom margin, so the frame sets NO row gap — one
   here would double it — and the panel carries its own right margin instead of a
   `column-gap`, which would otherwise push the column 8px off-centre on every page
   that has no panel at all.

   The 720px cap is on the CHILDREN (`max-width` + `justify-self: center`), never on
   the track: a `minmax(0, 720px)` track is 720px wide whatever the container, so on a
   390px phone it would overflow and scroll the page sideways — the one thing every
   layout here must not do. A `1fr` track that the children cap inside shrinks. The cap
   reaches every child because grid items are BLOCKIFIED: a custom element that is
   `display: inline` by default (most of ours, until their own :host says otherwise)
   still computes to block here, so `width`/`max-width` apply to it. */
.single-column-grid {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  padding: var(--space-2);
}
.single-column-grid > * {
  grid-column: 2;
  justify-self: center;
  width: 100%;
  max-width: 720px;
  min-width: 0;
}
/* <order-panel> handles its own show/hide + width via :host (shadow); the frame only
   says WHERE it sits, and lets it size itself rather than capping it like a card. */
.single-column-grid > order-panel {
  grid-column: 1;
  grid-row: 1;
  justify-self: start;
  width: auto;
  max-width: none;
  margin-right: var(--space-2);
}

/* Below the site's split breakpoint there is no room beside the column, so the panel
   stops being a side panel and drops UNDER the content it details (`order` is what
   moves it last — the same end position the old flex `column-reverse` gave). Every
   child moves to track 1: leaving them on `grid-column: 2` against a one-track
   template would place them in an IMPLICIT second column instead. */
@media (max-width: 960px) {
  .single-column-grid { grid-template-columns: minmax(0, 1fr); }
  .single-column-grid > * { grid-column: 1; }
  .single-column-grid > order-panel {
    grid-row: auto;
    order: 1;
    justify-self: center;
    width: 100%;
    max-width: 720px;
    margin-top: var(--space-2);
    margin-right: 0;
  }
}

/* The home page has NO frame of its own — it wears plain `.split-grid`, the shared
   7/5 split (the chart runs the same columns at `.fullpage-grid`'s width): the pair
   board in the main column, the visitor's balance in the side column. Its
   <header class="hero"> wears `.split-grid` TOO, so the hero is exactly as wide as the
   content under it; the
   hero's single child is a bare child of the frame, so it spans the whole row. The
   bespoke `.home-grid` and `.home-head` stay gone — a page picks the shared split, it
   does not mint its own. `.hero` (global.css) sets only `margin-block` + centring, so
   it cannot collide with the frame's `margin` shorthand whatever the load order. */

/* The ONE frame that is not in this file: `.three-columns-grid`, the /components
   gallery's own — the same 12 tracks as `.split-grid`, cut three ways (each card
   spans 4, stepping to 6 on a tablet and full width on a phone). It is declared in
   <components-page>'s SHADOW because everything it lays out lives in that shadow
   root, which a global class cannot reach; the page's <main> wears `.wide-column-grid`
   for width. Named here so the catalog of frames is complete in one place. */

/* Desktop: every page's layout carries an 8px left gutter, so content never butts
   the window's left edge and all skeletons share one left rhythm. ONE rule at the
   universal layout element (<main>, in every template); the `[class]` qualifier
   lifts it above each per-page layout class's own `padding` shorthand so it applies
   uniformly — including the otherwise flush-left `.fullpage-grid` pages. Scoped above
   the 560px phone breakpoint only, where the layouts below deliberately go
   full-bleed. */
@media (min-width: 561px) {
  body > main[class] { padding-left: var(--space-2); }
}

/* Phone: buy back the horizontal room the page gutters take. At 390px a 1rem
   gutter each side is 8% of the screen — the tables inside need it more. */
@media (max-width: 560px) {
  /* Every frame goes full-bleed on a phone — the tables inside need the horizontal
     room more than the gutter does, so the desktop 8px gutter is dropped here. ONE
     rule for three of the four: .split-grid (home, dex-volume), .fullpage-grid (chart,
     profile, connect) and .single-column-grid (tx/address/asset/monitor/DEX
     fill/Midnight); .wide-column-grid keeps its vertical padding below. The cards
     inside keep their own small padding so text never butts the edge. */
  .split-grid,
  .fullpage-grid,
  .single-column-grid { padding: 0; }
  /* A full-bleed frame's tables reach the edge — but pad the breadcrumb itself so its
     logo still lines up under the nav logo, matching the dapps breadcrumb. On desktop
     the body>main[class] gutter already supplies this, so the rule is only needed at
     the phone breakpoint. */
  .fullpage-grid > app-breadcrumb { padding-left: var(--space-2); }
  /* Dapps/events pages go edge-to-edge too — the row-per-line list inside wants
     the horizontal room more than the gutter does (the card keeps its own inset). */
  .wide-column-grid { padding: var(--space-2) 0; }
  .fullpage-grid { max-width: 100vw; }
}
