/* GameOnTime — public site theme (dark, gaming-oriented, BRD §6) */
/*
 * ================== THIS FILE NO LONGER DEFINES ANYTHING ==================
 *
 * It is the LEGACY page stylesheet, and it is shrinking. The design system —
 * every token and every component — is public/css/system.css, which the
 * layout loads BEFORE this file. Read that file first; it explains the split.
 *
 * NO COLOUR IS DEFINED HERE. It never was for the accents, and since 15 Aug
 * it is not for the greys either:
 *
 *   --accent, --accent-2, --accent-dim, --accent-rgb   \
 *   --bg, --bg-2, --card, --card-2                      |  all printed into
 *   --line, --line-2                                    |  every page by
 *   --text, --muted, --dim                              |  Brand::cssVariables()
 *   --green, --amber, --red                            /   from config/brand.php
 *
 * The `:root` block that used to sit here held nine of those as literal
 * hexes. `#0D0F17` was therefore written THREE times across the project and
 * `#22C55E`, `#F59E0B` and `#EF4444` twice each — in the codebase whose
 * standing rule is that a colour is decided in exactly one place. The
 * variable NAMES are unchanged, so every rule below reads what it always
 * read.
 *
 * Writing even a "harmless fallback" back into this file would be the second
 * copy that move deleted, and second copies drift. If a page renders with no
 * surfaces, the layout has stopped calling Brand::cssVariables() — which
 * SiteTokensTest asserts it does, after the stylesheet links.
 *
 * ------------------------------------------------------------------------
 *
 * WHAT IS STILL HERE: page-specific rules for the surfaces that have not
 * been migrated onto the system yet. `database/check_site_css.php` prints how
 * many, and that number is the size of the remaining migration.
 *
 * When you migrate a surface, DELETE its rules from this file in the same
 * pass. A page styled by both files is the two-systems problem the system
 * was built to end.
 */
