/* =============================================================================
   LONDON SPOT: home.css                                        [HOME page owns]
   -----------------------------------------------------------------------------
   Loads after base.css → layout.css → components.css. Every value below comes
   from a token in base.css or from the geometry of a file this page draws
   (the drawing's ratio, a brand mark's proportions); nothing here invents a
   colour, size or duration. Mobile first: every desktop rule is a
   `min-width` query, and a bounded range is written with 767.98px, never
   767px (design.md §14.1). Light mode only.

   A page stylesheet may use --z-pop, --z-sticky, --z-bar and --z-modal and
   nothing above them (design.md §4 "Layers"). This one sets no rung; its
   only literal z-index is inside .led, which isolates itself.

      0  Page level: the rhythm of the joins (design.md §4, §14.5)
      1  Catalog zone: rail + opening column
      2  The opening: statement, actions, the phone chip row, the shopfront
      3  Category cards
      4  The shelf grid (undamaged units)
      5  Brand panels
      6  Brand wall
      7  Facts strip
      8  The page-level error state
      9  Reduced motion
   ========================================================================== */


/* ── 0. PAGE LEVEL: the joins ─────────────────────────────────────────────
   Every gap a reader sees between two blocks is a named token, measured ink
   to ink (design.md §4 "Rhythm", §14.5): from the last painted pixel of one
   block to the first painted pixel of the next. A section to the next is
   --gap-section, the opening to the first section too, the brand wall to
   the facts strip --gap-tight, and the facts strip to the footer is the
   footer's own --gap-page-end. `.section` already pads half of
   --gap-section at each end (base.css), so two frames meet at exactly the
   token; the rules below take away what used to be added on top.

   A SECTION HEADING IS ITS WORDS, NOT ITS BOXES. The shared heading does
   this for every page (components.css §5, design.md §6 "Section heading"):
   the see-all link's 44px of air falls outside the row, the row is pulled
   up by --words-top and gives --words-foot back under the words (base.css,
   measured here on the painted pixels of every home heading, fix r2), and
   from 1024px the rail arrows' 44px frames are the row's first and last
   ink, so nothing is pulled there. The words stand --gap-section under the
   block above and --gap-head over their content.
   The one home case: a brand panel's title is a brand's name in Latin
   letters, which end on the baseline, so it gives back --words-foot-latin
   (.20 to .29, measured on PHILIPS, Amazon Basics and Beurer). A name with
   a descender would stand about 4px closer to its cards; none of the
   brands the build can pick has one today. */
.hpanel > .sechead{
  margin-bottom:calc(var(--gap-head) - var(--t-h2) * var(--words-foot-latin));
}
/* The same foot for the two English titles that end on the baseline, "New
   arrivals" and "Brands" ("Categories" and the shelf's title descend and
   keep the shared foot). With the Georgian foot their words stood 24.5px
   over their content on a phone and 25 to 26px from 768px, against 20 for
   every other heading; with this one, 20.5 to 21.5. From 1024px the new
   arrivals row is measured from its arrows' frames, so its rule stops
   there. A translation that brings a descender into either title drops
   its line here. */
:lang(en) #brands > .sechead{
  margin-bottom:calc(var(--gap-head) - var(--t-h2) * var(--words-foot-latin));
}
@media (max-width:1023.98px){
  :lang(en) #new > .sechead{
    margin-bottom:calc(var(--gap-head) - var(--t-h2) * var(--words-foot-latin));
  }
}


/* ── 1. CATALOG ZONE ───────────────────────────────────────────────────────
   Below 1024px the rail host renders nothing (layout.css hides .railhost) and
   the opening fills the width. From 1024px the rail sits left, the opening
   right. The rail is the one framed surface up here: the statement stands on
   the page itself, so the two do not read as two competing cards.

   The zone pays its half of the join to the first section, like a section
   does. What it ends on is ink in every layout: the drawing's kerb on a
   phone (the band of soft shadow under it is given back, §2), the address
   link's words from 768px (the link gives back its target's air and the
   foot of its line box, §2) or the rail's own frame from 1024px.
   ---------------------------------------------------------------------- */
.zone{ padding-block:var(--s-6) calc(var(--gap-section) / 2) }
@media (min-width:768px){ .zone{ padding-top:var(--s-8) } }

/* `stretch`, not `flex-start`. The opening paints the shopfront as its own
   background rather than stacking it underneath the type, so .led has no
   intrinsic height beyond its text. Stretching makes the flex line's cross
   size the TALLER of the two columns, so .zone__main takes the folded
   rail's height (layout.css §5, ten rows and the fold row, reserved before
   the script runs) whenever the type is shorter, and the two close level.
   The rail keeps its own height (align-self below); only the opening
   stretches. Unfolding the rail changes nothing here: the list is lifted
   out of the flow and covers the page instead of lengthening this row.
   The zone is also the query container the rail's panel measures itself
   against (100cqi, layout.css §5), so the panel runs to its far edge. */
