/* nrg.market cabinet — page layout only.
   Rule (cabinet-plan §K8): no colour, size or radius literal outside tokens.

   That rule — not CSP — is why the screens carry no inline style attributes:
   an inline style is a value with nowhere to put the token. Do not put them
   back on the grounds that CSP tolerates them. It very likely does: htm and
   preact write string style props through element.style.cssText, a CSSOM
   write, which style-src does not police — setAttribute with "style" appears
   nowhere in web/vendor/preact.mjs. К8 forbids them regardless, and
   web/tests/inline-styles.test.mjs fails if one comes back.

   Colours, spacing, radii below are all var(--nrg-*). The only bare pixel
   values are structural grid tracks and breakpoints taken straight from the
   design handoff ("сетка 216px 1fr", rail collapses to 62px at 760px). */

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  background: var(--nrg-bg);
  color: var(--nrg-text);
  font-family: var(--nrg-font-sans);
  font-size: var(--nrg-text-sm);
  line-height: var(--nrg-leading-normal);
  -webkit-font-smoothing: antialiased;
}
h1, h2 { margin: 0; font-weight: var(--nrg-weight-semibold); letter-spacing: var(--nrg-tracking-tight); }
h2 { font-size: var(--nrg-text-md); }
a { color: var(--nrg-accent); text-decoration: none; }
a:hover { color: var(--nrg-accent-hover); }
code { font-family: var(--nrg-font-mono); font-size: var(--nrg-text-xs); }

/* ---------- cabinet chrome: rail + main ---------- */
.cab { display: grid; grid-template-columns: 216px 1fr; min-height: 100vh; }
.cab__rail {
  display: flex; flex-direction: column;
  border-right: var(--nrg-border-width) solid var(--nrg-line);
  background: var(--nrg-surface);
  padding: var(--nrg-space-4) var(--nrg-space-3);
  gap: var(--nrg-space-4);
  position: sticky; top: 0; height: 100vh;
}
.cab__brand { font-size: var(--nrg-text-lg); padding: 0 var(--nrg-space-2); }
.cab__brand span { color: var(--nrg-text-dim); }
.cab__nav { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--nrg-space-1); flex: 1; }
.cab__link {
  display: flex; align-items: center; gap: var(--nrg-space-3);
  padding: var(--nrg-space-2) var(--nrg-space-3);
  border-radius: var(--nrg-radius);
  color: var(--nrg-text-muted);
  min-height: var(--nrg-tap-min);
}
.cab__link:hover { background: var(--nrg-surface-hover); color: var(--nrg-text); }
.cab__link.is-active { background: var(--nrg-accent-soft); color: var(--nrg-accent); }
.cab__mono {
  font-family: var(--nrg-font-mono); font-size: var(--nrg-text-2xs);
  color: var(--nrg-text-dim); width: 34px; letter-spacing: var(--nrg-tracking-caps);
}
.cab__link.is-active .cab__mono { color: var(--nrg-accent); }
.cab__signout { align-self: flex-start; }

.cab__main { display: flex; flex-direction: column; min-width: 0; }
.cab__header {
  display: flex; align-items: center; gap: var(--nrg-space-4);
  padding: var(--nrg-space-3) var(--nrg-space-6);
  border-bottom: var(--nrg-border-width) solid var(--nrg-line);
  background: var(--nrg-surface-2);
  position: sticky; top: 0; z-index: var(--nrg-z-sticky);
}
/* The account switcher, for the people who have more than one account to be in
   (components/accounts.mjs). It is capped rather than left to the content: an
   account name is typed by a person, the header is sticky, and a long one would
   push the balance and the price off a laptop for the rest of the visit. The
   select shortens what it cannot show, and the whole row — name and role — is
   in the `title` of the control and of every option (components/accounts.mjs),
   so two names that differ only at the tail are still tellable apart. */
.cab__accounts { display: flex; align-items: center; min-width: 0; }
.cab__accounts .nrg-select { max-width: 220px; }

