/* ---------------------------------------------------------------------------
   The home screen, and the chrome that only it uses.

   Kept out of app.css for one reason that is not taste: app.css was at 390 lines against
   a 500-line ceiling, and the home screen is 200 of its own. Two files also mean the
   working screen — filters, results, reader, assistant — does not pay for this one in
   parse time on every navigation.
   --------------------------------------------------------------------------- */

/* Hero.

   WHAT IS IN THIS PHOTOGRAPH, AND WHY IT IS ALLOWED TO BE.

   `banner.jpg` was supplied by the owner of the project on 2026-09-11 and shows, from
   left to right: a city skyline at sunrise, a government building flying the national
   flag, a gavel, a pair of scales, and law books — one of them carrying the state emblem
   on its cover.

   docs/54 principle 5 forbids dressing as an authority, and its first 2026-09-11
   amendment still listed "no seals, no state emblem, no gavel or scales iconography" as
   absolutes. Three of those are in this image, so the contradiction was raised with the
   owner rather than edited away, and the owner confirmed the image. Principle 5 now reads
   as a test instead of a list: **would a reader take this as a claim that we are the
   issuing body?** A gavel as the site's *mark* fails it; a gavel inside a photograph of
   books and a skyline is subject matter and asserts nothing about the publisher. The
   wordmark stays a letter in a box, and the footer disclaimer — required by doc 00, at
   full size on every page — is what carries the claim in words.

   Two background layers: the photograph, and a scrim that fades the page ground across it
   from the left so the title has something to stand on.

   There were three. The blossom branch from the mockup's top-left corner was the first,
   composited with `multiply` on the theory that its cream ground would disappear into
   the page's. Measured on screen it did not: the two creams are a shade apart, so the
   crop stood there as a 275px rectangle with a hard vertical edge running down through
   the first letter of the title. That layer is gone; `img/blossom.jpg` stays in the tree
   in case a version with a real alpha channel ever arrives. */
/* No measure and no gutter of its own: the band supplies both to all three of its
   children now, so anything declared here would be a second inset on top of the first.
   It carried `max-width:1560px;margin:0 auto;padding:0 16px 0 64px` until the band was
   capped — and that 64px, copied off the mockup where the hero text is inset further than
   the cards, was measured at 1600px putting the title at x=77 while every card below it
   and the footer brand sat at x=29. */
.hero{padding:0}
/* 44px is a ninth step on a scale that was closed at 34, and it is added for exactly one
   element. 34px was sized for a heading standing on the page ground; this one stands on
   a 300px photograph, and at 34 it was the smallest thing in the band. It steps down the
   existing scale — 44 · 34 · 24 — rather than sliding on a clamp(), because a size that
   is different at every width is not on a scale at all. */
.hero h1{margin:0 0 12px;font-size:44px;line-height:1.14;letter-spacing:-.02em;
  font-weight:700;color:var(--head)}
/* Inline since 2026-09-20. It was `display:block`, which forced "Việt Nam" onto a line of
   its own at every width; the design supplied that day sets the title on one line, and at
   44px it still wraps there by itself on a narrow window — which is the break the old
   rule was imitating. All the <b> does now is colour the last two words. */
.hero h1 b{color:var(--accent);font-weight:700}

/* 58ch, and the number is measured rather than chosen. The sentence is one sentence —
   72 characters, 498px at 15px, which is 55ch in this face — so every cap below that was
   breaking it for no reason and every break was in the wrong place: 34ch left "lý" alone
   on line two, 44ch split "ngôn ngữ" across lines. 58 gives it the one line it wants with
   slack for a translation, and still wraps rather than overflowing on a narrow screen. */
.hero p{margin:0;color:var(--muted);font-size:15px;max-width:58ch;line-height:1.6}
/* `--sky` — the page ground as raw channels, so the scrim can be taken at four alphas —
   is declared in app.css, not here. It moved on 2026-09-12, when the document page grew a
   hero band of its own: those pages load app.css and doc.css and never this file, so a
   token defined here would have left the scrim transparent and the title sitting on an
   unwashed photograph. Same failure as `.themer` before it moved. */