.zone__in{
  display:flex; align-items:stretch;
  gap:var(--s-5);
}
@media (min-width:1024px){ .zone__in{ container:zone / inline-size } }
@media (min-width:1280px){ .zone__in{ gap:var(--s-8) } }

.zone__main{ flex:1 1 auto; min-width:0 }

/* The rail host sits on --z-pop (layout.css §5), so its mega panel is never
   painted under the column that follows it in the DOM. flex-start against
   the stretched line: the rail is a bordered card and a stretched one would
   grow its own empty space below the last category. */
@media (min-width:1024px){
  .zone__rail{ align-self:flex-start }
}


/* ── 2. THE OPENING ────────────────────────────────────────────────────────
   One lead moment: a statement about what the shop is, one primary action,
   one quiet secondary link, and a drawing of the shop's own front door
   (design.md §6 "The home opening block"). No rotation, no dots, no
   photograph under a scrim with type over it, and nothing here animates.

   PHONES (below 768px): the blocks stack. Under the actions stands one
   swipeable row of category chips, then the drawing in a 1.9:1 box, the
   ground the block stands on, edge to edge (D15, the owner reviews it). The
   budget: at 390x844 the first section heading reaches the first screen,
   and at 320x640 the chip row does, so the first screen always holds a way
   into the aisles.

   FROM 768px the drawing leaves the flow and is painted behind the type,
   bottom right, at --art of the column; the type keeps to the left --text,
   and the building starts at 1 - (--art x .5765) of the column, so no word
   crosses a brick. The actions stand in a column (the button, the address
   link under it), so the link never stands on the drawing's street and
   shadow band, where it read 3.80:1 (design.md §6 "No text over the
   drawing", audit TC6): the column's last line is its own words, under
   the button, left of where the drawing's ink begins.
   ---------------------------------------------------------------------- */
/* `height:100%` carries the stretch the last step down: .zone__in stretches
   .zone__main to the rail's height, but a block child does not inherit
   that. isolation: the type's z-index 1 and the drawing's 0 are local. */
.led{
  position:relative; isolation:isolate;
  display:flex; flex-direction:column; align-items:flex-start;
  height:100%;
}
/* the type rides above the drawing; the drawing never takes a pointer */
.led__h, .led__lead, .led__act{ position:relative; z-index:1 }

/* The one display-size type on the site. Below 480px it is the page title
   step, --t-h1; from 480px --t-display (design.md §3, §14.6).

   WHY THE MEASURE IS IN `em` AND THE BOX HAS A FLOOR. Google Sans arrives
   with `font-display: swap`, so the first paint sets this sentence in the
   system's face for mkhedruli and the second one re-sets it. The system
   faces are wider: "ლონდონიდან თბილისში" is 12.57em in Google Sans and
   13.71em in the stand-in, the clause before it 10.52em and 11.77em. A
   measure of 12.2em sits between all four, so the first clause always fits
   its line and the second always wraps: three lines in both faces below
   768px, measured at every step of the ladder and between them. The 360px
   step to the display size that used to sit here set the sentence in four
   lines in one face and three in the other, a 34px jump when the font
   arrived (CLS 0.19, audits H3, L5, M6); it is gone. `min-height` holds the
   box at the line count both faces give. Both numbers are measured from
   THIS sentence; change the copy and measure again.

   EACH LANGUAGE RESERVES ITS OWN LINES. The English sentence is shorter
   (18.9em in Google Sans, 23.7em for the Georgian) and takes two lines on
   a phone, where the Georgian takes three; held at the Georgian count it
   left a blank line under the headline (50.5px from its ink to the lead's
   against 15.5 in Georgian at 390, 91 against 16 at 1440; consistency
   review B2). The English counts are below and from 768px. */
.led__h{
  max-width:12.2em;
  min-height:3lh;
  margin:0;
  font-size:var(--t-h1); line-height:var(--lh-h1); font-weight:700;
  letter-spacing:var(--ls-heading); color:var(--ink);
  text-wrap:balance;
  /* never split a word (audit D6): every measure below is wider than
     „ლონდონიდან", the sentence's longest word, at its own size */
  overflow-wrap:normal;
}
/* English below 768px: two lines in both faces at every width from 320,
   the longer line 10.12em in Google Sans and 10.26em in the stand-in face
   against a measure of 12em at 320px and 12.2em above it. */
:lang(en) .led__h{ min-height:2lh }
@media (min-width:480px){
  .led__h{ font-size:var(--t-display); line-height:var(--lh-display) }
}

/* The lede role (design.md §3): --t-lede, 16px and 18px from 768, at most
   --measure-short, --gap-head-in under the h1. The measure is em, never ch:
   a ch is the zero of whichever face happens to paint, and it moved the
   column while the fonts loaded (SH13). */