.cab__bal { display: flex; align-items: center; gap: var(--nrg-space-2); flex-wrap: wrap; }
.cab__bal .nrg-balance__label { margin-left: var(--nrg-space-3); }
/* The tariff, spelled out beside the chip that explains it: the unit price and
   what one transfer comes to. Three gap widths, and they say what belongs to
   what — the header's own step before the group, a wider one between the two
   figures, the tightest inside the pair that is a single figure. At one gap
   throughout, «34 sun / unit» and «1 transfer =» ran together into one line of
   text. */
.cab__price { display: flex; align-items: center; gap: var(--nrg-space-3); flex-wrap: wrap; }

/* The per-transfer figure is the wide one — a caps label, six decimals and a
   unit — and it is shown only in a window that can hold the whole bar on one
   line, which the common laptop cannot. Measured, not guessed: the header
   comes to ~1217px in German with a six-figure balance (French and Spanish are
   within ten pixels), and the rail takes 216 of the viewport. Under that the
   bar wrapped, and a sticky header costs its second line on every screen all
   day; the price of a transfer is also on the New order screen and on the
   public site. English would fit in less, but one threshold is one behaviour.

   Written as hidden-by-default and restored above the threshold, so a rule
   lost in a later edit hides a figure — which somebody notices — instead of
   quietly putting the bar back on two lines in eight languages of eleven. The
   exception sits here rather than in the responsive section at the foot of the
   file: it is not a tweak at a breakpoint, it is the other half of this rule. */
.cab__transfer { display: none; align-items: center; gap: var(--nrg-space-2); }
@media (min-width: 1440px) { .cab__transfer { display: flex; } }
.cab__content { padding: var(--nrg-space-6); overflow-x: hidden; }

/* ---------- generic screen scaffolding ---------- */
.screen { display: flex; flex-direction: column; gap: var(--nrg-space-6); }
.screen--full { height: calc(100vh - 120px); }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--nrg-space-6); }
/* Grid and flex items refuse to shrink below their content by default
   (`min-width: auto`), and an <input> carries an intrinsic width of about
   twenty characters however narrow the column is. Two of those plus the rail
   is wider than a laptop viewport: the panel grew, the table and the hint went
   off the right edge, and the whole page scrolled sideways — which it must
   never do. The floor is removed here, once, for the row and for the fields
   inside it. */
.grid-2 > * { min-width: 0; }
.nrg-field { min-width: 0; }
.nrg-field .nrg-input, .nrg-field .nrg-select, .nrg-field textarea { width: 100%; min-width: 0; }
.cards-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--nrg-space-4); }

/* The address cell of the orders list, when the address needs a word with it.
   A mode C order has no recipient — the cell carries the wallet instead, and
   the qualifier under it is what keeps the column honest (screens/orders.mjs).
   Stacked rather than inline: the chip is monospace and full-width here, and a
   word beside it would push the column wider on every row, including the many
   that need no word at all. */
.addr-cell { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; }

/* New order: two one-press panels beside the full form.
   The narrow track is sized to what the panels hold — a headline, a price, one
   address field — and the wide one takes the rest, because the form's textarea
   and its per-recipient table are what actually need width. The floor is
   measured, not chosen: a TRON address is 34 monospace characters and comes to
   266px at 13px, while the wallet field inside a 340px track — the fixed width
   this used to be — is 264px wide inside its padding. Two pixels short, on the
   one field the panel exists for, which is why the address scrolled in it. The
   floor is that measurement with a little slack; above it the track takes a
   share of the window instead, up to 480px, and the share is small enough that
   the form keeps the greater part at every width the two columns exist at
   (below 1080px they stack).
   Both tracks are `minmax(0, …)`: a track has the same refusal to shrink below
   its content as a grid item (`1fr` alone means `minmax(auto, 1fr)`), and an
   <input> carries about twenty characters of intrinsic width whatever the
   column says — the live defect `.grid-2 > *` above was fixed for. */