/* `center 46%`, not `right center`. The crop this replaced was 516px wide and had to be
   pinned to the right edge to show anything at all; `banner.jpg` is 2030×775 and `cover`
   scales it by width at every aspect wider than 2.62:1, so the horizontal keyword does
   nothing here and the vertical one does all the work.

   The band grows with the window, and that number comes from the picture rather than from
   taste. `banner.jpg` is 2.62:1 and `cover` scales it by width at every aspect wider than
   that, so the band shows a horizontal slice whose height is fixed by the content while
   the image gets taller and taller: at 1284px it has 60px to spare, at 1600px it is 17px
   short, and at 2140px — a not unusual desktop — it is **147px short** and cuts the top
   off the scales and the bottom off the gavel.
   The subjects sit between y=210 and y=700 of 775 in the source, which is 63% of its
   height, so the band needs `0.63 × width / 2.62` to hold them. That used to be `24vw`,
   because the band was full-bleed and grew without limit; capped at 1560 it is a constant
   — and the width in that sum is the **border** box, 1560, not the 1528 content box,
   because `background-clip` is at its default and the photograph fills the padding too:
   0.63 × 1560 / 2.62 = **376px**. `min-height` rather than `height`, so on any window
   where the content is taller than that — every window under about 1100px — it does
   nothing. */
/* The band *is* the panel, and it is sized to the cards below it — `calc(100% - 32px)`
   capped at 1528, the measure `#home` gives the grid. The band, the rule above it and
   every card share one pair of vertical edges, which is the answer the owner asked for on
   2026-09-12 looking at the home screen: the photograph's right edge stops where the
   column under it stops.

   It was the 1560 measure — the topbar's — until then, on the argument that the band's
   nearest neighbour is the rule above it rather than the cards a gap below. That argument
   is still true and it is now satisfied from the other direction: the rule was trimmed to
   1528 to meet the band (see `.topbar` below), instead of the band widened to meet it.

   Two things this went through, both worth not repeating:

   It was first built as a 1560 band with `padding:40px 16px 26px` and
   `background-clip:content-box`, so the photograph stopped where the padding ended. The
   edges landed where intended and the corners came out **square** — an inner box's radius
   is the outer radius minus the padding on that side, so 12−16 and 12−40 are both ≤ 0.
   Any padding at least as large as the radius squares the corner off, and no amount of
   `border-radius` can show through a content-box clip. Sizing the band to the picture
   instead means the radius applies to the painted edge itself.

   Then it was sized to the cards, then to the topbar, and now to the cards again — the
   loop above records why, so the next pass does not reopen it. */
header:has(.hero:not([hidden])) .searchband{
  width:calc(100% - 32px);max-width:1528px;margin:0 auto;
  /* No horizontal padding, and that is the whole of the width change made on 2026-09-12.
     The band used to be the 1560 measure with 16px of padding: the photograph painted out
     to the rule above it while the title, the pill and the chips sat 16px in, on the
     cards' left edge. Shrinking the box by that same 32px and dropping the padding leaves
     every child exactly where it was and pulls the painted edge in to the cards' edge, so
     the picture's right edge and the column below it end on the same pixel. */
  padding:40px 0 26px;
  /* 0.63 × 1528 / 2.62 — the same sum as before against the band's new border box. */
  min-height:367px;
  border-radius:12px;
  display:flex;flex-direction:column;justify-content:center;
  /* The left is the page ground, not a tint of it. The scrim used to reach full opacity at
     24% and let the photograph through from about a third of the way across, which put the
     title on a lit sky; the words are the point of this half, so the wash now holds solid
     to 32% and does not start clearing until 46%. The picture keeps the right half, where
     nothing is set on it. */
  background:
    linear-gradient(94deg,rgb(var(--sky)) 0%,rgb(var(--sky)) 32%,rgba(var(--sky),.88) 46%,
      rgba(var(--sky),.28) 64%,rgba(var(--sky),0) 78%),
    url(/img/banner.jpg) center 46%/cover no-repeat}
/* A guard, kept after the bug it was written for was designed away. A flex item with an
   auto cross-axis margin is **not** stretched — the spec stretches only when neither cross
   margin is auto — so while the three children still carried `margin:0 auto` they
   shrink-wrapped to their own content and then centred that: measured at 2140px, the title
   sat at x=838 instead of x=354, in the middle of the band and on the brightest part of
   the photograph. They no longer carry auto margins, so this is redundant today; it costs
   one declaration and it is what stops the next `margin:0 auto` from doing it again. */
header:has(.hero:not([hidden])) .searchband>*{width:100%}
/* The header cannot be sticky while it is 300px of photograph: pinned, the hero would
   own the top third of the screen for the whole page. It is sticky only on the working
   screen, where it is a 44px bar over a search box.

   It is also not a panel here. app.css paints every header `--panel` over the full
   viewport and closes it with a border: on the working screen that is a white bar holding
   a search box, which is what it is. On this screen the header holds a rounded band with
   its own photograph, so the panel showed up as two white margins either side of the band
   and a full-bleed rule under it — a strip of a different ground than the cards three
   pixels below, which is what the owner saw on 2026-09-12. `--bg` puts the gutters beside
   the band on the same ground as the rest of the page.

   The closing rule stays — it was dropped with the panel in the first pass and the owner
   asked for it back the same minute — but it can no longer be the header's own border,
   which ran the full width of the window. It is drawn as the header's own last line box
   instead, on the band's measure, so it starts and ends where the band and the cards do. */