.led__lead{
  max-width:var(--measure-short);
  margin:var(--gap-head-in) 0 0;
  font-size:var(--t-lede); line-height:var(--lh-lede);
  color:var(--ink-2);
  text-wrap:pretty;                   /* no one-word last line under the copy */
}

/* One primary action and, under it, one quiet link. The link wears the
   section heading's see-all class (design.md §6 "Links", "See all"), so
   the page has one vocabulary for "go and read the rest", its label on the
   column's edge by the class's own negative inline margins. Its block end
   gives back the air of its 44px target and the foot of its line box under
   the descenders (--words-foot, §0): the column ends on the link's painted
   words, which is where the next gap is measured from. */
.led__act{
  display:flex; flex-direction:column; align-items:flex-start;
  margin:var(--s-6) 0 0;
}
.led__more{
  margin-block-end:calc((var(--t-sm) * var(--lh-ui) - 44px) / 2 - var(--t-sm) * var(--words-foot));
}
/* The link stands flush under the button, and the button (positioned for
   its press) painted over the top of an outside ring; below 768px the link
   also starts 4px from the screen's edge, where an outside ring's left side
   fell off it (final accessibility check, 4). Its ring draws inside its own
   44px box, clear of both, and nothing in the opening moves. */
.led__more:focus-visible{ outline-offset:var(--ring-in) }

/* ── the category chips (phones) ──────────────────────────────────────────
   Every category, the drawer's order, as suggestion chips (design.md §6
   "Badge / chip", the suggestion role: 44px, --paper, a --bw-1 --bd-2 edge)
   with the category's icon. One row that scrolls sideways and bleeds to the
   screen's edges like a rail (§14.2 lets the phone opening's chip row cross
   the gutter). The row's height is reserved before the chips arrive. The
   scroller clips, so a chip's focus ring is drawn inside it, --ring-in. */
.led__cats{
  display:flex; gap:var(--s-2);
  align-self:stretch;
  min-height:44px;
  margin:var(--s-4) calc(var(--gut) * -1) 0;
  padding-inline:var(--gut);
  scroll-padding-inline:var(--gut);
  overflow-x:auto; overscroll-behavior-x:contain;
  scrollbar-width:none;
}
.led__cats::-webkit-scrollbar{ display:none }
.led__cats > li{ flex:none; display:flex }
.led__chip .icon{ color:var(--ink-2) }
.led__chip:focus-visible{ outline-offset:var(--ring-in) }
.led__chip--skel{ width:var(--s-24); border-color:var(--page-2); background:var(--page-2) }
@media (min-width:768px){ .led__cats{ display:none } }

/* ── the shopfront ─────────────────────────────────────────────────────────
   This shop's own front door, drawn in the two inks of the logo. It carries
   no card, no border, no radius and no shadow: the paper it was drawn on is
   remapped at build time to --page, so the street simply is the page and
   only the ink shows. Do not put it in a .card.

   ONE FILE, TWO FRAMES (§15.1): the wide crop is 2269x1002 (2.264:1). Below
   768px it fills a 1.9:1 box, `cover`, anchored right: the height is the
   file's own, so it is cut at the cornice exactly as the wide crop is, and
   the empty street on the left gives way while the door and the fascia
   stay whole (R2, no new file). The box is reserved by its ratio before the
   bytes land.

   THE BAND UNDER THE KERB. The drawing's hard ink ends at 90% of its
   height, at the kerb. The band under it is not bare paper: it holds the
   drawing's soft cast shadow, 13 to 20 levels off --page for about 12px
   under the kerb and fainter to the foot of the box (verify r2, issue 2).
   A soft cast shadow is not ink (design.md §4: a shadow adds nothing to
   the rhythm), so on a phone, where the drawing is the opening's last
   block, its box gives that band back (a tenth of the 1.9:1 box's height,
   the box being the column plus both gutters wide) and the join to the
   first section is measured from the kerb: 63 to 64.5px at 320 to 430. */
.led__art{
  display:block; align-self:stretch;
  margin:var(--s-4) calc(var(--gut) * -1) 0;
}
.led__img{
  display:block; width:100%; height:auto;
  aspect-ratio:1.9;
  object-fit:cover; object-position:100% 50%;
}
@media (max-width:767.98px){
  .led__art{ margin-bottom:calc((100% + 2 * var(--gut)) / -19) }
}

