/* builder.css - the start screen.
 *
 * Traced from "Report Builder 1920x1080.html". The design uses hardcoded hex
 * throughout; every one of them is a token here, and the tokens are the same
 * block the report uses, so the two surfaces are one rebrand rather than two.
 *
 * The design is a fixed 1920x1080 frame. This is not: same proportions, same
 * spacing, but it holds together from a phone to a wide monitor, because the
 * person who paid for a report will open it on whatever they have.
 */

:root{
  --page:#FBFAF7; --card:#FFFFFF; --rail:#F4F2EA;
  --line:#E3DFD3; --line-card:#E0DCD0; --line-head:#E7E3D8;
  --ink:#16181A; --body:#2C3035; --second:#55595E; --muted:#6B6F76;
  --faint:#8A8578; --faintest:#A8A296;
  --green:#1F4D3A; --green-tint:#EBF1ED; --green-dark:#163828;
  --red:#C2544A;
  --row-hover:#F9F7F0;
  --line-ctrl:#DEDACE;
  --scroll:#D6D1C2;
  --serif:'Source Serif 4',Charter,Georgia,'Times New Roman',serif;
  --sans:'IBM Plex Sans',system-ui,-apple-system,'Segoe UI',sans-serif;
  --mono:'IBM Plex Mono',ui-monospace,'SF Mono',Menlo,Consolas,monospace;
}

*{box-sizing:border-box}
body{margin:0;background:var(--page);color:var(--ink);font-family:var(--sans);
font-size:15px;line-height:1.55;-webkit-font-smoothing:antialiased}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-thumb{background:var(--scroll);border-radius:6px;
border:3px solid transparent;background-clip:content-box}

/* ------------------------------------------------------------------ head */
.head{border-bottom:1px solid var(--line);background:var(--rail)}
/* nowrap up here, and it is load bearing. align-items:flex-end was always
   right and was never the problem: the two blocks were on DIFFERENT flex
   lines, so there was no shared baseline to align to. Measured 2026-08-31 on
   a 1920 viewport with real totals: the text wanted 720px, the figures 725px,
   the gap 48px, and the content box is 1464px. 1,493 into 1,464 does not go,
   so the figures wrapped underneath and sat 48px below the paragraph.

   The figures grow with the numbers in them, so this cannot be solved by
   picking widths that happen to fit today: 253,785,350 views is wider than
   0, and a second channel's worth of reports would push it further. The text
   column shrinks instead (min-width:0 lets it, which flex-shrink alone does
   not), and the figures keep their natural width. Below 1180 they stack on
   purpose, which is what the query further down restores. */
.head-in{max-width:1560px;margin:0 auto;padding:34px 48px 30px;display:flex;
align-items:flex-end;gap:48px;flex-wrap:nowrap}
.head-txt{display:flex;flex-direction:column;gap:10px;max-width:720px;
min-width:0;flex:1 1 auto}
.eyebrow{font-family:var(--mono);font-size:12.5px;letter-spacing:.14em;
text-transform:uppercase;color:var(--faint)}
h1{font-family:var(--serif);font-size:42px;line-height:1.1;margin:0;
font-weight:400;color:var(--ink)}
.sub{font-size:17px;line-height:1.55;color:var(--second);text-wrap:pretty;
margin:0}