header:has(.hero:not([hidden])){position:static;background:var(--bg);border-bottom:0}
/* THE RULES END IN A FADE, AND THE NUMBER IN IT IS THE CORNER RADIUS.

   Cut to 1528 the two rules still overhung, by a few pixels at each end and only at the
   ends — because the thing they are meant to be flush with is not a rectangle. The band
   and the cards carry `border-radius:12px`, so their painted edge leaves the vertical at
   12px from the corner and curves away; a straight line drawn to the full 1528 runs past
   that curve into empty ground, which is what the owner saw as the line "lòi ra" once the
   widths already matched.

   Shortening both lines by 12px a side is the other answer and it trades one artefact for
   another: the line then stops dead 12px short while the card's edge below it is still
   heading out to the corner, and at that scale a hard end reads as a mistake too. Fading
   instead spends exactly the radius — opaque from 12px to width−12px, out to nothing at
   each end — so the rule is at full strength wherever there is a straight edge under it
   and gone by the point where the curve has left. */
header:has(.hero:not([hidden]))::after{content:"";display:block;height:1px;
  width:calc(100% - 32px);max-width:1528px;margin:0 auto;
  background:linear-gradient(90deg,transparent 0,var(--line) 12px,
    var(--line) calc(100% - 12px),transparent 100%)}
/* The rule above the band, cut to the band. `.topbar` takes the 1560 measure with a 16px
   gutter, so its bottom border ran 16px past the band on each side — visible the moment
   the header stopped being a white panel, because the line then had nothing to be the
   edge of. Same trick as the band: take 32px off the box and drop the padding, so the
   wordmark and the badges do not move and only the border's ends come in.
   The border itself goes: a border cannot fade, so the line is painted as a 1px strip of
   the same gradient as the rule below, laid on the bottom edge of the box. `.topbar` is a
   flex container, so this cannot be an `::after` — that would be a fourth flex item. */
/* `14px` top and bottom, not 8, since 2026-09-20 — the same pair `.topbar` and
   `.doc-page header .wrap` carry. At 8 the wordmark sat at y=12 on the home screen and
   y=18 everywhere else and the bar stood 54px tall against 66, so crossing from the home
   screen into a document dropped the whole bar 6px and pushed the page under it down 12.
   The horizontal 0 is the width trick above, not a measure: 32px off the box with no
   padding puts the wordmark at x=29, which is where the 1560 bar's 16px gutter puts it. */
header:has(.hero:not([hidden])) .topbar{width:calc(100% - 32px);max-width:1528px;
  padding:14px 0;border-bottom:0;
  background-image:linear-gradient(90deg,transparent 0,var(--line) 12px,
    var(--line) calc(100% - 12px),transparent 100%);
  background-size:100% 1px;background-position:bottom;background-repeat:no-repeat}
header:has(.hero:not([hidden])) #search-form{margin:28px 0 0;padding:0}
/* The cap is on the wrapper, not on the pill. They used to be the same element; now the
   dropdown is the pill's sibling inside `.searchbox`, and a cap left on the pill alone
   sized the field to 700px while the list under it stayed 840 — a list wider than the box
   it belongs to, which is the one shape that makes the two read as separate controls. */
header:has(.hero:not([hidden])) .searchbox{max-width:700px}
header:has(.hero:not([hidden])) .searchpill{padding:4px 4px 4px 16px;
  box-shadow:0 2px 4px rgba(22,36,63,.06),0 12px 32px rgba(22,36,63,.1)}
/* 16, because iOS Safari zooms the page when a field under 16px takes focus. The
   placeholder is 66 characters — it is the one sentence on the home screen that tells a
   reader unaccented input is fine — and it was cut inside the 700px pill at 15px, so check
   that it still fits when this changes. */
header:has(.hero:not([hidden])) .searchpill input[type=search]{font-size:16px;padding:9px 0}
header:has(.hero:not([hidden])) .searchpill button{padding:9px 20px}
/* The date qualifier sits beside the pill again, and the reason it once did not has gone.
   It was given its own full-width line when the whole form was capped at 760px: sharing
   that row left 412px for the search box and cut the placeholder at "có dấu hoặc", on the
   one screen where the reader has nothing else to go on. The form is the page's measure
   now and the pill caps itself at 700, so there is 505px of empty band to the right of it
   — measured — and a whole row was being spent to avoid a collision that cannot happen.
   `order:9` stays: it follows the pill, because it qualifies the query rather than being
   part of typing it. */