@media (min-width:768px){
  /* ONE DECISION, TWO NUMBERS, AND THEY HAVE TO ADD UP. --art is how much of
     the column the drawing takes and --text how much the words take; the
     building is 1308/2269 of the drawing, so it starts at
     1 - (--art x .5765) from the left. At 74% and 52% that is 57% against
     52%, a clear five points of paper between the last word and the first
     brick. Move either and check the other. */
  .led{ --art:74%; --text:52% }

  .led__art{
    position:absolute; inset-block-end:0; inset-inline-end:0; z-index:0;
    width:var(--art); margin:0;
    pointer-events:none;      /* the drawing is not a link and never was */
  }
  .led__img{ aspect-ratio:2269 / 1002 }

  /* 10em against the 12.2em the stacked version can afford; whichever is
     narrower wins, so the headline never grows past the text zone. The
     Georgian sentence sets in four lines here in both faces, so its floor
     is four.

     THE ENGLISH SENTENCE TAKES THREE OR FOUR, and which one follows the
     measure, not the breakpoint: three while the measure holds the widest
     line of the three-line setting („appliances, from", 7.803em in Google
     Sans; the stand-in face needs 7.73em, so its count is never the
     larger), four below it. The measure is --text of the column here and
     60% of it below 1280px (the rule after this block), so English takes
     four lines beside the rail up to about 1124px and from 1280 to 1300px,
     three everywhere else from 768px, and never two (10.12em, over the
     10em cap). The column is the query container, so 52cqi and 60cqi are
     the same 52% and 60% the max-width takes; `7.804em - measure` (the
     threshold rounded up a thousandth) is positive only under it, and
     clamped between 0 and 1lh it adds the fourth line there and nothing
     elsewhere: measured pixel by pixel from 1110 to 1140px and from 1286
     to 1316px, every width reserves the lines Google Sans sets. The plain
     3lh stands first for a browser without container units. */
  .led{ container:led / inline-size }
  .led__h{ max-width:min(10em, var(--text)); min-height:4lh }
  :lang(en) .led__h{
    min-height:3lh;
    min-height:calc(3lh + clamp(0px, (7.804em - 52cqi) * 1000, 1lh));
  }
  .led__lead{ max-width:min(var(--measure-short), var(--text)) }
}

/* Where the column is narrow (a tablet, or a laptop beside the rail) 52%
   is narrower than „ლონდონიდან" at the display size, and the headline split
   it: „ლონდონიდ / ან" at 1024 (audit D6). The headline alone takes 60%
   there. It stays clear of the building because it is four lines at the top
   of the block and the drawing sits on the block's floor; the lead and the
   actions, which do share its height, keep the 52% that clears the brick.
   The English reservation follows the same 60%. */
@media (min-width:768px) and (max-width:1279.98px){
  .led__h{ max-width:min(10em, 60%) }
  :lang(en) .led__h{ min-height:calc(3lh + clamp(0px, (7.804em - 60cqi) * 1000, 1lh)) }
}


/* ── 3. CATEGORY CARDS ─────────────────────────────────────────────────────
   One card per category (design.md §6 "Category card"): a 4:3 photograph,
   the category's name and its real count, on the scroll rail the new
   arrivals use (components.css §13). One link and one tab stop; the whole
   card is the anchor.

   The cards are a step narrower than a product card at the two phone steps
   (58% and 40% of the row) and match it from 768px (3.3 in view, so the
   fourth card shows its edge, §14.4); from 1280px four, where the product
   rail shows five. The phone steps are BOUNDED, against this sheet's
   mobile-first habit and on purpose: a media query adds no specificity,
   home.css loads after components.css, and an open-ended `min-width:480px`
   here would outrank the component's own 768 and 1024 steps. 1280 is the
   component's last step, so that one can be open-ended.
   ---------------------------------------------------------------------- */
@media (max-width:479.98px){ .catrail > *{ flex-basis:58% } }
@media (min-width:480px) and (max-width:767.98px){ .catrail > *{ flex-basis:40% } }
@media (min-width:1280px){
  .catrail > *{ flex-basis:calc((100% - var(--s-4) * 3) / 4) }
}

/* EVERY CARD IN A ROW IS THE ROW'S HEIGHT. The rail stretches its items; the
   item, its heading and the link pass the stretch down as flex items, so the
   photo, the name and the frame end on one line across the row (the link
   used to be `height:100%` of an h3 with no height, and the cards stood at
   three heights, audits L14, H5). The h3 is there for the outline; the type
   is set on the name. */
.catcard{ display:flex; min-width:0 }
.catcard__h{ display:flex; flex:1 1 auto; min-width:0; margin:0; font:inherit; letter-spacing:0 }
.catcard__a{
  container:catcard / inline-size;
  display:flex; flex-direction:column; flex:1 1 auto; min-width:0;
  background:var(--paper);
  border:var(--bw-1) solid var(--bd);
  border-radius:var(--r);
  overflow:hidden;
  color:var(--ink);
  transition:transform    var(--d-hover) var(--ease),
             box-shadow   var(--d-hover) var(--ease),
             border-color var(--d-hover) var(--ease),
             background-color var(--d-press) var(--ease-out);
}