/* the four figures, with a hairline between each */
.kpi{margin-left:auto;display:flex;align-items:stretch;padding-bottom:6px;
flex:0 0 auto}
.kpi>div{display:flex;flex-direction:column;align-items:center;gap:4px;
padding:0 20px}
.kpi .bar{width:1px;background:#E0DCD0;padding:0}
.kpi b{font-family:var(--mono);font-size:30px;font-weight:500;
letter-spacing:-.01em;color:var(--ink)}
/* text-transform, not typed caps. The four labels used to be written UPPERCASE
   in index.html, which renders identically and reads as shouting to anything
   that is not a browser, including a screen reader. Every other small label on
   this page is sentence case in the markup and uppercased here; these now
   match. */
.kpi i{font-style:normal;font-size:12.5px;color:var(--faint);
letter-spacing:.1em;text-transform:uppercase}

/* ------------------------------------------------------------------ body */
/* 560, not the design's 520: the expectations label and the AI-suggest
   button both need 527px to stay on one line, and a label that wraps mid
   sentence reads as two thoughts. */
.cols{max-width:1560px;margin:0 auto;padding:34px 48px 64px;display:grid;
grid-template-columns:560px minmax(0,1fr);gap:44px;align-items:start}
/* The key step has one card and no right-hand panel, so the grid becomes a
   single centred column rather than a narrow card marooned on the left. */
.cols.one{grid-template-columns:minmax(0,560px);justify-content:center}
/* THE COLUMNS MAY BE NARROWER THAN WHAT IS IN THEM. A grid item's default
   min-width is auto, which is its min-content, and min-content for a keyword
   with no spaces in it is the whole keyword. So one long word anywhere in
   either column set the width of the column, the column set the width of the
   track, and the track set the width of the page.

   Measured 2026-08-30 in headless Edge, a 1,000-character keyword saved in
   ytr_recent and ytr_saved, viewport stepped 320 to 2,560: the single track
   under the 1180 query resolved to 7,406px inside a 310px viewport, the page
   was 7,428px wide, and all 567 widths in the sweep scrolled sideways. At
   10,000 characters the same page measured 76,056px.

   min-width:0 here is what lets the clamps below actually clamp: .chip
   truncates, .note and .kw wrap, and none of them can do anything while an
   ancestor is being sized to hold them whole. minmax(0,1fr) on the stacked
   layout says the same thing about the track itself, which is the other half
   of the same sentence and is cheap to say twice.

   THE FIRST COLUMN ONLY, and that is measured rather than tidy. The second
   column holds the saved-reports table, whose min-content is a real floor:
   three tracks, two gaps and two paddings come to 266px and nothing inside
   it can make that smaller, because .kw already wraps anywhere. Putting
   min-width:0 on that column as well let it shrink past its own floor, and
   at a 320px viewport the card went from 275px to 264px and the OPEN cell
   sat 2px into the padding. Two widths out of 1,681, and mine: the table
   column keeps min-width:auto so it is never squeezed below what it needs,
   which is the behaviour every breakpoint above was measured against. */
.cols>div:first-child{min-width:0}

.card{background:var(--card);border:1px solid var(--line-card);border-radius:6px;
padding:30px 32px}
.field+.field{margin-top:26px}
label{display:block;font-family:var(--mono);font-size:12.5px;letter-spacing:.14em;
text-transform:uppercase;color:var(--faint);margin:0 0 9px}
input[type=text],input[type=search],textarea{width:100%;font:inherit;
font-size:15.5px;color:var(--ink);background:var(--card);
border:1px solid var(--line-ctrl);border-radius:4px;padding:12px 14px}
textarea{min-height:96px;resize:vertical;line-height:1.5}
input::placeholder,textarea::placeholder{color:var(--faintest)}
input:focus,textarea:focus{outline:none;border-color:var(--green)}
.hint{font-size:13.5px;line-height:1.5;color:var(--faint);margin:9px 0 0}
/* "How it works", under the window buttons. A hint that opens something:
   same size and colour as the hint text beside it, underlined so it reads
   as a link, and a real button so it works from the keyboard. */
.hint.how{margin-top:8px}
#howit{border:0;background:none;padding:0;font:inherit;color:var(--faint);
text-decoration:underline;text-underline-offset:3px;cursor:pointer}
#howit:hover{color:var(--ink)}
/* The dialog itself, in the page's own voice: mono eyebrow, serif heading,
   and the four steps drawn as a route down the left, the way the window
   buttons and the report rail already speak. 660px wide so each step sits
   on one line. Step 2 is the filled marker, because the paragraph's whole
   point is that number. */
/* .co-bandbox sets width, padding and shadow later in this file and wins on
   a bare .how-box: the first render came out 420px wide with step 4
   clipped. Two classes, so this rule outranks it. */
.co-bandbox.how-box{position:relative;width:min(660px,100%);max-width:660px;
padding:40px 44px 36px;border:1px solid var(--line-card);border-radius:14px;
background:var(--card);box-shadow:0 24px 60px rgba(20,22,26,.18)}
.how-x{position:absolute;top:14px;right:16px;width:34px;height:34px;border:0;
background:none;font-size:26px;line-height:1;color:var(--faint);cursor:pointer;
border-radius:6px}
.how-x:hover{color:var(--ink);background:var(--rail)}
.how-eyebrow{font-family:var(--mono);font-size:12px;letter-spacing:.16em;
text-transform:uppercase;color:var(--faint)}
.how-head h3{font-family:var(--serif);font-size:30px;font-weight:500;
line-height:1.15;color:var(--ink);margin:8px 0 0}
.how-head::after{content:"";display:block;width:44px;height:2px;
background:var(--green);margin:16px 0 18px}
.how-lede{font-size:16.5px;line-height:1.6;color:var(--body);margin:0}
.how-lede b{color:var(--green);font-weight:600}
.how-steps{list-style:none;margin:26px 0 0;padding:0;position:relative}
.how-steps::before{content:"";position:absolute;left:16px;top:24px;bottom:24px;
width:1px;background:var(--line)}
.how-steps li{display:grid;grid-template-columns:34px 1fr;gap:16px;
align-items:center;padding:11px 0;font-size:16px;line-height:1.45;
color:var(--body);white-space:nowrap}
.how-steps li+li{border-top:1px solid var(--line)}
.how-n{position:relative;width:34px;height:34px;border-radius:50%;
display:inline-flex;align-items:center;justify-content:center;
font-family:var(--serif);font-size:17px;color:var(--green);
background:var(--green-tint);border:1px solid var(--line-ctrl)}
.how-steps li:nth-child(2) .how-n{background:var(--green);color:var(--page);
border-color:var(--green)}
.how-steps li:nth-child(2) span:last-child{color:var(--ink);font-weight:500}
@media (max-width:640px){
  .how-box{padding:28px 22px 24px}
  .how-head h3{font-size:26px}
  .how-steps li{white-space:normal;align-items:start}
}

/* six buttons, two rows of three, one selected */
.wins{display:grid;grid-template-columns:repeat(3,1fr);gap:0;
border:1px solid var(--line-ctrl);border-radius:4px;overflow:hidden}
.wins button{font:inherit;font-size:14.5px;padding:11px 4px;background:var(--card);
color:var(--second);border:0;border-right:1px solid var(--line-ctrl);
border-bottom:1px solid var(--line-ctrl);cursor:pointer}
.wins button:nth-child(3n){border-right:0}
.wins button:nth-child(n+4){border-bottom:0}
.wins button:hover{background:var(--row-hover)}
.wins button.on{background:var(--green);color:var(--page)}