.neworder-grid {
  display: grid;
  grid-template-columns: minmax(0, clamp(352px, 36%, 480px)) minmax(0, 1fr);
  gap: var(--nrg-space-6); align-items: start;
}
/* A named way to order: heading, one line, then whatever that way is made of.
   Both columns are built the same so the two names sit on one baseline. */
.neworder-col { display: flex; flex-direction: column; gap: var(--nrg-space-4); min-width: 0; }
.neworder-way { display: flex; flex-direction: column; gap: var(--nrg-space-1); }
/* The heading of a way keeps the size of a heading, not of a panel title: it
   names a choice, and the panel titles under it name the volumes within it. */
.neworder-way h2 { font-size: var(--nrg-text-lg); }
.neworder-way .nrg-field__hint { margin: 0; }
.neworder-quick { display: flex; flex-direction: column; gap: var(--nrg-space-6); min-width: 0; }
/* The volume is the panel's name, so it is set at the size of a name and not
   of a heading in a list of headings. */
.quick .panel__head h2 { font-size: var(--nrg-text-xl); }
.quick__case { margin: 0; }
/* The one press, made the width of the panel. Scoped to the action row on
   purpose: the small buttons inside a refusal callout are not this button. */
.quick .panel__actions .nrg-btn { width: 100%; }
.stack { display: flex; flex-direction: column; gap: var(--nrg-space-3); }

/* A cell that acts like a link but is a button: selecting the endpoint whose
   delivery log is shown below. Anchors navigate; this one does not. */
.nrg-linkish {
  background: none; border: none; padding: 0; cursor: pointer;
  color: var(--nrg-accent); font: inherit; text-align: left;
}
.nrg-table tr.is-selected { background: var(--nrg-surface-hover); }

/* The second factor's QR comes as finished markup from the server (its own
   colours, so it scans in either theme — app/core/totp.py). Only the box it
   sits in is ours. */
.totp-qr { width: 180px; }
.totp-qr svg { width: 100%; height: auto; display: block; }
.totp-step { border-top: var(--nrg-border-width) solid var(--nrg-line-soft); padding-top: var(--nrg-space-4); }

/* A user-agent string is text somebody else chose: long, arbitrary, and not
   worth a horizontally scrolling table. The screen truncates it as well —
   this is the guard for whatever gets through. */
.ua-cell {
  display: inline-block; max-width: 40ch; vertical-align: bottom;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-family: var(--nrg-font-mono); font-size: var(--nrg-text-2xs);
  margin-right: var(--nrg-space-2);
}

/* The reminder sits above the screen it interrupts, and wraps on a narrow
   viewport instead of pushing the content sideways. */
.reminder {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--nrg-space-4); flex-wrap: wrap;
  margin-bottom: var(--nrg-space-6);
}
.reminder__text { display: flex; flex-direction: column; gap: var(--nrg-space-1); min-width: 0; }

/* ---------- modal backdrop ---------- */
/* .nrg-modal is the card; the design system leaves the ground under it to the
   app. The dimming is the page's own ink at low opacity — a colour of its own
   would be a literal, and a literal that is wrong in one of the two themes. */
.modal-backdrop {
  position: fixed; inset: 0; z-index: var(--nrg-z-modal);
  display: flex; align-items: center; justify-content: center;
  padding: var(--nrg-space-6);
  background: var(--nrg-text);
  background: color-mix(in srgb, var(--nrg-text) 55%, transparent);
}

/* The QR's two colours, deliberately the same in both themes — this is the one
   thing in the cabinet that is not read by a person but by a camera. They are
   tokens rather than literals in the markup, and they are defined once, outside
   any [data-theme] or prefers-color-scheme block: a QR that changed with the
   theme would be an inverted code half the time, and scanners are not unanimous
   about those. Same decision, same reason as the server's 2FA code
   (app/core/totp.py, dark/light fixed explicitly). */