/* object-fit:cover, not contain: these are photographed scenes with air
   built into them, not cut-out products on a white field. The hairline
   under the well keeps the photograph from bleeding into the name. */
.catcard__ph{
  display:block; position:relative; flex:none;
  aspect-ratio:4 / 3; min-height:0; overflow:hidden;
  background:var(--page-2);
  border-bottom:var(--bw-1) solid var(--bd);
}
.catcard__ph img{ display:block; width:100%; height:100%; object-fit:cover }
/* the fallback well for a category added before its photograph is made */
.catcard__ph--icon{ display:grid; place-items:center; color:var(--ink-3) }

/* The name and its count. A NAME NEVER BREAKS INSIDE A WORD (design.md §3):
   where the card is too narrow for the longest word of the longest name
   beside the count („საყოფაცხოვრებო", 130px at 14px/600, plus the gap and
   „1 902", 36px), the count leaves the name's line and stands at the foot
   of the card, so the name has the card's whole text width („საყოფაცხოვრებო"
   split mid-word at 320px, audit TC1). That is a question of the card's own
   width, not the window's: a card is 167 to 259px on phones but only 179px
   at 480px, where a viewport step at 480 split three names. So the step is
   the card's (a container query, §4 "Breakpoints"): from 224px of card the
   count stands beside the name's first line. The body takes the rest of the
   card's height, so every frame in a row ends on the row's line and, below
   the step, every count of a row on one line. */
.catcard__b{
  display:flex; flex-direction:column; align-items:flex-start; gap:var(--s-1);
  flex:1 1 auto; min-width:0;
  padding:var(--s-3) var(--s-4);
}
@container catcard (min-width:224px){
  .catcard__b{ flex-direction:row; align-items:baseline; gap:var(--s-3) }
}
/* The name role at --t-sm, 600 because here the name is the whole card.
   THE CLAMP IS MEASURED, NEVER ASSUMED: three lines below 1280px and two
   from 1280px, because „მსხვილი საყოფაცხოვრებო ტექნიკა" needs three at 768
   and 1024 (audit H15). A name that arrives longer moves the step; the
   ellipsis is the fallback for unexpected data, not the plan. */
.catcard__n{
  flex:1 1 auto; min-width:0; max-width:100%;
  font-size:var(--t-sm); line-height:var(--lh-name); font-weight:600;
  display:-webkit-box; -webkit-box-orient:vertical;
  -webkit-line-clamp:3; line-clamp:3; overflow:hidden; overflow-wrap:break-word;
}
@media (min-width:1280px){
  .catcard__n{ -webkit-line-clamp:2; line-clamp:2 }
}
/* The count role beside a name (design.md §3): --t-sm, 400, --ink-3,
   tabular, grouped by LS.num like every other count on the site. */
.catcard__c{
  flex:none;
  font-family:var(--f-disp); font-size:var(--t-sm); line-height:var(--lh-ui);
  font-weight:400; color:var(--ink-3);
  font-variant-numeric:tabular-nums; font-feature-settings:"tnum" 1;
}

@media (hover:hover){
  .catcard__a:hover{ transform:translateY(-2px); box-shadow:var(--sh-2); border-color:var(--bd-2) }
}
.catcard__a:active{ background:var(--paper-2); transform:none }
.catcard__a:focus-visible{ outline:var(--ring) solid var(--focus); outline-offset:var(--ring-off) }
/* The photograph never animates, the card does. */

/* The skeleton is the same card box and reserves what the row will hold: the
   lines of the longest name at this card's width (--n), in the page's
   language, plus the count's line under the name's step, so the row keeps
   its height when the names arrive (design.md §4: a skeleton reserves the
   rhythm of what replaces it). The row is as tall as its tallest card, and
   that is the longest name, so its line count is a function of the card's
   own width, which is what the container steps below answer; a viewport
   step reserved the clamp instead and stood one line taller than the
   cards at 1440 in Georgian and at every width in English (verify r1).
   Measured on the 22 names of each language by setting every card from
   150 to 340px: „მსხვილი საყოფაცხოვრებო ტექნიკა" takes three lines on a
   card under 255px, two from 255px and one from 326px; the longest English
   name two lines under 280px and one from 280px. The steps are the card's
   content box (the card less its two hairlines). A renamed category moves
   them: measure again. */
.catcard--skel{ pointer-events:none }
.catcard--skel .catcard__b{
  --n:3;
  min-height:calc(2 * var(--s-3) + var(--n) * var(--t-sm) * var(--lh-name) +
                  var(--s-1) + var(--t-sm) * var(--lh-ui));
}
:lang(en) .catcard--skel .catcard__b{ --n:2 }
@container catcard (min-width:224px){
  .catcard--skel .catcard__b{ min-height:calc(2 * var(--s-3) + var(--n) * var(--t-sm) * var(--lh-name)) }
}
@container catcard (min-width:253px){ .catcard--skel .catcard__b{ --n:2 } }
@container catcard (min-width:278px){ :lang(en) .catcard--skel .catcard__b{ --n:1 } }
@container catcard (min-width:324px){ .catcard--skel .catcard__b{ --n:1 } }
.catcard--skel .skel-line{ flex:none; width:88%; align-self:flex-start }


