Width is geometry, which is why this page sits beside geometry and beside motion, which takes the ruling about whether a rung animates its own rebuild, rather than in a stage of its own. Three ways to answer a wider screen, read top down, and the point is last. Three rungs, each named by what arrives at it. Twelve distinct widths were counted in the product before a single one of them was called a decision, and three of the twelve turned out to have no name at all.
Read top down. Take the first that works. A point is only permitted once the two above it physically cannot answer, and the audit row has to say what could not. "It is easier to write that way" is not a reason.
1. Fluid, and it is the default
The content stretches by itself. flex-wrap, clamp(),
percentages, minmax(auto-fit). Drag the right edge of the box: nothing here
is told when to wrap.
one rule, no widths named, works at every width including the ones nobody drew
2. Container, and it is the answer for prose
The content could stretch and must not. A line past roughly 75
characters loses the eye on the way back to the start of the next one.
--measure is 46ch, and ch is the width of a zero in
the element's own font, so one number caps an 11px legal line and a 13px paragraph at the
same character count. It said 66ch until 2026-08-12 and 66 was never 66 characters: a zero
in DM Sans is 1.48 average prose advances, so 66ch bought about 98 characters and the cap
that was supposed to land inside the 60 to 75 band landed 30 per cent over it. 46 is
67.5 / 1.48, and swept rather than only derived: the window where every capped
placement sits in the band is 45ch to 48ch. Drag both boxes.
The market price is what people are willing to pay right now, not a forecast anybody published. It moves when the balance of buyers and sellers moves, and the resolution rule beneath it never does. This paragraph is capped at the measure.
max-width: var(--measure) = 46ch = about 66 characters
The market price is what people are willing to pay right now, not a forecast anybody published. It moves when the balance of buyers and sellers moves, and the resolution rule beneath it never does. This paragraph is capped at nothing, which is what 12 elements in the product did until step 4 placed the token.
no cap. At 1440 the worst of them measured 154ch, and it is capped now
3. Point, and there are two kinds of it
A media query asks about the SCREEN and a container query asks about the PLACE, and confusing them is the expensive mistake: a card does not know whether it stands in a one-column feed or in a three-column grid, and on a desktop there are narrow columns too. The shell measures the window; a component measures its own box. Drag this one, and note that the window never changes.
@container (min-width: 420px) - a specimen of the stand: the system declares 0 of these today
container-type is declared by whoever PLACES the component, never by the component itself. A place is not a property of a brick.
A width with no event at it is a width somebody will round. The full argument
lives in components/tokens.css under "the breakpoint ladder"; this is the registry.
The ladder went to rem on 2026-08-13, backlog 135. 40rem, 47.5rem
and 56.25rem are 640, 760 and 900 at the default browser font and move with it: a reader
who set a 24px default reaches the desk at 960 and the rail at 1350, and keeps one column
until then. The stage had kept them in px on the ground that the TYPE was px, which was true and
expired the hour the type moved. 6,300 readings over 105 screens at twenty widths and three
browser defaults: 0 horizontal scroll, 0 readings with anything but exactly one navigation
carrier, and 0 differing readings of 2,100 at the default. The first instrument reported
the rungs not moving, because it set html{font-size} and a length in a media
query resolves against the INITIAL font size and ignores every declaration on the root element.
Only the browser's own default moves both. The 1140 harness stays in px: a docked panel is 220
physical pixels whatever the reader's font is.
A rung is one pixel and it belongs to the wide side. Below a rung is
max-width:639.98px, never max-width:640px: both of those match at
exactly 640, and the rung then renders a page that exists at no other width. That cost this
repository 73 screens for a day. The .98 is not ceremony either, because a
zoomed window reports a fractional width and an integer bound leaves a gap where neither branch
applies.
A breakpoint cannot be a token, and the registry is what replaces one.
@media (min-width: var(--bp)) is invalid CSS: the query is resolved before the
variable cascade, there is no error, the rule simply never fires. There is no build step here to
compile it either. So the literal stays where the browser needs it and the ladder is kept by
being read. That turns the limitation into the instrument: the only possible check is to
read every media query in the product and ask whether its number is on the list above, and
no number may appear that is not.
Three numbers were on no ladder when this page was written,
and two of them are gone. 960 and 1280 hard-coded a column count in all 104 grey
files that the paint computes with auto-fit and no query at all; step 4 deleted both
along with the two-column rule at 640, and neither tree declares a count any more. 1440
stays: it is the grey harness, the twin of 1140 standing at a different number, and a harness is
not the product.
repeat(auto-fit, minmax(min(100%, var(--grid-col-min)), 1fr)).
One rule, one number, no media query anywhere in the pattern. Drag it and watch the
columns appear: nobody wrote 2, 3 or 4.
--grid-col-min: 300px - and the track works at 1100px, which nobody designed for
The min(100%, ...) is the part that makes it safe. Without
it a 300px floor overflows a 360px phone the moment the gutter is counted, which is a horizontal
scroll on the smallest screen caused by a rule written for the largest.
There is no --grid-gap, and that is a decision.
The track gaps at var(--space-16) and the space ladder is already the gap ladder, so
a second name for 16px would be one number with two spellings.
The fork is answered A, and it was answered at 03a rather than here.
This stage decides the FORM of the navigation and never its items, so the three questions are
asked of ia/docs/sitemap.md and the answers are read off it.
| the question | the answer | where it is written |
|---|---|---|
| how many top-level items | four: Events, My Bets, Favorites, Profile | bottom-nav table |
| a second level that must stay visible | no: the categories band rides the sticky header and only on the browse screens | D-desktop-1 |
| side space for new behaviour | no: the audit named 0 new behaviour | section 07 above |
Four items and no permanent second level is branch A, the items move into the header. The product's version of A is the lean header: Events becomes the logo, My Bets and Profile fold into the avatar menu, Favorites and Notifications become icons in the utility cluster, and the balance is the cluster's swap. No rail arrives, and the desktop introduces no destination the phone does not have. It was already built, so step 3 is a proof rather than a design.
| read over 106 painted screens | below 640 | 640 and above |
|---|---|---|
.bottom-nav, computed | painted on 105 of 106 | display:none on all 105 |
.desk-only, 178 elements | none on all 178 | flex on all 178 |
| tab stops inside the bar | 4 | 0 |
Primary (mobile) in the accessibility tree | present | absent |
| header tab stops | 3 | 7 at 640, 8 from 760 |
The swap happens at one pixel, in one direction, and the carrier that leaves leaves the paint, the tab order and the accessibility tree together. A hidden carrier does not linger here, which is the whole reason the check is a Tab walk and not a stylesheet read.
What "exactly one carrier" is actually true of, stated rather than assumed. Below the rung it is bottom nav plus footer on 73 screens and the footer alone on 32; above it, header plus footer on 73 and the footer alone on 32. There is exactly one PRIMARY carrier at every width and there is a footer at every width, and the footer is not a defect: it never changes at a rung and it carries Events and My Bets on all 105. The 32 are the logged-out screens, where the bar and the cluster have nothing to point at.
What the Tab walk found that no stylesheet could: 440 focus stops on
invisible controls, on 88 screens, at every width. All of them are the five links of the
condensed category band. max-height:0 takes a band off the page,
overflow:clip takes it away from the pointer and opacity:0 takes its
ink, and not one of the three touches the tab order. Every one of the five also sits under
aria-hidden="true", so the stop was invisible to the eye and unnamed to a screen
reader at once. visibility is the property that closes it, and it is in both trees
now: 440 to 0 in the paint and 0 in the grey, the band still opening on all 87 grey files,
and the layout control at 0 differing rows of 24, which it had to be, because
visibility reserves the box it hides. The open state is left on purpose: with
.scrolled forced on the band is 54px of visible operable links still calling itself
aria-hidden, and on 48 of the 105 screens it is the only category navigation in
the document. Which way that resolves is a question about the navigation model, and this stage
may not answer it: docs/backlog.md item 118.
Three instrument errors, recorded because each one changed a number. A
rect plus a display walk called a shut dropdown painted 1,752 times, because a
closed <details> puts its children at content-visibility:hidden
where they keep a box and are never rendered; checkVisibility is the only instrument
that caught both that and the opacity:0 band. The first Tab walk was capped at 120
stops and never reached the bottom bar, which sits after the footer in the DOM, so it reported
0 stops in a carrier that has 4: the bar's first stop on the event feed is number 87 of
118. And the harness arrived in the accessibility tree as a fifth landmark, which is the
fifth reading this chrome has entered in this stage. The ghost census itself was wrong
twice before it was right: it first called 1,063 controls ghosts by counting everything invisible,
and display:none is the RIGHT way to hide, because it takes the control out of
the tab order with it. 1,063 became 446, of which 440 were the band. And 18 of the 105 were
hiding behind a modal: a shown <dialog> makes the rest of the document
inert, so the honest pair is 440 on 88 screens now and 525 on 105 the moment a sheet is shut.
The registry holds, and it was checked rather than trusted. Every
@media in components/ read and every number compared against the
ladder: 36 width queries on 2026-08-21, every number on the registry, and 0 in any of the 120
documents in ui-visual/. Three are named one-offs, 560, 620 and 980, and each
carries beside it what collapsing it to the nearest rung would cost in pixels. The total
read 33 on this page for eight days while the source moved four times, to 35, back to 33,
to 37 and down to 36, which is what a number typed on a page nothing recomputes does.
| the measure, at 1440 over 106 screens | before | after |
|---|---|---|
| continuous wrapping text blocks | 775 | 777 |
| over 75ch | 15 | 3 |
.resolution, event-detail.css | 9 at up to 106ch | capped |
.sys-note, state-block.css | 1 at 154ch, the longest line in the product | capped |
.protect-page, notice.css | 2 at 77ch, plus one 117-character line that never wrapped | capped |
.feed-seo, two paragraphs and a dd | 89ch | left: --container-read already decided it |
Step 1 said 38 and the number is 12. That pass measured the element's
BOX, and .related-list li is a flex row of a 46px thumbnail, a question clamped to
two lines and an odds figure: a 106ch box with no 106ch line in it, 27 times, which was 27
of the 38. The corrected filter is the finding, and it lives beside the token: of 775 candidates
it throws out 261 standing on one line, 40 line-clamped, 27 whose child is laid out as a
row, and 3 holding a block of their own. A cap was also written and taken off within the
hour: the walk reported one dd at 89ch and the only dd family the
how-it-works page has is .hiw-faq dd, so the rule went there with a paragraph of
reasoning. Read by ancestor chain rather than by tag name the element is
dd < dl < section.feed-seo, a family already decided and measuring inside its
own rule. A selector is not an identification, and the reverted rule keeps its comment so
the next reader does not repeat it.
The grey tree computes its columns now instead of declaring them, which
closes docs/backlog.md 116. Three rules and two unnamed widths, 960 and 1280, deleted
from all 104 grey files and replaced by the one fluid track the paint already used. Counted in a
browser: painted 1/1/1/1/2/2/2/3/3/4/4 and grey 1/2/2/2/2/2/3/3/4/4/4 from 360 to 1600.
The mechanism agrees and the container does not, which is a different statement from the
one the row opened with: the grey reaches each step earlier because its content column is wider at
the same window and its gap is 10px against the painted 16.
Container thresholds: still none in the product, and the reason is a
measurement rather than a preference. @container and
container-type are 0 in components/, 0 in ui-visual/ and 0
in wireframes/, and 1 each in ui-kit/_page.css, which is the
specimen two paragraphs up: .tk-cq and its one query exist so a reader can drag a box
and watch the third mechanism answer. A container query earns its place when one component stands
in two materially different
slots, because that is the case a media query answers wrongly, and the three families the audit
marked "container" each stand in exactly one place in this product. A container query with one
placement is a media query wearing a different name. The threshold to revisit is the first
component placed in two columns of different widths.
Backlog 129, answered 2026-08-13: still none, and the threshold named above was the wrong test. One component in two columns of different widths is NECESSARY and was read as sufficient: 35 of 45 components fill their container and have no width behaviour at all, and a component with no rule has no branch that can fire wrongly. So the population was taken instead from the queries themselves - 52 selectors inside the 33 width queries of 2026-08-13: 14 are the page frame, the shell or the harness, 2 set a positioning context, 36 are a component in a slot - and the 25 that stand on both sides of their own rung were tested for SEPARABILITY: does any container width divide the placements the way the rung does. 24 of 25 did, so a container query would have resolved identically at every placement on all 105 screens.
What the measurement found instead was the opposite defect and
it was one token. Both page insets STEPPED at DESK 640, --gutter 14 to 40 and
--plate-inset 16 to 28: 38px a side spent at the pixel where the window got one
pixel wider, so the content column went 611 to 560 and the feed card went 577 to 502 and did
not reach 577 again until 715. Nine component rules are keyed to that rung and every one of them
fired on the wrong side of its own box. Both insets ramp now, DESK 640 to DETAIL 760, and the
length is derived rather than chosen: 38px a side has to be spent at no more than half a pixel per
pixel of window, so the ramp cannot be shorter than 76px, and 760 is the next rung on the ladder.
0 geometry readings of 18,660 differ below 640 or at 760 and above.
And the ramp made the first real container-query case this system has ever
had. Separability re-run after the fix reads 22 of 25: taking the discontinuity out of
the column at 640 also took away the thing that let a container threshold stand in for the window
there. .opt-row and .yesno.compact now sit in a container measuring 551
to 570 at 639 and 552 to 571 at 640, so two rows of the same width lay their outcome pair out
completely differently across one pixel. Filed as backlog 145 rather than converted, because
declaring container-type changes what an element's width MEANS and that needs its own
measurement.
Mechanical, by grep, over four corpora, because their fates differ. Taken before a single decision, for the reason this stage exists: an audit without a transcript adds a third breakpoint beside two nobody noticed.
| corpus | @media | @container | fluid | container | fate |
|---|---|---|---|---|---|
components/ the home | 38, 33 about width | 0 | clamp 8, minmax 12, auto-fit 1, flex-wrap 31 | max-width 28, min-width 32, ch 6 | stays |
ui-visual/ the screens | 0 | 0 | 0 | 0 | nothing to move |
ui-kit/ the stand | 11, all in _page.css | 1, with 1 container-type | clamp 10, minmax 13 | max-width 12, ch 15 | not a product rule |
wireframes/ grey | 1,386 in 104 files | 0 | minmax 431, flex-wrap 2,142 | max-width 1,265 | the evidence |
The most expensive trap of this stage is already closed on the painted
side. A screen file may not carry a media query, and the 106 painted screens carry none. The
only width sign in the whole painted tree is 46 percentages, and all 46 sit inside a
style= attribute with values like 88%, 58% and 30%. Those are odds-bar fills,
which is a datum, and a datum is one of the three things the element is allowed to carry.
What is genuinely new: @container and
container-type are 0 in the three corpora that are the product,
components/, ui-visual/ and wireframes/. No component in
this system measures its own place. Every adaptive rule here asks about the window, including the
ones standing inside a column whose width the window does not describe.
The fourth corpus is not 0 and this table said it was until 2026-08-12.
_page.css declares one container-type and one @container,
both of them .tk-cq and its box in section 02, and they were added to this stand on
2026-08-11 by the same step that published this transcript: the grep was taken before the
specimen was written and the number was never re-read. A transcript is a measurement with a
date on it, and the one thing that can invalidate it is the work it was taken for. The claim
it made about the product still holds; the claim it made about all four corpora did not, and the
caption on the specimen itself hedged correctly the whole time, which is how it was found.
Corpus: all 104 grey screens, read against jtbd.md and
cjm-as-is.md. The question is not how to stretch a phone layout but what a wider
screen gives the person in the job they came to do.
| family | n | the job | answer | by what |
|---|---|---|---|---|
| Event feed | 9 | FJ1, find it before the moment passes | WIDER / grid | fluid, no query |
| Category feeds x4 | 32 | FJ1 within a theme | WIDER / grid | fluid + RAIL 900 |
| Favorites | 3 | FJ1 over what was saved | WIDER / grid | fluid |
| Event detail | 13 | FJ2, MVP job 1: why this number | WIDER | DETAIL 760 |
| Active bets | 9 | MJ and FJ5, watch the positions | WIDER | DESK 640 |
| Notifications | 5 | FJ1, do not miss the moment | WIDER / air | container |
| Wallet | 3 | FJ4, what happens to my money | WIDER / air | container |
| Profiles | 7 | SJ2, a record that can be checked | WIDER | fluid |
| How it works | 1 | EJ2, is this a serious place | WIDER / air | container + RAIL 900 |
| Deposit | 7 | FJ3, pay with a card | SAME | the sheet caps at 464 |
| Sign in | 4 | get in | SAME | the sheet caps at 410 |
| Win and loss | 6 | EJ1, SJ1, FJ5, EJ3 | SAME | the sheet caps at 420 |
| System | 5 | 404, 500, maintenance, cookie, toasts | SAME | - |
SAME 22, WIDER 82 of which grid 44, NEW BEHAVIOUR 0.
New behaviour is refused, and not on taste
The product has exactly one list-and-detail pair, and
ia/docs/flows.md says what that pair is for: "Both land on Event Detail, so FJ2
(context before the bet) is preserved for everyone. There is no Feed to bet edge: nothing
bypasses the context screen." Event Detail is not the next screen after the feed, it is a
mandatory context screen, and it carries growth zone 2 from the as-is journey, "explain the
number, tell the story". A split view would halve exactly the screen this product exists to
widen. There is no second pair either: bets, notifications and the wallet have no detail screen
at all.
What the audit found instead: 38 lines that run too long
Measured at 1440 across all 106 painted screens with every dialog open,
counting only text that actually wraps, because a box is not a line. The band
DESIGN.md states is 60 to 75ch.
| n | worst | element | verdict |
|---|---|---|---|
| 27 | 117ch | .related-list p, event detail | defect |
| 9 | 106ch | .rules-panel .resolution | defect, and the loudest |
| 1 | 154ch | .sys-note | defect |
| 1 | 166ch | .protect-page | defect |
| 2 | 89ch | .feed-seo p | already decided, --container-read says why |
The loudest is the 106ch one. .resolution is the named
resolution rule, which is the second design principle of this product written out as a sentence,
and it runs 40 per cent over the measure on the screen where trust is decided.
The argument for rem is real and it is not the one that decides
here. A rung in px reads the window only, so a person who has enlarged their browser font sits at
a desk width with a phone's worth of text in the line. It was measured before it was
believed, root font 16px against 24px, control first.
| 16px root | 24px root | |
|---|---|---|
the control: 10rem measures | 160px | 240px, so rem does respond |
body | 16px | 24px, because nothing sets it |
| heading | 36px | 36px - clamp(28px,4vw,38px) |
| feed prose | 13px | 13px - --text-13 |
| footer legal | 11px | 11px - --text-11 |
The whole type scale is px. Eighteen size tokens are px literals, the
display sizes are clamp() of px and vw, and 222 of the 228 font-size declarations in
this system resolve to a number the user's setting cannot move. So putting the RUNGS in rem while
the TYPE stays in px would be worse than leaving them: the layout would switch at a
different window width for that person while every word on it stayed exactly the same size. A
breakpoint answering a question the product does not ask anywhere else looks like
accessibility and does nothing. The rungs stay px, and the real finding is filed rather than
dressed up: docs/backlog.md item 115.
AND IT WAS ACTED ON, 2026-08-12, SO THIS SECTION IS THE ARGUMENT AND
NOT THE TREE. The type is in rem: ten --text-* steps and eight
--display-* clamps are ratios to the root, the root is the reader's own setting
because nothing sets font-size on html, :root or
body, and every step divides by 16 exactly, so the move measured 0 differing font
sizes of 44,547 readings at the default. At a 24px root the phone page is 38.4 per cent
longer and carries every word, against 0.2 per cent and no extra word the day before.
The rungs stayed px on a different ground than the one above, which is now spent: a rung in
rem finally means what it is meant to mean, and whether it should is a decision nobody has taken,
filed as item 135 rather than smuggled in with the type.
ITEM 135 WAS ANSWERED THE NEXT DAY, 2026-08-13: THE RUNGS ARE IN
rem AND THIS PAGE WENT ON SAYING OTHERWISE FOR EIGHT DAYS. The badge at the top
of this page has read 3 rungs in rem since that day, and the heading of this section read
the rungs are in px underneath it: one document, two answers, and the reader who scrolls
meets them in that order. They are 40rem, 47.5rem and 56.25rem, with the
narrow sides written exactly as 39.99875rem and 47.49875rem so the pair rule still
holds, and the 1140 harness stays in px because a docked panel is 220 physical pixels whatever
the reader's font is. A length in a media query resolves against the INITIAL font size, so
the first instrument built for this measured nothing: it wrote html{font-size:24px}
and reported the rungs not moving. Only the browser's own default setting moves them, and at a
24px default the desk arrives at 960.
Re-run over the whole tree 2026-08-21, and the sweep that closed 135 had
measured 105 screens at the default only. 2,880 renders, 120 documents, three browser
defaults at eight widths each, with the rungs read at their MOVED positions and
pointer:coarse asserted in the page. Four controls first: 10rem gives
160 / 200 / 240, (min-width:56.25rem) is true at 16px and false at 20px in the same
1000px window, the same root twice differs in 0 of 40, and a planted 2000px box takes the
overflow from 0 to 1610.
| at 320, logged out | root 16 | root 20 | root 24 |
|---|---|---|---|
| documents scrolling sideways, of 120 | 0 | 0 | 36 |
.left, the wordmark | 86.09 | 103.61 | 121.14 |
.utility, the cluster | 193.14 | 180.39 | 186.64 |
| its right edge, against 306 | 306.00 | 306.00 | 329.72 |
The cause is the wordmark, and the row's own record says the opposite.
header.css closes its longest comment with the utility landing on 306 exactly
as the proof the fix worked, and it is exact at 16px and at 20px. A row measured to land
exactly on its container has zero slack, and .logo is
--logo-size:var(--text-16), a rem token since backlog 115: the wordmark takes 35px
across the range while the two icon marks sit on the 44px touch floor, which is px and does not
move. The branch that was asserted was the pointer and the one that was not was the root.
Filed as docs/backlog.md 230 and not fixed: choosing what gives way at 320 on a
24px default is a product decision.
A defect lives between the points. Three snapshots at three widths prove three widths, and the worst width is the one where something no longer fits and no rung has fired yet. 320 to 1600 at 40px, 10px within 20 of each rung, one pixel either side of each rung: 50 widths.
| readings | result | |
|---|---|---|
| painted tree, horizontal scroll | 106 x 50 = 5,300 | 0 chasm widths |
| grey tree, horizontal scroll | 104 x 50 = 5,200 | 0 chasm widths |
carriers and .desk-only | 5,250 | 0 disagreements |
The control came first, because 0 is the answer a blind probe gives too. A 2000px block injected into five screens was seen in 20 of 20 readings at 320, 640, 900 and 1600, and only then was the 0 worth reporting. New behaviour, step 5, is answered in the short form: the audit named none, the product has exactly one list-and-detail pair, and Event Detail is a mandatory context screen carrying the growth zone the product exists to serve. A split view would halve exactly the screen this stage widens. A step answered with a reason is an answer.
--plate-inset is the inset INSIDE the two-stone plate, 28px and 16px below the
desk. It exists because --gutter, the gutter OUTSIDE the plate, had been taking
that step alone since the stage shipped: the two are nested, only one of them stepped, and a
360px phone spent 42px a side, 84 of 360, before a card began. The comment beside the
one that stepped read "this is the one responsive token", which was true when it was
written and is exactly the sentence that stops the next reader looking for a second.
Neither steps any more, since 2026-08-13: both are a clamp() ramping from
DESK to DETAIL, because two nested steps taken at one pixel took 76px out of the content column
at the rung, and that column is what every width query above it is really asking about.
--measure,
--grid-col-min, --rail-width and --menu-min exist;
--grid-gap does not, because the space ladder is already the gap ladder, a
column-count token does not, because the track counts, a --sticky-gap does not, for
the same reason as the first, and rem rungs do not, for the reason in section 08. The test
for a name is how many files share the fact: 44 of the 88 layout literals stand in one file
and stay there, and of the 15 shared values only two were one fact.