.btn{width:100%;font:inherit;font-size:16px;font-weight:500;padding:15px 16px;
border:0;border-radius:4px;background:var(--green);color:var(--page);
cursor:pointer;margin-top:26px}
.btn:hover{background:var(--green-dark)}
.btn:disabled{opacity:.55;cursor:default}
.btn.quiet{background:var(--card);color:var(--green);
border:1px solid var(--line-ctrl);font-weight:400;font-size:14.5px;
padding:12px 14px;margin-top:0}
.btn.quiet:hover{background:var(--green-tint)}
.btn.quiet:disabled:hover{background:var(--card)}

.recents{margin-top:26px}
.recents .lab{font-family:var(--mono);font-size:12px;letter-spacing:.14em;
text-transform:uppercase;color:var(--faint);margin-bottom:11px}
.chips{display:flex;flex-wrap:wrap;gap:9px}
/* A CHIP IS ONE LINE AND NEVER WIDER THAN ITS ROW. The label is whatever the
   customer typed, and a keyword with no spaces in it does not wrap on its
   own: a flex item's min-width is auto, which is its min-content, which for
   an unbreakable string is the whole string. Measured 2026-08-30 in headless
   Edge with a 1,000-character keyword in ytr_recent, at a 320px viewport:
   the chip alone was 7,406px, .chips 8,225px, and the page 8,247px against a
   310px client width, so the whole layout scrolled sideways at every width
   from 320 to 2,560. min-width:0 lets it shrink; max-width:100% stops it
   claiming a row wider than the column; the ellipsis is what it shrinks to.
   Truncated rather than wrapped because a chip is a control, and a control
   fifty lines tall is not one. The full phrase goes back in the box when it
   is clicked, and the title attribute is app.js's to add. */
.chip{font:inherit;font-size:14px;padding:8px 13px;border-radius:16px;
border:1px solid var(--line-ctrl);background:var(--card);color:var(--second);
cursor:pointer;min-width:0;max-width:100%;overflow:hidden;
text-overflow:ellipsis;white-space:nowrap}
.chip:hover{border-color:var(--green);color:var(--green)}

/* the readings, ticked into the box above. A guide, not a filter. */
.ideas{margin-top:14px;border-top:1px solid var(--line-head);padding-top:14px}
.ideas .hint{margin:0 0 10px}
.idea{display:flex;gap:10px;align-items:flex-start;padding:9px 0;
border-bottom:1px solid var(--line-head);cursor:pointer}
.idea:last-child{border-bottom:0}
.idea input{margin:3px 0 0;flex:none;accent-color:var(--green)}
.idea span{display:flex;flex-direction:column;gap:2px}
/* .idea IS a <label>, so it inherits the field-label rule above: mono,
   uppercase, .14em tracking. That is right for a one-word field label and
   wrong for two lines of prose. Reset it on the label itself rather than on
   the children, so anything added inside it later reads normally too.
   Robert, 2026-08-28: "the font here is all caps? ... that needs to be
   fixed." */
.idea{font-family:var(--sans);text-transform:none;letter-spacing:normal;
color:var(--ink)}
.idea b{font-size:14.5px;font-weight:600;color:var(--ink);line-height:1.4}
.idea i{font-style:normal;font-size:13.5px;line-height:1.5;color:var(--faint)}
.idea:hover b{color:var(--green)}

/* ---------------------------------------------------------- saved reports */
.saved-top{display:flex;align-items:center;gap:18px;flex-wrap:wrap;
margin-bottom:18px}
.saved-top h2{font-family:var(--serif);font-size:27px;font-weight:400;margin:0;
color:var(--ink)}
.saved-tools{margin-left:auto;display:flex;align-items:center;gap:10px;
flex-wrap:wrap}
.saved-tools input{width:220px;min-width:0;padding:9px 13px;font-size:14.5px}
/* flex:none, and it is not cosmetic. .sorts clips its own overflow to keep
   the pill corners, so a squeezed .sorts does not scroll or wrap, it deletes
   its last button. Measured 2026-08-30 at a 900px viewport: the box was 211px
   wide holding 279px of buttons, and A-Z was cut off and unclickable. It now
   holds its width and the search box gives ground instead. */
.sorts{display:flex;gap:0;border:1px solid var(--line-ctrl);border-radius:16px;
overflow:hidden;flex:none}
.sorts button{font:inherit;font-size:13.5px;padding:8px 15px;border:0;
background:var(--card);color:var(--second);cursor:pointer}
.sorts button:hover{background:var(--row-hover)}
.sorts button.on{background:var(--ink);color:var(--page)}

/* container-type, and this is the whole point of the block below. Every rule
   that decides how many columns fit asks THIS BOX how wide it is, not the
   window. The window has never been the number that matters: the card is
   ~644px at a 1280 viewport because it shares the row with a 560px form, and
   it is ~846px at a 900 viewport because at that width the form is above it
   rather than beside it. A viewport breakpoint gets both of those wrong, in
   opposite directions, which is exactly what it was doing.

   overflow is auto rather than hidden so that if a column ever does not fit
   the user gets a scrollbar and can still reach OPEN. Clipping is how the
   reports became unreachable last time; a scrollbar is ugly and recoverable. */