:root{
  /* The one legacy alias: the system's name for this 14px is --gt-radius-lg
     and that is the definition. The count that stood here — "46 rules below
     say `var(--radius)`" — was a HAND-MAINTAINED NUMBER and it is measured
     ZERO, at this commit and at every commit back through 291de2f: the only
     `var(--radius)` in this file is the one inside this comment. It is
     deleted rather than corrected, per the standing rule, and it cost
     something before it went: V-13a Batch 1 read it, believed it, and put
     `--radius` into a guard's docblock as a name site.css reads. Whether the
     alias itself should go is BUG-230's question and needs its own pass —
     removing a value while anything still reads it is a SILENT change. */
  --radius: var(--gt-radius-lg);
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
/* Reduced motion means the jump is a jump. This rule had no override for
   the whole life of the file and nothing on the homepage triggered it until
   the hero gained an action → #games (18 Aug); the verifier sampled scrollY
   under emulated reduce: 0, 11, 240, 369, 425, 447 … — a 500ms glide. */
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
/* An anchored section clears the sticky header by the system's offset, so
   its title is the first thing on screen after the jump and not the tile
   under it. Scoped to sections that are targets; a form field's own anchor
   is its own business. */
/* 🔴 BUG-584 (V-30 B4): `<main id="main">` is the skip link's target and it
   had no scroll-margin, so following the link scrolled the page to main's
   own top and the sticky bar covered the landing — MEASURED before: after
   the jump scrollY 73, #main's top at 0 under a 73px header (61/61 at 390),
   both languages. With the offset the jump clamps at the document's top and
   main's top edge meets the bar's bottom edge — MEASURED after: 0px of main
   under the bar at 1536 and 390, both languages, signed out and in. */
#main,
.section[id]{scroll-margin-block-start:var(--gt-scroll-offset)}
body{
  background:var(--bg); color:var(--text);
  /* ONE source for the face — V-30 B3. This line used to spell the stack out
     (`Inter,-apple-system,"Segoe UI",Arial,sans-serif`) beside a token that
     spelt it a second time, and MEASURED (the batch's impact pass): overriding
     `--gt-family` alone moved `.got-btn` by 1.08px and nothing else, because
     the body — and by inheritance the whole site — was reading THIS line and
     not the token. Now the token is the only place the face is decided, which
     is also what lets /ar re-point it to the Arabic stack in one rule. */
  font-family:var(--gt-family);
  line-height:1.6; -webkit-font-smoothing:antialiased;
  /* THE SHORT-PAGE RULE (18 Aug, the UI/UX round's Batch 0). Seven customer
     pages are shorter than the screen and the footer floated mid-viewport
     — measured at y 396 on the 404, 485 on the cards page, 511 on the cart,
     657/691/708/799 elsewhere in a 900 viewport. The body is a column and
     <main> takes what is left, so the footer sits at the bottom of the
     screen on a short page and after the content on a long one. Measured
     after: 404 footer 396→809, cards 485→809, document 900 both. */
  min-block-size:100dvh; display:flex; flex-direction:column;
}
main{flex:1 0 auto}
a{color:inherit;text-decoration:none}
/* The container reads the shell tokens (Batch 0): the same 1180 it always
   was, with a gutter that grows 20→40px with the viewport instead of a fixed
   20px at every width. */
.container{max-width:calc(var(--gt-container) + 2 * var(--gt-gutter));margin:0 auto;padding:0 var(--gt-gutter)}
/* 🔴 THE SHELF'S MEASURE — FLUID, NOT A WIDER COLUMN (V-06 Batch 4, 22 Aug).

   V-05 Batch 2 stood here for a few hours and said: the reading measure is
   1140, a page that is nothing but a shelf takes 1240, and above 1800 it
   takes 1560. That whole scheme is DELETED rather than retuned, because V-06
   is a different idea and not a different setting of that one.

   WHAT WAS WRONG WITH IT, MEASURED ON THIS TREE at 1536 before the change:
   the shelf's box was 1320 wide inside a 1536 viewport, so the grid's left
   edge sat at 148 and 216px of the page was margin. That space is the
   catalogue's. The container is now capped at --gt-shelf-max (1680) with
   FIXED gutters, so below 1680 the shelf is the viewport less its gutters and
   the tile floor — not a column width — decides how many cards a row holds.
   Measured after: the grid's left edge is 48 at 1536 and the row holds five.

   THE GUTTERS ARE THREE FIXED STEPS OF THE SPACING SCALE, NOT --gt-gutter.
   The shell's gutter is clamp(20px, 3vw, 40px) and cannot produce these: at
   1100 it resolves to 33 where the shelf needs 24, and at 390 to 20 where the
   shelf needs 16. They are two different jobs — one is the reading measure's
   air, this one is tuned so the fourth track survives 1100. That is the ONE
   number in this container tuned rather than derived, and it is a GUTTER
   rather than a hand-written column count on purpose: the count still comes
   from the floor at every width, including this one.

   🔴 THE MIDDLE STEP IS 24 AND THE REFERENCE SAYS 32, WHICH IS A DIVERGENCE
   THAT EXISTS TO KEEP THE REFERENCE'S OWN PROMISE. Four tracks want 1020 of
   content. At 32 a 1100 viewport gives 1036 — sixteen pixels — and FIFTEEN OF
   THOSE ARE A SCROLLBAR THE MEASUREMENT DID NOT HAVE: the round's harness
   drives a Chrome whose clientWidth equals the viewport, while a real Windows
   Chrome takes 15px out of the layout viewport before this gutter resolves.
   Driven at the equivalent narrower viewports: 1085 (a 15px bar) gave 1021 and
   four tracks by ONE PIXEL, and 1083 (a 17px bar) gave 1019 and THREE. At 24
   the same three readings are 1052 / 1037 / 1035, all four tracks, with 32 /
   17 / 15 of slack, and 1080 (a 20px bar) still holds. The count at every
   other width has room to spare, so this is the only step that moved.
   `--gt-tile-min`'s comment in system.css carries the table.

   NO `min(100%, …)` GUARD. It was needed while the cap was written as
   `calc(measure + 2 * gutter)` with the gutter growing; here the cap is a
   flat 1680 on a border-box element, so below 1680 the declaration is inert
   and the div is simply the width of its parent. A guard for a state nothing
   can reach is the kind this project calls indistinguishable from a bug.

   THREE WEARERS, AND EACH IS A DECISION RATHER THAN AN OVERSIGHT: `/games`,
   the homepage's `#games` section (they render the same <x-games-grid>, so
   one shelf gets one measure — the reference's homepage file says "ONE
   CONTAINER. Same as /games."), and SINCE V-18b the homepage's `#store`
   section, so its heading and first card share the games band's left edge —
   Omar's alignment ask. The store's grid DOES fill this box since V-18d:
   `.got-store-grid` (system.css) is FIXED counts now (6/3/2), so V-01's
   empty-track finding — which was about an uncapped `auto-fill` strip
   minting tracks nothing fills — cannot recur: the track count is written,
   not derived from a floor, and six cards fill six tracks. The V-18b 1140
   cap died with the auto-fill grid. The HERO alone stays at the reading
   measure: a centred column of words has no tracks to gain. */
.container--shelf{max-width:var(--gt-shelf-max);padding-inline:var(--gt-space-10)}
@media (max-width:71.875em){   /* 1150 — this is what keeps 4 tracks at 1100 */
  .container--shelf{padding-inline:var(--gt-space-7)}
}
@media (max-width:32.5em){     /* 520 */
  .container--shelf{padding-inline:var(--gt-space-5)}
}

/* ---------- header ---------- */
.site-header{
  position:sticky;top:0;z-index:50;
  /* 🔴 THIS WAS `rgba(13,15,23,.85)` UNTIL 22 AUG — `brand.ink`'s channels
     written out as literals, which `BrandPaletteTest` could not see because it
     knows hex strings. It was found by BUILDING THE LIGHT THEME: the bar
     stayed black across the top of a white page. A rule that is right in one
     theme and wrong in the other is BUG-096's family, and the fix is the same
     one — read the value from the emitter, which now publishes the page's
     channels for exactly this. */
  /* V-13 Batch 4.2 — treatment C, tinted glass (Omar, 24 Aug: "now it is
     black only, add a small touch to show system colors in the header bar").
     The wash is a LAYER OVER the same glass, never a replacement: 13% blue
     at the inline-start easing through 5% to 7% of the second accent toward
     the inline-end, then clear. Channels come from the emitter (--blue-rgb,
     --accent-secondary-rgb, --bg-rgb) so both themes composite their own
     values — the rule above records what happened last time literals were
     written here. A gradient's angle is physical, so the [dir="rtl"] rule
     below mirrors it (100deg → 260deg). NO motion: treatment D was rejected
     — the bar is sticky, and a permanent traveller would compete with the
     hero rails wherever both are visible. */
  background:
    linear-gradient(100deg,rgba(var(--blue-rgb),.13) 0%,rgba(var(--blue-rgb),.05) 34%,rgba(var(--accent-secondary-rgb),.07) 76%,transparent 100%),
    rgba(var(--bg-rgb),.85);
  backdrop-filter:blur(12px);
  border-bottom:1px solid transparent;
}
[dir="rtl"] .site-header{
  background:
    linear-gradient(260deg,rgba(var(--blue-rgb),.13) 0%,rgba(var(--blue-rgb),.05) 34%,rgba(var(--accent-secondary-rgb),.07) 76%,transparent 100%),
    rgba(var(--bg-rgb),.85);
}
/* The hairline becomes the brand's own line: transparent → blue → accent →
   second accent → transparent, fading at both ends. A ::after and not
   border-image, so the border-box geometry above does not move — the
   transparent border keeps the 1px of height the flat line occupied, and
   since V-30 B4 that pixel is inside `--gt-header-height`'s figure: `.nav`
   takes the token less this border, so the header's border-box lands on
   the token exactly. Mirrored for RTL like the wash.

   🔴 THE GRADIENT IS THE TOKEN — V-42d B2, 11 Sep 2026. This line carried the
   brand's edge gradient as a private literal from 18 Aug; V-40 minted
   `--gt-gradient-edge` for the wallet capsule and the top-up cards rather than
   write a third copy, and left this one because converting it touches every
   page. It is converted now, and "touches every page" was MEASURED as the
   header strip of seven kinds of page, signed out and in, both locales, both
   themes — 48 strips, pixel-identical before and after (the round's report).
   The RTL token is `270deg` with the same stops, which is the same line as
   the mirrored literal that stood here (26/60/84 are 100 − 74/40/16). */
.site-header::after{
  content:"";position:absolute;inset-inline:0;bottom:-1px;block-size:1px;
  background:var(--gt-gradient-edge);
  opacity:.8;
}
[dir="rtl"] .site-header::after{
  background:var(--gt-gradient-edge-rtl);
}
/* ---- the header row — REBUILT 18 Aug (the UI/UX round's Batch 2) ---------

   ONE LINE ON THE WIDE ROW, TWO ON THE PHONE (V-30 B5). The 14 Aug note
   that stood here let the row WRAP at phone width so that nothing could be
   pushed off the inline end (BUG-205, BUG-206, BUG-208 are the measurements
   it carried); it made the header 103px for a guest and 159px signed in at
   390 — three rows, the account toggle alone on the last — and the 18 Aug
   rebuild superseded it: the language switch and the guest's sign-in sit
   inside the ☰ disclosure (`.got-navmenu`, system.css), a full-width SHEET
   under the header below the breakpoint and inline content at it and
   above. Since V-30 B5 the row wraps ONCE, on purpose, below 52em: the pill
   navigation (`.got-tabs`, system.css — outside the disclosure) is a
   full-width second line under brand · ☰ · basket · balance · account,
   because the first line cannot take it (MEASURED at 390: three text tabs
   overflow it by 192–264px, three 44px icon pills by 24px for an English
   guest). The header is 64.00 on the wide row and 116.00 on the phone, both
   `--gt-header-height` (system.css); nothing is off-screen at 320 (MEASURED:
   a 272px pill in a 288px content box, scrollWidth = clientWidth).

   THE BREAKPOINT IS 52em (832px), the width at which the wide row stops
   fitting with every target at 44px — measured, both languages, signed-in —
   and it is the same line system.css draws for the two sheets and for
   --gt-scroll-offset. 640 remains the phone line for things that are about
   a PHONE (the logo step, the tile ratio); this one is about the ROW.

   Sizes are tokens: the tap floor, the spaces, the text scale. GAP-099: the
   brand and the footer's links are 44px targets here; the pill's tabs, the
   switch, the toggles and the sheet rows are the system's.

   ============ V-33 B4: THE WIDE ROW IS A THREE-COLUMN GRID ================

   The row was `display:flex; justify-content:space-between` and the centre
   zone a flex ITEM (`flex: 1 0 auto`) between two side zones of different
   widths — so the pill centred in the LEFTOVER, not in the header, and by a
   different amount per locale and per signed-in state (Omar saw it, 3 Sep:
   right of centre in Arabic, further left in English). MEASURED BEFORE at
   1440, pill centre minus header centre: guest −98.23 (/) and +97.91 (/ar);
   signed in −125.14 and +128.98. The brand was 197.86 wide, the end zone
   135.5 (guest) or 293.67 / 301.38 (signed in).

   Now the row is a grid of the THREE ZONES the header is made of — brand ·
   `.got-header__nav` · `.got-header__end` (system.css; the end zone wraps
   the ☰ disclosure and the account cluster, so the row has exactly three
   children) — and the middle column is `auto`: the pill's own width, in the
   middle of two equal `1fr` tracks, which is the header's centre by
   construction and not by leftover.

   THE TWO SIDE TRACKS ARE NOT WRITTEN THE SAME WAY, ON PURPOSE. The brand's
   is `minmax(0, 1fr)`: the brand is still the one item on the row allowed
   to give (its rule below), and the track may shrink under it. The end
   zone's is `minmax(max-content, 1fr)`: its contents are 44px targets, a
   figure and a name that never give, so the track may not go under them —
   with `1fr` on both sides and `min-inline-size: 0` on the end zone, the
   cluster would overflow its track TOWARD the pill at any width where the
   equal split cannot hold it (MEASURED signed in: the cluster is 452.13 (/)
   and 459.83 (/ar) wide, and an equal track at 1150 is 362, at 1280 it is
   403). So: equal tracks wherever both zones fit — MEASURED 487/487 at
   1440 and 407/407 for a guest at 1280, the pill's centre ON the header's
   in every state — and where the end zone is wider than half the slack, its
   track holds and the brand's takes what is left, so the pill shifts (1366
   signed in: 2.12 / 9.83 short of centre), which is what the flex row did at
   EVERY width. The full table, by width and state, is in the B4 report.
   The brand carries `min-inline-size: 0` (its rule below) — that is what
   lets its track go under the wordmark; the end zone carries NONE, because
   its floor is the track's `max-content` and a minimum on the item changes
   nothing there (the B4 verifier MEASURED one rendering byte-identically
   deleted at six width/state combinations). */
.nav{
  display:grid;
  grid-template-columns:minmax(0,1fr) auto minmax(max-content,1fr);
  align-items:center;
  gap:var(--gt-space-5);
  /* V-30 B4: the row's floor is THE TOKEN, less the header's 1px transparent
     border, so the header's border-box IS --gt-header-height (system.css).
     It binds: the tallest row items at 1536 are the pill and the language switch at 46.00
     (the wordmark is 45.98) + 2×8 padding = 62, one under the 63 this
     resolves to, and the 44px targets + 16 = 60.
     MEASURED header 64.00 at 1536 and at 390, both languages, signed out
     and in. It was a bare `72px` — one of five disagreeing copies. */
  min-block-size:calc(var(--gt-header-height) - var(--gt-border-hair));
  padding-block:var(--gt-space-3);
}
@media (max-width:52em){
  /* No min-block-size here any more: system.css re-declares the token in
     this band and the rule above reads it, so ONE declaration sizes both
     rows (this was `min-block-size:0` — 8 + 44 + 8 = 60 — until V-30 B4).
     HeaderHeightTest asserts nothing in any band sizes `.nav` a second way.
     `flex-wrap` since V-30 B5: the pill navigation is a full-width second
     LINE of this row on the phone (`.got-header__nav`, system.css), and
     the gap is the space between the two lines as well as between items.
     V-33 B4: the wide row is a grid now (above), so THIS band is where the
     row is a flex row at all — the phone's two lines are a wrapping flex
     row of brand · ☰ · cluster · (line 2) the pill, spread by
     `space-between`. The end zone is `display: contents` in this band
     (system.css), so the ☰ and the cluster are this row's own items, at
     the x positions V-30 B5 measured — the B4 fix pass re-measured them
     against the pre-batch tree, all four states, both languages. */
  .nav{ display:flex; justify-content:space-between; gap:var(--gt-space-3); flex-wrap:wrap; }
}

/* The brand: 44px tall as a target however tall the logo is — and THE ONE
   THING ON THE ROW THAT MAY GIVE. Every other item is content-sized and
   `flex-shrink:0` (the balance is a figure, the tabs are names); the brand
   shrinks first, and the wordmark scales with it (block-size auto under a
   max, max-inline-size 100%), so a longer balance narrows the logo a little
   rather than pushing the account toggle into the gutter or off the screen.
   The verifier found exactly that at 401–409px with a $10.00 balance and off
   the viewport at 401–412 with $1,000.00 — the mark line below had been set
   from ONE balance figure. */
/* V-33 B4: `justify-self:start` because the brand is a GRID item on the wide
   row now (`.nav` above). A grid item's default is `stretch`, and this is a
   link: stretched, the whole first track — hundreds of pixels of empty header
   — would be the home link and the focus ring would draw around all of it.
   `start` gives it its content width, still shrinkable under the track
   (`min-inline-size:0`, and the wordmark's `max-inline-size:100%`). Logical:
   `start` is the right edge on /ar. `flex:0 1 auto` is for the phone band,
   where the row is a flex row. */
.brand{ display:inline-flex; align-items:center; min-block-size:var(--gt-tap-min); flex:0 1 auto; min-inline-size:0; justify-self:start; }
/* 46px to match the panels' 3rem lockup, so the mark carries the same weight
   whichever part of GameOnTime you are looking at. Steps down on a phone,
   where the row has far less room to give. */
/* The box is reserved BEFORE the file lands (C-06, 19 Aug — the D3 verifier
   measured 0×0 until then and a 198px jump of the nav row): the attributes
   give the ratio (aspect-ratio: auto 542/126), and a ratio cannot size an
   unloaded image on its own — `inline-size:auto` was overriding the
   attributes' hint. So the inline size is WRITTEN, from the same numbers
   (46px tall × 542/126), the block size follows the ratio, and the max rules
   below still clamp it (34px under 52em; a squeezed row shrinks the width
   and the height follows — no distortion, the ratio transfers). */
.brand-logo{display:block;inline-size:calc(542 / 126 * 46px);block-size:auto;max-block-size:46px;max-inline-size:100%}
/* THE LIGHT WORDMARK IS A `<picture>` SOURCE, NOT A SECOND IMAGE.

   The first version put two `<img>`s in the markup and swapped them with
   `display`, and it cost 98 KB on every request: Chrome fetches an image whose
   element is `display:none`, measured on the live page
   (logo-horizontal.png 112,489 bytes AND logo-horizontal-light.png 97,951).
   GAP-104 already flags these two files as oversized; downloading both would
   have made a known problem worse.

   A `<picture>` downloads the one source that matches. It cannot answer
   `[data-theme]`, and it does not need to: /design is the only page that
   forces a theme and the server picks the file there.

   `.brand-word` is the <picture> itself, and the <28em breakpoint hides IT —
   which is also what removed the specificity fight the container was
   originally added for: `:root[data-theme="light"] .brand-logo--light` was
   (0,2,1) against a media query's (0,1,0), so on a light phone the wordmark
   sat beside the mark. There is nothing left to out-specify. */
.brand-word{display:block;min-inline-size:0}
@media (max-width:52em){ .brand-logo{max-block-size:34px;inline-size:calc(542 / 126 * 34px)} }   /* the written width follows the smaller height: a max-height alone would clamp the height and leave the width at 198 (measured 19 Aug: distorted at 700) */   /* with the row's own breakpoint, so the row is 60 everywhere below it (measured 63 with the 46px logo in the 641–831 band) */
/* Below 28em (448px) the WORDMARK gives way to the MARK. Measured 18 Aug on
   the signed-in row — wordmark 146 + ☰ 44 + basket 44 + balance 59 + account
   44 + four 8px gaps = 369px, so the wordmark fits from 410 with a $10.00
   balance and from 434 with $1,000.00 (verifier); 448 leaves 408 of content
   for a $10,000.00 row, and beyond that the brand's shrink above is the net.
   With the 32px mark the row is 255, and a four-figure balance fits at 320.
   The name stays on the link's aria-label at every width. */
/* The mark scales under its max like the wordmark does (the verifier forced
   a $1,000.00 balance at 320: the link shrank to 33px and a fixed-size mark
   painted 8px under the ☰). And the brand never gives below the tap floor:
   on the mark row it holds 44 wide, so the LAST thing to go at 320 with a
   five-figure balance is a few pixels of gutter, not the target. */
.brand-mark{display:none;inline-size:calc(225 / 145 * 2rem);block-size:auto;max-block-size:2rem;max-inline-size:100%}   /* the same reservation for the mark (225×145) */
@media (max-width:28em){
  .brand{min-inline-size:var(--gt-tap-min)}
  /* The <picture>, not the image inside it. Hiding the container hides
     whichever source the browser resolved, and there is no theme selector on
     the brand any more for this bare class to have to out-specify. */
  .brand-word{display:none}
  .brand-mark{display:block}
}

/* THE GAMES ROW (`.nav-links`) LEFT THIS FILE IN V-30 B5. It was one link
   to /games inside the ☰ sheet; the navigation is the pill (`.got-tabs`,
   system.css), a system component outside the disclosure, on the row at
   every width. Its 44px floor, its ring and its `[aria-current]` paint all
   live beside the component now. Nothing here may name `.got-tabs`: a legacy
   rule on a system class would WIN (site.css loads after the system). */


/* 🔴 BUG-234. THE FIRST TWO TAB STOPS ON EVERY PAGE HAD NO VISIBLE FOCUS RING.

   `.brand` and `.nav-links a` had no `:focus-visible` rule of their own, so
   they fell through to Chrome's default `outline: auto` — which computes to
   `rgb(16, 16, 16)` at 1px. On this header's background (`rgb(13, 15, 23)`)
   that measures 1.01:1. Not faint: INVISIBLE.

   MEASURED BY TABBING, not by reading. A harness pressed Tab through every
   focusable control on /design, /cart and /ar/cart and read `outlineColor`,
   `outlineWidth` and the composited backdrop off each one. Every design-system
   component came back with the accent ring and its dark band; these two came
   back at 1.01:1. It is the first thing a keyboard user meets on any page of
   the site, and nothing anywhere reported it.

   The ring is the SYSTEM'S, by its tokens, so these links cannot drift from
   the components — and when these surfaces are migrated (GAP-080) this rule
   goes with them rather than being reinvented. `border-radius` so the ring
   follows the logo's box instead of boxing it.

   🔴 WIDENED FOR BUG-239. The first version of this fix named TWO SELECTORS,
   because the sweep that found the defect happened to be pointed at the header.
   A later sweep tabbed all 149 focusable controls on fourteen rendered pages
   and found FIVE MORE links falling through to the same 1px `rgb(16,16,16)` —
   1.01:1 on the page, 1.11:1 on a card:

     · both links inside the registration consent label (Terms, Privacy)
     · the "Sign in" / "Create account" link in the auth aside
     · BOTH FOOTER LINKS, which are on every page of the site
     · and the "Remember me" CHECKBOX on the sign-in form — not a link at all,
       which is why the first pass of this fix missed it too. The registration
       consent checkbox two hundred lines down has carried a ring since the day
       it was written; its neighbour on the other form never did.

   That is the lesson rather than the addition: BUG-234 was fixed as two
   selectors when it was a rule about CONTROLS THAT CARRY NO RING. A focus ring
   exists only where somebody wrote one, and nothing sweeps for its absence, so
   a fix reaches exactly as far as the instrument that found it was aimed —
   twice now, at two different widths of the same mistake.

   `.got-legal a` carries its own ring beside its component (V-20 B7 — this
   sentence used to say it "already" did, and that was false on this tree:
   the enumeration found the support address unclaimed for hover AND focus.
   A comment claiming a ring is not a ring). `.got-account__table td a`
   still has none and renders only on /design's specimen, not on any
   customer page — stated rather than left reading as coverage. `.got-lang
   a`, `.got-account__ref`, `.got-consent input` and the account menu keep
   theirs. This list is the controls that had NONE.

   🔴 TWO LEFT THIS LIST WHEN THE CHECKBOX WAS MIGRATED, and they left because
   their SELECTORS STOPPED EXISTING, not because the ring did.
   `.got-check input` is now `.got-check__box` and `.got-consent__text a` is
   now `.got-check__label a`; both rings live in `system.css` beside the
   component they belong to, which is where a ring stops being a name in a
   list somebody has to keep. A rename is how BUG-234's list would lose an
   entry silently, so the list in `SiteTokensTest` moved in the same pass.
   A THIRD LEFT IN V-30 B5 the same way: `.nav-links a` is `.got-tabs__tab`,
   ringed in system.css beside the pill, and the list moved with it. */
.brand:focus-visible,
.site-footer a:focus-visible,
.got-auth__minor a:focus-visible,
.got-auth__aside a:focus-visible{
  outline:var(--gt-ring-width) solid var(--gt-ring-color);
  outline-offset:var(--gt-ring-gap);
  border-radius:var(--gt-radius-sm);
  box-shadow:var(--gt-ring-shadow);
}
/* ---- `.btn`, `.btn-primary`, `.btn-ghost`, `.btn-block`, `.btn-sold-out`,
   `.buy-note`, `.got-cart__add` — GONE 18 Aug (Batch 3 of the UI/UX round).
   The service page's controls are the system's `.got-btn` now: BUG-250 (the
   buy box in Arial) and BUG-308 (Buy now white on 1.66–2.58:1) close with
   the migration; the price aside's own rules are in pages.css. */

/* ---------- THE HERO — A CENTRED COMPOSITION, COMPRESSED (V-06 Batch 5, 22 Aug)

   THE JOB IS HEIGHT. Measured on the rendered page at 1536x735 immediately
   before this batch, with the entrance off: the hero was 684.47 tall, "Choose
   your game" sat at 821.47 and the first card at 905.45 — so a 735px window
   opened on a headline, a paragraph, one poster and nothing this site sells.
   After: 447.86 / 520.86 / 564.05, identical in both languages and identical at
   1280, 1536 and 1920. The reference file's answer is not a smaller headline,
   it is a different composition: ONE COLUMN, CENTRED, 880 WIDE, holding a chip,
   the offer, the lead and an action, with two quiet rows under them.

   WHAT CAME OUT WITH IT. The featured panel (V-02 Batch 7) and every rule it
   had are DELETED rather than left behind — CSS loaded later wins on equal
   specificity and losing is silent, so a migrated surface's old rules go in
   the same pass. Call of Duty was on this page TWICE, once beside the hero and
   once as the first tile; since Batch 1-3 the tile IS a 2:3 poster with the
   words on it, which is the picture the panel existed to provide. `.hero__grid`
   goes with it (there is no second column) and so does `.hero__actions` (the
   action is a direct child of the flex column, so the entrance stagger can
   reach it by `nth-child`).

   THE AXIS CHANGES, AND THAT REVERSES 18 AUG'S DECISION ON PURPOSE. That round
   moved the hero onto the sections' start axis because a centred hero over
   start-aligned sections was two axes 570px apart at 1920. This is the third
   answer and it is the reference's: the hero is centred inside its OWN 880px
   measure, which is centred in the same `.container` every section uses, and
   the catalogue below keeps its start-aligned rhythm. The two axes cannot be
   570px apart any more because the hero no longer has a long line — every line
   in it is short, and short centred lines sit about the page's own middle.

   NO BRAND HEX AND NO CHANNEL TRIPLE. The reference writes five colours out as
   literals — 31,161,255 / 122,214,255 / 34,197,94 / 23,27,40 / 20,26,38 — and
   every one of them is a value `config/brand.php` decides. They read
   `--blue-rgb`, `--accent-rgb`, `--success-rgb`, `--bg-rgb` and `--wash-rgb`
   here, which the emitter publishes and the light block overrides. */
/* The section step is the START padding; the END is a smaller step, because
   the catalogue section below it opens with none at all (it wears `.got-index`
   — see home.blade.php) and the fade already dissolves this block into it. */
.hero{position:relative;overflow:hidden;padding-block:var(--gt-space-10) var(--gt-space-9)}

/* -------------------------------------------------------------- 1 · DEPTH
   Four static layers behind the words, plus the dissolve. `pointer-events`
   off and `aria-hidden` on the wrapper: none of this is content, and none of
   it may sit between a finger and the action.

   EVERY LAYER IS PLACED WITH LOGICAL PROPERTIES, so the composition mirrors on
   /ar with no `[dir]` rule at all. The gradients inside them are the part that
   cannot: an angle and a stop position are physical by definition.

   🔴 AND "PHYSICAL" IS STRONGER THAN THE FIRST CUT OF THIS COMMENT SAID. It
   said each gradient is written symmetric about its own middle, "which makes it
   its own mirror image" — as though /ar rendered a reflected form that happened
   to match. IT DOES NOT RENDER A REFLECTED FORM AT ALL. `direction` does not
   touch a gradient angle: the 100deg band paints the same pixels on /ar that it
   paints on /en. Measured 22 Aug, each declaration on a fixed 200x60 control on
   both pages at 1536, corners sampled at dsf 1, with an ASYMMETRIC control
   (120deg black->white) beside them, so a sampler blind to a difference shows
   up as a bug rather than as a result:

     band  100deg  /en  TL 10,12,18  TR 11,13,20  BL 11,14,20  BR 10,12,18
     sweep 100deg  /en  TL 13,15,21  TR 23,25,31  BL 23,25,31  BR 13,15,21
     control       /en  TL 4,4,4     TR 216,216,216  BL 39,39,39  BR 251,251,251
     /ar is byte-identical to /en for all three, the control included.

   So what actually makes the `[dir]` rule unnecessary is the symmetry of the
   FILL, not a reflection nobody performs: a palindromic stop list about a 50%
   midpoint is invariant under REVERSAL (t is t+180, so 100deg reads as 280deg),
   which is 180deg ROTATIONAL symmetry — TL matches BR and TR matches BL, above,
   within 1/255 of dither. It is NOT reflection (t -> 360-t), and the reading
   above says so: TL and TR differ. The layer is the same picture whichever end
   of the page you start from, which is the property that was wanted. A rule
   that only fires in the language nobody tests in is the worst kind there is
   (BUG-096); the cheapest way to not have one is to not need one. */
/* ===================================================================
   THE LIVING BACKGROUND — ONE DEFINITION, TWO PAGES (V-38, 7 Sep 2026)
   ===================================================================

   Omar: «شايف الواجهة الزرقة المتحركة بالصفحة الرئيسية — ضيفها بالخلفية».

   These layers were `.hero__*` and belonged to the home hero. The wallet now
   sits behind the same light, so they were RENAMED page-neutral and are read
   by both pages. They were NOT copied: a second copy is the two-systems
   problem, and this file has paid for it before.

   🔴 EVERY INFINITE ANIMATION IS DEFINED INSIDE
   `@media (prefers-reduced-motion: no-preference)` FURTHER DOWN, AND THE BASE
   STATE HERE IS FULLY VISIBLE. That is the whole shape and it must not be
   inverted into "animate always, cancel under reduce": a reduced-motion
   visitor gets the still layers, never a strobe, and never an invisible
   layer either. MEASURED before this lift and after it: 16 animations on the
   home page under no-preference, ZERO under reduce, in both languages.

   Transform and opacity only; nothing on a loop is under five seconds.
   `pointer-events:none` here and `aria-hidden` on the wrapper in the markup —
   the layers are decoration and nothing in them may be reachable. `z-index:0`
   with the content in its own stacking context above.

   The band's travel has no logical form, so the distance is a custom property
   the `[dir]` rule flips. Renaming it did not change that.
   =================================================================== */
/* 🔴 ONE FAMILY, TUNED BY PROPERTIES — V-42d B1, 11 Sep 2026. The wallet's
   BODY now carries a second, fainter instance of this background under its
   whole page (GAP-252: "low behind the ledger" could not be built from the
   header). It is NOT a second definition of any layer — `LivingBackgroundTest`
   holds each layer to exactly one rule — so what a second instance may differ
   in is expressed as custom properties the shared rules read, with the home
   hero's own values as the defaults: the two glows' alphas, the vertical seat
   of each glow (a percentage of the container's HEIGHT, which on a page-tall
   container would put both ellipses off the page entirely), and a mask the
   wallet's header instance uses to dissolve into the body's light instead of
   into flat `--bg`. `.got-livebg--faint` below sets those properties and
   nothing else. */
.got-livebg{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden;
  -webkit-mask-image:var(--gt-livebg-mask,none);mask-image:var(--gt-livebg-mask,none)}
/* The two glows are sized by `padding-block-end` rather than a height, so each
   stays an ellipse of its own width at every viewport. Both are off-canvas on
   two sides: the light comes from outside the block, not from a shape in it. */
.got-livebg__glow{position:absolute;border-radius:50%;filter:blur(70px);will-change:transform}
.got-livebg__glow--a{
  inline-size:var(--gt-livebg-a-w,56%);padding-block-end:var(--gt-livebg-a-d,38%);
  inset-inline-start:var(--gt-livebg-a-start,-6%);top:var(--gt-livebg-a-top,-34%);
  background:radial-gradient(circle,rgba(var(--blue-rgb),var(--gt-livebg-alpha-a,.22)),transparent 68%);
}
.got-livebg__glow--b{
  inline-size:var(--gt-livebg-b-w,46%);padding-block-end:var(--gt-livebg-b-d,32%);
  inset-inline-end:var(--gt-livebg-b-end,-8%);top:var(--gt-livebg-b-top,auto);bottom:var(--gt-livebg-b-bottom,-32%);
  background:radial-gradient(circle,rgba(var(--accent-rgb),var(--gt-livebg-alpha-b,.16)),transparent 68%);
}
/* 🔴 THE FAINT INSTANCE — V-42d B1. Custom properties ONLY; every rule that
   paints a layer stays the one above. The alphas are the header's × 0.5 as
   the brief's starting point, then MEASURED on the composited pixels of both
   themes (the round's report has the table) — the light must read as a wash
   at the edge of the eye behind the ledger and never as a colour. The seats
   are in rem because this instance sits in a container as tall as the page:
   the family's percentage seats are of the container's height, so on the
   wallet's body `top:-34%` would put the blue ellipse 440px above the page.
   Both glows sit under the header, where the page's light comes from, and
   the dot field's own radial mask and the `__fade` do the rest — the wash
   thins down the page and dissolves into `--bg` before the footer. */
.got-livebg--faint{
  --gt-livebg-alpha-a:.16;--gt-livebg-alpha-b:.11;
  /* A glow may never end on an edge (BUG-309). This instance is clipped at
     the container's box, where the blue is still bright, so it fades out
     across its own inline edges before the clip — symmetric, so it needs no
     [dir] twin. */
  --gt-livebg-mask:linear-gradient(to right,transparent,#000 1.5rem,#000 calc(100% - 1.5rem),transparent);
  --gt-livebg-a-w:110%;--gt-livebg-a-d:70%;--gt-livebg-a-start:-35%;--gt-livebg-a-top:-6rem;
  --gt-livebg-b-w:90%;--gt-livebg-b-d:60%;--gt-livebg-b-end:-30%;--gt-livebg-b-top:22rem;--gt-livebg-b-bottom:auto;
}
/* On a phone the container is 350px wide and the page is 2000px tall, so an
   ellipse sized off the WIDTH is a spot near the top of a long page — MEASURED
   at 390: the card gap read +0.5 of 255 with the wide seats above. Deeper
   ellipses, and the cyan seated where the ledger begins. Still properties
   only; the layer rules are untouched. */
@media (max-width:52em){
  .got-livebg--faint{
    --gt-livebg-a-d:140%;--gt-livebg-a-top:-10rem;
    --gt-livebg-b-d:130%;--gt-livebg-b-top:34rem;
    /* The container IS the viewport here, so the clip is the screen's own
       edge and there is nothing to fade before. */
    --gt-livebg-mask:none;
  }
}
/* 🔴 THE THIRD GLOW — V-41, AND IT IS THE WALLET'S ALONE.
   Omar: «صفحة my wallet فيها لمسة زرقة جميلة، اضف لمسة زهرية خافتة».

   SCOPED BY MARKUP, NOT BY A MODIFIER, AND THAT IS THE DECISION THE BRIEF
   ASKED FOR IN WRITING. The rule below is defined ONCE, here, beside its two
   siblings — it is part of the shared family and retunes with it. What makes
   it wallet-only is that only `wallet/index.blade.php` renders the element.
   Nothing was copied and nothing was branched: a `.got-account__head--lit`
   modifier would have put a page's name inside a page-neutral block, and a
   second copy of the glow rules is the two-systems problem this family was
   renamed to avoid (V-38). The home hero renders four layers and is therefore
   untouched by construction rather than by a rule that excludes it.
   `LivingBackgroundTest` asserts both halves of that: defined once, on the
   wallet, and ABSENT from the home page.

   WHERE IT LANDS, AND BOTH CANDIDATES WERE RENDERED BEFORE ONE WAS CHOSEN.

   The brief offered "opposite corner from the cyan" or "low behind the
   ledger". MEASURED: the second is not reachable from this container.
   `.got-livebg` lives inside `.got-account__head--lit`, the page HEADER —
   x130 y104, 1180x160 at 1440 — and the ledger is a sibling further down that
   no descendant of this wrapper can paint behind. Reaching it needs a second
   background container, which is structure and not appearance.

   🔴 SO THE FIRST CUT TOOK "THE OPPOSITE CORNER" LITERALLY, AND AN AMPLIFIED
   DIFFERENCE IMAGE SHOWED THAT PHRASE DOES NOT MEAN WHAT IT SOUNDS LIKE HERE.
   At `inset-inline-start:-10%; bottom:-30%` the ellipse measured x3..460 — its
   core sat TOP-START, over "My wallet" and its lead, which is the BLUE's own
   corner. The header is 160px tall and `padding-block-end` is a percentage of
   WIDTH, so every one of these ellipses is twice the height of the box it
   sits in and the vertical offsets barely separate them. **In this container
   only the inline axis reads.** The blue occupies roughly the start half and
   the cyan the end half, so "the corner opposite the cyan" IS the blue's
   corner, and that version deepened the imbalance Omar asked to answer
   instead of answering it.

   What ships is the second candidate, rendered beside the first: the core at
   x403..933, centre x668. Blue at the start · pink through the middle · cyan
   at the end, which is three lights separated on the axis that actually
   reads. Its core also stops short of the balance capsule (which begins near
   x777), so the one money figure on the page is not sitting in a pink wash.

   FAINT MEANS FAINT, AND THE ALPHA IS THE MEASUREMENT'S ANSWER RATHER THAN
   THE BRIEF'S OPENING GUESS. The brief said "start around .07-.09 and measure
   it: it must read as warmth at the edge of the eye". Measured at the glow's
   own centre, clear of every text box, on the composited pixels:

       alpha   dark delta R/G/B      light delta R/G/B
       .08         +4 / +2 / +2         -1 / -4 / -2
       .10         +6 / +2 / +4         -2 / -5 / -3
       .12         +7 / +3 / +5         -2 / -6 / -3
       .14         +8 / +3 / +5         -2 / -7 / -4
       .16         +9 / +4 / +6         -2 / -8 / -4

   .08 came out at +4/+2/+2, which is under the threshold at which it reads as
   anything; .16 would equal the cyan, which the brief forbids outright. .12
   is where the warmth appears while staying visibly under both siblings, and
   in every row the RED channel leads by the margin `#FC82D1`'s own hue
   predicts — so it is the pink and not noise. Control points away from the
   glow measured an exact 0/0/0.

   The light theme barely moves at any alpha because a pale ground swallows a
   translucent wash; `#C2298C` there is the darker token, and the delta is a
   warm grey rather than a pink. That is the correct outcome and not a bug in
   the token — a light page is not a dark page with different numbers.

   🔴 AND THE PEAK OF A WHOLE FRAME IS NOT THIS NUMBER. A frame-wide diff
   peaks at 63-91 on the light theme, and every one of those pixels is a
   GLYPH EDGE: removing an element repaints the text and subpixel
   anti-aliasing lands a hair differently. A background layer is measured on
   its own smooth field, away from type.

   FAINT MEANS FAINT: .12 against the blue's .22 and the cyan's .16, smaller
   than both so it reads as warmth at the edge of the eye. It was RAISED FROM
   .08 after the measurement above — .08 moved the composited pixel by 4 units
   of 255, which is under the threshold at which it reads as anything, and the
   table is the record of how .12 was chosen rather than liked.

   It is also the only one of the three whose stops are measured on BOTH
   themes, because pink on a light ground is the case a dark-only eye does not
   check.

   🔴 THIS PARAGRAPH SAID `.08` FOR ONE COMMIT AFTER THE RULE BELOW SAID `.12`.
   It was the pre-correction draft, left standing when the value moved — a
   justification that had become false, sitting six lines under the table that
   refutes it, in the one place the next round would look for the agreed
   number. A number that changes after measurement changes in EVERY sentence
   of the file that names it.

   Its period is 43s — not 26 and not 34. The hero's own docblock gives the
   reason for two: "so the light behind the words never visibly repeats". A
   third that copied either would put two of the three permanently in phase. */
.got-livebg__glow--c{
  inline-size:44%;padding-block-end:30%;inset-inline-start:24%;bottom:-64%;
  background:radial-gradient(circle,rgba(var(--accent-secondary-rgb),.12),transparent 68%);
}
/* The dot field. `--wash-rgb` is white on the dark palette and the light
   theme's own ink on the light one, which is exactly this layer's polarity:
   the reference states it as two hard-coded colours in two theme blocks, and
   one theme-following token says the same thing once. Masked radially so it
   fades out at the edges instead of ending on a line. */
.got-livebg__dots{
  position:absolute;inset:0;opacity:.5;
  background-image:radial-gradient(rgba(var(--wash-rgb),.055) 1px,transparent 1px);
  background-size:26px 26px;
  -webkit-mask-image:radial-gradient(120% 80% at 50% 20%,#000 30%,transparent 78%);
  mask-image:radial-gradient(120% 80% at 50% 20%,#000 30%,transparent 78%);
}
/* One band of light crossing the section. `translateX()` has no logical form,
   so the distance is a custom property the `[dir]` rule flips — the same
   mechanism `--gt-sweep-to` uses on the catalogue tile. */
.got-livebg__band{
  position:absolute;top:0;bottom:0;inline-size:38%;inset-inline-start:-40%;
  background:linear-gradient(100deg,transparent,rgba(var(--accent-rgb),.07) 50%,transparent);
  will-change:transform;
  --gt-livebg-band-to:370%;
}
[dir="rtl"] .got-livebg__band{--gt-livebg-band-to:-370%}
/* The hero dissolves into the page instead of ending on an edge. `to bottom`
   is the block axis, which is the same in both directions and has no logical
   spelling to prefer. */
.got-livebg__fade{
  position:absolute;inset-inline:0;bottom:0;block-size:96px;
  background:linear-gradient(to bottom,transparent,var(--bg));
}

/* -------------------------------------------------- 2 · THE COMPOSITION
   The container is the page's, unchanged; the 880px measure is inside it. The
   `z-index` here is not decoration: it puts the words in a stacking context
   above `.got-livebg`, which is what lets the accent's glow sit at `z-index:-1`
   behind its own words without falling behind the whole layer stack. */
.hero .container{position:relative;z-index:1}
.hero__inner{
  max-inline-size:55rem;margin-inline:auto;text-align:center;
  display:flex;flex-direction:column;align-items:center;
}
/* 🔴 `.hero__eyebrow` WAS HERE AND IS DELETED — Omar, 23 Aug. It was the
   system's micro-label in a chip, carrying "Boost today. Dominate tomorrow." —
   which is the wordmark's own strapline, set into the brand image in the
   header of every page. His decision: repetition that close is redundancy,
   not emphasis, so the element, the key and THE HEIGHT all go.

   THE HEIGHT IS THE PART A DELETION GETS WRONG. `.hero__inner` is a flex
   column with NO `gap`: every row's air is its own `margin-block-start`, and
   the headline's `--gt-space-5` was the gap BETWEEN THE CHIP AND THE HEADLINE.
   Left in place with the chip gone it would have become 16px of nothing at the
   top of the column — a removed child that leaves its gap behind has not been
   removed, it has been hidden. It is deleted with the chip, and the section's
   own `padding-block` is what sets the headline off the header again.

   Measured on the rendered page, entrance settled, dark, both languages, by
   stashing this change and re-running the same instrument on the same tree —
   and the drop is the chip's own box plus exactly that margin, nothing else:

                        1920 / 1536 / 1280 / 1100        390
     hero height        447.86 -> 398.67  (-49.19)   455.81 -> 406.63  (-49.18)
     "Choose your game" 520.86 -> 471.67  (-49.19)   516.81 -> 467.63  (-49.18)
     first card top     564.05 -> 514.86  (-49.19)   580.75 -> 531.56  (-49.19)

   The chip measured 33.19 tall and the margin is 16, which is the 49.19 — so
   nothing is left reserving space for it, which was the question. /ar is
   byte-identical to /en at every width, before and after. */
/* NO TRACKING ON THE HEADLINE, and the reference asks for -.028em. CLAUDE.md's
   standing decision (Omar, 20 Aug) is no negative tracking before launch, and
   the measurement behind it is that one value cannot serve both scripts: the
   same declaration moves a Latin string 40% and an Arabic one 4%, because
   Chrome tracks at non-joining boundaries only. `--gt-leading-display` is new
   and is the one number this rule adds — see system.css for its derivation. */
.hero h1{
  font-size:var(--gt-text-display);font-weight:var(--gt-weight-heavy);
  line-height:var(--gt-leading-display);
  max-inline-size:18ch;text-wrap:balance;
}
/* 🔴 THE WORDMARK'S LEAN REACHES THE PAGE'S OWN HEADINGS — V-02, 22 Aug.

   `skewX(-5deg)` is the logo's gesture and until that round it was applied to
   ONE element on the whole site: the catalogue tile's title. That is the
   audit's V-1 finding, and it is why the tiles feel like GameOnTime and the
   pages feel like a dark admin template. It costs one rule.

   🔴 IT IS SCOPED TO ENGLISH BY `[lang="en"]`, AND THAT IS NOT A STYLE CHOICE.
   The tile decides per-element with `Locale::directionOfText`, because a game's
   name is the ADMIN'S OWN WORDS and can be Arabic on an English page. These
   headings are TRANSLATED STRINGS: the language of the page IS the question, so
   the page's `lang` answers it. Arabic script joins, and skewing it is the
   distortion this project's own direction forbids by name — "Arabic typography
   is not distorted: no lean, no tracking games." The rule is absent on /ar and
   an absence cannot be got wrong.

   MEASURED BEFORE SHIPPING, because a skew moves glyphs sideways by
   `tan(5deg) x line-height` and a heading that leans off its container is worse
   than one that does not lean: at the display step the shift is ~4.9px at the
   top of the line, `transform-origin` is the box's centre so it is half that at
   each edge, and every one of these headings sits inside a container with at
   least a 20px gutter.

   🔴 `.got-index__title` JOINED THE LIST IN V-06 BATCH 5, AND ITS ABSENCE WAS
   A SILENT NARROWING RATHER THAN A DECISION. Batch 4 minted that class for
   `/games`, and Batch 5 gives the homepage's catalogue band the same class —
   so without this line the homepage would have carried ONE leaning heading
   (the store's, still `.section-head h2`) and one not, four hundred pixels
   apart, and `/games` would have been the one page in the product whose
   heading did not lean. Re-measured on the rendered page this round with the
   entrance finished, at 390 and 1536, in both languages, for all three: NOTHING
   CROSSES ITS CONTAINER'S INLINE-START. The tightest is the catalogue band at
   390, whose leaned edge sits 14.8px inside the container's; the hero headline
   at 390 is 16.6 and the store heading 18.5, each 3.4px in from the 20px gutter
   they would occupy unskewed. On /ar all three read `transform: none`, which is
   the `[lang="en"]` scope doing its job.

   `display:inline-block` on the two INLINE-level ones is not decoration: a
   transform does not apply to a non-replaced inline box at all, so the tile's
   own title carries it only because the component sets `display:block`. */
[lang="en"] .hero h1,
[lang="en"] .section-head h2,
[lang="en"] .got-index__title,
[lang="en"] .got-cat__title{
  transform:skewX(-5deg);
}
/* The accent words. A `<span>` and not the reference's `<em>`: `em` is
   emphasis, and a screen reader stressing half a headline for a colour change
   is the markup claiming something the design is not saying. */
.hero__accent{position:relative;color:var(--accent)}
/* The pulse behind the accent is its OWN LAYER, never the text — animating a
   colour or an opacity on type is what makes a page feel like a boosting site,
   and it is also unreadable while it moves. `z-index:-1` resolves inside
   `.hero .container`'s stacking context (see above), so it sits over the four
   depth layers and under every word. */
.hero__accent::before{
  content:"";position:absolute;inset:-18% -6%;z-index:-1;pointer-events:none;
  border-radius:40px;opacity:.42;
  background:radial-gradient(60% 70% at 50% 55%,rgba(var(--accent-rgb),.20),transparent 72%);
}
/* 16px on a 58ch measure — the reference's own numbers, and both are steps
   this system already has (`--gt-text-md` is 16 and is the only size in the
   scale that is the body size). It was `--gt-text-lg` (18) on a 60ch measure
   until this batch, which is a card heading's size used as prose. */
.hero p{
  margin-block-start:var(--gt-space-4);
  color:var(--muted);font-size:var(--gt-text-md);
  line-height:var(--gt-leading-normal);max-inline-size:58ch;
}

/* 🔴 THE ACTION IS ITS OWN CONTROL AND NOT `.got-btn--primary`, WHICH IS A
   DECISION AND NOT A DRIFT.

   The reference's CTA differs from the system's primary button in its fill (a
   gradient), its ink, its shadow, its padding, its hover and its sweep. Wearing
   `.got-btn got-btn--primary` and overriding six of that component's seven
   decisions from site.css would be a page silently repainting the system —
   "CSS loaded later wins on equal specificity, and losing is silent" — which is
   worse than a second control, because the next reader would believe the hero
   was using the system button and it would not be.

   So it BORROWS THROUGH THE TOKENS instead, which is this project's own line
   between "through the system" and "in the system": the tap floor, the radius,
   the type step, the weight, THE WHOLE TRANSITION, and — the part that
   matters most — THE WHOLE FOCUS RING, verbatim from `--gt-ring-*`. That ring
   is the two-tone one: a page-coloured band held by `box-shadow` between the
   control and a 2px accent outline at `outline-offset`. The reference asks for
   `outline:3px solid var(--cyan)` with no band, and this codebase has already
   measured that at 1.00:1 on an accent-filled control — a ring the same colour
   as the thing it surrounds. The band is why the system's ring may sit on this
   gradient at all.

   🔴 THE TRANSITION IS THE TOKEN AND NOT A LIST WRITTEN OUT AGAIN. It was
   `transform var(--gt-duration-base) …, box-shadow var(--gt-duration-base) …`,
   which borrowed the token's VALUES and skipped the token itself — and that is
   the exact thing `--gt-transition-control`'s own comment forbids: "a component
   says `transition: var(--gt-transition-control)` rather than restating the
   property list." Measured before and after on the rendered page at 1536, read
   off `getComputedStyle` of the real button: it hovered at 200ms/200ms where
   `.got-btn` and every other control on the page hover at 80ms transform and
   140ms box-shadow, so the hero's own action was 2.5x slower than its
   neighbours for no stated reason. Now measured at `0.14s, 0.14s, 0.14s,
   0.14s, 0.08s` over `background-color, border-color, color, box-shadow,
   transform` — read off the rendered button, and read off `.got-btn` on the
   same page in the same breath, where it is the same five numbers.

   THE TWO PSEUDO-ELEMENTS ARE NOT IN THE TOKEN AND MUST NOT BE. `::before` is
   the light crossing the button once, at `--gt-duration-sweep` (measured 0.72s
   here) — a one-shot sweep and not control feedback; `::after` is the arrow's
   nudge at `--gt-duration-base`. Both are declared on the pseudo-element that
   owns them, which is where a component's own gestures belong; the token is for
   the CONTROL's hover and press. Re-measured after the swap, both languages:
   the lift is still exactly -2px, the shadow still deepens, the sweep still
   crosses (+268.4px on /, -209.5px on /ar, mirrored by the custom property) and
   the arrow still nudges +3 / -3.

   THE GRADIENT NEEDS NO `[dir]` RULE, AND THE MECHANISM IS NOT REFLECTION —
   THE FIRST CUT OF THIS COMMENT STATED ONE IT HAD NOT MEASURED. It said "the
   RTL form (240deg) is the LTR form reflected". There is no RTL form: a
   gradient angle is physical and `direction` does not touch it, so /ar paints
   the 120deg fill /en paints, to the byte. Measured 22 Aug on a fixed 200x60
   control carrying this exact declaration, on / and /ar at 1536, dsf 1:

     /en  TL 78,190,255  TR 91,196,255  BL 91,197,255  BR 79,190,255
     /ar  TL 78,190,255  TR 91,196,255  BL 91,197,255  BR 79,190,255

   Identical, not mirrored. What the palindromic stop list actually buys is
   invariance under REVERSAL (120deg reads as 300deg), i.e. 180deg ROTATIONAL
   symmetry — TL matches BR and TR matches BL above, within 1/255 — so the fill
   reads the same from either end of the page. It is NOT reflection-symmetric:
   TL and TR differ by 13 in the red channel. The reference puts the stop at
   60%, which would have broken that rotational symmetry and needed a rule. The
   sweep and the arrow DO move sideways, and `translateX` has no logical form,
   so both flip through a custom property.

   INK, NOT `--gt-ink-on-accent`. That token is `var(--bg)`, which follows the
   theme — correct on `.got-btn--primary`, whose fill follows the theme too.
   This fill does NOT: `--sky` and `--cyan` are artwork colours the light block
   deliberately never overrides. So its ink is `--gt-on-accent-ink`, the
   on-artwork family, which the light block never names either.

   PIXEL-SAMPLED, NOT DERIVED, and in BOTH schemes because that is the claim:
   screenshotted at 1536, the glyph core reads rgb(13,15,23) on a fill of
   rgb(122,214,255) — 11.74:1 — and the two readings are IDENTICAL in dark and
   light, which is what "this control does not follow the theme" looks like from
   the outside. (The gradient's darker end, `--sky`, computes at 9.08:1 with the
   same ink; that one is arithmetic, and it is stated as arithmetic.) */
.hero__cta{
  position:relative;overflow:hidden;
  display:inline-flex;align-items:center;justify-content:center;
  gap:var(--gt-space-3);
  margin-block-start:var(--gt-space-7);
  min-block-size:var(--gt-tap-min);
  padding-block:var(--gt-space-4);padding-inline:var(--gt-space-7);
  border-radius:var(--gt-radius-md);
  font-family:var(--gt-family);
  font-size:var(--gt-text-sm);font-weight:var(--gt-weight-bold);
  line-height:var(--gt-leading-snug);
  color:var(--gt-on-accent-ink);
  background:linear-gradient(120deg,var(--sky),var(--cyan) 50%,var(--sky));
  box-shadow:0 10px 26px -12px rgba(var(--blue-rgb),.65),
             inset 0 1px 0 rgba(255,255,255,.35);
  transition:var(--gt-transition-control);
  --gt-hero-sweep-to:420%;
  --gt-hero-arrow-nudge:3px;
}
[dir="rtl"] .hero__cta{--gt-hero-sweep-to:-420%;--gt-hero-arrow-nudge:-3px}
/* The light band that crosses the button once on hover. `::before`, because
   `::after` is the arrow. */
.hero__cta::before{
  content:"";position:absolute;top:-40%;bottom:-40%;inline-size:34%;
  inset-inline-start:-45%;pointer-events:none;
  background:linear-gradient(100deg,transparent,rgba(255,255,255,.45),transparent);
  transform:translateX(0);
  transition:transform var(--gt-duration-sweep) var(--gt-ease-standard);
}
/* The arrow is DRAWN, never typed: U+2192 is not Bidi_Mirrored, so a glyph in
   the markup would point back into the page on /ar (BUG-119). */
.hero__cta::after{
  content:"\2192";display:inline-block;
  transition:transform var(--gt-duration-base) var(--gt-ease-standard);
}
[dir="rtl"] .hero__cta::after{content:"\2190"}
.hero__cta:hover{
  transform:translateY(-2px);
  box-shadow:0 18px 38px -14px rgba(var(--blue-rgb),.8),
             inset 0 1px 0 rgba(255,255,255,.4);
}
.hero__cta:hover::before{transform:translateX(var(--gt-hero-sweep-to))}
.hero__cta:hover::after{transform:translateX(var(--gt-hero-arrow-nudge))}
/* The ring stays IN ADDITION to everything hover does — it has been traded for
   a hover reward four times in this project. The rest shadow is kept behind
   the band so a focused button does not lose its own body. */
.hero__cta:focus-visible{
  outline:var(--gt-ring-width) solid var(--gt-ring-color);
  outline-offset:var(--gt-ring-gap);
  box-shadow:var(--gt-ring-shadow),
             0 10px 26px -12px rgba(var(--blue-rgb),.65),
             inset 0 1px 0 rgba(255,255,255,.35);
}
/* V-20 B7 (28 Aug): every `.got-btn` kind presses by `--gt-press-shift`; this
   — the biggest button on the site — was the one button-shaped control with no
   `:active` at all (measured: pressed computed styles were byte-identical to
   hovered, transform -2px and the raised throw). Same press as the system's
   buttons: the shift down, and the throw returns to its RESTING value so the
   control does not stay lifted while it is being pushed in (the
   `.got-btn:active` lesson — the shadow goes down with the button; the values
   restate the rest rule above, which this legacy file owns). LAST of this
   component's states on purpose, as `.got-btn:active` is in system.css: every
   selector here is (0,2,0), source order decides, and a pressed button is the
   hovered — sometimes focused — one. */
.hero__cta:active{
  transform:translateY(var(--gt-press-shift));
  box-shadow:0 10px 26px -12px rgba(var(--blue-rgb),.65),
             inset 0 1px 0 rgba(255,255,255,.35);
}
@media (prefers-reduced-motion:reduce){
  .hero__cta:hover{transform:none}
  .hero__cta:hover::before{transform:translateX(0)}
  .hero__cta:hover::after{transform:none}
  /* The press keeps its colour change nowhere (it has none) and loses its
     movement, exactly as the hover above does. */
  .hero__cta:active{transform:none}
}
/* A hairline that fades at both ends, so it is a breath and not a divider.
   Symmetric, therefore direction-agnostic. */
.hero__rule{
  margin-block-start:var(--gt-space-7);
  inline-size:min(26.25rem,70%);block-size:1px;
  background:linear-gradient(to right,transparent,var(--line) 22%,var(--line) 78%,transparent);
}
/* ------------------------- THE ACCENT RAILS — V-13 Batch 3, 24 Aug 2026
   Omar approved B2 from 04_Brand/design-studies/hero-accent-rails.html:
   standard pace (7s), under the CTA, pink stronger (.8). The single rule
   becomes two rails in the same slot — same measure, same margin, still one
   flex child, so the entrance stagger's indexing does not move.

   Each rail's hairline is a ::before LAYER rather than a background, so the
   echo can be literally "the same hairline at half strength" — opacity .5 on
   the layer, no second colour, theme-correct by construction.

   THE MASK IS THE CLIP. `overflow:hidden` would cut the traveller on a
   vertical edge; the mask fades it out on the same curve the hairline itself
   fades on. Mask-clip is the border box, so a segment translated off the
   rail — including the base state below — paints nothing at all. */
.hero__rule--rails{block-size:auto;background:none;display:grid;gap:4px}
.hero__rail{
  position:relative;block-size:1px;
  -webkit-mask-image:linear-gradient(to right,transparent,#000 14%,#000 86%,transparent);
  mask-image:linear-gradient(to right,transparent,#000 14%,#000 86%,transparent);
}
.hero__rail::before{
  content:"";position:absolute;inset:0;
  background:linear-gradient(to right,transparent,var(--line) 22%,var(--line) 78%,transparent);
}
/* The echo must not weigh as much as the thing it echoes. */
.hero__rail--echo::before{opacity:.5}
/* The traveller. `translateX` has no logical form, so the distances are
   custom properties the [dir] rule flips — the same mechanism as
   --gt-livebg-band-to above. The BASE state is off-rail (and therefore
   invisible under the mask): a reduced-motion visitor keeps both hairlines
   and never sees a stranded segment, and the pink's 0.42s start-up delay
   parks it off-rail rather than at the rail's start. NO fill mode — a
   forwards/both fill would own `transform` forever, which is the defect the
   motion block's own docblock measures below.

   The bright cores are color-mix over WHITE (not a brand colour, and the
   palette guard excludes it by argument) — the mock's #DFF3FF/#FFD9F0
   without minting two literals no test could see. First color-mix in this
   codebase: a browser without it drops the declaration and the rails
   degrade to plain hairlines, which is the safe direction for decoration. */
.hero__railseg{
  position:absolute;inset-block:0;inset-inline-start:0;
  inline-size:34%;border-radius:1px;
  will-change:transform;
  --gt-rail-from:-115%;--gt-rail-to:295%;
  transform:translateX(var(--gt-rail-from));
}
[dir="rtl"] .hero__railseg{--gt-rail-from:115%;--gt-rail-to:-295%}
.hero__railseg--blue{
  background:linear-gradient(90deg,transparent,var(--blue) 30%,var(--accent) 52%,color-mix(in srgb,var(--accent) 35%,#FFFFFF) 58%,var(--accent) 66%,transparent);
}
.hero__railseg--pink{
  background:linear-gradient(90deg,transparent,var(--accent-secondary) 48%,color-mix(in srgb,var(--accent-secondary) 30%,#FFFFFF) 56%,var(--accent-secondary) 64%,transparent);
  opacity:.8;
}
/* A gradient's angle is physical and these two are asymmetric (the tail
   leads the stops), so the Arabic page gets the stops mirrored — the
   background-position lesson, one property over. */
[dir="rtl"] .hero__railseg--blue{
  background:linear-gradient(90deg,transparent,var(--accent) 34%,color-mix(in srgb,var(--accent) 35%,#FFFFFF) 42%,var(--accent) 48%,var(--blue) 70%,transparent);
}
[dir="rtl"] .hero__railseg--pink{
  background:linear-gradient(90deg,transparent,var(--accent-secondary) 36%,color-mix(in srgb,var(--accent-secondary) 30%,#FFFFFF) 44%,var(--accent-secondary) 52%,transparent);
}
/* The four facts are the SYSTEM's facts row (`<x-facts>`), and this is a
   page-scoped skin over it: centred, wider apart, and the dot gains the soft
   ring the reference draws. Page-scoped and not a redefinition — the selector
   carries a class the system does not own, which is the distinction
   `SiteTokensTest` draws between an override and a second answer. */
.hero__trust{margin-block-start:var(--gt-space-5);justify-content:center;gap:var(--gt-space-3) var(--gt-space-8)}
.hero__trust .got-facts__item::before{box-shadow:0 0 0 3px rgba(var(--success-rgb),.14)}

/* -------------------------------------------------------------- 3 · MOTION

   TRANSFORM AND OPACITY ONLY, nothing under five seconds on a loop, no
   particles, no parallax. The two glows drift out of phase (26s against 34s)
   so the light behind the words never visibly repeats.

   🔴 EVERY ANIMATION IN THIS BLOCK IS DEFINED INSIDE
   `prefers-reduced-motion: no-preference`, AND THE ELEMENTS ARE FULLY VISIBLE
   IN THEIR BASE STATE. Authoring `opacity:0` on the entrance elements and
   revealing them with `rise` would hand a reduced-motion visitor a permanently
   invisible hero — the whole page's offer, gone, in the one setting nobody who
   ships it is using. The system's reduced-motion block rewrites the DURATION
   tokens to 1ms, and that mechanism cannot be used here for the same reason it
   is not used on the loading ring: these four are INFINITE, and an infinite
   animation at 1ms is a strobe. They are switched off where they are defined,
   which is the only place that works. */
@keyframes got-livebg-drift-a{
  0%,100%{transform:translate3d(-2%,-1%,0) scale(1)}
  50%{transform:translate3d(3%,2%,0) scale(1.08)}
}
@keyframes got-livebg-drift-b{
  0%,100%{transform:translate3d(2%,1%,0) scale(1.05)}
  50%{transform:translate3d(-3%,-2%,0) scale(1)}
}
/* The third drift. Its own shape as well as its own period — a scaled copy of
   either sibling would trace the same path more slowly, which is a repeat the
   eye finds faster than a phase one. */
@keyframes got-livebg-drift-c{
  0%,100%{transform:translate3d(-1%,2%,0) scale(1.02)}
  50%{transform:translate3d(4%,-2%,0) scale(1.1)}
}
@keyframes got-livebg-band{
  0%{transform:translateX(0)}
  100%{transform:translateX(var(--gt-livebg-band-to))}
}
@keyframes got-hero-lume{0%,100%{opacity:.42}50%{opacity:1}}
/* The rails' travel. One keyframe pair for both segments — the custom
   properties resolve per element, and [dir="rtl"] flips them, so the same
   animation runs right-to-left on /ar (the .got-livebg__band mechanism). */
@keyframes got-hero-rail{
  from{transform:translateX(var(--gt-rail-from))}
  to{transform:translateX(var(--gt-rail-to))}
}
/* 🔴 THE ENTRANCE MOVES `translate`, NOT `transform`, AND IT FILLS
   `backwards`, NOT `both`. TWO DEFECTS, ONE MECHANISM, AND FIXING ONLY THE
   FIRST MOVED IT RATHER THAN CLOSING IT.

   THE MECHANISM. A forwards-filling animation keeps its final keyframe applied
   after it ends, and an animation's value outranks every declaration in the
   cascade short of `!important`. So a `to` keyframe does not RESTORE the
   property it names, it OWNS it, permanently, for as long as the element wears
   the animation.

   DEFECT ONE, WHICH THIS BATCH SHIPPED FOR TWENTY MINUTES: the reference
   animates `transform` with `transform:none` as the `to`. Measured on the
   rendered page at 1536, 1.5s after load, against a control heading outside the
   animated column:

     .hero h1              matrix(1,0,0,1,0,0)          the wordmark's LEAN, gone
     #store h2 (control)   matrix(1,0,-0.0874887,1,0,0) the same skew, still there
     .hero__cta on hover   matrix(1,0,0,1,0,0)          the -2px LIFT, dead

   Two features silently cancelled by a third, in a hero that looked perfect in
   every screenshot — the lean is 4.9px at the top of a 56px line and nobody
   finds that by eye. `translate` is one of the INDEPENDENT transform
   properties: it composes with `transform` instead of replacing it, so
   `skewX(-5deg)` and `translateY(-2px)` both survive — during the entrance as
   well as after it, which is why the property change is kept and not merely
   traded for the fill-mode change below.

   🔴 DEFECT TWO, FOUND BY A VERIFIER AND NOT BY THE FIX: with `both` still on
   it, THE SAME TRAP SIMPLY MOVED TO `translate`. A verifier put the identical
   declaration at identical specificity on a subject and on a control:

     CONTROL  #store h2  translate:0 30px  ->  computed "0px 30px"   took it
     SUBJECT  .hero h1   translate:0 30px  ->  computed "0px"        SWALLOWED

   Nothing declares `translate` on these ten elements today, so it cost nothing
   — but the docblock explained the `transform` trap at length while quietly
   standing on the same one, which is how a fix reaches exactly as far as the
   instrument that found it was aimed.

   `backwards` IS WHAT AN ENTRANCE ACTUALLY NEEDS and `both` is that plus a
   permanent claim on the property. Backwards hides the element during its
   delay, which is the whole job; forwards holds a final state that is
   BYTE-IDENTICAL to the base state here (`opacity:1`, no `translate`), so it
   buys nothing and takes the property out of the cascade forever. Re-measured
   this round on the rendered page at 1536, both languages, entrance finished:

                        settled .hero    #index title   first card   .hero h1 top
     `both`   (was)        447.86           520.86        564.05        170.19
     `backwards` (now)     447.86           520.86        564.05        170.19

   IDENTICAL — so the base state does NOT need an offset the fill was
   supplying, which was the open question. The verifier's "h1 top 200.19" under
   `backwards` was its own probe's `translate:0 30px` being HONOURED: that 30px
   is the proof the property came back, not a layout shift. With the fill
   changed, the subject reads `0px 30px` and matches the control. Sampled
   frame by frame across the entrance, the last fact still starts at opacity
   0.04 inside its 0.52s delay and every row settles at `1 / none` with no jump
   at the hand-over.

   Still transform-and-opacity-only: read `document.getAnimations()` on the page
   and every entrance reports `['translate','opacity']`. */
@keyframes got-hero-rise{
  from{opacity:0;translate:0 14px}
  to{opacity:1;translate:none}
}
@media (prefers-reduced-motion:no-preference){
  .got-livebg__glow--a{animation:got-livebg-drift-a 26s ease-in-out infinite}
  .got-livebg__glow--b{animation:got-livebg-drift-b 34s ease-in-out infinite}
  /* 26s · 34s · 43s. Infinite, so it is DECLARED here and absent under reduce,
     with the layer fully visible in its base state above — the family's shape,
     and inverting it into "animate always, cancel under reduce" is what would
     hand a reduced-motion visitor either a strobe or an empty box. */
  .got-livebg__glow--c{animation:got-livebg-drift-c 43s ease-in-out infinite}
  .got-livebg__band{animation:got-livebg-band 19s linear infinite}
  .hero__accent::before{animation:got-hero-lume 7.5s ease-in-out infinite}
  /* The rails (V-13 Batch 3). ONE duration and ONE easing for both, and the
     pink FOLLOWS by a fixed positive delay — two different durations would
     drift in and out of phase. Infinite, so they live here and are absent
     under reduce, where the base state is both hairlines fully visible and
     both travellers parked off-rail. NO fill mode, deliberately. */
  .hero__railseg--blue{animation:got-hero-rail 7s cubic-bezier(.45,0,.25,1) infinite}
  .hero__railseg--pink{animation:got-hero-rail 7s cubic-bezier(.45,0,.25,1) infinite;animation-delay:.42s}
  /* The entrance, staggered down the column. It reaches by POSITION and not by
     a list of class names, so a seventh row added tomorrow is covered.
     `backwards`, NEVER `both` — a forwards fill takes `translate` out of the
     cascade permanently, which is the trap the docblock above measures, and
     HomepageTest holds this word.

     🔴 EVERY DELAY MOVED UP ONE STEP WHEN THE EYEBROW WENT (23 Aug), AND THAT
     IS THE COST OF REACHING BY POSITION. `nth-child` indexes the column, so
     deleting the FIRST child does not remove a step — it hands each remaining
     row the delay of the row above it, and the headline would silently have
     inherited the chip's 0 while the facts row kept a .34 written for a column
     one longer. The sequence is unchanged in shape: five rows .07 apart
     starting at 0, then the last three facts continuing the same .06 beat.

     READ OFF THE RENDERED PAGE AND NOT OUT OF THIS FILE, at 1536, and it takes
     TWO READINGS because a `backwards` fill leaves the timeline the moment it
     finishes: `document.getAnimations()` sampled EARLY gives 0 / 70 / 140 /
     210 / 280 ms down the column and 340 / 400 / 460 for facts two to four,
     and `getComputedStyle().animationDelay` on the settled page agrees. At
     2.2s `getAnimations()` reports only the four ambient loops, which is what
     a finished entrance looks like and not a missing one.

     THE FIRST FACT TAKES NO DELAY OF ITS OWN — it never has. It is held back
     by the row it sits in (`.hero__trust`, .28 now, backwards), so its own 0
     is not a fifth row starting early; the base rule gives it the same .5s
     rise and the parent decides when the group appears. */
  .hero__inner>*{animation:got-hero-rise .62s var(--gt-ease-standard) backwards}
  .hero__inner>*:nth-child(2){animation-delay:.07s}
  .hero__inner>*:nth-child(3){animation-delay:.14s}
  .hero__inner>*:nth-child(4){animation-delay:.21s}
  .hero__inner>*:nth-child(5){animation-delay:.28s}
  .hero__trust .got-facts__item{animation:got-hero-rise .5s var(--gt-ease-standard) backwards}
  .hero__trust .got-facts__item:nth-child(2){animation-delay:.34s}
  .hero__trust .got-facts__item:nth-child(3){animation-delay:.40s}
  .hero__trust .got-facts__item:nth-child(4){animation-delay:.46s}
}
/* `.pill` and `.dot` — GONE 18 Aug with the catalogue batch: the game and
   cards pages' eta chip is `.got-facts` now. */


/* ---------- sections (rhythm as ONE token, 18 Aug) ----------
   A section carries padding-block-START only, so the gap between any two
   blocks is exactly one --gt-section-y and never two paddings summed (it was
   46+46 = 92 between grids and 98 from the hero's chips to the first title,
   none of it on the scale). The last section pads its end so the footer has
   the same air. Heads: title --gt-text-xl heavy, lead --gt-text-sm muted, on
   one row; the hierarchy between the hero and the sections is carried by
   position and weight, not by a bigger h2. */
.section{padding-block-start:var(--gt-section-y)}
.section:last-of-type{padding-block-end:var(--gt-section-y)}
.section-head{display:flex;align-items:end;justify-content:space-between;margin-block-end:var(--gt-space-7);gap:var(--gt-space-5);flex-wrap:wrap}
/* V-01, 20 Aug — THE SECTION HEAD MOVES UP A STEP, 22 → 28.
   B-5: the page read evenly grey because a SECTION head sat 4px above a
   CARD head (22 against the media tile's 18, both at weight 800), and 4px
   is not a register. Measured on the rendered page before and after: the
   distance is 10px now, and the homepage reads 56 / 28 / 18 / 16.
   It is safe to take the page-title step because `.section-head` renders
   on the HOMEPAGE AND NOWHERE ELSE (two uses, both in home.blade.php),
   and that page's h1 is the display clamp at 56 — so no screen in the
   product puts a 28px h2 beside a 28px h1. Check that before reusing the
   class. */
.section-head h2{font-size:var(--gt-text-2xl);font-weight:var(--gt-weight-heavy);line-height:var(--gt-leading-tight)}
.section-head p{color:var(--muted);font-size:var(--gt-text-sm);margin-block-start:var(--gt-space-1)}

/* ---------- game grid ---------- */
.grid{display:grid;gap:var(--gt-tile-gap)}
/* The home grid's tracks. The tiles themselves are the design system's media
   card (`.got-gamecard` in system.css — the hover-skill); the ten legacy
   `.game-card` / `.game-cover` / `.game-body` / `.game-meta` rules that used
   to follow this line were DELETED on 17 Aug when both home sections moved
   onto it, so the tile has one definition. This track rule stays here
   because it is the home page's LAYOUT and the home page is not migrated:
   a rule in pages.css would make it a page styled by both files.

   THE TRACK FLOOR IS 15rem (240px) AS OF V-06 — 14rem (224) from 17 Aug, then
   16.25rem (260) for the few hours V-05 Batch 2 stood. It came back down
   because the container changed KIND: V-05 held the shelf to a 1240 column and
   raised the floor so four cards filled it; V-06's container is fluid to 1680
   and the floor is the only thing deciding a count. The arithmetic it produces
   at all six of the round's widths is written out at the token, in system.css.

   THE SIZES IN THIS COMMENT WERE 276x368, THEN 295x531, AND ARE NEITHER NOW.
   MEASURED on the rendered page at 1536 on 22 Aug after this batch: five
   tracks, and the tile is 272x408 (2:3 — the card IS the artwork since V-06
   Batch 1-3, so its height is its width and a half and nothing inside it can
   grow it). A comment carrying the previous round's numbers beside the new
   rule would have read as a measurement of it. */
/* 🔴 SUPERSEDED BY THE BLOCK BELOW — V-05, 22 Aug. KEPT, NOT DELETED, because
   the argument in it was right about its own catalogue and is the reason the
   replacement exists; but it is the REVERTED decision and a 🔴 marker with no
   date on it advertises the wrong answer to whoever reads the file next.

   IT SAID: auto-FIT, not auto-FILL, and "it is the one place on the site that
   is". At THREE GAMES that was correct and measured — a four-track row drew
   three 270px posters and a 270px hole at the reading end, and auto-fit
   collapsed the empty track to give three tracks at 364px, the row exactly
   full.

   WHAT CHANGED IS THE CATALOGUE, NOT THE ARGUMENT. At seven games the row is
   full, there is no empty track to collapse, and the two keywords render
   identically (measured — see below). What auto-fill buys back is the case
   that produced this block in the first place: if the catalogue ever drops
   below the track count again, auto-fit inflates the survivors to 400px and
   auto-fill does not. The sentence "it is the one place on the site that is"
   is now false: no CUSTOMER surface uses auto-fit any more. Checked rather
   than asserted, and the check found one the claim would have been wrong
   about — `/design`'s specimen grid (pages.css) is still auto-fit ON PURPOSE,
   because a reference page showing one component must not leave a hole beside
   it. `.got-cat__grid` is auto-FILL and always was, for the mirror-image
   reason written at its own rule: a catalogue GROUP of one service keeps its
   column rather than stretching one card across the row. Three grids, three
   answers, each decided where it lives. */
/* 🔴 `auto-fill`, NOT `auto-fit` — AND THE FIRST VERSION OF THIS COMMENT GAVE
   A REASON THAT IS NOT TRUE AT THIS CATALOGUE SIZE. Kept, corrected, because
   the wrong reason is instructive.

   It said: with seven tiles the second row holds three, `auto-fit` would
   collapse the empty tracks, and those three would stretch and render LARGER
   than the four above them. MEASURED, both keywords, same page, same width —
   and the figures below were taken on V-05's 1240 CONTAINER, which V-06 Batch
   4 replaced. They are kept as the measurement that settled the KEYWORD, not
   as a description of what this grid renders today:

     1536, 7 tiles   auto-fill 4x295, rows [295x4][295x3]   IDENTICAL
                     auto-fit  4x295, rows [295x4][295x3]
     1920, 7 tiles   both 5x296                             IDENTICAL
     1536, 3 tiles   auto-fill 4 tracks, row [295x3]
                     auto-fit  3 tracks, row [400x3]        DIFFERENT

   `auto-fit` collapses an empty TRACK — a column with no item in it in ANY
   row — not an empty CELL in the last row. With seven items across four
   columns every column is occupied, so there is nothing to collapse and the
   two keywords are the same thing today.

   SO THE TRUE, NARROW CLAIM: `auto-fill` is insurance for the case where the
   catalogue holds FEWER items than the row has tracks. That is not
   hypothetical — it is exactly V-01's finding of 20 Aug, and the third line
   of the table above is it happening: drop to three games and `auto-fit`
   gives three 400px tiles, which is the "widening buys dead space and
   shrinks nothing, it just inflates" shape. `--gt-container-wide` was left
   applied to nothing for that reason, and its guard names the condition for
   a wider shelf as "four or more games". There are seven, so the shelf
   widens — and `auto-fill` is what keeps that true if the catalogue ever
   shrinks back.

   🔴 NO `gap` IS WRITTEN HERE, AND V-06 IS THE FIRST ROUND WHERE THAT COSTS
   SOMETHING RATHER THAN SAVING IT. The V-06 reference writes `gap:18px`;
   `.grid` gives this grid `--gt-tile-gap`, which is `--gt-space-6`, which is
   20. The 2px is a DELIBERATE divergence and there are four reasons, of which
   the measurement is the first: at all six of the round's widths the two gaps
   produce THE SAME TRACK COUNT, and the card differs by at most 2px — measured
   at 20: 247/272/281/248/350/358; the same arithmetic at 18:
   249/274/282/250/351/358.
   Second, 18 is not a step of the 4px spacing scale, and V-01's finding was
   that twenty-nine hand-picked sizes are what makes a surface read grey.
   Third, `--gt-tile-gap` is SHARED with `.got-cat__grid` — the service grid on
   a game page — and ContainerWidthTest derives `--gt-container-wide` from that
   grid's floor and this gap, so moving it re-derives a token about a different
   grid. Fourth, HomepageTest pins this rule as a SINGLE declaration and
   database/falsify.php anchors on its exact text, so a `gap` here would not be
   a second copy of a decided value — it would be a second copy in the one
   place two guards read byte for byte. */
.grid-games{grid-template-columns:repeat(auto-fill,minmax(var(--gt-tile-min),1fr))}
/* 🔴 THE PHONE'S HAND-WRITTEN TWO-COLUMN RULE IS DELETED (V-05 Batch 2), and
   the deletion is the fix rather than a simplification of it.

   It read `repeat(2, minmax(0, 1fr))` under 40em and it was a MEASURED
   decision on 22 Aug: with three games, two 169px posters per row gave a
   2,034px page against 2,046 for one-up, so two-up was the same length and
   put two games on screen at once. Both halves of that have changed. Omar's
   direction for this round is one column on mobile; and with SEVEN games a
   169px poster is not a poster, it is a thumbnail of a poster.

   What replaces it is nothing at all, and that is the point: the track count
   the direction asks for is the count the fluid grid already produces at
   every width, so there is no breakpoint here to fall out of step with the
   floor above it — which is what a hand-written column count always
   eventually does.

   🔴 THE FIGURES THAT STOOD HERE WERE V-05'S AND V-06 BATCH 4 RE-DERIVED
   THEM, because the container they were measured in is gone. They said 335
   of content at 390 and 706.9 at 768, both taken through `--gt-gutter` and a
   15px scrollbar. `.container--shelf` no longer reads `--gt-gutter` and the
   round's harness drives a Chrome with no scrollbar gutter, so MEASURED on
   the rendered page at 22 Aug: 358 of content at 390 (two tracks at the 240
   floor want 500, so ONE lands) and 720 at 768 (three want 760, so TWO land).

   AND THE BAND NOBODY LOOKS AT IS NAMED RATHER THAN LEFT, re-derived with
   them: the 1<->2 boundary is a 548 viewport, not 595 — two tracks want 500
   of content and the gutter under 1150 is 24 a side. BISECTED at one-pixel
   steps: one track at 547, two at 548. Just under it, at 547, the
   single column is 499px wide and the card is 749px TALL, which is taller
   than most windows that size. Nothing overflows and nothing clips, in either
   language; it is a look nobody has approved rather than a defect, and it
   stays filed as a gap with the numbers. A band measured and accepted and a
   band nobody ever measured look identical six weeks later.

   THE COST IS REAL AND IT IS STATED: one-up at 390 with seven games is a
   much longer page than two-up would be. It is measured in the round report
   rather than left to be discovered, and reverting it is this one rule
   coming back. */
/* `.arrow` — MOVED 18 Aug to pages.css (THE CATALOGUE), with the BUG-119
   note about why the glyph is drawn and not typed. */

/* ---------- service list — GONE 18 Aug (Batch 3): the tile is the system's
   `.got-card--interactive` with `.got-card__head` / `__lead` / `__foot`, the
   type tag is `.got-pill`, the grid is `.got-cat__grid` in pages.css. */

/* ---------- breadcrumb — GONE 18 Aug: `.got-crumb` in system.css, 44px
   links (BUG-242's ring went with it — the system's is on the link). */

/* ---------- configurator, price aside, empty state — GONE 18 Aug (Batch 3).
   `.cfg`, `.field`, `.qty`, `.opts`/`.opt`, `.buy`, `.total*`, `.buy__lines`
   are LAYOUT in pages.css THE CATALOGUE; the panel, the label, the input, the
   check, the buttons, the facts and the state are the system's. The two long
   notes that stood here — BUG-242's inward ring inside the clipping stepper
   group, and the `top:92px` sticky offset "hand-computed from a header height
   nothing declares" — describe rules that no longer exist: the group has no
   overflow:hidden so the ring is the system's, and the aside sticks at
   --gt-scroll-offset, the same line every anchored section clears. */
/* The footer (18 Aug): the section rhythm above it, the same air inside it,
   and its two links are 44px targets — the recipe .got-account__ref uses,
   equal negative block margin so the row keeps its height (GAP-099: they were
   96×22 and 80×22, on every page). */
.site-footer{border-top:1px solid var(--line);margin-top:var(--gt-section-y);padding:var(--gt-space-6) 0;color:var(--muted);font-size:var(--gt-text-xs)}
.foot{display:flex;justify-content:space-between;align-items:center;gap:var(--gt-space-5);flex-wrap:wrap}
/* The links wear 8px of inline padding, so the GROUP steps out by 8 and the
   first glyph sits on the container's edge like the © line beside it (the
   breadcrumb does the same per link; the footer did not — measured 19 Aug,
   glyphs at 28 against text at 20). Gap 8: what is left between two targets. */
.foot__links{display:flex;gap:var(--gt-space-3);flex-wrap:wrap;margin-inline:calc(-1 * var(--gt-space-3))}
.foot a{
  display:inline-flex;align-items:center;
  min-block-size:var(--gt-tap-min);padding-inline:var(--gt-space-3);
  margin-block:calc(-1 * var(--gt-space-3));border-radius:var(--gt-radius-sm);
  color:var(--muted);
}
.foot a:hover{color:var(--text);background:var(--gt-wash-soft)}

/* ============================================================
   Customer accounts — sign in, register, reset, account home
   ------------------------------------------------------------
   Deliberately on the site's own surface rather than a scaffold's
   look: this is the first screen a stranger sees before sending
   money, so it has to feel like the same company as the home page.
   Brand colours come from config/brand.php via --accent.
   ============================================================ */
.got-auth{ max-width:29.5rem; margin:0 auto; padding-inline:20px; }

/* The card is the system's `.got-card--raised` (Batch 4, 18 Aug) — "a single
   card that IS the page's content" — so the box rule went; the class stays
   for the centring below. Title at the page-title step, lead muted. */
.got-auth__title{ font-size:var(--gt-text-2xl); font-weight:var(--gt-weight-heavy); line-height:var(--gt-leading-tight); }
.got-auth__lead{ color:var(--muted); font-size:var(--gt-text-sm); line-height:var(--gt-leading-normal); margin-block-start:var(--gt-space-2); }

/* 🔴 `.got-auth__status` AND `.got-auth__errors` ARE GONE FROM THIS FILE.

   They are `.got-message--success` and `.got-message--error` now, aliased in
   system.css under their old names so the eight templates still saying them
   keep working unchanged. What they carried and what moved with them:

     · the logical-padding correction of 14 Aug (BUG-209) — a physical
       `padding:.7rem .9rem .7rem 1.6rem` on a box with a `border-inline-start`
       stranded the marker gutter on the END side in RTL, and the 5px list disc
       painted ON TOP of the 3px border at x=1205–1209 on /ar/cart. The system
       rule is `padding-inline: <start> <end>` for exactly that reason and says
       so;
     · `rgba(34,197,94,.12)` and `rgba(239,68,68,.12)`, which were `--green`
       and `--red` written out a second time in channel form — invisible to
       BrandPaletteTest, which only ever checked the three accent keys. They
       are `var(--gt-tint-success)` and `var(--gt-tint-danger)` now, built from
       `--success-rgb` / `--danger-rgb` off config/brand.php.

   The `margin-top` did NOT move. Spacing between a message and what precedes
   it belongs to the page, not to the message — a component that carries its
   own outer margin cannot be placed. Callers set it. */
/* The two ways out of a form — "Forgotten your password?" under it, "Create
   one" / "Sign in" beside the card — are 44px targets by the recipe (GAP-100:
   they were 18px tall): inline-flex, the tap floor, padding-inline with an
   equal negative block margin so the line keeps its rhythm. Both stand on a
   line of their own or at the end of one, so no prose is stretched. */
.got-auth__minor{ margin-block-start:var(--gt-space-4); font-size:var(--gt-text-xs); }
.got-auth__minor a, .got-auth__aside a{
  display:inline-flex; align-items:center;
  min-block-size:var(--gt-tap-min); padding-inline:var(--gt-space-2);
  margin-block:calc(-1 * var(--gt-space-3)); border-radius:var(--gt-radius-xs);
  color:var(--accent);
  transition:var(--gt-transition-control);
}
/* V-20 B7 (28 Aug): every other 44px inline link on the site answers hover
   (nav, footer, crumbs, order links — all wash); these five auth links
   (forgot-password, create-account, sign-in, and the two policy links) had
   the tap recipe and the ring and no hover answer at all. Same wash. */
.got-auth__minor a:hover, .got-auth__aside a:hover{ background:var(--gt-wash-soft); }
.got-auth__aside{ text-align:center; margin-block-start:var(--gt-space-5); font-size:var(--gt-text-xs); color:var(--muted); }

/* ---- forms ---- */
.got-form{ display:flex; flex-direction:column; gap:1rem; margin-top:1.5rem; }

/* 🔴 `.got-field`, `.got-btn` AND THEIR STATES ARE GONE FROM THIS FILE.
   They are components in system.css now. Two things they used to do are
   worth naming, because both were defects rather than decisions:

   · THE BUTTON HAD ONE HOVER FOR ALL OF ITS KINDS — `filter:brightness(1.06)`
     on `.got-btn`. On the primary that reads; on `.got-btn--quiet`, whose
     background is `transparent`, brightening nothing produces nothing, so the
     quiet button had NO HOVER STATE AT ALL and nobody had noticed. The system
     gives each kind a real one.
   · THE PRIMARY WAS A GRADIENT, `linear-gradient(90deg, --accent, --blue)`.
     A horizontal gradient does not mirror: under dir="rtl" the light end
     stayed on the left while every other directional thing on the page
     flipped, so the Arabic button was lit from the wrong side. It is a flat
     accent fill in the system, which is correct in both directions and is
     also what let the focus ring be measured against a single known colour.

   `.got-field input`'s focus was `box-shadow:0 0 0 3px rgba(accent,.22)` with
   `outline:none` — a ring drawn as a shadow, which vanishes in forced-colours
   mode, where `outline` survives. The system uses a real outline. */

/* `.got-check` MIGRATED to system.css. This rule was the sign-in form's
   "Remember me" row and it is the third private answer to the same question,
   after `.got-consent` and `.got-pay__gate` — three rows, three gaps, three
   font sizes, and a checkbox that measured 13x13 here and 16.8x44 on the
   registration form.

   `align-items:center` was the one real difference and it is deliberately
   NOT carried over: it centres the box against the WHOLE label, which is
   right for one line and wrong the moment the sentence wraps — which is what
   the consent row does. `flex-start` plus a box sized to the line box is
   correct for both, and it is why `--gt-check-size` is 18px and not a round
   number. Found by `test_nothing_the_system_owns_is_redefined_by_the_legacy_stylesheet`,
   which went red the moment the class became the system's: leaving this here
   would have meant site.css loading later and WINNING, with the component
   looking like it did not work for reasons nobody could find. */


.got-credit__facts .got-order__note{ margin-block-end:var(--gt-space-5); }
.got-credit__facts .got-order__note:last-child{ margin-block-end:0; }

/* ---- V-40: the top-up page's method ROW ----------------------------------

   🔴 THESE STAY IN THE LEGACY SHEET AND THAT IS THE OWNERSHIP RULE, NOT
   LAZINESS. They are page-context overrides of `.got-pay__method`, which
   site.css has owned since it was written. Moving them to system.css named
   `got-pay__method` and `got-pay__method-head` as SYSTEM-owned classes, and
   `SiteTokensTest` then — correctly — refused site.css's own long-standing
   rules for them as a legacy sheet redefining the system. One class cannot be
   owned by both files, and the row is not this round's to take.

   The compound is what beats `site.css:2868`'s `flex-direction:column`, which
   sits ~1400 lines below and wins on source order at equal specificity. It is
   a compound rather than a move for V-35's reason: a move is correct only
   until the next append. */
/* THE METHOD ROW'S MARK AND BADGE. The mark is DECORATION — the study renders
   no radio input either, and three of these four rows have no endpoint, so
   nothing here is submittable. The row's WORDS carry the meaning. */
.got-pay__method.got-credit__method {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--gt-space-4) var(--gt-space-5);
  /* 🔴 IT WRAPS, AND THE MEASUREMENT IS WHY. At 390 the row is the mark, the
     badge, the name and "Not available yet"; nowrap squeezed the name's box to
     27px against 37px of text and CLIPPED "PayPal" and "Skrill" on three rows
     — measured on the rendered page, in four views. The tag drops to its own
     line instead, which costs a row of height and loses no word. */
  flex-wrap: wrap;
}
.got-credit__method .got-pay__tag { flex: none; }
.got-credit__methodbody {
  flex: 1 1 auto;
  min-inline-size: 0;
  display: block;
}
.got-credit__method .got-pay__method-head {
  display: block;
  margin: 0;
}
.got-credit__methodsub {
  display: block;
  margin-block-start: var(--gt-space-1);
  font-size: var(--gt-text-xs);
  color: var(--gt-ink-muted);
}
.got-credit__radio {
  flex: none;
  inline-size: var(--gt-space-6);
  block-size: var(--gt-space-6);
  border: var(--gt-border-bar) solid var(--gt-line-strong);
  border-radius: var(--gt-radius-pill);
  display: grid;
  place-items: center;
}
.got-credit__method--on .got-credit__radio {
  border-color: var(--gt-accent);
}
.got-credit__method--on .got-credit__radio::after {
  content: "";
  inline-size: var(--gt-space-3);
  block-size: var(--gt-space-3);
  border-radius: var(--gt-radius-pill);
  background: var(--gt-accent);
}
.got-credit__badge {
  flex: none;
  display: grid;
  place-items: center;
  inline-size: var(--gt-space-10);
  block-size: var(--gt-space-8);
  border-radius: var(--gt-radius-md);
  background: var(--gt-wash-strong);
  color: var(--gt-ink-muted);
  font-size: var(--gt-text-3xs);
  font-weight: var(--gt-weight-bold);
  letter-spacing: var(--gt-tracking-label);
}
.got-credit__method--on .got-credit__badge {
  background: var(--gt-tint-success);
  color: var(--gt-success);
}
.got-credit__method--on {
  border-color: var(--gt-accent);
  background: var(--gt-tint-accent);
}

/* ---- account home ---- */
/* Block padding only: the inline gutter is the container's (`.container`
   pads `var(--gt-gutter)`, 20→40px with the viewport). This rule used to
   write `20px` on both sides, so at 1440 the account pages' content column
   started 20px OUTSIDE the header's and the footer's (measured 19 Aug: h1 at
   x=130 against the logo at 150; 3px at 768). */
.got-account{ padding-block:var(--gt-space-9) var(--gt-space-11); }
.got-account__head{
  display:flex; align-items:flex-start; justify-content:space-between;
  gap:1rem; flex-wrap:wrap; margin-block-end:1.75rem;
}
/* The account pages' h1 at the page-title step — the same step the order,
   auth and legal pages use (28/800/1.2). It had no rule, so it took the
   base h1 (32/700) with the BODY's line-height of 1.6 (measured 19 Aug: a
   51px box for one line). */
.got-account__head h1{ font-size:var(--gt-text-2xl); font-weight:var(--gt-weight-heavy); line-height:var(--gt-leading-tight); }
/* The order list: 8px inside a row (the row and its Pay button), so the gap
   BETWEEN rows must be more than 8 or a wrapped button sits equidistant from
   its own order and the next one (measured 19 Aug at 390: 8 above, 8 below,
   three payable orders, three floating buttons). Page-scoped on purpose — the
   system's `.got-lines` keeps its 8 for the strip, where nothing wraps under
   a row. */
.got-account .got-lines{ gap:var(--gt-space-6); }
/* V-01: `.9rem` was 14.4px — OFF THE SCALE. The lead is --gt-text-sm,
   which is the 14px every other lead on the site already uses. */
.got-account__lead{ color:var(--muted); font-size:var(--gt-text-sm); margin-top:.3rem; }
/* The account home's "at a glance" strip and the wallet's balance hero are
   system components with no outer margin (spacing belongs to the page). This
   page puts a panel's worth of air under each. */
.got-account > .got-stats,
.got-account > .got-stat{ margin-block-end:1.5rem; }

/* 🔴 THE WALLET'S RHYTHM — V-37, 7 Sep 2026, AND IT WAS MEASURED BACKWARDS.

   MEASURED at 1440 before this block existed: 28px between the heading block
   and the balance card, 24px between the balance card and the ledger. The
   heading sat FURTHER from its own figure than the two sections sat from each
   other — so the eye had nothing telling it which things belong together, and
   the title read as floating above a detached box. Space between sections
   must exceed space within them; here it was the other way round by 4px.

   The fix is two numbers and it is the whole of "the heading joins the
   composition": the head is pulled ONTO the balance it introduces (28 -> 16)
   and the ledger is pushed away from both (24 -> 40). Ratio 1:2.5 where it
   was 1.17:1.

   PAGE-SCOPED ON PURPOSE. `.got-account__head` is worn by /account,
   /account/profile and /cart as well, and V-36 proved /account did not move —
   a claim this round keeps. `got-account--wallet` is not a class system.css
   styles, so these rules are this sheet's to make (SiteTokensTest's ownership
   rule is about the rightmost compound plus whether EVERY class in the part is
   system-owned; this one is not). */
.got-account--wallet .got-account__head{ margin-block-end:var(--gt-space-5); }
.got-account--wallet > .got-stat{ margin-block-end:var(--gt-space-9); }

/* 🔴 TWO PANELS ON THIS PAGE AS OF V-42b, AND THE SYSTEM CARD CARRIES NO
   OUTER MARGIN ON PURPOSE — spacing between panels belongs to the page.

   `.got-account__panel` is `.got-card--panel` in system.css and has no margin
   of its own; the only sibling rule in this sheet is
   `.got-formcol > .got-account__panel + .got-account__panel`, and this page's
   container is `.container.got-account.got-account--wallet`, not a formcol.
   So without this declaration the checking-transfers card and the ledger card
   TOUCH — two bordered cards sharing one hairline, which reads as one card
   with a rule through it.

   `--gt-space-8` (32px) and not the formcol's 24px: those two panels are a
   form and its siblings inside one column; these two are separate statements
   about the customer's money, and V-37's measured rule for this page is that
   space BETWEEN sections must exceed space WITHIN them. The ledger's own
   heading sits 16px off its rows.

   Page-scoped, in site.css, for the same reason the `h2` rule below is: the
   element is shared with /account, /account/profile and /cart, and V-36
   proved /account did not move — a claim this page's rules have to keep. */
/* V-42d B3: `--gt-space-6` (20px), not the 32 this rule carried. The top-up
   and the transfer pages put 20px between their cards (`.got-credit__split`
   and `.got-order__grid`), and where one money page differs from the other
   two, the two win. V-37's rule still holds — between exceeds within, and
   within is the head's 16px — it simply no longer needs 32 to hold. */
.got-account--wallet .got-account__panel + .got-account__panel{
  margin-block-start:var(--gt-space-6);
}

/* The ledger's heading, separated from the rows it heads. A hairline rather
   than more space: the panel is already padded, and another 40px inside a
   section whose whole problem was flatness would have re-made the flatness at
   a smaller scale. Token border, token colour — the same pair
   `.got-ledger__row` uses, because a hairline written as a pixel and a hex
   fails SiteTokensTest twice. */
/* V-42d B3: the wallet's card heads take the CARD-HEAD step the other two
   money pages use (`.got-order__panel h2`: `--gt-text-lg`, bold), not the
   account section step, and the hairline under them goes: with Study A's lit
   top edge on every card, a second rule six lines below it was two lines
   answering one question. The 16px under the head is the family's. */
.got-account--wallet .got-account__panel h2{
  font-size:var(--gt-text-lg); font-weight:var(--gt-weight-bold);
}

/* 🔴 STUDY D'S TOP — the heading and the balance on ONE line, the capsule at
   the end side. V-38, 7 Sep 2026.

   The head was a block with the capsule under it; the study puts them side by
   side and lets the ledger have the page. `flex-wrap` and no breakpoint: at
   390 the capsule drops below the heading and takes the full width on its own,
   which is what the study shows and what the wrap does without a media query
   that could fall out of step with the container.

   The capsule MOVED INSIDE the header in the Blade rather than being pulled
   beside it from here: two siblings cannot share a line without a wrapper, and
   the header already is one. It keeps no margin of its own — the head's margin
   separates the whole top block from the ledger, and two margins between the
   same two things is how V-37's rhythm went backwards in the first place. */
.got-account--wallet .got-account__head{
  display:flex; align-items:center; justify-content:space-between;
  gap:var(--gt-space-5) var(--gt-space-7); flex-wrap:wrap;
}
/* The header carries the living background, so it needs to be the positioned
   ancestor those absolutely-placed layers resolve against, and it needs the
   room for them to be worth painting. `isolation` gives the content its own
   stacking context above `.got-livebg`'s `z-index:0` without inventing a
   second z-index scale. The bleed is inline padding the container already
   pays for, pulled back out so the light reaches the page's edges the way it
   does on the home hero rather than stopping at the text column. */
.got-account__head--lit{
  position:relative; isolation:isolate;
  padding-block:var(--gt-space-8);
  padding-inline:var(--gt-space-6);
  margin-inline:calc(var(--gt-space-6) * -1);
  border-radius:var(--gt-radius-lg);
  overflow:hidden;
}
/* 🔴 THE WALLET'S BODY IS LIT — V-42d B1, GAP-252, Omar's «low behind the
   ledger». The page container is the positioned ancestor of the faint
   instance (`.got-livebg--faint`, rendered as its first child in the Blade),
   and everything else on the page sits above it in one stacking context —
   the same `:not(.got-livebg)` shape the header uses, for the same measured
   reason (a `> *` rule would catch the layer itself and pull it into flow).
   The header's own instance no longer ends in a fade to `--bg`: with light
   under the whole page, an opaque strip across the header's lower half read
   as a dark slab on a lit ground. It dissolves through a MASK instead, into
   the body's fainter light — set here as a custom property the family's
   base rule reads, so the layer is still defined once. The `__fade` moved to
   the body instance, where the page really ends. */
.got-account--wallet{ position:relative; isolation:isolate; }
.got-account--wallet > :not(.got-livebg){ position:relative; z-index:1; }
.got-account--wallet .got-account__head--lit > .got-livebg{
  --gt-livebg-mask:linear-gradient(to bottom,#000 52%,transparent 100%);
}
/* 🔴 `:not(.got-livebg)` AND IT IS LOAD-BEARING. The first cut wrote
   `> div{position:relative}`, which also matched the background layer — a
   DIV like any other — and beat `.got-livebg{position:absolute}` on
   specificity (0,1,1 against 0,1,0). The layer left the absolute flow, became
   a flex item, and took 306px of the header: the heading was pushed 330px
   inward and its lead wrapped to two lines. MEASURED on the rendered page,
   not deduced. The content still needs positioning to sit above a z-index:0
   layer, so the exclusion is the fix rather than dropping the rule. */
.got-account__head--lit > :not(.got-livebg){ position:relative; z-index:1; }
.got-account--wallet .got-account__head > div{ flex:1 1 18rem; min-inline-size:0; }
.got-account--wallet .got-account__head > .got-stat{ margin-block-end:0; }

/* Two controls where there was one. `flex-wrap` so they stack rather than
   squeeze on a phone, and `gap` rather than a margin on either child so the
   spacing does not have to be mirrored under dir="rtl" — logical properties
   only, which is this stylesheet's standing rule. */
.got-account__actions{ display:flex; align-items:center; gap:.6rem; flex-wrap:wrap; }

/* `.got-account__panel` itself is in system.css — it IS `.got-card--panel`,
   declaration for declaration, and keeping a second copy here was the only
   thing standing between five account pages and the system's card. */
/* 🔴 V-01, 20 Aug — THE WORST FLATNESS ON THE SITE, AND IT WAS OFF THE
   SCALE ENTIRELY. `1.05rem` is 16.8px at weight 700: measured on the
   rendered page, the "My orders" heading was SMALLER THAN THE 18px CARD
   TITLES BENEATH IT and 0.8px above body text. A section head that reads
   as body is why the account page had no shape.
   It is the section-head register now — --gt-text-xl at --gt-weight-heavy,
   the same 22/800 `.section-head h2` used to carry — so /account reads
   28 / 22 / 16 / 14 and the panel heading is a heading.
   The margin takes --gt-space-5, which IS the 1rem it already was: a
   legacy rule reading a NUMBER from a token is using the system, and it
   is the only kind of change this file still accepts. */
.got-account__panel h2{ font-size:var(--gt-text-xl); font-weight:var(--gt-weight-heavy); line-height:var(--gt-leading-tight); margin-block-end:var(--gt-space-5); }
/* .got-account__empty is gone (18 Aug): the empty account and the empty
   ledger are the system's .got-state now. */

/* BUG-100. The table's min-content width is roughly 340px and a 390px phone
   leaves the panel about 300px, so it overflowed the card and took the whole
   page sideways with it — and out of the OTHER edge under dir="rtl", because
   nothing anywhere in the chain had an overflow at all.
   overflow-x is symmetric rather than logical: it favours neither edge, so it
   is correct in both directions. The bleed either side is written with
   margin-inline / padding-inline, which do mirror, so the scroll runs edge to
   edge of the panel instead of being inset from its padding. */
.got-account__scroll{
  overflow-x:auto;
  margin-inline:-1.5rem;      /* .got-account__panel's padding */
  padding-inline:1.5rem;
  max-inline-size:calc(100% + 3rem);
}

.got-account__table{ inline-size:100%; border-collapse:collapse; font-size:.88rem; }
/* BUG-101. These two were --dim (#68748F), which measures 3.67:1 on --card
   (#171B28) and fails WCAG AA for small text — the header row at 11.2px and
   the muted cell at 14px. --muted (#93A0BC) on the same --card measures
   6.54:1 and is the precedented fix: BUG-010 was this exact value in this
   exact role on the registration hints. Both numbers are here on purpose —
   a comment quoting one reads as proof the rule was checked. */
.got-account__table th{
  text-align:start; font-size:var(--gt-text-3xs); letter-spacing:.07em; text-transform:uppercase;   /* was .7rem = 11.2px, under the 12px floor (BUG-342) */
  color:var(--muted); font-weight:600; padding-block-end:.6rem; padding-inline-end:1rem;
}
.got-account__table td{
  padding-block:.7rem; padding-inline-end:1rem;
  border-block-start:1px solid var(--line);
}
.got-account__table .got-num{ text-align:end; font-variant-numeric:tabular-nums; }

/* BUG-109. The order number is the ONLY route into the order page from a
   phone, and it was a ~40x23px tap target — under the 44px minimum BUG-037
   set for the panels. The padding is negative-margined back out so the row
   keeps its rhythm; inline-flex + min-block-size is what actually makes the
   hit area 44px rather than just the text box. */
.got-account__ref{
  font-weight:700;
  display:inline-flex; align-items:center;
  min-block-size:44px; min-inline-size:44px;
  padding-inline:.5rem; margin-inline:-.5rem;
}
.got-account__ref:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; border-radius:8px; }

/* The "—" in the Proof column: present, but not competing with the link
   beside it. --muted at 6.54:1 on --card, not --dim at 3.67:1 — see BUG-101
   above. Logical properties only; the table is RTL by build. */
.got-account__muted{ color:var(--muted); }
.got-account__table td a{ color:var(--accent); }

/* ---- store credit: the balance, and what moved it ----------------------
   `got-credit-*`, never `got-wallet-*` and never `got-balance-*`. The pro's
   payout screen already owns `got-wallet-*` in admin.css and it is the OTHER
   DIRECTION OF MONEY; two screens about opposite kinds of money sharing a
   class prefix is how one ends up restyled by an edit meant for the other.

   Logical properties only, like everything else in this file. The panel is a
   .got-account__panel and reuses its table, so nothing here restates a border,
   a padding or a cell rule — only what is genuinely new. */

/* Two panels stacked where there was one, and the gap between them is the
   only thing holding them apart — .got-account__panel has no margin of its
   own, so without this rule the two bordered cards touch.

   It lives on the credit panel rather than on .got-account__panel for the
   same reason it always did: the orders panel keeps its existing
   relationship with the pager, which sits INSIDE it.

   It is the START side now, not the end. The credit panel moved BELOW the
   orders (Omar, this round — above them it pushed "Your orders" 892px down
   on desktop and 1051px on mobile), so the gap has to move with it or it
   opens under the last card instead of between the two.

   AND THE TWO PARAGRAPHS ABOVE NOW DESCRIBE SOMETHING THAT NO LONGER EXISTS,
   which is said here rather than left to be inferred from a value that still
   works. The panel moved AGAIN — off /account entirely and onto its own page,
   /account/wallet, where it is the only card and has nothing above it to be
   held apart from. The declaration is left exactly as it is: it is spacing, it
   is harmless, and the round that moved the panel is functional only. The
   correct value is the next round's to decide. */
/* .got-credit, .got-credit__label, __balance, __direction and __amount used to
   be defined here, with their two [dir="rtl"] text-align rules. They moved to
   system.css's legacy-names section on 17 Aug (the client-area round), where
   the bidi reasoning went with them; the alignment is now the container's
   job (flex), so the [dir] rules were deleted rather than moved. */

/* ---- the orders pager (GAP-051) ----
   Hand-written because the public site has no Tailwind: Laravel's default
   `pagination::tailwind` view would compile to nothing here and fail
   silently. Logical properties throughout, so the row mirrors itself under
   dir="rtl" — the one thing that cannot mirror on its own is the chevron
   glyph, which is not Bidi_Mirrored, so it gets a [dir] override exactly as
   .arrow::after does (BUG-119 / BUG-097).

   ---- Colours, MEASURED AS COMPOSITED (BUG-140) ----
   Every figure below is the colour a browser actually paints, on --card
   (#171B28), which is .got-account__panel's background. The public site has no
   light mode, so there is one measurement per rule and not two.

   This paragraph used to say the disabled step used --muted "rather than --dim
   (3.67:1)" and quoted --muted at 6.53:1 as the reason. Both numbers were true
   of the TOKENS and neither was true of the rule: `opacity:.65` sat on the same
   declaration and dragged the rendered text to rgb(104,113,136) = 3.52:1 —
   BELOW the colour the sentence rejects — while the border came out at 1.14:1,
   so the control did not read as a control. Fourth time in this project
   (BUG-010, BUG-101, BUG-118): a comment quoting one number reads as proof the
   rule was checked. An alpha is part of the colour. Measure after it, or do not
   use one.

   No opacity here now, only explicit colours:
     .got-pager__step        --text  on --card = 13.86:1, --line-2 border 3.66:1 (was 1.57 before BUG-344)
     .got-pager__step--off   --muted on --card =  6.53:1, --line-2 border 3.66:1 (was 1.57 before BUG-344)
     (the colour turned down, for the record: --dim on --card = 3.66:1)
   The disabled pill keeps the LIVE step's border on purpose, so it still reads
   as a control; what says it is disabled is the text colour, aria-disabled and
   the missing href. FinalRoundTest recomputes all of this from this file and
   fails if a figure above stops matching the rule below.

   Two notes so nothing here reads as a contradiction. --muted on --card is
   written 6.53:1 in this block and 6.54:1 twice further up: same pair, same
   measurement, 0.01 apart because those two were pixel-sampled off a rendered
   page and this one is computed from the tokens. Likewise the 3.52:1 above was
   sampled by a tester as 3.51:1 — the browser and the arithmetic round the
   composite's red channel to 103 and 104 respectively. Neither gap is a
   disagreement about the colour; both are recorded rather than quietly
   averaged. */
/* V-02, 22 Aug — ONE LINE OFF `TypeRegisterTest::SIZED_BY_HAND`, AND THE
   LIST CAN ONLY SHRINK. `.85rem` is 13.6px: not a step of the scale, and
   0.4px under the 14px every other secondary control on the site takes. The
   pager reads `--gt-text-sm` now, which is the step its role belongs to
   (controls and short labels), and its line comes off the constant in the
   same commit. The remaining 26 rules are GAP-123 and stay named. */
.got-pager{
  display:flex; align-items:center; justify-content:space-between;
  gap:.75rem; flex-wrap:wrap;
  margin-block-start:1.25rem; padding-block-start:1rem;
  border-block-start:1px solid var(--line-2);
  font-size:var(--gt-text-sm);
}
.got-pager__count{ color:var(--muted); font-variant-numeric:tabular-nums; }
.got-pager__step{
  display:inline-flex; align-items:center; gap:.4rem;
  min-block-size:44px; padding-inline:.9rem;   /* BUG-109's 44px tap target */
  border:1px solid var(--line-2); border-radius:999px;
  color:var(--text); font-weight:650; text-decoration:none;
}
.got-pager__step:focus-visible{
  outline:var(--gt-ring-width) solid var(--gt-ring-color);
  outline-offset:var(--gt-ring-gap);
  box-shadow:var(--gt-ring-shadow);   /* the system's ring, not a hand-written one (Batch 4) */
}
.got-pager__step--off{ color:var(--muted); border-color:var(--line-2); cursor:default; }

/* The chevrons. Written as ::before on "previous" and ::after on "next" so the
   glyph always sits on the outside of the label, and flipped under RTL. */
.got-pager__step--prev::before{ content:"\2190"; }
.got-pager__step--next::after{ content:"\2192"; }
[dir="rtl"] .got-pager__step--prev::before{ content:"\2192"; }
[dir="rtl"] .got-pager__step--next::after{ content:"\2190"; }

/* ---- header account links ---- */
/* The account cluster: basket, balance, the account menu — or, for a guest,
   Create account. It no longer wraps: the row cannot overflow now that the
   games and the switch are behind ☰ below the breakpoint. */
.nav-account{ display:flex; align-items:center; gap:var(--gt-space-3); flex-shrink:0; }
/* V-02, 22 Aug — TWO MORE LINES OFF `TypeRegisterTest::SIZED_BY_HAND`, and the
   list may only shrink. `.88rem` is 14.08px and `.84rem` is 13.44px: two
   neighbouring header controls, a pixel apart, neither on the scale, and both
   belonging at the 14px step every other secondary control on the site takes.
   The button's PADDING stays a pair of literals — it is a hand-fitted control
   height in the header row, not a position in the spacing rhythm, and forcing
   it onto the scale would change the row's measured height for no reason. */
.nav-account a{ font-size:var(--gt-text-sm); }
.nav-account .got-btn{ padding:.45rem .9rem; font-size:var(--gt-text-sm); }

/* ---- language switcher — MIGRATED 18 Aug to system.css (`.got-lang`), with
   the ☰ nav menu it now sits inside. Deleted here, not left as a copy: the
   legacy stylesheet loads after the system and a copy here would win. */

/* `.got-btn` and `.got-field input` came off this list on 15 Aug — they are
   system components and the system answers the query once, by rewriting its
   duration tokens, which reaches every component including ones written after
   the query. That is the property a list of class names cannot have, and it
   is why four more blocks like this one still exist in this file: each names
   the classes its author happened to know about.

   (`.got-lang a` left this list on 18 Aug with the switch's migration.) */

/* ---- the signed-in header: the balance, and the two destinations ---------
   `got-credit-*` and never `got-wallet-*`. The pro's payout screen owns
   `got-wallet-*` in admin.css and it is the OTHER DIRECTION OF MONEY — see
   StoreCreditEntry's docblock, which bans the identifier while the customer's
   own word for the page stays "wallet".

   FUNCTIONAL ONLY. Appearance is the next round's; what is here is the
   collapse, the tap targets and the two rules that are correctness rather than
   looks (`white-space:nowrap`, and the positioning that stops the menu panel
   growing the sticky header). */

/* The balance. A FIGURE THAT IS A LINK — never an input, never a box that
   could be mistaken for one.

   `white-space:nowrap` is correctness and not tidiness: an isolated LTR run
   that WRAPS is an LTR run in two pieces, and the bidi algorithm gets to
   reorder the pieces. Same reason .got-pay__ltr and .got-credit__amount carry
   it.

   IT IS DELIBERATELY ABSENT FROM THE `[dir="rtl"]` ALIGNMENT LIST that
   .got-credit__balance and .got-credit__amount are on, AND THE CONDITION FOR
   THAT IS THIS RULE ITSELF: it is a SHRINK-WRAPPING FLEX ITEM inside
   .nav-account, so its box is exactly as wide as the figure and there is no
   spare width for `text-align` to move anything within. Give it `display:block`,
   an `inline-size`, a `min-inline-size` or `flex:1` and it acquires the
   identical defect those two were fixed for, and it must join that list in the
   same edit. */
.got-credit__navbalance{
  display:inline-flex; align-items:center;
  /* V-30 B6: the wallet glyph and the figure are ONE UNIT — the space
     INSIDE it is a step below the row's gap (`--gt-space-3` on .nav-account),
     so the eye groups glyph-with-figure before it groups figure-with-basket.
     MEASURED at 1536, both languages: 6px inside the unit, 26.39px from the
     basket's glyph to the wallet's (the basket's glyph is centred in its 44px
     square, then the 8px row gap, then this link's padding). */
  gap:var(--gt-space-2);
  min-block-size:var(--gt-tap-min);    /* BUG-037's tap minimum — the token since V-33 B4 (it was a literal 44px, the one in the header row); the basket and the account toggle read the same token, so the three utilities are one height by construction */
  padding-inline:.4rem;
  border-radius:var(--gt-radius-sm);   /* the shape the hover wash and the ring share */
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-weight:700; font-size:.9rem; color:var(--text);   /* 13.9:1 on --bg */
  font-variant-numeric:tabular-nums;
  transition:var(--gt-transition-control);
}
/* V-20 B7 (28 Aug): this chip is a LINK to the wallet and it was the one
   control in the signed-in header that answered hover with nothing — measured
   beside its own siblings: `.got-cart__nav:hover` and
   `.got-accountmenu__toggle:hover` both wash (`rgba(255,255,255,.04)` on this
   tree) and this stayed byte-identical hovered. Same family, same wash. */
.got-credit__navbalance:hover{ background:var(--gt-wash-soft); }
/* V-20 B7: the ring is THE SYSTEM'S — it was `outline:2px solid var(--accent);
   outline-offset:2px` with NO band, a parallel focus treatment (measured via
   Tab on this tree: box-shadow `none` while every neighbour wears
   `--gt-ring-shadow`). A ring without its second tone is the shape that has
   regressed four times in this project; the radius moved onto the base rule
   (`--gt-radius-sm` is the same 8px) so the wash and the ring share it. */
.got-credit__navbalance:focus-visible{
  outline:var(--gt-ring-width) solid var(--gt-ring-color);
  outline-offset:var(--gt-ring-gap);
  box-shadow:var(--gt-ring-shadow);
}
.got-credit__navfigure{ white-space:nowrap; font-variant-numeric:tabular-nums; }   /* V-30 B3: the header balance, a figure that changes under the same label */
/* V-30 B6: the unit's glyph — the basket's size (`.got-cart__navicon`, pages.css)
   and stroke, `currentColor` so it and the figure are one colour that cannot
   drift apart. V-33 B4: one step up with the basket's, `--gt-space-7` (24px,
   was 20): Omar found the header's basket "small and plain", and the cluster's
   glyphs are ONE size through ONE token (HeaderAccountTest) so the wallet's
   moves with it — a 20/24 mix reads as two icon sets. */
.got-credit__navicon{ inline-size:var(--gt-space-7); block-size:var(--gt-space-7); display:block; flex:0 0 auto; }

/* Visible to a screen reader and to nothing else — the same declarations as
   .got-order__sr, written out rather than shared because the two live in
   different blocks of this file and a utility reached across block boundaries
   is a utility somebody edits for one caller. It exists because an `aria-label`
   on the link would REPLACE the figure rather than introduce it. */
.got-credit__navlabel{
  position:absolute; inline-size:1px; block-size:1px;
  padding:0; margin:-1px; overflow:hidden; white-space:nowrap;
  clip-path:inset(50%); border:0;
}

/* ---- the basket entry in the header — MIGRATED 15 Aug ---------------------

   `.got-cart__nav`, `.got-cart__navicon`, `.got-cart__navcount` and
   `.got-cart__navlabel` are in public/css/pages.css now, with the basket page
   they belong to. Splitting one component across two stylesheets and two
   systems was the alternative and it is the thing this round exists to stop.

   `.got-cart__navlabel` is gone entirely, class and all. It was nine
   declarations hand-copied from `.got-credit__navlabel` eight lines further
   down, and the comment on it said so — "a utility reached across block
   boundaries is a utility somebody edits for one of them". That was true
   while there was nowhere to put the utility. `.got-sr-only` is where it goes
   now, and the layout says that instead. `.got-credit__navlabel` below and
   `.got-order__sr` on the order page are the other two copies; they follow
   when those surfaces are migrated.

   The MEASUREMENTS that block carried are not lost — BUG-205's before/after
   table for this row, and the BUG-206 note about the third row at 360px, are
   facts about THIS header and stay with the header section above. */
/* ---- a capped form column — Phase C1 --------------------------------------

   `.container` is 1180px, which is right for a table of orders and wrong for a
   column of text inputs: on a desktop the name field was ~1500px of box holding
   a two-word name. A field as wide as the page promises far more than the thing
   it holds and makes the eye travel from the label to the caret and back.

   `max-inline-size`, not `max-width`, and no `margin:auto` — the column stays
   at the inline START of the container, so it lands on the left in English and
   the right in Arabic with no [dir] rule. Centring it would put it in the same
   place in both, which is the one thing that is wrong in both.

   45rem because that is roughly the 66-character measure for this stack's body
   size; it bounds the LINE, which is what the eye is actually paying for. */
.got-formcol{ max-inline-size:45rem; }
/* Two panels stacked in the form column touched edge to edge on the profile
   page (measured, 17 Aug); the system's card carries no outer margin on
   purpose — spacing between panels belongs to the page — so this is where the
   page says it. */
.got-formcol > .got-account__panel + .got-account__panel{ margin-block-start:1.5rem; }

/* Actions at the inline end, sized to their content. A full-bleed button in a
   capped column reads as the PAGE's primary action rather than the card's, and
   this page has three cards each with its own. `justify-content:flex-end` follows
   the writing mode, so it mirrors with no override. */
.got-formactions{
  display:flex; justify-content:flex-end; flex-wrap:wrap; gap:.6rem;
  margin-block-start:1.25rem;
}

/* ---- `.got-profile__email .got-account__ref` — GONE 21 Aug (Batch 2). The
   read-only email row it nudged became the email card's own change form, so
   the selector matched nothing: a rule nothing can exercise is
   indistinguishable from a bug, and a migrated surface deletes its old rules
   in the same pass. */

/* ---- the account menu — MIGRATED 18 Aug to system.css (`.got-accountmenu`)
   whole: toggle, name, caret, panel, email, rule, sign-out, and the phone
   arrangement — which is a full-width SHEET anchored to `.site-header` now,
   not a panel back in flow. The in-flow panel grew the sticky header to 414px
   at 390 when opened (measured, Phase 1); the sheet adds nothing to it. The
   two long notes that stood here (BLOCKING 4, Phase C1) described anchors and
   wraps that no longer exist and went with the rules. */

/* ============================================================
   Registration polish — 6 Aug
   ------------------------------------------------------------
   Hint text moved off --dim (#68748F), which measures 3.66:1 on
   the card and fails WCAG for small text, onto --muted at 6.53:1.
   Logical properties only, so Arabic mirrors correctly.
   ============================================================ */

/* The card sat high with dead space beneath it. Centre it in the
   space actually available, but never let a long form be cut off
   at the top on a short screen. */
/* Centred when there is room, top-aligned when there is not.
   justify-content:center was the bug: once the card is taller than the
   viewport, centring overflows BOTH ends and the top gets cut off with no way
   to scroll back to it. `margin-block:auto` on the child centres the same way
   but collapses to zero instead of going negative. */
.got-auth{
  min-block-size:calc(100dvh - 9rem);
  display:flex; flex-direction:column;
  padding-block:2rem 3rem;
}
.got-auth > *{ flex:none; }
.got-auth__card{ margin-block-start:auto; }
.got-auth__aside{ margin-block-end:auto; }

@media (max-width:640px){
  .got-auth{ min-block-size:0; padding-block:1.25rem 2.5rem; }
  .got-auth__card{ margin-block-start:0; }
  .got-auth__aside{ margin-block-end:0; }
}

/* 🔴 THE FIELD'S HINT, ERROR AND VALIDATION STATES ARE IN system.css NOW.

   Five rules moved and they were the clearest case in the file for why a
   design system was needed at all:

   · `.got-field__hint{color:var(--muted)}` was an OVERRIDE OF A RULE 680
     LINES ABOVE IT in this same file, which set the same class to `--dim`.
     Two declarations of one thing, far enough apart that the comment on the
     first one described the wrong colour for weeks (corrected 14 Aug). There
     is one now.

   · `.got-field__error` painted `#FCA5A5` — a light red that exists in no
     palette, is in no config, and was invisible to BrandPaletteTest because
     that guard only ever checked the three accent keys. The system's error
     text is `--gt-ink` on the field's own danger edge, which is measured to
     pass on all four surfaces.

   · `.got-field.is-invalid` and `.got-field--error` were TWO NAMES FOR ONE
     STATE — one written by the script as you type, one by the server when it
     refuses — that disagreed about what being wrong looks like. They are one
     rule with both spellings now, so the two refusals cannot diverge.

   · `rgba(239,68,68,.22)` and `rgba(34,197,94,.55)` were `--red` and `--green`
     written out again in channel form. `--danger-rgb` and `--success-rgb`
     come off config/brand.php.

   · `.got-field__error:empty{display:none}` went with them, and it had to:
     the system's error element has a `::before` marker, so leaving that line
     behind would have painted a red dot under every field on every auth page
     from the moment it loaded. */

/* ---- contact: channel + handle as one control ---- */
.got-combo{ display:flex; }
.got-combo__select{
  flex:none; padding:.65rem .6rem;
  background:var(--bg-2); color:var(--text);
  border:1px solid var(--line-2);
  border-start-start-radius:10px; border-end-start-radius:10px;
  border-inline-end:0;
  font:inherit; font-size:.88rem;
}
.got-combo__input{
  flex:1 1 auto; min-inline-size:0;
  border-start-start-radius:0 !important; border-end-start-radius:0 !important;
  border-start-end-radius:10px; border-end-end-radius:10px;
}
.got-combo__select:focus{ outline:none; border-color:var(--accent); }

/* ---- show / hide password — MIGRATED 18 Aug (Batch 4) to system.css as THE
   PASSWORD REVEAL, ring and all. The two blocks that stood here (the first
   from before BUG-243, the second BUG-243's) are gone together. ---- */

/* ---- trust signals — GONE 18 Aug (Batch 4): the register page's three
   reassurances are `.got-facts` now, no emoji; the note under them is
   `.got-auth__note`. ---- */
.got-auth__facts{ margin-block-start:var(--gt-space-5); }
.got-auth__note{ margin-block-start:var(--gt-space-2); font-size:var(--gt-text-2xs); color:var(--muted); text-align:center; }

/* ---- legal pages ---- */
/* The legal pages (Batch 4, 18 Aug): a reading column, the page-title step,
   the prose in INK — long-form reading, not a caption; muted is for the date
   line — and section heads one step up from the body. The Draft flag below
   is untouched: the lawyer's text is in flight and the flag says so. */
.got-legal{ max-inline-size:46rem; padding-block:var(--gt-space-9) var(--gt-space-11); }
.got-legal h1{ font-size:var(--gt-text-2xl); font-weight:var(--gt-weight-heavy); line-height:var(--gt-leading-tight); }
.got-legal h2{ font-size:var(--gt-text-lg); font-weight:var(--gt-weight-bold); line-height:var(--gt-leading-tight); margin-block:var(--gt-space-8) var(--gt-space-3); }
.got-legal p{ color:var(--text); font-size:var(--gt-text-md); line-height:var(--gt-leading-normal); margin-block-end:var(--gt-space-4); }
.got-legal a{ color:var(--accent); text-decoration:underline; text-underline-offset:var(--gt-space-1); border-radius:var(--gt-radius-xs); transition:var(--gt-transition-control); }
/* V-20 B7 (28 Aug): the prose links (the support address on /terms and
   /privacy) were claimed by NO hover rule and NO focus rule — the enumeration
   that runs the other way found them in both languages. The rest state was
   already a real affordance (accent + underline); the hover is the inline-link
   recipe's wash (as `.got-order__link:hover`), and the ring is the system's —
   a comment above the header ring list claimed these links "already carry
   their own rings", which was false on this tree until this rule. */
.got-legal a:hover{ background:var(--gt-wash-soft); }
.got-legal a:focus-visible{
  outline:var(--gt-ring-width) solid var(--gt-ring-color);
  outline-offset:var(--gt-ring-gap);
  box-shadow:var(--gt-ring-shadow);
}
/* An inline link in the prose (the support address) is a 24px target by the
   inline recipe: padding-block with the same negative margin, so the line's
   rhythm is untouched (21px measured 19 Aug; 29 now). */
.got-legal p a{ display:inline-block; padding-block:var(--gt-space-1); margin-block:calc(-1 * var(--gt-space-1)); }
.got-legal__date{ font-size:var(--gt-text-xs); color:var(--muted); }
.got-legal__flag{
  padding:.85rem 1rem; border-radius:10px; font-size:.84rem;
  background:rgba(var(--warning-rgb),.12); border-inline-start:3px solid var(--amber);
  color:var(--text) !important; margin-block-end:2rem;
}

/* `.got-submit` came off this list with the rule — it is a system button now,
   and the system answers this query ONCE by rewriting its duration tokens,
   which reaches every component including ones written after the query. */
/* (`.got-reveal__btn` left this query on 18 Aug with the reveal's migration —
   the system answers reduced motion once, through its duration tokens.) */
/* ============================================================
   Registration refinements — 6 Aug
   ============================================================ */

/* ---- consent: MIGRATED to .got-check in system.css ------------------------

   Seven rules stood here and all seven are gone, because every one of them
   was a private answer to a question the system now answers once:
   `.got-consent` (the row), `.got-consent input[type=checkbox]` (the size,
   with `margin-block-start:.12rem` to nudge the box onto its line),
   `.got-consent__text`, its link colour, its hover, and its own hand-written
   `outline:2px solid var(--accent)`.

   TWO OF THEM WERE ACTIVELY WRONG and are worth naming, because deleting a
   rule quietly is how a behaviour change becomes a bug report:

     · the size rule set `block-size` and NOT `min-block-size`, so
       `.got-field input { min-block-size: var(--gt-tap-min) }` won and the
       box rendered 16.8 x 44 — an 18px control stretched into a 44px column,
       measured, which is the misalignment Omar reported;
     · `.got-consent__text` was `--muted` and went to `--text` on hover. A
       consent sentence you must read to agree to is not hover-to-reveal
       text. The system paints it `--gt-ink` at 13.86:1 and does not change
       it, and `.got-pay__gate-text` next door already did exactly that — two
       callers of one idea disagreeing, which is the thing being ended.

   `.got-field--consent` went with them: a `--modifier` of a system component
   defined ONLY in the legacy stylesheet is the two-systems problem in
   miniature, and its `margin-block-start:.25rem` is now the component's own
   `padding-block`. */


/* ---- password rules that turn positive as they are met ---- */
.got-strength{ margin-block-start:.5rem; }

.got-strength__rules{ list-style:none; margin:0; padding:0; }
.got-strength__rules li{
  display:flex; align-items:center; gap:.4rem;
  font-size:.76rem; color:var(--muted);
  transition:color .15s ease;
}
.got-strength__dot{
  inline-size:.85rem; block-size:.85rem; flex:none;
  border-radius:50%; border:1.5px solid var(--line-2);
  display:grid; place-items:center;
  transition:border-color .15s ease, background-color .15s ease;
}
.got-strength__rules li.is-met{ color:var(--green); }
.got-strength__rules li.is-met .got-strength__dot{
  border-color:var(--green); background:var(--green);
}
/* the tick is drawn, not a font glyph, so it cannot go missing */
/* PHYSICAL borders, and the only intentional exception in this file — part
   of the BUG-096 sweep. The logical form (border-inline-end:0) dropped the
   RIGHT edge in English and the LEFT edge in Arabic, while the rotation
   stayed put, so the mark came out backwards on the Arabic page. A tick is
   a symbol, not a reading direction: it must NOT mirror. Written physically
   so there is nothing left to flip. Do not "correct" this to logical. */
.got-strength__rules li.is-met .got-strength__dot::after{
  content:""; inline-size:.3rem; block-size:.16rem;
  border:1.5px solid var(--bg); border-top:0; border-right:0;
  transform:rotate(-45deg) translate(.02rem, -.04rem);
}

.got-strength__meter{
  block-size:3px; border-radius:99px; background:var(--line);
  margin-block-start:.5rem; overflow:hidden;
  opacity:0; transition:opacity .15s ease;
}
.got-strength.is-started .got-strength__meter{ opacity:1; }
.got-strength__meter span{
  display:block; block-size:100%; inline-size:0;
  border-radius:99px; background:var(--amber);
  transition:inline-size .2s ease, background-color .2s ease;
}
.got-strength__meter span.is-step-1{ inline-size:33%; background:var(--amber); }
.got-strength__meter span.is-step-2{ inline-size:66%; background:var(--accent); }
.got-strength__meter span.is-step-3{ inline-size:100%; background:var(--green); }

.got-strength__word{ font-size:var(--gt-text-2xs); color:var(--muted); margin-block-start:.3rem; }   /* was .72rem = 11.5px, under the 12px floor (BUG-342) */
.got-strength__word:empty{ display:none; }

/* ---- a quiet tick once a field is good ---- */
/* Drawn as a background so no extra markup is needed.

   The comment here used to say "Passwords are skipped: the eye button already
   lives there". MEASURED FALSE: it is true only while the password is hidden.
   Press the eye and the input becomes `type=text`, so `input[type=text]` below
   matches it — the tick is painted behind the button and `padding-inline-end`
   drops from the reveal wrapper's 2.9rem to the 2.6rem set here, because this
   selector is the more specific of the two.

   Harmless today (the tick sits under an opaque button on a field nobody reads
   the end of) and filed rather than fixed, so the change is one rule and not
   two. It becomes load-bearing under any `dir`-based change to the reveal box —
   which is exactly why FIX 1 above is `unicode-bidi`, not `dir`. */
.got-field.is-valid input[type=text]:not(.got-combo__input),
.got-field.is-valid input[type=email]{
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2322C55E' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-size:1rem;
  background-position:right .85rem center;
  padding-inline-end:2.6rem;
}
/* Arabic mirrors the page, so the tick has to move with it. */
[dir="rtl"] .got-field.is-valid input[type=text]:not(.got-combo__input),
[dir="rtl"] .got-field.is-valid input[type=email]{
  background-position:left .85rem center;
}
/* 🔴 DELETED WITH BUG-247, and it is the reason that bug needed a rendered
   measurement rather than a reading of system.css.

   `.got-field.is-valid .got-combo__input{ border-color:rgba(34,197,94,.55) }`
   sat here. It is (0,3,0) and site.css loads AFTER system.css, so it was
   beaten by exactly one thing: the system's `.got-field.is-valid
   input:not([type="checkbox"])` at (0,3,1). The moment that rule was deleted
   — it existed only to paint the second stroke under the ring — this one won,
   and the contact handle was the ONE field on /register still drawing a
   border under its own focus ring: measured #1C7744 against a #22C55E ring,
   in both languages, while every other field measured one stroke.

   It was also a SECOND GREEN for one state — 55% alpha against the system's
   solid — so a valid contact handle never quite matched a valid name field
   even at rest. The system's `--gt-edge-color` reaches `.got-combo__input`
   through `.got-field input`, so deleting this leaves the field greener, not
   plainer.

   "When you migrate a surface, DELETE its old rules in the same pass" is
   already in CLAUDE.md. This is what the pass that does not do it looks
   like from the other side. */

@media (prefers-reduced-motion:reduce){
  .got-strength__dot, .got-strength__meter,
  .got-strength__meter span, .got-strength__rules li{ transition:none; }   /* .got-reveal__btn left with the reveal (Batch 4) */
}
/* ============================================================
   One order — the client area (GAP-014)
   ------------------------------------------------------------
   Logical properties only, as everywhere on this site, so this
   block itself needs no [dir] override.

   ONE thing about this page does, and it is deliberately NOT here:
   the back link's arrow. A directional GLYPH has no logical form
   either (U+2190 is not Bidi_Mirrored, so nothing flips it), and
   it lives with the other physical values at the foot of this
   file — see the BUG-097 and BUG-096 sections. Do not read this
   paragraph as "nothing on this page mirrors by hand".

   No brand hex. Colours are the site's own variables, and --accent
   arrives from config/brand.php via Brand::cssVariables().

   The chat bubbles are deliberately NOT a copy of the Filament
   thread's inline <style> block. That one is precompiled-CSS
   territory with hard-coded hues; this one is the public site and
   uses the same surfaces as every other panel on it.
   ============================================================ */
/* ---- the order page and the money pages — ALIGNED 18 Aug (Batch 5 of the
   UI/UX round), VISUALLY ONLY. Every rule below changed only what it paints
   or how much air it leaves; not one form action, field name, hidden value or
   language key moved — MoneyPagesBoundaryTest holds the seven templates'
   source to a baseline written before this batch's first edit. The transfer
   pages (pay-transfer, top-up-transfer) were not edited at all (KEEP: they
   are verified at pre-production with real claims). ---- */
.got-order{ padding-block:var(--gt-space-9) var(--gt-space-11); padding-inline:var(--gt-gutter); }

/* The way back: a 44px target by the recipe (GAP-100 — it was 18px tall on
   the order, pay and top-up pages), the arrow drawn below with a [dir] rule. */
.got-order__back{ font-size:var(--gt-text-xs); margin-block-end:var(--gt-space-3); }
.got-order__back a{
  display:inline-flex; align-items:center;
  min-block-size:var(--gt-tap-min); padding-inline:var(--gt-space-2);
  margin-inline-start:calc(-1 * var(--gt-space-2)); margin-block:calc(-1 * var(--gt-space-3));
  border-radius:var(--gt-radius-xs);
  color:var(--muted);        /* 6.53:1 on --bg */
}
.got-order__back a:hover{ color:var(--text); background:var(--gt-wash-soft); }
.got-order__back a:focus-visible{
  outline:var(--gt-ring-width) solid var(--gt-ring-color);
  outline-offset:var(--gt-ring-gap);
  box-shadow:var(--gt-ring-shadow);
}

.got-order__title{ font-size:var(--gt-text-2xl); font-weight:var(--gt-weight-heavy); line-height:var(--gt-leading-tight); margin-block-end:1.25rem; }
/* The status pill under the title (17 Aug): the pair reads as one heading, so
   the title's gap shrinks to the pill and the pill carries the 20px. Only the
   order page renders the pill; the pay and top-up pages had inherited the
   short gap (8px to the first panel against 20 everywhere else — measured
   19 Aug), so the default is the 20 and the pill's presence is the exception. */
.got-order__title:has(+ .got-order__status){ margin-block-end:var(--gt-space-3); }
.got-order__status{ margin-block-end:1.25rem; }

/* Flash messages, same shapes as the auth pages so the site reads as
   one site. Text stays in --text (13.9:1 on --card); the colour is
   carried by the edge bar only, which is a 3px rule and not a
   sentence. border-inline-start, so the bar sits on the reading
   edge in Arabic too. */
/* The system's message shape (radius, bar, tint), written here because the
   class also lives on the two KEEP transfer pages, which were not edited. */
.got-order__flash{
  margin-block-end:var(--gt-space-6);
  padding-block:var(--gt-space-4); padding-inline:var(--gt-space-6) var(--gt-space-5);
  border-radius:var(--gt-radius-md);
  font-size:var(--gt-text-xs); line-height:var(--gt-leading-normal); color:var(--text);
  background:var(--gt-tint-success);
  border-inline-start:var(--gt-border-bar) solid var(--green);
}
.got-order__flash--bad{ background:var(--gt-tint-danger); border-inline-start-color:var(--red); }

/* The shortfall notice (Round 2's _shortfall partial) had NO rule in any
   stylesheet: the card sat 0px above the pay CTA / the details grid / the pay
   panel where every other sibling gap is 20px, and its title touched its first
   line with the four lines at 0 between them (measured 19 Aug). The card is
   the system's; only its rhythm is written here. */
.got-shortfall{ margin-block-end:1.25rem; }
.got-shortfall .got-card__title{ margin-block-end:var(--gt-space-3); }
.got-shortfall__line{ font-size:var(--gt-text-sm); line-height:var(--gt-leading-normal); }
.got-shortfall__line + .got-shortfall__line{ margin-block-start:var(--gt-space-2); }
.got-shortfall__action{ margin-block-start:var(--gt-space-4); font-size:var(--gt-text-sm); line-height:var(--gt-leading-normal); }
/* V-30 B3: the figures these sentences carry are UNCLASSED `<bdi dir="ltr">`
   runs built by the partial's `$ltr` closure and by pay.blade.php's
   `$ltrFigure` — and the suite pins that markup byte for byte
   (CheckoutGroupPaymentTest, MoneyPagesUxTest), so the figure cannot grow a
   class. The rule reaches them by CONTEXT instead: the sentence's own class,
   then the isolate. */
.got-shortfall__line bdi, .got-shortfall__action bdi, .got-order__note bdi{ font-variant-numeric:tabular-nums; }

/* Details beside the conversation on a desktop, stacked on a tablet
   and a phone. Spelled out rather than left to a single breakpoint. */
.got-order__grid{ display:grid; gap:1.25rem; grid-template-columns:1fr; align-items:start; }
@media (min-width:62rem){
  .got-order__grid{ grid-template-columns:minmax(0,1fr) minmax(0,26rem); }
}
.got-order__col{ display:flex; flex-direction:column; gap:1.25rem; min-inline-size:0; }

/* The panel: the system's card with the lift (the account panels have it;
   two panels one pixel apart in weight was the inventory's finding). */
.got-order__panel{
  background:var(--card); border:1px solid var(--line);
  border-radius:var(--gt-radius-lg); padding:var(--gt-space-7); min-inline-size:0;
  box-shadow:var(--gt-lift);
}

.got-order__panel h2{ font-size:var(--gt-text-lg); font-weight:var(--gt-weight-bold); line-height:var(--gt-leading-tight); margin-block-end:var(--gt-space-5); }
/* BUG-340: a panel's LEAD sentence — body size, prose leading, the card's own
   gap under it. The pay page's "Choose how you would like to pay…" was the
   panel <h2> (three lines of 18px bold at 390); it is this now. */
.got-order__lead{ font-size:var(--gt-text-md); line-height:var(--gt-leading-normal); color:var(--muted); margin-block-end:var(--gt-space-5); }
.got-order__note{ color:var(--muted); font-size:var(--gt-text-sm); line-height:var(--gt-leading-normal); }   /* 6.53:1 on --card */
/* "Still to pay: $30.15" is the figure the pay page exists for, and it was a
   14px muted note with its <b> inheriting the muted colour (measured 19 Aug).
   The label stays a note; the FIGURE is ink at the money-total step, tabular,
   and the line stands off the method list. */
/* 🔴 THE WAY OUT, HELD OFF THE PRIMARY ACTION — V-42b item 2.

   The cancel form is a sibling <form> after the submit one inside the same
   panel, so without a margin its button sits hard against "I have sent it"
   and the two read as a pair of equals. They are not: one is the page's
   purpose and the other is the door out, which is why the button is
   `--quiet` and why this gap exists at all.

   `--gt-space-5` (16px) is the gap the panel already uses between a control
   and the thing under it; a larger one would detach the door from the form
   it belongs to and read as a third section. */
.got-pay__cancel{ margin-block-start:var(--gt-space-5); }

.got-pay__remaining{ margin-block-end:var(--gt-space-5); }
.got-pay__remaining b{
  display:block; margin-block-start:var(--gt-space-1);
  color:var(--text); font-size:var(--gt-text-xl); font-weight:var(--gt-weight-bold);
  line-height:var(--gt-leading-tight); font-variant-numeric:tabular-nums;   /* 13.9:1 on --card */
}
/* The proof link (M-11/M-12, 19 Aug): a 141×21 inline link with the browser's
   own ring while the back link on the same page had the recipe. Same recipe. */
.got-order__link{
  display:inline-flex; align-items:center;
  min-block-size:var(--gt-tap-min); padding-inline:var(--gt-space-2);
  margin-inline:calc(-1 * var(--gt-space-2)); margin-block:calc(-1 * var(--gt-space-3));
  border-radius:var(--gt-radius-xs);
  color:var(--accent); text-decoration:underline;
}
.got-order__link:hover{ background:var(--gt-wash-soft); }
.got-order__link:focus-visible{
  outline:var(--gt-ring-width) solid var(--gt-ring-color);
  outline-offset:var(--gt-ring-gap);
  box-shadow:var(--gt-ring-shadow);
}

/* ---- the brief: label on the reading edge, value on the far one ---- */
.got-order__rows{ display:flex; flex-direction:column; }
/* V-32 B7 (B-3): a pair that does not fit on one line becomes TWO LINES, not
   two wrapped columns — MEASURED on /ar/orders/35 at 390 (touch, 300px row):
   «موعد التسليم المتوقع» took 2 lines in 123.4px and its date 2 lines in
   160.6px with the time alone on the second. `flex-wrap` lets the value drop
   to its own line; the auto margin sits on the `dt` (never on the `dd`: the
   hash, network and reference values are emitted as `<dd dir="ltr">`, and a
   logical margin on one of them resolves in ITS writing mode, the wrong way
   round in an RTL row) so a pair on
   one line keeps label-at-start / value-at-end, and `flex-end` places a value
   that wrapped alone at the row's end in both directions. */
.got-order__row{
  display:flex; flex-wrap:wrap; justify-content:flex-end; gap:1rem;
  padding-block:.55rem; font-size:.88rem;
}
.got-order__row + .got-order__row{ border-block-start:1px solid var(--line); }
.got-order__row dt{ color:var(--muted); margin-inline-end:auto; }
/* BUG-621 (V-32 B7 close-out): an unbreakable value — a 64-hex transaction
   hash in `<dd dir="ltr"><bdi>` — MEASURED 554.5px wide in a 300px row at 390,
   overflowing the row on the side the document cannot scroll to. `anywhere`
   lets it break inside its own line; a date or a figure has soft breaks of its
   own and never reaches this. */
.got-order__row dd{ text-align:end; font-variant-numeric:tabular-nums; overflow-wrap:anywhere; }

/* ---- the store code: the thing they actually bought ---- */
.got-order__panel--code{ border-color:var(--line-2); }
.got-order__code{
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:1.15rem; font-weight:700; letter-spacing:.04em;
  padding:.75rem .9rem; border-radius:10px;
  background:var(--bg-2); color:var(--text);            /* 14.3:1 on --bg-2 */
  border:1px dashed var(--line-2);
  overflow-wrap:anywhere; margin-block-end:.6rem;
}
/* V-34 1c — ONE ROW PER CODE (Omar's D1). The list is a grid of rows; each
   row is the code box growing to fill and its own Copy button at the end,
   wrapping under the box when the row is narrower than both (390 with a long
   code). `min-inline-size:0` is what lets the box shrink below its
   `max-content` — without it a 25-character monospace token sets the row's
   width and the button leaves the panel on the side the page cannot scroll
   to (BUG-621's shape). Logical properties only; the row mirrors on /ar and
   the code inside keeps its own `dir="ltr"`. */
.got-order__codes{ list-style:none; margin:0 0 .6rem; padding:0; display:grid; gap:.5rem; }
.got-order__code-row{ display:flex; align-items:center; flex-wrap:wrap; gap:.5rem .6rem; }
.got-order__code-row .got-order__code{ flex:1 1 12rem; min-inline-size:0; margin-block-end:0; }
/* The button reads at the control size of the register (--gt-text-sm), not
   the transfer page's hand-picked .82rem — that one is in TypeRegisterTest's
   forgiven list and this one must not join it. */
.got-order__copy{ flex:0 0 auto; font-size:var(--gt-text-sm); padding:.5rem .9rem; }
/* The two swapped states are the transfer page's (.got-pay__copy), on the same
   --card the panel sits on, so the measured pairs carry over: --accent for the
   ~2s "Copied", --amber (7.99:1 on --card) for "Copy failed" — amber and not
   red because the code is still on the screen and still selected, so this is
   "do it yourself", not "something broke". */
.got-order__copy.is-copied{ color:var(--accent); border-color:var(--accent); }
.got-order__copy.is-failed{ color:var(--amber); border-color:var(--amber); }
.got-order__copy-note{ display:block; font-size:var(--gt-text-sm); margin-block-end:.6rem; color:var(--amber); }   /* 7.99:1 on --card */
/* `display:block` above beats the UA sheet's `[hidden]{display:none}`, so the
   hidden state is restated here or the note is on the page from first paint. */
.got-order__copy-note[hidden]{ display:none; }
/* V-35 B1 — the code is hidden until the customer asks (Omar's D1). A masked
   row is the same box holding bullets, with its "Show code" form sitting on
   the row beside it exactly where the Copy button sits on a revealed row —
   `.got-order__form` is a column with a top margin for the page's standalone
   forms, so both are undone here for the row. The confirmation step takes the
   full row beneath the mask (`flex-basis:100%`), its two controls in a line.
   No colour and no size of its own: the mask reads in the box's own colour
   and the buttons are the system's, so nothing here joins the contrast or
   the register sweeps. Logical properties only; the row mirrors on /ar.

   🔴 THE COMPOUND SELECTORS ARE THE FIX AND THEY ARE NOT COSMETIC. The form
   wears BOTH classes, and `.got-order__form` is declared LATER IN THIS SAME
   SHEET (the "forms" block below). The first version of these rules was
   written as the bare `.got-order__reveal-form` / `.got-order__reveal-form
   .got-btn` — equal specificity, so source order decided and the LATER rule
   won: MEASURED in real Chrome on 6 Sep 2026, `flex-direction: column`,
   `margin-block-start: 16px`, `align-self: flex-start`, every "Show code"
   button 8px below its mask's centre in both languages and the
   confirmation's two controls stacked (tops 933.88 / 992.27) while the
   sentence above claimed a line. TRAPS: *CSS loaded later wins on equal
   specificity, and losing is silent.*

   Compounds rather than a MOVE below that block, deliberately: a move is
   correct only until the next author appends a rule, and it says nothing
   about why the order mattered. `.got-order__form.got-order__reveal-form`
   (0,2,0) beats `.got-order__form` (0,1,0) wherever either is written, and
   it states the relationship — a `.got-order__form` that is ALSO the row's
   reveal form takes the row's layout. The `.got-btn` pair needs the same
   treatment for the same reason: `.got-order__reveal-form .got-btn` and
   `.got-order__form .got-btn` are BOTH (0,2,0) and the later one wins.
   `CodeRevealTest::test_the_reveal_forms_layout_wins_in_the_cascade` is the
   guard; V35B1F-24 and V35B1F-25 are its arms, one per rule, because a
   mutation that takes both together proves neither. */
.got-order__form.got-order__reveal-form{ flex-direction:row; flex-wrap:wrap; align-items:center; gap:.5rem .6rem; margin-block-start:0; }
.got-order__form.got-order__reveal-form .got-btn{ align-self:auto; }
.got-order__reveal{ flex:1 1 100%; }
.got-order__reveal .got-order__note{ margin-block-end:.5rem; }

/* ---- the small section label, wherever one is needed ---- */
/* Started life as the heading for the complaints list — BUG-105's key, now
   rendered — and by the time the pay pages landed FOUR OF ITS FIVE call sites
   were on the transfer page, sitting directly above a wallet address and an
   amount. (Four, not three: the pass added `reference_label` in the same
   breath as it wrote this comment. The fifth is site/orders/show.blade.php's
   complaints heading, and it is the only one this change is felt on that was
   not re-designed with it.)

   ALL CAPS AND .07em OF TRACKING WERE WRONG THERE, and restyling it globally
   is deliberate: adding a page-scoped override, or a second class, would give
   this site two definitions of "small section label" three files apart, which
   is exactly how a retired colour survived a week here. One definition, five
   call sites, one change.

   Sentence case, and the weight rather than the case is what separates the
   label from the value under it. Nothing asserts the class name, so the risk
   of the global change is entirely visual and it was re-rendered in both
   languages.

   AND ONE CORRECTION TO WHAT THIS COMMENT FIRST CLAIMED, because the numbers
   in it were derived rather than measured. The old rule was `.8rem` and this
   one is `.82rem`, which reads as "nearly no change" — but on the transfer
   page the old `.8rem` NEVER WON. Those labels were `<h2>` inside a panel, so
   `.got-order__panel h2` (0,1,1) beat `.got-order__subhead` (0,1,0) and they
   rendered at 1.05rem / 16.8px with 1rem beneath them. The uppercase, the
   tracking and the colour did apply; the size and the margin did not. THE
   SIZE DROP CAME FROM h2 -> h3 IN THE BLADE, not from this rule — there is no
   `.got-order__panel h3`, so this is the first time the declaration below has
   decided anything on that page. Do not "restore" the old figure by reading
   the diff; read the specificity.

   RE-MEASURED, not carried over. --muted #93A0BC is 6.53:1 on --card #171B28,
   which is every call site today, and 5.89:1 on --card-2 #1E2434, the other
   panel surface in this area — comfortable on both at this size. --dim
   #68748F was not considered: it measures 3.66:1 on --card and is the colour
   BUG-010, BUG-101 and BUG-118 each had to take back out of a reading role. */
.got-order__subhead{
  font-size:.82rem; font-weight:600; letter-spacing:0;
  color:var(--muted);          /* 6.53:1 on --card, 5.89:1 on --card-2 */
  margin-block-end:.4rem;
}

/* ---- complaints already raised ---- */
.got-order__complaints{ list-style:none; display:flex; flex-direction:column; gap:.75rem; margin-block-end:1.25rem; }
.got-order__complaint{
  padding:.85rem 1rem; border-radius:10px;
  background:var(--card-2); border:1px solid var(--line);
}
.got-order__complaint-head{
  display:flex; justify-content:space-between; align-items:baseline;
  gap:.75rem; flex-wrap:wrap; margin-block-end:.35rem;
}
.got-order__ref{ font-weight:700; font-size:.9rem; }
.got-order__badge{ font-size:var(--gt-text-2xs); color:var(--muted); }  /* 5.89:1 on --card-2; was .74rem = 11.8px, under the 12px floor (BUG-342) */
/* Amber on --card-2 measures 7.4:1, and 8.0:1 on --card — comfortably
   readable at this size on both surfaces this badge can sit on. */
.got-order__badge--open{ color:var(--amber); font-weight:600; }
.got-order__complaint-reason{ font-size:.9rem; }
.got-order__outcome{
  font-size:.84rem; color:var(--text); margin-block-start:.5rem;
  padding-block-start:.5rem; border-block-start:1px solid var(--line);
}

/* ---- the refusal sentence: never a missing button ---- */
.got-order__refusal{
  font-size:var(--gt-text-xs); line-height:var(--gt-leading-normal); color:var(--text);
  padding-block:var(--gt-space-4); padding-inline:var(--gt-space-6) var(--gt-space-5);
  border-radius:var(--gt-radius-md);
  background:var(--gt-tint-warning); border-inline-start:var(--gt-border-bar) solid var(--amber);
}

/* ---- forms ---- */
.got-order__form{ display:flex; flex-direction:column; gap:.9rem; margin-block-start:1rem; }
.got-order__form .got-btn{ align-self:flex-start; }

.got-order__textarea,
.got-order__select{
  inline-size:100%; padding:.65rem .8rem;
  background:var(--bg-2); color:var(--text);
  border:1px solid var(--line-2); border-radius:10px;
  font:inherit; font-size:.9rem; line-height:1.5;
  transition:border-color .15s ease, box-shadow .15s ease;
}
.got-order__textarea{ resize:vertical; min-block-size:5rem; }
.got-order__textarea:focus,
.got-order__select:focus{
  outline:none; border-color:var(--accent);
  box-shadow:0 0 0 3px rgba(var(--accent-rgb), .22);
}

/* ---- the conversation ---- */
.got-order__chat{ display:flex; flex-direction:column; }

/* BUG-099. This was `position:sticky` with a 5.75rem offset and no bound
   on its height. With a full thread the panel came to roughly 713px
   against about 676px of viewport on a 1024x768 laptop — and a sticky
   element TALLER than its viewport pins at the top with its bottom
   simply unreachable: the send button could not be scrolled to at all.
   Same family as the justify-content:center trap, which also broke by
   putting content outside the scrollable region rather than inside it.

   Two guards, because one is a threshold and the other is arithmetic:

   1. Sticky only on a screen tall enough for a useful panel. 44rem is
      704px, and the reported laptop is 768px tall — so it is ABOVE the
      threshold and does still get the sticky panel. (An earlier draft of
      this comment claimed the opposite. It was wrong, and a comment that
      contradicts its own rule is how the next person "fixes" working
      code.) The threshold rules out phones in landscape and short
      windows, where the offset leaves almost nothing.
   2. The guard that actually saves the 1024x768 case is this one: the
      panel can never exceed what is visible — its max-block-size is the
      viewport minus the offset and a margin — and the THREAD gives up
      its fixed height and shrinks instead, so the composer below it is
      always inside the sticky box and always reachable. */
@media (min-width:62rem) and (min-height:44rem){
  .got-order__chat{
    /* V-30 B4: the system's offset, which derives from the header's height
       token — this was `5.75rem` written twice, a copy that could not follow
       the header. MEASURED after: top 84px, max-block-size 852px at 960 tall. */
    position:sticky; inset-block-start:var(--gt-scroll-offset);
    max-block-size:calc(100dvh - var(--gt-scroll-offset) - var(--gt-space-7));
  }
  .got-order__chat .got-order__thread{
    flex:1 1 auto;
    /* 0, not a floor: a floor is what would let it push the send button
       back out of the box on a short-but-wide window. */
    min-block-size:0; max-block-size:none;
  }
}

.got-order__thread{
  display:flex; flex-direction:column; gap:.65rem;
  max-block-size:26rem; overflow-y:auto;
  padding:.85rem; border-radius:10px;
  background:var(--bg-2); border:1px solid var(--line);
}
/* BUG-341: the thread is a focusable scroll region now (tabindex="0"), so it
   wears the system's ring when the keyboard lands on it — the same three
   declarations as every other ring; :focus-visible, so a click leaves none. */
.got-order__thread:focus-visible{
  outline:var(--gt-ring-width) solid var(--gt-ring-color);
  outline-offset:var(--gt-ring-gap);
  box-shadow:var(--gt-ring-shadow);
}
/* No justify-content:center anywhere in here. A thread taller than its
   box would be clipped at both ends with no way to scroll back. */

.got-order__msg{
  max-inline-size:88%; padding:.6rem .75rem; border-radius:10px;
  background:var(--card); border:1px solid var(--line);
  font-size:.86rem;
}
/* BUG-104. This comment used to say the bubble sits "inline-start in
   English". It does not, and the code was never wrong: an auto margin
   on the START edge pushes the box to the END edge. The customer's own
   words sit on the inline-END edge — the right in English, the left in
   Arabic — which is where every messaging app puts them. It mirrors on
   its own because the margin is logical, not `left`.
   A comment describing the opposite of the rule beneath it is how the
   next person "fixes" a correct rule. */
.got-order__msg--self{ margin-inline-start:auto; background:var(--card-2); }
.got-order__msg--admin{ border-inline-start:3px solid var(--accent); }
/* BUG-102. toneFor() returns 'other' for a message from the PRO, and
   there was no rule for it — the one bubble the customer cannot place
   was the only unstyled one, while self, admin and system all had a
   treatment. Marked like the admin's but on the amber side, so "someone
   on our side who is not the office" reads as its own voice.
   Amber measures 8.0:1 on --card, and this is a 3px edge rule rather
   than text, so it is comfortable either way. */
.got-order__msg--other{ border-inline-start:3px solid var(--amber); }
.got-order__msg--system{
  max-inline-size:100%; background:transparent; border:0;
  padding-inline:0; color:var(--muted); font-size:var(--gt-text-xs);   /* 6.74:1 on --bg-2; was .8rem = 12.8px */
}

.got-order__msg-head{
  display:flex; justify-content:space-between; align-items:baseline;
  gap:.75rem; flex-wrap:wrap; margin-block-end:.3rem;
}
.got-order__msg-who{ font-weight:650; font-size:.78rem; }
.got-order__msg-head time{ font-size:var(--gt-text-2xs); color:var(--muted); }   /* was .72rem = 11.5px, under the 12px floor */
.got-order__msg-body{ overflow-wrap:anywhere; }

/* Visible to a screen reader, and to nothing else. */
.got-order__sr{
  position:absolute; inline-size:1px; block-size:1px;
  padding:0; margin:-1px; overflow:hidden; white-space:nowrap;
  clip-path:inset(50%); border:0;
}

@media (prefers-reduced-motion:reduce){
  .got-order__textarea, .got-order__select{ transition:none; }
}
/* ============================================================
   The back link's arrow — BUG-097 / GAP-001
   ------------------------------------------------------------
   This was a literal &larr; typed into the Blade. U+2190 is not
   Bidi_Mirrored, so NO browser flips it: the Arabic page drew an
   arrow pointing away from where the link actually goes, which
   is the one thing a directional glyph exists to get right.

   Drawn from CSS instead, with the direction carried by a [dir]
   rule rather than by a character in the markup — so there is no
   hardcoded directional glyph left anywhere in the view, which
   is what GAP-001 names.
   ============================================================ */
.got-order__back a::before{
  content:"\2190";                 /* leftwards arrow */
  display:inline-block;
  margin-inline-end:.4rem;
}
[dir="rtl"] .got-order__back a::before{
  content:"\2192";                 /* rightwards arrow: "back" in Arabic */
}

/* ============================================================
   RTL: the properties that have NO logical form — BUG-096
   ------------------------------------------------------------
   Everything else on this site mirrors on its own, because it is
   written in logical properties. A gradient cannot be: an angle
   and a percentage position are physical by definition. So each
   one needs an explicit [dir="rtl"] override, or the light on
   every button and every hero stays on the left-hand side of a
   right-to-left page — which reads as a rendering fault rather
   than a design.

   BUG-046 filed six of these on the ADMIN side and the public
   side was never swept. This is that sweep: every gradient in
   this file, not only .got-btn--primary, which is the one the
   tester reported. Add a gradient above, add its mirror here.

   The arithmetic, so the next one is not guessed:
     linear-gradient  — mirrored angle is 360deg - angle
     radial-gradient  — mirrored x position is 100% - x

   (The two background-position rules and the drawn tick are the
   other three physical values in this file. Both of those are
   already handled where they are written.)
   ============================================================ */


/* 🔴 BOTH OF THE HERO'S MIRRORS ARE GONE — V-06 Batch 5, 22 Aug, and they are
   DELETED rather than re-aimed because the things they mirrored no longer
   exist and the things that replaced them do not need mirroring.

   `[dir="rtl"] .hero::before` mirrored a two-stop glow painted with
   `background-position` on the section itself. The depth is four positioned
   LAYERS now, each placed with `inset-inline-start` / `inset-inline-end`, so
   the composition mirrors on its own; the gradients INSIDE them are written
   symmetric about their own middle (a centred circle, a 50% midpoint, a mask
   at 50%), so the fill reads the same from either end of the page and there is
   nothing for a mirror to fix. NOT "each one is its own mirror image", which is
   what this said until it was measured: /ar renders no reflected form at all —
   a gradient angle is physical and ignores `direction`, and /ar's pixels are
   /en's to the byte. The symmetry that matters is 180deg ROTATIONAL (invariance
   under reversal, t is t+180), not reflection (t -> 360-t). The corner readings
   for all three of this hero's gradients are beside the layers themselves.

   `[dir="rtl"] .hero h1 .grad` mirrored the headline's clipped gradient text.
   The accent half of the headline is a flat `--accent` now, and a flat fill is
   correct in both directions by construction — the same argument that deleted
   the primary button's mirror below.

   The rule at the top of this section still stands: ADD A GRADIENT ABOVE, ADD
   ITS MIRROR HERE. What this batch shows is the cheaper half of it — a
   gradient written symmetric never joins this list at all, and a rule that
   only fires in the language nobody tests in is the worst kind there is. */

/* ([dir="rtl"] .total is gone with its gradient — 18 Aug.) */

/* 🔴 THE PRIMARY BUTTON'S MIRROR IS GONE, AND SO IS THE GRADIENT IT MIRRORED.

   This rule was `[dir="rtl"] .got-btn--primary{ background:linear-gradient(
   270deg, var(--accent), var(--blue)) }` — BUG-096's fix, and it was correct
   for as long as the button was a gradient.

   The system's primary button is a FLAT accent fill. A flat fill has no light
   end to put on the wrong side, so there is nothing to mirror; the sweep's own
   rule — "add a gradient above, add its mirror here" — has no gradient to
   answer. Leaving the rule would have been worse than useless: it loaded after
   system.css and at (0,2,0) it would have REPAINTED the gradient on the Arabic
   page and nowhere else, which is BUG-096 turned inside out and shipped in one
   language only.

   That is why the flat fill was chosen, incidentally, and it is worth keeping
   beside the deletion: a horizontal gradient needs a direction rule for every
   single caller, and a flat fill is correct in both directions by
   construction. It also gave the focus ring one known colour to be measured
   against, which is how the 1.00:1 finding was possible at all. */

/* ==========================================================================
   Paying for an order — GAP-015
   ==========================================================================

   Logical properties only, like everything else here: the pay pages exist at
   /orders/../pay AND /ar/orders/../pay, and the second one is RTL.

   THE ONE THING THAT IS NOT MIRRORED IS THE ADDRESS ITSELF, and that is
   handled in the Blade with dir="ltr" + <bdi> rather than here. A wallet
   address is an LTR string whatever the page is; left to the bidi algorithm
   it renders with its punctuation and trailing characters reordered, which
   COPIES CORRECTLY AND READS WRONG — every string assertion passes and a
   human sends money somewhere else.
   ------------------------------------------------------------------------ */

.got-pay__methods{ list-style:none; display:flex; flex-direction:column; gap:var(--gt-space-4); }

/* A method the customer can use: raised on the overlay surface with the lift
   and the strong edge, so it is the dominant thing on the page (Omar, Batch 5:
   available methods first and dominant). Radius on the scale (12 was off it). */
.got-pay__method{
  border:1px solid var(--line-2); border-radius:var(--gt-radius-lg);
  padding:var(--gt-space-5) var(--gt-space-6);
  display:flex; flex-direction:column; gap:var(--gt-space-3);
  background:var(--card-2); box-shadow:var(--gt-lift);
}

/* Shown, and plainly not available. Never hidden: a customer who cannot see
   a card option assumes we do not take cards. Never dimmed by opacity either
   (the system forbids it): a dashed edge, no lift, the words in muted. */
/* BUG-344 (19 Aug): the dashed edge reads --line-2 as well, not --line — the
   hair line measured 1.24:1 on the card and an unavailable method's only
   boundary was invisible to low vision. Available and unavailable are still
   two different things: solid + lift + overlay fill against dashed + flat +
   the tag and the muted name. Both boundaries now clear 3:1. */
.got-pay__method--off{ opacity:1; border-style:dashed; border-color:var(--line-2); background:transparent; box-shadow:none; }
.got-pay__method--off .got-pay__method-name{ color:var(--muted); }

.got-pay__method-head{
  display:flex; align-items:center; justify-content:space-between; gap:var(--gt-space-4);
}
.got-pay__method-name{ font-weight:var(--gt-weight-bold); font-size:var(--gt-text-md); }

/* The "not available yet" tag: the micro-label's size and tracking. */
.got-pay__tag{
  font-size:var(--gt-text-3xs); text-transform:uppercase; letter-spacing:var(--gt-tracking-label);
  padding-block:var(--gt-space-1); padding-inline:var(--gt-space-3); border-radius:var(--gt-radius-pill);
  background:var(--bg-2); color:var(--muted);   /* 6.53:1 on --bg-2 and on --card */
  border:1px solid var(--line);
}

/* ---- the transfer page --------------------------------------------------
   Reading order on this card is NETWORK, then the warning, then the address.
   It used to be the warning first, so the page named the mistake before it
   gave the right answer. Moving it did not soften it: same amber, same
   weight, same rule, and still above the address, which is the only thing
   about its position that was ever load-bearing. A wrong-network transfer is
   lost for good, by us and by everybody else, so it is not a footnote. */
.got-pay__warning{
  border-inline-start:3px solid var(--amber);
  background:rgba(var(--warning-rgb),.12);
  padding:.7rem .9rem; border-radius:8px;
  font-size:.88rem; font-weight:600;
  margin-block-end:1.1rem;
}

/* Label + value, kept together and away from the next pair. The grouping is
   layout only — the label itself is .got-order__subhead, which is the site's
   one definition of that style and is not overridden here. */
.got-pay__block{ margin-block-end:1.1rem; }

/* "Step 1 of 2". A sequence marker, not a section label, which is why it is a
   pill rather than more small text: two of them on one page have to read as
   an ordered pair at a glance, in a grid that mirrors under dir="rtl".
   Measured against today's --accent, which config/brand.php owns and this
   file must never name: 10.87:1 on --bg-2 and 10.53:1 on --card. Both numbers
   move if the brand does — BrandPaletteTest is what stops the value being
   copied down here to make the comment permanent. */
.got-pay__step{
  display:inline-block;
  font-size:var(--gt-text-3xs); font-weight:700;   /* was .72rem = 11.5px, under the 12px floor (BUG-342) */
  padding:.2rem .6rem; border-radius:99px;
  background:var(--bg-2); color:var(--accent);
  border:1px solid var(--line-2);
  margin-block-end:.7rem;
}

/* The figure inside a sentence — the lead and the friction gate. It is a
   <bdi dir="ltr"> in the Blade because that is the only way to isolate an
   LTR money run with no element of its own; the weight and the colour are
   here so it reads as the number it is rather than as more prose.
   --text on --card measures 13.86:1, against 6.53:1 for the --muted sentence
   it sits inside. */
.got-pay__money{ font-weight:700; color:var(--text); font-variant-numeric:tabular-nums; }   /* V-30 B3 */
.got-pay__lead{ font-size:.9rem; margin-block-end:1.1rem; }

/* WHAT ELSE THIS ONE TRANSFER PAYS FOR — BUG-259.

   It sits directly under .got-pay__lead and answers the question that lead
   raises on a group claim: why is the figure bigger than the order this page
   is headed with. So it takes the lead's size and gives back the margin the
   lead was holding — one block of prose in two paragraphs, not two blocks.

   NO COLOUR OF ITS OWN. --muted is inherited from .got-order__note, measured
   at 6.53:1 on --card in the comment above; a second value here would be a
   colour scoped to a background nobody re-measured. */
.got-pay__covers{ font-size:.9rem; margin-block-start:-.7rem; margin-block-end:1.1rem; }

/* THE ASSET AND THE CHAIN NAME, INSIDE A SENTENCE. Same job as
   .got-pay__money and deliberately NOT the same rule: that one styles the
   figure, this one only stops a name coming apart.

   `white-space:nowrap` IS THE WHOLE DECLARATION AND IT IS LOAD-BEARING.
   Measured in a real render at 390px, the Arabic <h1> broke "Tron (TRC-20)"
   as `Tron (TRC-` / `20)`, and the friction gate tore it between "Tron" and
   "(TRC-20)" at 1280px as well as at 390px. A chain name split down the
   middle is the one value on this card a customer is meant to compare
   character by character against their own exchange.

   A NON-BREAKING HYPHEN WAS THE OTHER OPTION AND WAS REJECTED. U+2011 changes
   the STRING — config/payments.php, every assertSee, and what a screen reader
   announces — to close one of the two break points and leave the space
   between "Tron" and "(TRC-20)" tearing anyway. This keeps the value
   byte-identical.

   NO COLOUR AND NO WEIGHT HERE ON PURPOSE. Both sentences were re-rendered
   and signed off in this pass; a font change would put that back in play for
   a fix whose whole job is that nothing moves. */
.got-pay__ltr{ white-space:nowrap; font-variant-numeric:tabular-nums; }   /* V-30 B3: the minimum, the asset, the chain — figures in a sentence */

.got-pay__address{ font-size:1rem; margin-block-end:.65rem; }
.got-pay__copy{ font-size:.82rem; padding:.5rem .9rem; }

/* ==========================================================================
   THE FIELD WITH ITS CONTROL ATTACHED — V-35 Batch 3, Omar's D4
   ==========================================================================

   Omar, 6 Sep: «علامة الكوبي ملاصقة للAmount» — the Copy control belongs ON
   the field. It was a separate `.got-btn` BELOW its box, twice (the address
   and the amount), and the box above it was mostly air.

   MEASURED BEFORE, on the rendered page at 1440x900, dark, /en, order 81:
   the address box was 654px wide holding 326.4px of monospace; the button sat
   at y 915.2 against a box ending at 904.8 — 10.4px beneath it, at the
   column's start edge rather than beside the value. The amount box was the
   same 654px holding 127.6px of ink (a 28px figure and a 16px unit), i.e. 80%
   empty. Both numbers are in B3_AUTHOR.md with the after readings beside them.

   WHAT MOVES AND WHAT DOES NOT.

     · The BOX moves out to the wrapper: the border, the fill and the radius
       are declared here, and the value inside gives up its own so there is
       ONE surface rather than a box next to a button. `overflow` is NOT
       hidden — an `outline` is painted outside the border box, and clipping
       the wrapper would eat the copy button's focus ring. The button gets the
       wrapper's radius on its own END corners instead, through the LOGICAL
       corner properties, so it mirrors on /ar with nothing to flip.
     · `inline-size: fit-content` is the second half of the same complaint:
       the box is the width of what is in it, in both directions, so there is
       no empty half and no `text-align` argument to have. `max-inline-size:
       100%` is what keeps it inside the panel on a phone, and the address
       wraps inside its own line under the `overflow-wrap: anywhere` it
       already had.
     · The VALUE is untouched. Same element, same id, same `dir="ltr"` +
       `<bdi>` pair. Nothing here declares `user-select`, so both still
       drag-select, and `copy.js` still reads `#got-pay-address` and
       `#got-pay-amount` — the `execCommand` path, which is the only one that
       works on this plain-http origin.

   THE ROW MIRRORS BY CONSTRUCTION. `.got-pay__field` is a flex row in the
   PAGE's direction (the wrapper carries no `dir` of its own), so on /ar the
   value sits at the right and the control follows it at the left. That is
   also why the corner radii and the divider are written as logical
   properties: there is nothing here for a `[dir]` rule to fix.

   🔴 THE COMPOUND SELECTORS ARE DELIBERATE. `.got-pay__address` (0,1,0) is
   declared ABOVE this block and `.got-pay__amount` BELOW it, so a bare class
   here would win against one and lose to the other — silently, and only in
   one of the two boxes. `.got-pay__field .got-pay__address` (0,2,0) beats
   both wherever either is written. That is the V-35 Batch 1 lesson, taken
   before it could be paid for a second time: *CSS loaded later wins on equal
   specificity, and losing is silent.*

   TOUCH: the control is flush against the field on purpose — an attached
   control, not an adjacent one (ui-ux-pro-max `Touch Spacing` is about two
   ADJACENT TARGETS, and the value beside it is a read-only paragraph). The
   button stretches to the field's height, which is 51.6px at 1440 and more
   wherever the address wraps, so it clears the 44px floor by construction
   rather than by a `min-block-size` that could fall out of step. */
.got-pay__transfer{
  display:flex; flex-wrap:wrap; align-items:flex-start;
  gap:1.1rem 1.25rem; margin-block-end:1.1rem;
}
/* The QR keeps the size system.css gives it and may not be squeezed by the
   column beside it; the column takes the rest and drops UNDER the code when
   the panel cannot hold both. The basis is what decides that — no @media, so
   there is no breakpoint to fall out of step with the grid above. */
.got-pay__transfer > figure{ flex:0 0 auto; }
/* 🔴 THE BASIS IS THE COLUMN'S OWN CONTENT, AND THAT IS THE WHOLE FIX FOR
   BUG-641 (F1, V-35 B3 fix pass, 6 Sep 2026).

   `flex: 1 1 21rem` was a NUMBER standing in for a question, and the number
   was wrong: 21rem is 336px, so the column sat beside the code at any width
   the panel could spare 336px — and the deposit address needs 470px to stay
   on one line. MEASURED on the rendered page before this line changed, at
   1440x900, /en, dark, order 81: the panel's inner width is 654px, the code
   and the row's gap take 228 of it, the column got 426, and the 34-character
   address broke after `…jQ7uEfA` onto a second line. 768 wrapped it too (443.9
   available, 2.7px short of the ink), and 390 made THREE lines of it. The one
   string on this page a customer compares character by character against a
   wallet, broken mid-token at the width the site is looked at.

   `flex-basis: auto` asks the layout engine the question directly: the
   column's flex base size becomes its own max-content width — which IS the
   one-line width of the widest field in it, address length included — so the
   row keeps the code beside the column exactly when there is room for both
   and drops the code above it when there is not. No number to be wrong, and
   it follows a longer address (a BTC one, a different chain) with nothing
   edited. Still no @media, so there is still no breakpoint to fall out of
   step with the grid above.

   MEASURED AFTER, same page, same four widths, both locales, both themes:
   1440 beside=no, one line; 1024 beside=yes (the panel is 704.6 wide there
   because the grid is single-column), one line; 768 beside=no, one line;
   390 beside=no, two lines. The readings are in B3_FIX.md.

   `min-inline-size: 0` stays: it is what lets the column shrink below its
   max-content once it is ON its own line, so a phone gets a 300px column
   rather than a 470px one pushing the page sideways (BUG-621's shape). */
.got-pay__values{ flex:1 1 auto; min-inline-size:0; }
/* A label that FOLLOWS a field stands off it. Written as "after a field"
   rather than "not the first one": the rhythm belongs to the relationship
   between a finished field and the next label, not to a position in a list,
   and a third field added later gets it without this rule being widened.
   MEASURED without it: 10.4px between the address field and "Amount to
   send", against the 21.4px the label already keeps above its own box. */
.got-pay__values .got-pay__field ~ .got-order__subhead{ margin-block-start:1rem; }

.got-pay__field{
  display:flex; align-items:stretch; flex-wrap:nowrap;
  inline-size:fit-content; max-inline-size:100%;
  border:1px solid var(--line-2); border-radius:10px;
  background:var(--bg-2);
  margin-block-end:.65rem;
}
/* The value gives up the box it used to draw for itself. `min-inline-size:0`
   is what lets a 34-character monospace token shrink below its max-content
   instead of pushing the control out of the panel on the side the page cannot
   scroll to (BUG-621's shape). */
.got-pay__field .got-pay__address,
.got-pay__field .got-pay__amount{
  flex:1 1 auto; min-inline-size:0;
  border:0; border-radius:0; background:none;
  margin-block-end:0;
  display:flex; align-items:center;
}
/* THE CONTROL, AND ITS BORDER IS NOT REMOVED — that is the one thing this
   rule must not do. `.got-pay__copy.is-copied` and `.got-pay__copy.is-failed`
   below say what they say by naming the state's colour, which the button's
   own edge then reads (through `--gt-edge-color`; see those rules), so a
   `border: 0` here would have deleted half of the only feedback a copy gives,
   in a way no test on this page can see. It keeps its border and is pulled
   one pixel outward on three sides instead, so the border it already had
   BECOMES the field's edge along the control and the divider on the value's
   side. A negative logical margin, so it mirrors on /ar with nothing to flip.

   Everything else — the quiet fill, the press and THE FOCUS RING — is the
   system's `.got-btn` and is not restated here. The wrapper deliberately does
   not clip: an `outline` is painted outside the border box, and an
   `overflow: hidden` on the field would have eaten this button's ring.

   🔴 `flex-shrink: 1`, AND THE ONE THAT GIVES GROUND FIRST IS THE CONTROL —
   V-35 B3 fix pass, the phone half of BUG-641. It was `flex: 0 0 auto`, so on
   a 300px field the control held its whole 120px label width and left the
   address 148px: MEASURED at 390x844, /en, THREE lines of a 34-character
   address, where the pre-batch page (no control on the row at all) made two.

   With both items able to shrink, flexbox resolves it the way the page needs
   and without a width written down anywhere: the address has
   `min-inline-size: 0` above and can go on wrapping, the control's automatic
   minimum size is its own min-content, so the control gives ground down to
   the width of its longest word and stops, and the address keeps the rest.
   MEASURED at 390 after: /en two lines, /ar two lines — the pre-batch line
   count, with the control still attached. Nothing shrinks at 768 and wider,
   where the field is under its max-content and there is nothing to resolve. */
.got-pay__field .got-pay__copy{
  flex:0 1 auto; align-self:stretch;
  margin-block:-1px; margin-inline:0 -1px;
  border-start-start-radius:0; border-end-start-radius:0;
  border-start-end-radius:10px; border-end-end-radius:10px;
  background:var(--card-2);
}
.got-pay__field .got-pay__copy:hover{ background:var(--card); }
/* 🔴 AND THE PRESS TINT HAD TO COME BACK — F5, V-35 B3 fix pass.
   `.got-btn--quiet:active{ background: var(--gt-press) }` (system.css) is
   what tells a person the control took the press. The two rules above are
   (0,2,0) and (0,3,0) in a stylesheet that loads later, so both out-cascaded
   it and the tint stopped painting on exactly the two controls this batch was
   about — MEASURED with forced pseudo-states, both themes: `:active` read the
   field's `--card-2` and `:hover:active` read `--card`.

   It is restored as a STATE LAYER rather than as a fourth fill, which is the
   technique `.got-btn--secondary:active` already uses for the same reason:
   `background-image` paints over whatever `background-color` the control is
   wearing, so the press darkens the resting fill and the hover fill alike and
   there is no "the copy button but pressed" colour to keep in step with them.
   Written AFTER the hover rule so it wins on source order at equal
   specificity, which is what makes hover+press read as press. */
.got-pay__field .got-pay__copy:active{
  background-image:linear-gradient(var(--gt-press), var(--gt-press));
}
/* The confirmed state, for the ~2s the label is swapped. A colour as well as
   a word, because the swap is the only feedback a copy gives and the word
   alone is easy to miss on a phone. The class is removed by the same timer
   that puts the label back, so the two can never disagree.

   🔴 IT DECLARES THE STATE'S COLOUR AND DOES NOT PAINT A BORDER — BUG-247,
   V-35 B3 fix pass. It used to write `border-color: var(--accent)` here, at
   (0,2,0) in a stylesheet that loads after `.got-btn:focus-visible`'s (0,2,0),
   so it WON while the control was focused: MEASURED, real Tab then focus,
   1440, dark — border `rgb(122,214,255)`, band, outline `rgb(122,214,255)`.
   An accent edge under an accent ring with the page colour between them is
   the doubled stroke, and this state is reachable from the keyboard in two
   presses (Tab to Copy, Enter). The batch's own note called the agreement
   correct; agreement is the DEFINITION of BUG-247, not an argument against it.

   Both invariants hold together only through the token. `--gt-edge-color`
   carries the state colour to the button's own `border-color` declaration
   (system.css, `.got-btn--quiet`, at a specificity the focus rule beats), so
   at rest the edge is the state — BUG-248 — and focused the edge joins the
   band and the ring alone carries the state — BUG-247. One value, two
   strokes, never both at once. Nothing here writes `border-color`, and
   nothing here writes a ring: `.got-btn:focus-visible` already reads
   `--gt-ring-color`, and a second ring recipe on this page is BUG-508. */
.got-pay__copy.is-copied{
  --gt-edge-color: var(--accent);
  --gt-ring-color: var(--gt-edge-color);
  color:var(--accent);
}

/* AND THE STATE THAT SAYS IT DID NOT WORK — new, and the reason it is new is
   that the button used to claim success on an origin where copying is
   impossible. `.got-btn--quiet` is transparent over --card, so both of these
   are measured on --card #171B28: --amber #F59E0B is 7.99:1 there. Amber and
   not --red: the address is still on the screen and still selectable, so this
   is "do it yourself", not "something broke".

   Eight seconds rather than the success state's two — see the script.

   🔴 BUG-248, CLOSED HERE — V-35 Batch 3. This rule painted the border amber
   and left the ring the accent: a control that says one thing with its edge
   and another with its ring, which is BUG-245's shape one component over, and
   `FocusVisibilityTest`'s own "the other way round" sweep named this rule as
   the debt it could not reach (that sweep is system.css only, on the argument
   written beside it — reaching `--gt-edge-color` is what migrating a legacy
   component MEANS).

   IT IS FIXED THROUGH THE SYSTEM'S MECHANISM AND NOT WITH A PARALLEL RING.
   `--gt-edge-color` is declared once and the ring is DEFINED AS it, exactly
   as `.got-field--error` and `.got-btn--destructive` do it in system.css, so
   the two strokes cannot drift: there is only one value. No `:focus-visible`
   rule is written here — `.got-btn:focus-visible` already reads
   `var(--gt-ring-color)`, and a second ring recipe on this page is precisely
   what BUG-508 was.

   🔴 AND THE FIRST VERSION OF THIS RULE ALSO WROTE `border-color:
   var(--gt-edge-color)` HERE, WHICH TURNED BUG-248 INTO BUG-247 — corrected
   in the V-35 B3 fix pass. `.got-pay__copy.is-failed` is (0,2,0) and it sits
   in the sheet that loads AFTER system.css, so it tied with
   `.got-btn:focus-visible` (0,2,0) and won on source order: MEASURED, 1440,
   both locales, both themes — border `rgb(245,158,11)` UNDER an outline
   `rgb(245,158,11)` in dark and `rgb(138,86,0)` under `rgb(138,86,0)` in
   light, with the band between. That is the doubled stroke, and it is why
   `.got-btn--destructive` — which the rule claimed to copy — does NOT paint
   its own border from its state rule: it declares the tokens and lets
   `.got-btn--destructive{border-color:var(--gt-edge-color)}`, at (0,1,0),
   carry them, so the focus rule out-specifies the edge with no exception
   written anywhere. This rule now does the same: the tokens here, the edge on
   the button (`.got-btn--quiet` in system.css, which reads
   `var(--gt-edge-color, var(--gt-line-strong))` for exactly this reason).

   THE SUCCESS STATE IS ANSWERED THE SAME WAY. It was left alone on the
   argument that `--accent` IS the ring's resting colour so the two agree —
   which is the definition of the defect, not a defence against it. It
   declares the tokens now too, above. */
.got-pay__copy.is-failed{
  --gt-edge-color: var(--amber);
  --gt-ring-color: var(--gt-edge-color);
  color:var(--amber);
}
.got-pay__copy-note{
  display:block; font-size:.78rem; margin-block-start:.45rem;
  color:var(--amber);                                     /* 7.99:1 on --card */
}
/* The UA sheet's `[hidden]{display:none}` is one declaration in a lower
   cascade origin and the `display:block` above beats it outright. Without
   this line the note is on the page from the first paint, permanently. */
.got-pay__copy-note[hidden]{ display:none; }

.got-pay__network{
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-weight:700; font-size:1rem;
  color:var(--text);                                    /* 13.86:1 on --card */
}

/* THE AMOUNT BOX. One of only two values on this page that must not be got
   wrong, and until now it was set at body size in the same monospace as the
   network line above it. Given the address's treatment and a size that can be
   read across a room, because a customer checking their wallet app against
   this page is reading two figures, not one.

   Name collision, said out loud: admin.css also has .got-pay__amount,
   for the pro wallet. Different stylesheet, different page, no page loads
   both — and the two rules have now DIVERGED (that one is a green 1.05rem
   line in a Filament card). Neither is a fallback for the other. */
.got-pay__amount{
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-weight:700; font-size:1.75rem; line-height:1.25;
  padding:.6rem .9rem; border-radius:10px;
  background:var(--bg-2); color:var(--text);            /* 14.3:1 on --bg-2 */
  border:1px solid var(--line-2);
}

/* The top-up page's balance figure (19 Aug, M-07) wears the wallet's
   `.got-credit__balance` — and the wallet's figure is a SHRUNK flex item, so
   its dir="ltr" never had a width to be misaligned in. Here it is a block in
   a full-width `.got-pay__block`, and a full-width LTR block puts its text at
   the LEFT edge of an RTL page (the D1 verifier measured it: figure at x 45,
   label «رصيدك» at 306). fit-content gives it no width to be wrong in: the
   box sits at the container's inline-start in both directions. The hook is
   the page's own class beside the system's, so the legacy sheet never names
   a system selector. */
.got-pay__figure{ inline-size:fit-content; }   /* the page's own hook: site.css may not redefine the system's .got-credit__balance (ClientAreaUxTest) */

/* The reference — what the customer quotes when they email us about a
   transfer we cannot find. It was the last line of the card in muted 13px,
   which is where a page puts something it does not expect to be read. */
.got-pay__reference{
  margin-block-start:1.35rem; padding-block-start:1.1rem;
  border-block-start:1px solid var(--line);
}
/* 🔴 QUIETER, AND ONTO A STEP OF THE SCALE — V-42b2 Batch 3, 11 Sep 2026.

   MEASURED on the rendered page: this was `1.05rem`, which lands at 16.8px —
   not a step of anything, and LOUDER than the network value beside it (16px)
   on a page whose two loudest things are supposed to be the address and the
   amount. The reference is a code to quote if something goes wrong, not a
   thing to act on.

   `--gt-text-md` is 14px, the scale's own step, and the weight stays 600 so a
   monospace code is still scannable. It is `--text` and not `--muted`: a
   customer may have to read this over a chat window, and quiet is about
   weight, not about being hard to see (BUG-118's rule). */
.got-pay__refcode{
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-weight:600; font-size:var(--gt-text-md); letter-spacing:.03em;
  color:var(--text); margin-block-end:.4rem;            /* 13.86:1 on --card */
}

/* ---- ON THE ARABIC PAGE, THE VALUE SITS UNDER ITS OWN LABEL --------------
   Each of these four is `dir="ltr"` so its characters come out in the order
   they were typed. That is the protection and it stays. What it ALSO does,
   unasked, is decide the alignment: `text-align` on these boxes resolves
   against the BOX's direction, not the page's, so `start` means LEFT — and on
   the Arabic page the label is at the right while its value strands at the
   far left. MEASURED at 768px, single column: the card is 728px wide, the
   labels start near x=723 and the amount, the address, the network and the
   reference all begin at x=45. Roughly 640px of empty card between a label
   and the thing it names. The pass made it more obvious by turning the amount
   into a full-width bordered panel with a 28px figure alone in the far corner.

   THE FIX IS ALIGNMENT, NEVER `dir`. Dropping or flipping `dir` would reorder
   the characters of a wallet address, which is the unrecoverable mistake this
   whole file is built around.

   There is no logical property for "align to my PARENT's start edge" — the
   same gap `background-position` has, and it is handled the same way, with a
   `[dir="rtl"]` override. `end` here is the box's own end, which for a
   `dir="ltr"` box is the right — the Arabic page's reading edge. The English
   page is untouched: it never enters this block, and `start` is already right
   there. */
[dir="rtl"] .got-pay__network,
[dir="rtl"] .got-pay__address,
[dir="rtl"] .got-pay__amount,
[dir="rtl"] .got-pay__refcode{ text-align:end; }

/* ---- the friction gate --------------------------------------------------
   THIS IS .got-consent's GEOMETRY, FOR .got-consent's REASON, and the comment
   there names the failure it prevents. What went wrong here is that
   .got-pay__gate had `flex:none` on the box and nothing else: `flex:none` is
   `flex:0 0 auto`, so the basis stayed `auto` — which is the `inline-size:100%`
   that `.got-field input` puts on every input in a `.got-field` — and
   `flex-shrink:0` then forbade it shrinking back. Measured at 1400px the
   CHECKBOX was 366px wide and the sentence was a 41px column overflowing the
   card by 38px, one word per line, with the validation error rendering in it.

   Three things fix it, all of them lifted from .got-consent:

     · an explicit inline-size AND block-size on the box. Specificity (0,2,1)
       beats `.got-field input` at (0,1,1) whatever the source order, which is
       what makes this survive somebody moving either rule.
     · flex:1 1 auto and min-inline-size:0 on the TEXT, so the sentence takes
       the rest of the card and wraps like a sentence.
     · cursor:pointer, because the row is a <label> and clicking the words
       toggles the box.

   .got-field input's own 100% is NOT touched. It serves registration, login,
   both password flows, the complaint form and the chat composer — the whole
   auth funnel — and .got-consent solved this exact problem without going near
   it. The error message is a sibling of the label rather than a third child
   of the row, so the one sentence that says why a payment did not go through
   is full width instead of in the 41px column. */
.got-pay__gate-field{ margin-block-start:.25rem; }

/* 🔴 THE SENTENCE THAT ENDED ON AN ORPHAN — V-35 B3, problem 6.
   MEASURED at 1440x900, /en, the gate's label box is 340px and the sentence
   set as "I confirm I sent $11.50 in USDT on the" (254.0px) / "Tron (TRC-20)
   network." (172.2px): a full line and a stub. It is not a bug in the wrap —
   `.got-pay__ltr` holds "Tron (TRC-20)" together with `white-space: nowrap`
   ON PURPOSE (a chain name split down the middle is the one value here a
   customer compares character by character against their exchange), so a
   110px unbreakable run that will not fit at the end of line one MUST go to
   line two whole, and everything before it stays behind.

   `text-wrap: balance` is the answer to the SHAPE rather than to the wrap: it
   asks the layout engine to even the lines out, so the run that has to move
   takes some of the sentence with it. Not a copy change, not a width change,
   and it cannot reorder or re-break the isolate itself.

   AND IT IS SCOPED TO THIS GATE, deliberately. `.got-check__label` is the
   system's consent row and it is worn by registration and by the checkout;
   balancing every consent sentence on the site is a change to pages this
   batch has not rendered, and a fix reaches exactly as far as the instrument
   that found it was aimed. (0,2,0) against the system's (0,1,0), so it wins
   wherever either is written.

   Chrome falls back to `wrap` where `balance` is unsupported, which is the
   line-for-line state that shipped before this batch — so the worst case of
   this declaration is the thing it replaced. */
.got-pay__gate-field .got-check__label{ text-wrap:balance; }

/* ---- THE TWO STEPS AS A PAIR — V-35 B3, problem 4 ----------------------
   MEASURED before this batch at 1440x900: Step 1's card was 764.9 tall and
   Step 2's 567.0 (/en) and 503.0 (/ar), so the page ran on for 197.9px and
   261.9px respectively beside a card that had already ended. Moving the QR
   beside the address (`.got-pay__transfer` above) took most of it — the
   after readings are in B3_AUTHOR.md — and this closes what is left: the two
   cards are one row of equal height, which is what "step 1 and step 2" is.

   🔴 IT IS A MODIFIER AND NOT AN EDIT TO `.got-order__grid`, because that
   grid is also the ORDER PAGE's, where `align-items: start` is load-bearing:
   the right column there holds `.got-order__chat`, which is `position:
   sticky` with a `max-block-size` derived from the viewport (BUG-099), and a
   stretched grid item is not the same box for a sticky child to sit in. This
   batch has not rendered that page, so it does not change it.

   🔴 AND THE SENTENCE THAT STOOD HERE DESCRIBED A COMPOUND THE TREE DOES NOT
   HAVE — corrected in the V-35 B3 fix pass, F4. It read "the compound
   `.got-order__grid.got-order__grid--steps` (0,2,0) beats `.got-order__grid`
   (0,1,0) wherever either is written", which was true of the FIRST version of
   this block and false of the one that shipped: `--steps` never reached the
   markup (see the `:has()` note below, which says why), so the class it named
   appears nowhere in the tree. It was a false comment written inside the
   paragraph that cites Batch 1's lesson about false comments, which is as
   plain a demonstration of that lesson as this round is going to get.

   What is actually written is one line below, and the specificity claim is
   made there against the selector that is really there rather than restated
   here — one place for it, so the next rewording cannot leave two copies
   disagreeing (the "fix one copy of a false sentence and the other survives"
   shape, V-30).

   THE FOOT OF STEP 2 IS ANCHORED so the extra height is spacing and not a
   hole above the button: the panel is a column, the form takes the slack, and
   the submit sits at the card's foot. On a phone the cards are content-height
   and `margin-block-start: auto` resolves to nothing. MEASURED at 390x844,
   both locales and both themes, on both transfer pages: the gate-to-submit
   distance is 14.4px — the spacing the form's own rhythm gives it, with no
   slack pushed in between.

   🔴 THE EARLIER WORDING SAID "the phone layout is byte-identical to what it
   was", AND THAT WAS A CLAIM ABOUT THE WHOLE PAGE MADE FROM A READING OF THIS
   BLOCK. It is not true of the page — this batch changes the phone layout
   elsewhere (the fields, and the address's line count) — and what was actually
   measured was these rules resolving to nothing at that width. Corrected in
   the V-35 B3 fix pass; the 14.4px above is what IS measured, and whether the
   same four rules deleted would give the same number is NOT, because deleting
   them was not run. */
/* 🔴 THE HOOK IS `:has()` AND NOT A MODIFIER CLASS ON THE GRID, AND THAT IS
   A GUARD'S DOING RATHER THAN A PREFERENCE. The first version of this added
   `got-order__grid--steps` to the `<div>`'s class attribute;
   `CryptoPayPageTest::test_the_facts_row_and_the_strip_sit_above_both_steps`
   locates the grid with `strpos($html, 'class="got-order__grid"')` — CLOSING
   QUOTE INCLUDED — and went red on the first run. The guard is reading a
   marker, not a class list, so the marker is left exactly as it was and the
   condition is expressed in the stylesheet instead.

   It reads well as a sentence, which is the second reason to keep it: a grid
   that CONTAINS the submit step is a pair of steps and its two cards are one
   row. `:has()` carries no combinator inside the parentheses on purpose — the
   suite's cascade reader splits a selector on ` > + ~` to find its subject,
   and a `>` inside `:has()` would hand it the wrong one. (0,2,0) against
   `.got-order__grid`'s (0,1,0), so it wins wherever either is written.

   The order page is untouched: nothing in it wears `.got-order__panel--submit`,
   so its `align-items: start` — load-bearing for `.got-order__chat`'s sticky
   box (BUG-099) — is not reached by this rule at all. */
.got-order__grid:has(.got-order__panel--submit){ align-items:stretch; }
/* Step 1 is wrapped in `.got-order__col` (a flex column, because the order
   page stacks several panels in it). Stretching the GRID stretches the
   column, not the card inside it, so the card has to be told to fill —
   MEASURED before this line: the column read 567.0 and the card inside it
   503.3, and the two steps still ended 63.7px apart on the screen. */
.got-order__grid:has(.got-order__panel--submit) .got-order__col > .got-order__panel{ flex:1 1 auto; }
.got-order__panel.got-order__panel--submit{ display:flex; flex-direction:column; }
/* 🔴 AND THE PILL HAD TO BE TOLD NOT TO STRETCH, WHICH IS WHAT MAKING A CARD
   A FLEX COLUMN COSTS. `.got-pay__step` is `display: inline-block` and that
   is enough in normal flow; as a FLEX ITEM the cross-axis default is
   `stretch`, so "Step 2 of 2" ran the full 416px width of the card while
   "Step 1 of 2" stayed a pill — two members of an ordered pair rendered as
   two different objects. Caught by looking at the render, not by a number.
   `align-self` on the item, not `align-items` on the panel: the inputs and
   the submit below it must keep stretching. */
.got-order__panel.got-order__panel--submit > .got-pay__step{ align-self:flex-start; }
.got-order__panel.got-order__panel--submit .got-order__form{ flex:1 1 auto; }
.got-order__panel.got-order__panel--submit .got-order__form .got-btn{ margin-block-start:auto; }

/* MIGRATED to .got-check, same pass as the consent row. The four rules that
   stood here — the row, the box's size (with a THIRD magic nudge,
   `margin-block-start:.28rem`, for the same job the consent row did with
   `.12rem`), the text, and a hand-written `outline:2px solid var(--accent)`
   that could not follow a field's state — are the system's now.

   `.got-pay__gate-field` stays: the error message being a SIBLING of the
   label rather than a third child of the flex row is a decision about this
   page's layout, not about what a checkbox is. */

/* ---- the submit button, switched off until the gate is ticked -----------
   DECORATION, and deliberately so. The attribute is set by JavaScript and is
   never in the markup, so no-JS gets a working button and TWO server-side
   refusals behind it: 'understood' => ['accepted'] in
   OrderPaymentController::submitCrypto(), and CryptoTransferProvider::submit()'s
   own throw, now fed `$request->boolean('understood')` instead of a hardcoded
   `true`.

   This comment said THREE, counting the input's `required`, which is
   client-side and not a refusal at all. It then said three again while the
   real number was ONE — the provider's throw could not fire from that
   controller. Two is the measured number as of BUG-163; the blade beside it
   says the same thing and TransferPagePassTest drives both.

   🔴 THE FOUR DISABLED RULES THAT USED TO BE HERE ARE IN system.css NOW, and
   the specificity argument they carried has gone with the problem it solved.

   They were written as `.got-btn.got-btn--primary:disabled` = (0,3,0) ON
   PURPOSE, to out-specify `[dir="rtl"] .got-btn--primary` (0,2,0) further up
   this file, which would otherwise have repainted the gradient over the
   disabled state on the Arabic page only — "a disabled button that looks
   enabled in one language is worse than no state at all".

   That rule is deleted (see the sweep above): the system's primary button is
   a flat fill and there is no gradient to out-specify. So the disabled state
   is a plain `.got-btn:disabled` in the system, at (0,1,1), reached in both
   languages by the ordinary cascade rather than by an arms race.

   The requirement it named is unchanged and is met there: it has to LOOK
   unavailable and STILL BE READABLE (BUG-066, BUG-118). The system's disabled
   button is --muted on --bg-2, measured at 6.74:1 — better than the 5.89:1
   this rule achieved on --card-2, and it is one rule instead of four. */

/* ---- the file input -----------------------------------------------------
   An unstyled browser default in the middle of a designed form. `.got-field
   input` already gives it the box; what it could not reach is the button the
   browser draws INSIDE that box, which stayed a native grey rectangle with
   its own font. ::file-selector-button is the standard; the -webkit- twin is
   for Safari, which has not shipped the standard name.

   Both are needed and neither is a fallback for the other: a browser that
   understands the standard name ignores the -webkit- rule and vice versa.

   The box rule is written `.got-field input.got-order__input--file` = (0,2,1)
   rather than as a bare class: `.got-field input` is (0,1,1) and would beat a
   single class on padding whatever the order, which is the same specificity
   trap the friction gate above was actually broken by. */
.got-field input.got-order__input--file{
  padding:.4rem .45rem;
  font-size:.84rem; line-height:1.6;
  cursor:pointer;
}
.got-order__input--file::file-selector-button{
  margin:0; margin-inline-end:.7rem;
  padding:.45rem .85rem; border-radius:8px;
  border:1px solid var(--line-2);
  background:var(--card-2); color:var(--text);          /* 12.5:1 on --card-2 */
  font:inherit; font-weight:600;
  cursor:pointer;
  transition:border-color .15s ease, background-color .15s ease;
}
.got-order__input--file::-webkit-file-upload-button{
  margin:0; margin-inline-end:.7rem;
  padding:.45rem .85rem; border-radius:8px;
  border:1px solid var(--line-2);
  background:var(--card-2); color:var(--text);
  font:inherit; font-weight:600;
  cursor:pointer;
}
.got-order__input--file:hover::file-selector-button{ border-color:var(--accent); }

/* 🔴 THE ENHANCED FILE CONTROL LIVES IN `system.css` — V-41d, and it was put
   there by the suite rather than by preference. Written here first, it failed
   `SystemCoverageTest` ("a control shipped that the browser is drawing — give
   it a system class") and `TypeRegisterTest` (two hand-picked sizes in the
   legacy sheet). Both were right: it is an interactive control, and this file
   is not where the design system lives. The rules ABOVE stay here, because
   they style the NATIVE input, which is what a visitor sees when the script
   does not run. See `.got-file` in system.css. */

/* ---- "we are checking it" ----------------------------------------------- */
.got-pay__checking{ border-color:var(--line-2); }
.got-pay__reassure{ font-weight:600; margin-block-end:1rem; }

/* ---- the last attempt, turned down -------------------------------------- */
.got-pay__rejected{ border-inline-start:3px solid var(--amber); margin-block-end:1.25rem; }
.got-pay__reason{ font-weight:600; margin-block-end:.5rem; }

/* ---- the way in, from the order page and the list ----------------------- */
.got-pay__cta{ background:none; border:0; padding:0; margin-block-end:1.25rem; }

/* .got-account__pay — the underlined "Pay for this order" text link under an
   order number in the old table — is gone (18 Aug): on the order cards the
   way in is a system button beside the row (.got-line__actions .got-btn). */

/* ---- the error pages (404, 419) — 17 Aug. They are the site's own pages
   now, not Laravel's default. One block on a page with nothing else on it:
   centred within the reading column, generous vertical rhythm, and the way
   back as a real button. Logical properties throughout, so it mirrors. ---- */
/* The 404 / 419 (Batch 4, 18 Aug): the system's raised card — the one card
   that IS the page — a measure wide, centred, the title at the page-title
   step, the sentence in muted at the body size, the way back a primary
   button. The language mechanism ($errorPage, the alternates) is untouched. */
.got-error{
  max-inline-size:44rem; margin-inline:auto; margin-block:var(--gt-space-10);
  text-align:center;
}
.got-error h1{ font-size:var(--gt-text-2xl); font-weight:var(--gt-weight-heavy); line-height:var(--gt-leading-tight); margin-block-end:var(--gt-space-4); }
.got-error__note{ font-size:var(--gt-text-md); line-height:var(--gt-leading-normal); color:var(--muted); max-inline-size:52ch; margin-inline:auto; }
.got-error__actions{ margin-block-start:var(--gt-space-7); }