:root {
  --nrg-qr-plate: #ffffff;
  --nrg-qr-modules: #000000;
}
.qr { width: 100%; height: 100%; display: block; }
.qr__plate { fill: var(--nrg-qr-plate); }
.qr__modules { fill: var(--nrg-qr-modules); }

/* The expandable transaction cell and the details row under it. */
.tx-toggle { display: inline-flex; align-items: center; gap: var(--nrg-space-2); }
.tx-caret { color: var(--nrg-text-dim); font-size: var(--nrg-text-2xs); }
.details-row > td { background: var(--nrg-surface-2); }
.deposit-details { padding: var(--nrg-space-2) 0; }
.nrg-link-out { align-self: flex-start; }

/* A transaction id is 64 characters with nowhere to break: without this it
   runs out of its own box and takes the panel with it. */
.nrg-code { overflow-wrap: anywhere; }

/* A value that is read, not edited — the sign-in email. Not an input: the
   account's identity has no endpoint to change it (api-spec.md §9.2), and a
   disabled input invites the try anyway. */
.value-mono { font-family: var(--nrg-font-mono); }
.row-gap { display: flex; gap: var(--nrg-space-3); flex-wrap: wrap; }
/* Empty div that eats the free space of a flex row, pushing what follows to
   the far end. Used in the header, both toolbars and the api-keys panel head. */
.spacer { flex: 1; }

.panel {
  border: var(--nrg-border-width) solid var(--nrg-line);
  border-radius: var(--nrg-radius-lg);
  background: var(--nrg-surface);
  padding: var(--nrg-space-6);
  display: flex; flex-direction: column; gap: var(--nrg-space-4);
  min-width: 0;
}
.panel__head { display: flex; align-items: center; gap: var(--nrg-space-3); }
/* .panel is a flex column with gap var(--nrg-space-4); these margins add to
   that gap, setting the trailing blocks off from the body of the panel. */
.panel__error { margin-top: var(--nrg-space-3); }
.panel__actions { margin-top: var(--nrg-space-4); }
.card {
  border: var(--nrg-border-width) solid var(--nrg-line);
  border-radius: var(--nrg-radius-lg);
  background: var(--nrg-surface);
  padding: var(--nrg-space-4);
  display: flex; flex-direction: column; gap: var(--nrg-space-2);
}
.card__head { display: flex; align-items: center; justify-content: space-between; gap: var(--nrg-space-2); }

.toolbar {
  display: flex; align-items: center; gap: var(--nrg-space-3);
  padding-bottom: var(--nrg-space-3);
}
/* Wide content scrolls inside its own box; the page never scrolls sideways.
   `overflow-x: auto` is spelled out rather than left to the shorthand because
   it is the rule being kept, and `max-width: 100%` is what stops a parent grid
   track from handing this box more width than the screen has. */
.table-scroll {
  overflow: auto; overflow-x: auto; max-width: 100%; flex: 1;
  border: var(--nrg-border-width) solid var(--nrg-line);
  border-radius: var(--nrg-radius-lg);
}
.table-scroll .nrg-table thead th { position: sticky; top: 0; z-index: var(--nrg-z-sticky); }
.pager-bar { display: flex; gap: var(--nrg-space-3); padding-top: var(--nrg-space-3); }

.deposit-row { display: flex; gap: var(--nrg-space-6); flex-wrap: wrap; align-items: flex-start; }
.deposit-detail { display: flex; flex-direction: column; gap: var(--nrg-space-3); flex: 1; min-width: 240px; }

/* ---------- page-level sizing of design-system components ----------
   Sizes the design system leaves to the page. Where the component already sets
   the property, the selector is compound (component class + page class) so it
   outranks the single-class rule in components.css — that file is vendored
   verbatim and its SRI hash is in index.html, so it must not be edited. */
.nrg-input.input--area { height: auto; padding: var(--nrg-space-3); }
/* Skeletons hold the height of the block they stand in for, so the panel does
   not jump when data lands; .nrg-skeleton's own height is a single 10px bar.
   Both heights are whole steps of the spacing scale: 5 × 16 and 5 × 24. */