.tbl{border:1px solid var(--line-card);border-radius:6px;overflow:auto;
background:var(--card);container-type:inline-size}
.rowgrid{display:grid;
/* Fixed tracks, each sized to the widest thing its column can actually hold,
   measured 2026-08-30 in the browser: "28 Aug 14:19" is 101px, a ten-figure
   view count is 109px, the COMMENTS heading is 78px, "10 VIDEOS >" is 92px.
   Nothing here shrinks.

   The previous version made every track minmax(0,Npx) so it could give
   ground. It stopped the overflow and produced a worse bug: at a 1280
   viewport every column collapsed to 53px and the table showed "Comme...",
   "148,37..." and "28 Aug...". A view count truncated to its first six digits
   is not a smaller truth, it is a different number. So a column that will not
   fit is REMOVED at a width where it cannot be read, and the ones on screen
   are always complete. See the container queries below for what goes at each
   step down.

   Two later corrections, both measured rather than guessed. WATCHED was 96px
   and "100 VIDEOS ->" measures 98, so a three-digit count clipped by two
   pixels; two pixels is still a partial cell and the whole point here is that
   nothing on screen is ever partial. And the keyword column's floor of 120px
   wrapped "how to fix a sourdough starter that..." to four lines and made the
   row 120px tall. 150 holds the common ones on two.

   Where each track actually runs out, measured 2026-08-30 at 14px IBM Plex
   Mono and again with the font forced to fallback, the wider of the two:
     BUILT     106  holds "28 Aug 14:19" at 100.8. built() never prints a
                    year, so 12 characters is the longest it can be.
     VIDEOS     68  holds 5 figures. The largest run in test/live is 545.
     COMMENTS   78  holds 9 characters, so up to 9,999,999. This is the one
                    track sized from its heading (COMMENTS is 76.4) rather
                    than from its widest value, and it is the only one with a
                    reachable ceiling: 12,345,678 needs 84 and ellipsises.
                    The largest of the thirteen runs in test/live is 51,468,
                    so there is 194x of headroom, and widening it to 88 costs
                    10px at every breakpoint below and pushes a 320px phone
                    under the three-column minimum. Left at 78 deliberately.
     VIEWS     112  holds 13 characters, so ten figures. Largest real run is
                    65,388,529.
     WATCHED   108  holds "100 VIDEOS ->" at 98.
     OPEN       68  holds "OPEN ->" at 49.3. */
grid-template-columns:minmax(150px,1fr) 106px 68px 78px 112px 108px 68px;
gap:14px;padding:13px 20px;align-items:center}

/* Order of sacrifice. BUILT goes first: it is the only column with no sort
   tab behind it, so losing it costs the least. WATCHED and OPEN are links,
   the two ways into a report, and they are the last things to go.

   Every number below is the width the layout BELOW it starts at, which is the
   same thing as the width the layout ABOVE it needs: tracks + gaps + the two
   paddings. They were 816, 696, 576 and 399 and three of the four were wrong,
   because they were all worked out with the 14px gap and 20px padding of the
   full-width grid, and every one of these blocks drops to a 10px gap and 18px
   padding. Measured 2026-08-30 by stepping the card 1px at a time:

     seven columns  150+106+68+78+112+108+68 + 6*14 + 40 = 814   was 817
     without Built  150+ 68+78+112+108+68     + 5*10 + 36 = 670   was 697
     without Views  150+ 68+78+108+68         + 4*10 + 36 = 548   was 577
     without Watch  140+ 68+78+68             + 3*10 + 36 = 420   was 400
     without Vids   100+ 78+68                + 2*10 + 36 = 302   was 341

   Four of the five threw a column away before it stopped fitting: Built by
   3px, Views by 27, Watched by 29 and the narrow keyword floor by 39, which
   costs the reader a column for nothing. The fifth went the other way and was
   a real bug: four columns need 420px of card and the query only stepped down
   at 399, so between 400 and 419 the row overflowed the table. Measured at a
   456px window: 2px of horizontal scrollbar inside the card, and the OPEN
   column sitting hard against the border with none of its 18px padding.

   The value is the minimum itself, not one less. A container query on
   max-width:814px matches at 814.0 and at 813.9 but not at 814.4, so the
   layout above it is only ever used at a width that can hold it, fractional
   widths included. One pixel of the other way and a 814.5px card would try to
   put 814px of columns in it and lose half of one. */
@container (max-width:814px){
  .rowgrid{grid-template-columns:minmax(150px,1fr) 68px 78px 112px 108px 68px;
  gap:10px;padding:13px 18px}
  .rowgrid>.c-built{display:none}
}
@container (max-width:670px){
  .rowgrid{grid-template-columns:minmax(150px,1fr) 68px 78px 108px 68px}
  .rowgrid>.c-views{display:none}
}
@container (max-width:548px){
  .rowgrid{grid-template-columns:minmax(140px,1fr) 68px 78px 68px}
  .rowgrid>.c-watched{display:none}
}
@container (max-width:420px){
  .rowgrid{grid-template-columns:minmax(100px,1fr) 78px 68px}
  /* Videos is the third cell in both the heading row and every data row, and
     unlike the others it carries no class of its own. nth-child, not a class,
     because the data rows are written by app.js and this file cannot add one
     to them. */
  .rowgrid>:nth-child(3){display:none}
}
/* A 320px phone leaves this card 274px of content box. Measured 2026-08-30:
   at the gap and padding above, three columns need 302px, so the last one
   scrolled out of sight. 302, not the 340 this was: same correction as the
   four above, and between 302 and 340 the keyword column now keeps its 100px
   floor instead of dropping to 80. Three columns at this gap and padding need
   80+78+68 + 2*8 + 24 = 266, which a 320px phone has. */