header:has(.hero:not([hidden])) #search-form label.field{order:9;margin-left:4px;
  background:var(--panel);border:1px solid var(--line);border-radius:14px;
  padding:3px 14px 3px 16px;color:var(--ink)}
/* One pill, not a bordered box inside a bordered pill — the same treatment, and the same
   reason, as `.searchpill`. It also needs the ground for a reason the chips already
   proved: the row sits on the photograph, and 12px of `--muted` on a lit sky is illegible
   in the light theme and worse in the dark one, where the scrim is dark and the picture
   behind this end of the band is not. */
header:has(.hero:not([hidden])) #search-form label.field input[type=date]{
  border:0;background:transparent;padding:5px 0;font-size:16px}
header:has(.hero:not([hidden])) #search-form label.field:focus-within{
  border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
header:has(.hero:not([hidden])) #search-form label.field input:focus{outline:0}
header:has(.hero:not([hidden])) .chips{margin:10px 0 0;padding:0;align-items:center}
header:has(.hero:not([hidden])) .chips .hint{display:none}
/* A label for the row, so four unexplained pills under a search box read as suggestions
   rather than as filters that are already on. `aria-hidden` in the markup: the pills are
   buttons that say what they do, and a heading announced before them adds nothing. */
/* On the same line as the chips it labels, since 2026-09-20. It carried `flex:0 0 100%`,
   which spent a whole row on two words and pushed the chips down; the design supplied
   that day sets label and chips on one line and lets the chips wrap under themselves,
   which is what `flex-wrap` on the row already does. The magnifier glyph went with it —
   the box above is the search, and a second one here named the same thing twice. */
.chiplabel{display:inline-flex;align-items:center;font-size:13px;font-weight:600;
  color:var(--head);margin-right:4px;flex:0 0 auto;align-self:center}
/* The chips sit on the photograph's scrim, so they need a ground of their own — at 13px
   on a sky they were unreadable at the right end of the row. */
/* Back to a full pill. The radius pass on 2026-09-20 put these at 10px on the rule that
   a control a reader operates is not a badge — and the design supplied the same day draws
   them as pills anyway. It is right to: these are not controls the reader sets, they are
   four example queries, and the pill is what says "pick one of these" rather than "this
   is a field". The search box, the sign-in button and the date field keep their 10–14px;
   the exception is here, and it is one. */
header:has(.hero:not([hidden])) .chips .ghost{background:var(--panel);
  border-radius:99px;padding:8px 18px;font-size:13px}
/* Below 1000px the photograph is mostly scrim: the text needs the width, and what is
   left of the image behind it is the sky. The blossom goes with it — at 64px of a 640px
   band it sits under the first word of the title. */
@media (max-width:1000px){
  .hero h1{font-size:34px}
  /* Below this the band is not wide enough to hold both, and the pill is what must not
     shrink — it is the one control on the screen. The qualifier takes its own line again. */
  header:has(.hero:not([hidden])) #search-form label.field{flex:1 0 100%;
    margin-left:0;margin-top:8px}
}
/* On a phone the banner is a tint, not a picture, and that is a decision rather than a
   miss. `banner.jpg` is 2.6:1; at 430px `cover` scales it by height, so the viewport shows
   a 430-of-1289px window — a third of the frame — and the third with the most room for
   text in it (`76% 58%`: horizon, building, flag) is also the palest part of the source.
   Scrim opacity was walked down from .93 to .52 and the picture never became legible as a
   picture; it only ever became a wash, because a pale sunrise sky under any alpha of a
   near-white page ground is a pale sunrise sky.
   Settled at .84/.62/.9: the texture is there, and the 24px title keeps a ground it reads
   on. Aiming the crop at the dark objects instead — books and gavel, around `88% 72%` —
   does make the photograph visible, and puts navy type on dark wood. That trade is not
   worth it for the element; the fix, if the picture must show on a phone, is a portrait
   crop of the same scene wired as a second source here, not a different scrim. */
@media (max-width:640px){
  /* Only the padding and the scrim change here. The band's own width, max-width, margin
     and radius are inherited from the rule above, which is what keeps its edges on the
     cards' edges at this width too — `calc(100% - 32px)` does the work that a hard-coded
     gutter used to, and gets it right without this block having to know the number. */
  header:has(.hero:not([hidden])) .searchband{padding:24px 0 20px;
    background:
      linear-gradient(180deg,rgba(var(--sky),.84) 0%,rgba(var(--sky),.62) 47%,
        rgba(var(--sky),.9) 100%),
      url(/img/banner.jpg) 76% 58%/cover no-repeat}
  .hero h1{font-size:24px}
  .hero p{font-size:14px}
  header:has(.hero:not([hidden])) #search-form{margin-top:16px}
  header:has(.hero:not([hidden])) .searchpill{padding:4px 4px 4px 12px}
}