/* ── 4. THE SHELF GRID: undamaged units ────────────────────────────────────
   The product grid table of design.md §14.3: 2 columns, 3 from 480px, 4
   from 1024px, 5 from 1280px, --grid-gap between the cards. The same card
   at the same width as the brand panels below it and, from 1024px, as the
   new-arrivals rail above it.

   A GRID SHOWS WHOLE ROWS. home.js renders fifteen equal cards and the grid
   paints three rows of them at every width: 6 at two columns, 9 at three,
   12 at four and all 15 at five (three rows is also what keeps a phone page
   under seven screens, §14.15). A card hidden here costs no bytes: LS.card
   marks everything past the first row `loading="lazy"`, and a lazy image in
   a display:none subtree is never fetched. `display:flex`, not `revert`,
   because flex is what .card is and the skeleton wears the same class.
   ---------------------------------------------------------------------- */
.pgrid{
  display:grid; gap:var(--grid-gap);
  grid-template-columns:repeat(2,minmax(0,1fr));
}
@media (min-width:480px) { .pgrid{ grid-template-columns:repeat(3,minmax(0,1fr)) } }
@media (min-width:1024px){ .pgrid{ grid-template-columns:repeat(4,minmax(0,1fr)) } }
@media (min-width:1280px){ .pgrid{ grid-template-columns:repeat(5,minmax(0,1fr)) } }

.pgrid > :nth-child(n+7){ display:none }
@media (min-width:480px){
  .pgrid > :nth-child(n+7){ display:flex }
  .pgrid > :nth-child(n+10){ display:none }
}
@media (min-width:1024px){
  .pgrid > :nth-child(n+10){ display:flex }
  .pgrid > :nth-child(n+13){ display:none }
}
@media (min-width:1280px){
  .pgrid > :nth-child(n+13){ display:flex }
}


/* ── 5. BRAND PANELS ───────────────────────────────────────────────────────
   Zero to three light panels, one per brand the data build found with 20
   products or more (home.js §5): the brand's name with the see-all link at
   the far edge of the same row (the client moved the link there, fix brief
   image 4), then ONE ROW OF THE GRID ABOVE IT (design.md §14.2, §14.3):
   the build sends five products and the panel paints as many as the shelf
   grid has columns, 2, 3, 4 or 5, each card the shelf card's width.

   A FRAMED PANEL NEVER INSETS A GRID. The frame bleeds outward and the
   cards stand on the page's own column track: below 768px the panel is a
   band from screen edge to screen edge (its fill and hairlines cross the
   gutter, its content stays on it); from 768px the frame reaches --s-5 into
   the gutter and takes its radius. The 20px of padding that used to sit
   inside the frame made the same card 117px wide on a 320px phone and 446px
   at 1023px (audits L4, C14, M18, H4).
   ---------------------------------------------------------------------- */
.hpanel{
  margin-inline:calc(var(--gut) * -1);
  padding:var(--s-6) var(--gut);
  background:var(--page-2);
  border-block:var(--bw-1) solid var(--bd);
}
@media (min-width:768px){
  /* the frame's own hairline is part of the bleed, so the content box is
     the container's to the pixel */
  .hpanel{
    margin-inline:calc((var(--s-5) + var(--bw-1)) * -1);
    padding-inline:var(--s-5);
    border:var(--bw-1) solid var(--bd);
    border-radius:var(--r-lg);
  }
}

/* The link's hover wash is --page-2, which is this panel's own fill; on the
   panel the wash is the card surface instead, so the hover still shows. */
@media (hover:hover){
  .hpanel .sechead__all:hover{ background:var(--paper) }
}

.hgrid{
  display:grid; gap:var(--grid-gap);
  grid-template-columns:repeat(2,minmax(0,1fr));
}
@media (min-width:480px) { .hgrid{ grid-template-columns:repeat(3,minmax(0,1fr)) } }
@media (min-width:1024px){ .hgrid{ grid-template-columns:repeat(4,minmax(0,1fr)) } }
@media (min-width:1280px){ .hgrid{ grid-template-columns:repeat(5,minmax(0,1fr)) } }

.hgrid > :nth-child(n+3){ display:none }
@media (min-width:480px){
  .hgrid > :nth-child(n+3){ display:flex }
  .hgrid > :nth-child(n+4){ display:none }
}
@media (min-width:1024px){
  .hgrid > :nth-child(n+4){ display:flex }
  .hgrid > :nth-child(n+5){ display:none }
}
@media (min-width:1280px){
  .hgrid > :nth-child(n+5){ display:flex }
}