@container (max-width:302px){
  .rowgrid{grid-template-columns:minmax(80px,1fr) 78px 68px;gap:8px;
  padding:12px 12px}
}
.thead{background:var(--rail);border-bottom:1px solid var(--line-head);
font-family:var(--mono);font-size:11.5px;letter-spacing:.1em;
text-transform:uppercase;color:var(--faint)}
.trow{border-bottom:1px solid var(--line-head);font-size:15px}
.trow:last-child{border-bottom:0}
.trow:hover{background:var(--row-hover)}
.trow .kw{color:var(--ink);font-weight:500;overflow-wrap:anywhere}
/* Heading and value share one alignment. They were both nominally right but
   the heading is uppercase mono with .1em tracking, which adds a trailing
   space, so the two never lined up. Centred in the column, header and value
   together. Robert, 2026-08-28: "The text and headings should be in the
   centre of the columns." */
.num{font-family:var(--mono);font-size:14px;font-variant-numeric:tabular-nums;
text-align:center;color:var(--second)}
.thead .num{text-align:center;padding-right:.1em}
.rowgrid>div:last-child{text-align:center}
/* The keyword is the one worth reading in full, so it wraps. The tracks above
   are wide enough that the ellipsis never fires; it is a last resort for a
   figure larger than anything the API has returned, not a layout mechanism. */
.rowgrid>div{min-width:0}
.rowgrid>.num,.rowgrid>.c-built{overflow:hidden;text-overflow:ellipsis;
white-space:nowrap}

.open{font-family:var(--mono);font-size:12px;letter-spacing:.08em;
color:var(--green);text-decoration:none;white-space:nowrap;padding-right:.08em}
.open:hover{text-decoration:underline}
/* The watcher column. WATCHED? is an invitation, not an action they owe us,
   so it sits back until there is something behind it. */
.c-watched{text-align:center}
.dimlink{color:var(--faint)}
.dimlink:hover{color:var(--green)}
.empty{padding:30px 20px;color:var(--faint);font-size:15px;text-align:center}

/* --------------------------------------------------------------- results */
#busy{margin:26px 0 0;padding:13px 16px;border-radius:4px;
background:var(--green-tint);color:var(--green);font-size:14.5px}
#busy[hidden]{display:none}
/* The search summary, and the one other place the keyword is echoed. It is
   PROSE, so it wraps rather than truncating: a sentence cut off at the third
   word is worse than a long word broken across two lines, and the reader has
   to be able to see the whole phrase the search actually ran on.
   overflow-wrap:anywhere and not break-word, because only `anywhere` is
   allowed to shrink min-content, and min-content is what was pushing the
   page: measured 2026-08-30, a 1,000-character keyword put .note at 8,187px
   inside a 310px viewport. */
.note{margin-top:20px;padding:14px 16px;border:1px solid var(--line-card);
border-radius:5px;background:var(--card);font-size:14.5px;color:var(--body);
overflow-wrap:anywhere}

/* Between 1181 and 1500 the two columns are still side by side but the page
   gutters and the 44px gap are eating the only column that can give: the form
   is a fixed 560. 48+48+44 = 140px of whitespace against a 644px table.
   Pulling the gutters back to the 22px this file already uses below 1180 puts
   ~50px into the table, which is the difference between the BUILT column
   surviving at 1366 and the VIEWS column surviving at 1280. */
@media (max-width:1500px){
  .cols{padding-left:22px;padding-right:22px;gap:22px}
  .head-in{padding-left:22px;padding-right:22px}
}
@media (max-width:1180px){
  /* 1fr, NOT minmax(0,1fr), and that is measured. 1fr is minmax(auto,1fr),
     and the auto floor is what keeps this track at the saved table's own
     266px minimum when the viewport has less than that to give. Flooring it
     at 0 instead let the track sit at the available 264px at a 320px
     viewport and put the OPEN cell 2px into the padding, at 2 of the 1,681
     widths swept. The blowout this file had to fix is handled on the grid
     ITEM above, where the unbreakable text actually is, not by taking the
     table's floor away. */
  .cols{grid-template-columns:1fr;gap:34px;padding:26px 22px 56px}
  .head-in{padding:26px 22px 22px;gap:22px;flex-wrap:wrap}
  .kpi{margin-left:0}
  .kpi>div{padding:0 16px}
}
@media (max-width:900px){
  h1{font-size:32px}
  .kpi{flex-wrap:wrap;gap:10px 0}
  .kpi .bar{display:none}
  .kpi>div{padding:0 18px 0 0}
  .card{padding:22px 18px}
  /* No .rowgrid rules here any more. They used to hide three columns and drop
     to a three-track grid at a 900px viewport, where the card is 846px wide
     and every column fits comfortably. Worse, four cells were left in a
     three-track grid, so OPEN wrapped onto a second line under the keyword
     and stopped lining up with any heading. The container queries above do
     this properly. */
  .saved-tools{margin-left:0}
  .saved-tools input{flex:1 1 200px;width:auto}
}