.nrg-skeleton.skeleton--fields { height: calc(var(--nrg-space-4) * 5); }
.nrg-skeleton.skeleton--table { height: calc(var(--nrg-space-6) * 5); }
/* The savings item takes the slack of the balance row. 180px is the width it
   may shrink to before wrapping — a structural track like .cards-row's 200px
   and .deposit-detail's 240px, not a value off the spacing scale. */
.balance-grow { flex: 1; min-width: 180px; }

/* The cheap tariff zone. The modifier is ours, not the design system's: it
   used to be `.is-night` there, keyed to a zone name that no longer exists
   (schedules are re-cut without a release, `api-spec.md` §2.1). Toning it
   here keeps components.css byte-identical to docs/site/assets/ — the copy
   whose sha384 sits in VENDOR.md precisely so a local patch shows up in
   review. Same tokens as the component it tones, so the chip keeps its
   place on the scale. */
.nrg-zone.is-cheap { border-color: var(--nrg-info-soft); background: var(--nrg-info-soft); }

/* ---------- theme toggle: the top-right corner of every screen ---------- */
/* The icon is sized from the button's own font size, not from a pixel literal:
   a glyph that tracks the control it sits in needs no entry on the scale, and
   К8 leaves no room for a stray 18px. */
.theme-toggle { padding: 0 var(--nrg-space-2); }
.theme-toggle svg { width: 1.2em; height: 1.2em; display: block; }

/* Signed-out screens have no header for it to sit in, so it takes the corner
   of the page itself (positioned against .auth-shell below). */
.theme-corner { position: absolute; top: var(--nrg-space-4); right: var(--nrg-space-4); }

/* ---------- auth screens ---------- */
.auth-shell {
  min-height: 100vh; display: flex; align-items: center; justify-content: center;
  padding: var(--nrg-space-6); background: var(--nrg-bg);
  position: relative; /* the anchor for .theme-corner */
}
.auth-card {
  width: min(400px, 100%);
  border: var(--nrg-border-width) solid var(--nrg-line);
  border-radius: var(--nrg-radius-lg);
  background: var(--nrg-surface);
  padding: var(--nrg-space-8);
  display: flex; flex-direction: column; gap: var(--nrg-space-4);
}
.auth-brand { display: flex; align-items: baseline; gap: var(--nrg-space-2); color: var(--nrg-text-dim); }
.auth-brand strong { color: var(--nrg-text); font-size: var(--nrg-text-lg); }
.auth-title { font-size: var(--nrg-text-xl); }
.auth-form { display: flex; flex-direction: column; gap: var(--nrg-space-4); }
.auth-form .nrg-btn { width: 100%; }
.auth-links { display: flex; flex-direction: column; gap: var(--nrg-space-2); font-size: var(--nrg-text-sm); }
.auth-error { margin: 0; }

/* ---------- responsive ---------- */

/* Too narrow for a column beside the form — the 500-address textarea and its
   per-recipient table stop being readable in what is left. The panels move
   above it and go side by side rather than stacking: stacked, they are two
   full-width blocks between the person and the form, and the screen would open
   on a wall of one-press panels with the form below the fold. */
@media (max-width: 1080px) {
  .neworder-grid { grid-template-columns: minmax(0, 1fr); }
  .neworder-quick { flex-direction: row; }
  .neworder-quick > * { flex: 1; }
}


/* rail collapses to monograms */
@media (max-width: 760px) {
  .cab { grid-template-columns: 62px 1fr; }
  .cab__brand span, .cab__link .cab__label, .cab__signout { display: none; }
  .cab__mono { width: auto; }
  .grid-2 { grid-template-columns: 1fr; }
  .cab__bal { display: none; }
  /* No room for two of them abreast either — back to one under the other. */
  .neworder-quick { flex-direction: column; }
}