/* the panel while the data is on its way: the frame, a heading bar and one
   row of skeleton cards, the height of what replaces it. The heading row is
   the title's line box, as a loaded row is (§0), and takes the same
   margins. The panel's own fill is the skeleton's --page-2, so the heading
   bar takes the next step, --bd, to be seen on it. */
.hpanel--skel .sechead{ min-height:calc(var(--t-h2) * var(--lh-h2)) }
.hpanel--skel .sechead > .skel-line{ width:var(--s-24); height:var(--s-5); background:var(--bd) }


/* ── 6. BRAND WALL ─────────────────────────────────────────────────────────
   The twelve biggest brands that have a mark on file, one tile each, most
   products first, each tile a link to the brand's products (home.js §6).

   THE WALL CLOSES AT A FULL ROW at every width it takes: 2 columns, 3 from
   480px, 4 from 768px, 6 from 1024px (design.md §14.3). Twelve divides by
   all four; if fewer marks match the data, home.js marks the tiles that
   would open a short row at each column count and they step aside there.

   ONE INK, EQUAL AREA (design.md §15.6, OD15, the owner reviews it). The
   files in assets/img/brands are trimmed to their ink, so a file's width
   and height are the mark's proportions. Each mark is painted through a
   mask in --ink-2 (no brand red beside the one accent), and sized to the
   same area rather than the same height, at most 40px tall: a mark of
   proportions r is sqrt(r) times as wide as the square of that area and
   sqrt(r) times less tall. The square's side (--mk) is the widest mark's
   share of the tile's content width, so that mark just fits the narrowest
   tile, capped at 48px so the wall stays quiet on a wide screen. home.js
   writes the mark's file (--logo), r (--r), sqrt(r) (--sr) and the widest
   sqrt(r) on the wall (--sr-max). The tile is the query container.
   ---------------------------------------------------------------------- */
.brow{
  display:grid; gap:var(--grid-gap);
  grid-template-columns:repeat(2,minmax(0,1fr));
}
@media (min-width:480px) { .brow{ grid-template-columns:repeat(3,minmax(0,1fr)) } }
@media (min-width:768px) { .brow{ grid-template-columns:repeat(4,minmax(0,1fr)) } }
@media (min-width:1024px){ .brow{ grid-template-columns:repeat(6,minmax(0,1fr)) } }

@media (max-width:479.98px){ .brow__i--x2{ display:none } }
@media (min-width:480px) and (max-width:767.98px){ .brow__i--x3{ display:none } }
@media (min-width:768px) and (max-width:1023.98px){ .brow__i--x4{ display:none } }
@media (min-width:1024px){ .brow__i--x6{ display:none } }

/* The tile is the product card's own surface and hairline, one step
   quieter: no shadow at rest, the same 2px lift and --sh-2 on hover. Its
   height is the 40px mark cap and its padding, the block padding a step
   tighter on phones, where six rows of two stand one above the other. */
.brow__a{
  container-type:inline-size;
  display:grid; place-items:center;
  height:calc(40px + 2 * var(--s-4)); padding:var(--s-4);
  background:var(--paper);
  border:var(--bw-1) solid var(--bd);
  border-radius:var(--r);
  transition:transform    var(--d-hover) var(--ease),
             box-shadow   var(--d-hover) var(--ease),
             border-color var(--d-hover) var(--ease),
             background-color var(--d-press) var(--ease-out);
}
@media (min-width:768px){
  .brow__a{ height:calc(40px + 2 * var(--s-6)); padding:var(--s-6) var(--s-5) }
}
.brow__logo{
  --mk:min(48px, calc(100cqi / var(--sr-max, 2.75)));
  display:block; flex:none;
  height:min(40px, calc(var(--mk) / var(--sr, 1)));
  aspect-ratio:var(--r, 1);
  max-width:100%;
  background:var(--ink-2);
  -webkit-mask:var(--logo) center / contain no-repeat;
          mask:var(--logo) center / contain no-repeat;
}
@media (hover:hover){
  .brow__a:hover{ transform:translateY(-2px); box-shadow:var(--sh-2); border-color:var(--bd-2) }
}
.brow__a:active{ background:var(--paper-2); transform:none }

.brow__skel{ display:block; width:100%; height:calc(40px + 2 * var(--s-4)); border-radius:var(--r) }
@media (min-width:768px){ .brow__skel{ height:calc(40px + 2 * var(--s-6)) } }