/* ------------------------------------------------------------ empty state */
/* Nothing built yet. The heading above the table already says "No saved
   reports", so a strip of column headings over nothing, plus a search box and
   four sort tabs with nothing to search or sort, is furniture for data that
   does not exist. Both go until there is a row.
   The [hidden] test is what separates the two empty states: app.js unhides
   #none only when a search filtered everything out, and in THAT case the
   table stays, because the user needs the box to clear their query. */
.tbl:has(#rows:empty):has(#none[hidden]){display:none}
.saved-top:has(+ .tbl #rows:empty):has(+ .tbl #none[hidden]) .saved-tools{
display:none}

/* ------------------------------------------------------------------ focus */
/* input:focus above sets outline:none, which on its own leaves a keyboard
   user with a 1px border colour change as the entire focus indicator. The
   ring goes back for keyboard focus only, so clicking into a field still
   looks the way it was drawn. Offsets are negative inside .wins and .sorts
   because both clip their overflow to keep their corners, and a positive
   offset would be cut off. */
input:focus-visible,textarea:focus-visible{outline:2px solid var(--green);
outline-offset:1px}
.btn:focus-visible,.chip:focus-visible,.open:focus-visible{
outline:2px solid var(--green);outline-offset:2px}
.wins button:focus-visible,.sorts button:focus-visible{
outline:2px solid var(--green);outline-offset:-3px}
.wins button.on:focus-visible,.sorts button.on:focus-visible{
outline-color:var(--page)}

/* ------------------------------------------------------------- checkout
   To Report Checkout 2, with every number read out of that file rather than
   judged by eye: a 720px breadcrumb bar, an 800px page, a 16px card padded
   52/56/56, rows on a 22px/1fr/auto grid, and a 34px total.

   One column, top to bottom. Robert, 2026-08-31: "down the page represents
   progression as well." What you searched, what came back, what we caught,
   what it costs, pay. It scrolls on purpose; the 50:50 version it replaces
   put the price beside the decision instead of after it.

   The container is the WRAPPER, not the card. An element cannot answer its
   own container query. */
.co-wrap{position:fixed;inset:0;z-index:60;display:none;overflow-y:auto;
container:cobox / inline-size;color:#14161A;
background-color:#F7F7F4;
background-image:linear-gradient(180deg,rgba(247,247,244,0) 0%,
rgba(247,247,244,.55) 45%,rgba(247,247,244,.92) 100%),
radial-gradient(circle,#D8D6CD 1px,transparent 1.4px);
background-size:auto,26px 26px;
font-variant-numeric:tabular-nums}
.co-wrap.on{display:block}
/* The page behind is locked. .co-wrap is fixed, but the document underneath
   keeps its height and scrolls behind it, which reads as this box scrolling. */
html.co-lock,body.co-lock{overflow:hidden;height:100%}
/* One reset, scoped. h2, h3, h4 and p all still carried browser defaults in
   here: 19px each side of a set title, which is where a fold kept going. */
.co-wrap h2,.co-wrap h3,.co-wrap h4,.co-wrap p,.co-wrap ul{margin:0}

/* the breadcrumb */
.co-top{border-bottom:1px solid #E6E4DD;background:rgba(255,255,255,.72)}
.co-top-in{max-width:720px;margin:0 auto;padding:20px 40px;display:flex;
align-items:center;gap:9px;font-size:14px}
.co-top-in .sep{color:#C9C6BE}
.co-top-in .now{font-weight:500}
.co-top-in .next{color:#6E6B62}
.co-top-in button{border:0;background:none;font:inherit;color:#6B6E75;
cursor:pointer;padding:0}
.co-top-in button:hover{text-decoration:underline}

.co{max-width:800px;margin:0 auto;padding:48px 40px 80px}
.co-card{background:#fff;border:1px solid #E6E4DD;border-radius:16px;
box-shadow:0 1px 2px rgba(20,22,26,.03),0 18px 44px -28px rgba(20,22,26,.16);
padding:52px 56px 56px;display:flex;flex-direction:column;gap:44px}

/* what you searched */
.co-head{display:flex;flex-direction:column;gap:9px}
.co-head .eyebrow{font-size:13px;font-weight:600;letter-spacing:.06em;
text-transform:uppercase;color:#6E6B62}
.co-head h2{font-family:var(--serif);font-size:40px;line-height:1.1;
letter-spacing:-.015em;font-weight:400}
.co-head p{font-size:16.5px;line-height:1.6;color:#55585E;padding-top:4px}

/* what came back */
.co-kpi{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:1px;
background:#E6E4DD;border:1px solid #E6E4DD;border-radius:10px;
overflow:hidden;margin-top:10px}
.co-kpi>div{min-width:0;background:#fff;padding:15px 12px;display:flex;
flex-direction:column;gap:3px;align-items:center;text-align:center}
.co-kpi b{font-size:25px;font-weight:500;letter-spacing:-.02em;color:#14161A}
.co-kpi i{font-style:normal;font-size:13.5px;color:#6B6E75;white-space:nowrap}
.co-kpi>div:nth-child(3),.co-kpi>div:nth-child(4){background:#F4F7F5}
.co-kpi>div:nth-child(3) b,.co-kpi>div:nth-child(4) b{color:#1F4D3A}

/* what we caught */
.co-sets{display:flex;flex-direction:column}
.co-sets>#coopts{margin-top:18px}
.co-intro{font-size:15.5px;line-height:1.65;color:#55585E}
.co-intro p+p{margin-top:10px}
.co-intro b{font-weight:500;color:#14161A}

/* Each row is its own card with a gap between, not a stack of stripes: two
   ticked rows in a row used to merge into one tinted block. Robert,
   2026-09-02: "the rows need to be seperated with a gap between them". */
.co-opt{border:1px solid #EDEBE5;padding:20px 16px;margin:0 -10px;
border-radius:10px;display:grid;grid-template-columns:22px minmax(0,1fr) auto;
gap:20px;align-items:center;cursor:pointer;background:#FFFFFF}
.co-opt+.co-opt{margin-top:10px}
.co-opt.on{background:#F4F7F5;border-color:#CFDDD5}
.co-opt:hover .tick{border-color:#1F4D3A}
/* A CHECKBOX, not a radio. Robert, 2026-09-01: "i prefer the check box its
   clearer and it denots the micro commitment that ive been wanting." It
   still behaves as one of two, because the options are not additive. */
.co-opt .tick{width:20px;height:20px;border-radius:5px;
border:1.5px solid #C9C6BE;background:#fff;position:relative}
.co-opt.on .tick{border-color:#1F4D3A;background:#1F4D3A}
.co-opt.on .tick:after{content:"";position:absolute;left:6.5px;top:3px;
width:5px;height:9px;border:solid #fff;border-width:0 2px 2px 0;
transform:rotate(45deg)}
/* 15px, not 15.5: Robert's longest heading is 71 characters and it broke
   onto a second line at 15.5. Measured 2026-09-02. */
.co-opt h4{font-size:15px;font-weight:600;line-height:1.35;color:#14161A}
.co-opt.on h4{color:#14161A}
.co-opt p{font-size:13.5px;color:#6B6E75;margin-top:4px;line-height:1.5}
.co-opt .cnt{font-size:17px;font-weight:500;white-space:nowrap;color:#14161A}

/* "Total" stacks over the GST line on the left; the price aligns to the
   bottom, so it shares the GST line's row rather than floating above it.
   Robert, 2026-09-02. */
.co-total{border-top:1px solid #EDEBE5;padding:24px 2px 0;display:flex;
align-items:flex-end;justify-content:space-between;gap:20px}
.co-total .labs{display:flex;flex-direction:column}
.co-total .lab{font-size:17px;font-weight:600}
.co-total .amt{display:flex;align-items:baseline;gap:9px}
.co-total .amt b{font-size:34px;font-weight:500;letter-spacing:-.025em;
line-height:1}
.co-total .amt i{font-style:normal;font-size:14px;color:#6B6E75}

/* under the total: the GST line and the way into the price table */
.co-totalsub{padding:8px 2px 0;font-size:13px;color:#6B6E75}

/* The way into the price table sits above the choice, where they are still
   deciding, rather than beside the pay button where they are committing. */
.co-pricelink{margin-top:10px}
.co-pricelink button{border:0;background:none;padding:0;font:inherit;
font-size:13.5px;color:#1F4D3A;cursor:pointer;text-decoration:underline;
text-underline-offset:2px}
.co-pricelink button:hover{color:#14161A}

/* the price table */
.co-bandwrap{position:fixed;inset:0;z-index:70;display:none;
align-items:center;justify-content:center;padding:24px;
background:rgba(20,22,26,.34)}
.co-bandwrap.on{display:flex}
.co-bandbox{background:#fff;border:1px solid #E6E4DD;border-radius:14px;
box-shadow:0 18px 44px -18px rgba(20,22,26,.3);width:min(420px,100%);
max-height:86vh;overflow-y:auto;padding:22px 24px 24px}
.co-bandtop{display:flex;align-items:center;justify-content:space-between;
gap:16px;margin-bottom:14px}
.co-bandtop h3{font-size:17px;font-weight:600;color:#14161A}
.co-bandsub{font-size:13px;color:#6B6E75;margin-top:3px}
.co-bandtop button{border:0;background:none;font-size:24px;line-height:1;
color:#8A8578;cursor:pointer;padding:0 2px}
.co-bandtop button:hover{color:#14161A}
/* Three columns: the range, the tag, the price. The tag used to be appended
   to the range and sat hard against it. A column of its own centres it and
   keeps the ranges and prices from shifting when one row is tagged. */
.co-band{display:grid;grid-template-columns:auto minmax(0,1fr) auto;
align-items:baseline;gap:10px;padding:10px 10px;border-radius:7px;
font-size:14.5px;color:#55585E}
.co-band+.co-band{border-top:1px solid #EDEBE5}
.co-band b{font-weight:500;color:#14161A;font-variant-numeric:tabular-nums}
.co-band.here{background:#F4F7F5;color:#14161A;border-top-color:transparent}
.co-band.here b{color:#1F4D3A}
.co-band .you{font-size:11.5px;font-weight:600;letter-spacing:.06em;
text-transform:uppercase;color:#1F4D3A;text-align:center;white-space:nowrap}
.co-band.over{color:#8A8578}

/* pay */
.co-payblock{display:flex;flex-direction:column;gap:14px}
.co-payhead{display:flex;align-items:center;justify-content:space-between;
gap:12px}
.co-payhead .lab{font-size:13px;font-weight:600;letter-spacing:.06em;
text-transform:uppercase;color:#6E6B62}
.co-payhead .brands{display:flex;gap:6px;align-items:center}
.co-cardfail{color:var(--red);font-size:13.5px;line-height:1.5}
.co-cardfail:empty{display:none}
/* 5px on top of the block gap. Robert, 2026-09-01: "its just a tiny bit
   too close to the field above it". */
.co-btn{display:block;width:100%;margin-top:5px;padding:15px;border:0;
border-radius:8px;
background:#1F4D3A;color:#fff;font:inherit;font-size:16px;font-weight:500;
cursor:pointer}
.co-btn:hover{background:#193F2F}
.co-btn[disabled]{background:#C9C6BE;cursor:not-allowed}
/* The padlock sits ON the line, not above it, so the row is centred as a
   whole rather than the text being centred around a floating icon. */
.co-fine{font-size:13px;color:#6B6E75;line-height:1.5;display:flex;
align-items:center;justify-content:center;gap:6px}
.co-fine svg{flex:none;opacity:.75}
.co-fine b{font-weight:500;color:#14161A}

@container cobox (max-width:700px){
  .co{padding:26px 16px 56px}
  .co-card{padding:28px 22px 30px;gap:30px;border-radius:12px}
  .co-head h2{font-size:30px}
  .co-kpi{grid-template-columns:repeat(2,minmax(0,1fr))}
  .co-top-in{padding:16px 18px}
  .co-opt{gap:14px;padding:18px 8px}
}

/* the working popup */
.co-mask{position:fixed;inset:0;background:rgba(251,250,247,.93);
display:none;align-items:center;justify-content:center;z-index:5}
.co-mask.on{display:flex}
.co-work{background:var(--card);border:1px solid var(--line-card);
border-radius:9px;padding:30px 34px;width:min(440px,86vw);text-align:center;
box-shadow:0 8px 34px rgba(22,24,26,.10)}
.co-work h3{font-family:var(--serif);font-size:22px;font-weight:400;
color:var(--ink)}
.co-work .step{font-size:13.5px;color:var(--second);margin-top:9px;
min-height:19px}
.co-work .eta{font-family:var(--mono);font-size:31px;color:var(--green);
margin-top:14px;line-height:1}
.co-bar{height:5px;border-radius:3px;background:var(--line);margin-top:16px;
overflow:hidden}
.co-bar i{display:block;height:100%;width:0;background:var(--green);
transition:width .35s ease}
.co-work .fail{color:var(--red);font-size:13.5px;margin-top:12px;
text-align:left;line-height:1.5}

/* ------------------------------------------- phones, measured on devices */
/* Every rule below comes from the device sweep of 2026-09-02
   (test/mobile/sweep.js): iPhone 16 at 320 CSS px (Display Zoom on) through
   iPad Pro, on WebKit for Apple and Chromium for Android, real device
   descriptors with their own pixel ratio, user agent and touch. Desktop is
   untouched: these fire on width, or on a coarse pointer (a finger). */
@media (max-width:1180px){
  /* The four figures are a flex item with flex:0 0 auto, so their basis is
     their own max-content width (515px once the views read 15,819,214) and
     they never shrank: at 320 the page scrolled 217px sideways and the strip
     ran off the hero band. Full width lets the wrap rule at 900 do its job. */
  .kpi{flex:1 1 100%;max-width:100%;min-width:0}
}
@media (max-width:640px){
  /* The breadcrumb broke inside its phrases ("Confirm what gets / read").
     Each crumb is one word-group now and the row wraps between them. */
  .co-top-in{flex-wrap:wrap;row-gap:2px}
  .co-top-in>*{white-space:nowrap}
  /* "videos you're keeping" was cut to "ideos you're keepin": nowrap inside
     a minmax(0,1fr) cell of the two-column grid at 320. */
  .co-kpi i{white-space:normal}
  /* YOUR REPORT sat on top of the $11 and ran out of the dialog. */
  .co-band{align-items:center}
  .co-band .you{white-space:normal;font-size:10.5px;line-height:1.2}
  .co-bandbox{padding:18px 16px 18px}
  /* "AUD, one-off" broke into three lines at 320, one of them at the
     hyphen. The price keeps its width; the GST line wraps instead. */
  .co-total .amt{flex:none}
  .co-total .amt i{white-space:nowrap}
}
@media (pointer:coarse){
  /* iOS zooms the page into any field under 16px when it is focused, and
     leaves it zoomed. 15.5 and 14.5 on a mouse; a finger gets 16. */
  #topic,#exclude,#expect,#find,#key{font-size:16px}
  /* Tap targets. The visible text does not move: the padding grows the hit
     area and the negative margin hands the same space back to the layout.
     Measured before: How it works 78x20, OPEN 49x15, Search 43x22,
     How our prices are calculated 180x21, the dialog's close 18x24. */
  #howit{padding:10px 0;margin:-10px 0}
  .open{display:inline-block;padding:12px 6px;margin:-12px -6px}
  .co-top-in button{padding:10px 8px;margin:-10px -8px}
  #cobands{padding:10px 0;margin:-10px 0}
  .co-bandtop button{padding:8px 10px;margin:-8px -10px}
}