/* ── 7. FACTS STRIP ────────────────────────────────────────────────────────
   Four short factual lines in one framed strip. Not four cards: a card row
   would say these four facts are four separate offers, and they are one set
   of terms. The hairlines between the cells are the container's own
   background showing through a --bw-1 grid gap, so the dividers are correct
   at one, two and four columns without a single border rule.

   It belongs with the brand wall above it: --gap-tight between them, so the
   wall's section keeps no padding at its end. Nothing below it: the footer
   owns the page's end (--gap-page-end).

   It stays at the end on a phone too (audit H13, decided in fix r2). Three
   of its four facts are on the first phone screen already (the h1, the
   lead, the header's phone link, the address link) and the bottom bar calls
   from every screen; the warranty's full terms belong on the product page,
   per grade. Under the opening, its 220 to 307px would push the first
   section heading off the first screen at every phone width.
   ---------------------------------------------------------------------- */
#brands{ padding-bottom:0 }
.facts{ margin-top:var(--gap-tight) }

.facts__l{
  display:grid; grid-template-columns:minmax(0,1fr);
  gap:var(--bw-1);
  background:var(--bd);
  border:var(--bw-1) solid var(--bd);
  border-radius:var(--r);
  overflow:hidden;
}
@media (min-width:480px) { .facts__l{ grid-template-columns:repeat(2,minmax(0,1fr)) } }
@media (min-width:1024px){ .facts__l{ grid-template-columns:repeat(4,minmax(0,1fr)) } }

/* THE FIRST LINES OF A ROW SHARE ONE LINE. The cells of a row stretch to
   the tallest, and a cell centred in that height put its words wherever its
   line count left them: at 1024 the order label stood 11px above the first
   lines beside it and the one-line warranty 11px below them (verify r1).
   Every cell now starts at its padding, as the rows of a table do, and its
   icon stands centred on the first line (the icon's 24px slot gives back
   what it is taller than the line). */
.facts__i{
  display:flex; align-items:flex-start; gap:var(--s-3);
  padding:var(--s-4);
  background:var(--paper);
}
.facts__ic{
  flex:none; display:grid; place-items:center;
  width:24px; height:24px;
  margin-block:calc((var(--t-sm) * var(--lh-sm) - 24px) / 2);
  color:var(--ink-2);
}
/* The one Union Jack on the site: the "original British goods" mark. It is
   drawn at 20px inside the 24px slot the line icons share, because it is
   the only FILLED mark in the row: a solid disc at 24px carries visibly more
   ink than a stroke drawing in the same box. The slot keeps its 24px, so
   every label starts on the same edge. */
.facts__flag{ width:20px; height:20px; display:block }
/* A fact never ends on a lone word (design.md §3 "Line breaks"). */
.facts__t{
  min-width:0; font-size:var(--t-sm); line-height:var(--lh-sm); color:var(--ink);
  text-wrap:pretty;
}

/* The order line: the label, then the number as a call link on a 44px
   target (design.md §6 "Links", standalone), beside the label where the
   cell is wide enough and under it where it is not. A phone number never
   wraps (.nb).
   THE NUMBER IS A LINE OF THE CELL. Its link box is the number's own line,
   and the 44px target is drawn round it by ::before, 11px above and below
   (a pseudo-element counts for the hit, design.md §14.15). As a 44px box it
   stood 32.8px under the label, where the cell's other lines are 21.7px
   apart, and a phone cell carried 11px more under the number than over
   the label (verify r1); pulled back with negative margins, its focus ring
   crossed the label's words. Now the ring hugs the number, and under the
   label the pair keeps a label's --s-1 from its value (the contact rows'
   gap), which also keeps the ring clear of the label's descenders; beside
   the label the two share one line. */
.facts__t--call{
  display:flex; flex-wrap:wrap; align-items:center;
  gap:var(--s-1) var(--s-2);
}
.facts__tel{ position:relative; font-weight:600 }
.facts__tel::before{
  content:""; position:absolute;
  inset-inline:0; inset-block:calc((var(--t-sm) * var(--lh-sm) - 44px) / 2);
}


/* ── 8. THE PAGE-LEVEL ERROR ───────────────────────────────────────────────
   When the home data cannot be loaded there is one message and one retry,
   where the first data section stands (design.md §14.12), built by
   LS.empty(); the other data sections step aside until a retry lands, and
   so does the phone opening's chip row, which has nothing to list. The
   statement, the actions, the drawing and the facts strip ship in the page
   and stay. */
.home-failed #new > .sechead,
.home-failed .led__cats,
.home-failed #cats,
.home-failed #popular,
.home-failed #brandPanels,
.home-failed #brands{ display:none }
/* the message's section pays half the join, the strip the other half */
.home-failed .facts{ margin-top:calc(var(--gap-section) / 2) }


/* ── 9. REDUCED MOTION ─────────────────────────────────────────────────────
   base.css collapses every duration; the lifts are removed here.
   ---------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce){
  .catcard__a:hover{ transform:none }
  .brow__a:hover{ transform:none }
}
