/* בית הדיל - הדוכן.
   Drenched crate blue, one fluorescent accent, hand-cut price plates with hard
   shadows that have no blur in them. Nothing here eases into a colour.

   Authored for dir="rtl" only. All box offsets are logical; rotations, hard
   shadows and the rail transform are physical and are authored for RTL on
   purpose. See lib/layout.mjs before mirroring anything. */

:root{
  --crate-deep:#032D66;
  --crate:#004A9C;
  --crate-lit:#116BB5;
  --bone:#F2EFE0;
  --hivis:#FF8600;
  --ink:#09121F;
  --alarm:#E11D2E;
  --shadow:#010A17;
  --rule:rgb(242 239 224 / .18);
  --rule-ink:rgb(9 18 31 / .28);

  --t-mega:clamp(64px,13vw,200px);
  --t-board:clamp(44px,8.5vw,132px);
  --t-title:clamp(24px,3.4vw,46px);
  --t-h2:clamp(22px,2.4vw,30px);
  --t-lead:18px; --t-body:16px; --t-small:13.5px;
  --t-data:13px; --t-data-lg:17px; --t-micro:10.5px;
  --lh-tight:1.05; --lh-title:1.14; --lh-body:1.7;

  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px;
  --s6:32px; --s7:48px; --s8:72px; --s9:112px;
  --gutter:clamp(12px,4vw,48px);

  /* Offsets, not whole box-shadow values: the plate shadow is drawn with
     drop-shadow() on a holder element so it follows the cut polygon instead of
     the rectangle, and drop-shadow takes x/y/blur/colour separately. Same
     distances as the box-shadow forms these replaced. Kept blur-free. */
  --shadow-rest-x:3px;
  --shadow-land-x:10px;
  --shadow-lg-x:16px;
  --shadow-plate:10px 10px 0 var(--shadow);

  --z-band:1; --z-rail:2; --z-ledger:3; --z-plate:5;
  --z-tile:20; --z-sticky:60; --z-head:80;

  --ease-land:cubic-bezier(.2,.9,.25,1);
  --ease-out:cubic-bezier(.2,.8,.2,1);

  color-scheme:dark;
}

*,*::before,*::after{ box-sizing:border-box; border-radius:0; }

body{
  margin:0;
  background:var(--crate-deep);
  color:var(--bone);
  font:400 var(--t-body)/var(--lh-body) Heebo,'Arial Hebrew','Segoe UI',sans-serif;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}

/* ⚠ block-size:auto IS LOAD-BEARING, NOT TIDINESS.
   Every image element carries measured width/height attributes so the box is
   reserved before the file lands. Those attributes are presentational hints for
   the width AND height properties, so a rule that overrides only the width
   leaves the height pinned at the attribute value and the picture is drawn
   distorted. That is exactly what .chart img did: 800x145 declared, 345x145
   rendered on a phone, 2.3x too tall, live for weeks. Rules that genuinely want
   a fixed height (.rail img, .shots img) are more specific and still win. */
img{ display:block; max-width:100%; block-size:auto; }
h1,h2{ margin:0; }

h1,h2,.plate-title,.plate-price,.mast-name,.hang-price{
  font-family:Karantina,'Arial Hebrew',sans-serif;
  font-weight:700; line-height:var(--lh-title);
}
.mono,.code,.ledger,.idx,.sizes,.usd,.codes,.blurb,.plate-usd,.lb-n,.head-code{
  font-family:Cousine,ui-monospace,monospace;
  font-variant-numeric:tabular-nums;
}
bdi,.iso{ unicode-bidi:isolate; }

/* Graft 2: nothing on this site eases into a colour. Painted signage does not
   fade in, it is either painted or it is not. Two discrete jumps, 90ms. */
a,button,.filter{ transition:background-color 90ms steps(2), color 90ms steps(2); }

a{ color:inherit; }
:focus-visible{ outline:3px solid var(--hivis); outline-offset:3px; }

/* ⚠ THIS RULE WAS ONCE MISSING WHILE THE MARKUP USED IT, and the failure was
   silent: the class was inert, so the hero printed "בית הדיל" a second time in
   plain 32px ink directly under the artwork. Zero stylesheet rules matched
   .sr-only and the h1 measured 345x36 at full opacity.

   The masthead no longer hides its whole heading - the wordmark is drawn inside
   the h1 and only the readable brand name beside it is hidden - but every page
   still leans on this rule, so it stays load-bearing. */
.skip,.sr-only{
  position:absolute; inline-size:1px; block-size:1px; overflow:hidden;
  clip-path:inset(50%); white-space:nowrap;
}
.skip:focus{
  inline-size:auto; block-size:auto; clip-path:none;
  inset-block-start:var(--s2); inset-inline-start:var(--s2);
  z-index:var(--z-head); padding:var(--s3) var(--s5);
  background:var(--hivis); color:var(--ink); font-weight:800;
}

/* ---------------------------------------------------------------- the board */

.board{
  position:relative;
  min-block-size:min(72svh,620px);
  background:var(--hivis); color:var(--ink);
  padding:var(--s7) var(--gutter) var(--s6);
  display:flex; flex-direction:column; justify-content:center; gap:var(--s6);
}

/* The real animated logo. It carries the wordmark, so it stands alone here and
   the h1 beside it is sr-only. No ink plate: the artwork has its own white
   house and trolley and reads cleanly straight on the fluorescent board. */
/* The wordmark IS the masthead now. It is drawn, not typeset, so it scales by
   width alone and never reflows: one line, always, from a phone to a shopfront
   display. The cap height lands around 14vw, which is the size a name painted
   on a crate would actually be relative to the crate. */
.mast-name{
  display:block; margin:0 0 var(--s5);
  inline-size:min(100%, 980px);
}
.mast-word{
  display:block; inline-size:100%; block-size:auto;
  /* Nothing behind it: the board's fluorescent is the background. */
  background:none;
}

/* ⚠ The priced list that used to fill this board is GONE, on the owner's call:
   it repeated every product name and price that the bands below already carry,
   and at 19 products it had stopped being a stall list and become an index.
   The board is now the sign and the category tabs, nothing else, so it no longer
   needs the full viewport height it was sized for. */
.mast-tag{
  font:700 clamp(20px,3.4vw,34px)/1.1 Karantina,'Arial Hebrew',sans-serif;
  margin:0; max-inline-size:18ch;
}

/* The shekel sign is bidi class ET and migrates across the digits depending on
   its neighbours. Inside an explicit LTR isolate, ET-then-EN resolves the same
   way in every engine. */
.bp,.plate-price,.hang-price{ direction:ltr; unicode-bidi:isolate; }
.cur{ font-size:.34em; vertical-align:.72em; }

/* These were a secondary filter row; they are the whole navigation now, so they
   are sized as type rather than as chrome. */
.filters{ display:flex; flex-wrap:wrap; gap:var(--s3); }
.filter{
  font:700 clamp(24px,3.6vw,44px)/1 Karantina,'Arial Hebrew',sans-serif; letter-spacing:.01em;
  padding:var(--s3) var(--s5);
  background:transparent; color:var(--ink);
  border:3px solid var(--ink); cursor:pointer;
  min-block-size:48px;
}
.filter:hover{ background:var(--ink); color:var(--hivis); }
.filter[aria-selected="true"]{ background:var(--ink); color:var(--hivis); }

/* Search sits on the board because the board IS the navigation here. Same 3px
   ink border and zero radius as the category buttons, so it reads as one more
   control on the sign rather than a widget dropped on top of it. */
.seek{ position:relative; display:flex; margin-block-start:var(--s5); }
.seek-in{
  inline-size:100%; min-block-size:56px;
  font:700 var(--t-small)/1 Heebo,sans-serif;
  padding:var(--s4) var(--s5);
  padding-inline-end:56px; /* clear of the × */
  background:transparent; color:var(--ink);
  border:3px solid var(--ink); border-radius:0;
  -webkit-appearance:none; appearance:none;
}
.seek-in::placeholder{ color:var(--ink); opacity:.55; }
/* Safari draws its own clear button; ours is the one that is styled and the
   one the keyboard can reach, so the native pair is removed rather than
   letting two clear controls sit on top of each other. */
.seek-in::-webkit-search-decoration,
.seek-in::-webkit-search-cancel-button{ -webkit-appearance:none; appearance:none; }
.seek-x{
  position:absolute; inset-inline-end:0; inset-block:0;
  inline-size:56px;
  font:700 28px/1 Heebo,sans-serif;
  background:transparent; color:var(--ink); border:0; cursor:pointer;
}
.seek-x:hover{ background:var(--ink); color:var(--hivis); }
/* The colour-code picker. Wide tiles on purpose: the whole failure this fixes
   was a customer unable to tell two colourways apart at thumbnail size, so the
   grid is deliberately generous and reflows to two columns on a phone. */
.colours-lede{
  margin-block-end:var(--s5);
  font:400 var(--t-small)/1.6 Heebo,sans-serif; color:var(--bone);
  max-inline-size:60ch;
}
.swatches{
  list-style:none; margin:0; padding:0;
  display:grid; gap:var(--s4);
  grid-template-columns:repeat(auto-fill,minmax(150px,1fr));
}
.swatch{ display:flex; flex-direction:column; }
.swatch img{
  inline-size:100%; block-size:auto; display:block;
  background:var(--crate-deep);
}
/* The code is the control, not a caption: it is the string the customer has to
   carry to the supplier, so it is the full-width hit target under its photo. */
.swatch-code{
  inline-size:100%; min-block-size:44px;
  font:700 var(--t-small)/1 Cousine,monospace; letter-spacing:.04em;
  padding:var(--s3);
  background:var(--hivis); color:var(--ink);
  border:0; border-radius:0; cursor:pointer;
}
.swatch-code:hover{ background:var(--bone); }
/* The chosen colour has to be unmistakable: it is half of what gets carried
   across to the supplier, and a customer who cannot tell what is selected will
   not trust the button that follows. */
.swatch-code[aria-pressed="true"]{ background:var(--ink); color:var(--hivis); }

.pick{ margin-block-start:var(--s6); }
.pick-label{ margin:0 0 var(--s3); font:800 var(--t-small)/1 Heebo,sans-serif; }
.pick-sizes{ list-style:none; margin:0; padding:0; display:flex; flex-wrap:wrap; gap:var(--s2); }
.pick-size{
  min-inline-size:56px; min-block-size:44px;
  font:700 var(--t-small)/1 Cousine,monospace;
  background:transparent; color:var(--bone);
  border:2px solid var(--rule); cursor:pointer;
}
.pick-size:hover{ border-color:var(--hivis); }
.pick-size[aria-pressed="true"]{ background:var(--hivis); color:var(--ink); border-color:var(--hivis); }
.pick-say{ margin-block-start:var(--s4); font:400 var(--t-small)/1.5 Heebo,sans-serif; opacity:.85; }
.pick-buy{
  display:inline-block; margin-block-start:var(--s4);
  padding:var(--s4) var(--s6); min-block-size:52px;
  font:800 var(--t-small)/1.4 Heebo,sans-serif; letter-spacing:.02em;
  background:var(--hivis); color:var(--ink); text-decoration:none;
  box-shadow:var(--shadow-plate);
}
.pick-buy:hover{ background:var(--bone); }

/* The un-sliceable sheets. Shown whole and large, which is the entire point -
   it was already on the page at thumbnail size and nobody could read it. */
.codesheet{ margin:0; }
.codesheet img{ inline-size:100%; block-size:auto; background:var(--crate-deep); }
.colours-list{
  margin-block-start:var(--s4);
  font-size:var(--t-data); letter-spacing:.06em; opacity:.75;
}

.seek-said{
  margin-block-start:var(--s3);
  font:800 var(--t-small)/1.3 Heebo,sans-serif; color:var(--ink);
}

.panel[hidden]{ display:none; }
.showcase{ display:block; }
/* A revealed band should not snap in. Same landing ease as the plates. */
.showcase > .band{ animation:arrive 420ms var(--ease-land) both; }
@keyframes arrive{ from{ opacity:0 } to{ opacity:1 } }

.show-all{
  display:block; inline-size:calc(100% - var(--gutter) * 2);
  margin:var(--s6) var(--gutter) var(--s7);
  font:800 var(--t-small)/1 Heebo,sans-serif; letter-spacing:.02em;
  padding:var(--s4) var(--s5); min-block-size:48px;
  background:transparent; color:var(--hivis);
  border:3px solid var(--hivis); cursor:pointer;
}
.show-all:hover{ background:var(--hivis); color:var(--ink); }

/* The supplier's demo clip. Held to the same hard-edged language as the plates:
   no radius, one fluorescent rule, and the video sized by its own aspect ratio
   so nothing shifts when it decodes. The clips are portrait phone footage, so
   the cap is on HEIGHT - letting a 406x720 fill a desktop column would blow it
   up to a wall of pixels. */
.demo{ display:flex; flex-direction:column; align-items:flex-start; gap:var(--s4); }
.demo-v{
  display:block;
  max-block-size:min(70svh,620px); max-inline-size:100%;
  block-size:auto; inline-size:auto;
  background:var(--crate-deep);
  border:3px solid var(--hivis);
}
.demo-n{ font-size:var(--t-small); opacity:.72; margin:0; }
/* One clip per colourway, so a product can carry four. They wrap rather than
   stack: four full-height videos in a column is a page nobody scrolls to the
   end of. Each keeps its own aspect ratio, which is why the row is align-start. */
.demo-set{ display:flex; flex-wrap:wrap; align-items:flex-start; gap:var(--s4); inline-size:100%; }
.demo-one{ margin:0; display:flex; flex-direction:column; gap:var(--s2); max-inline-size:100%; }

/* Cookie notice. Same language as everything else: no radius, a hard offset
   shadow, one fluorescent edge. It sits at the block-end so it never covers the
   masthead, and it is `position:fixed` with its own z-index ABOVE the sticky buy
   bar - a notice you cannot reach past is worse than no notice.
   ⚠ It reserves nothing and shifts nothing: fixed, so the page beneath it does
   not reflow when it appears or goes. */
.consent{
  position:fixed; z-index:calc(var(--z-sticky) + 10);
  inset-inline:0; inset-block-end:0;
  display:flex; flex-wrap:wrap; align-items:center; gap:var(--s4);
  padding:var(--s4) var(--gutter);
  background:var(--crate-deep); color:var(--bone);
  border-block-start:3px solid var(--hivis);
}
.consent[hidden]{ display:none; }
.consent-t{ margin:0; flex:1 1 22ch; font-size:var(--t-small); line-height:1.45; }
.consent-b{ display:flex; gap:var(--s3); flex:0 0 auto; }
.consent button{
  font:800 var(--t-small)/1 Heebo,sans-serif;
  padding:var(--s3) var(--s5); min-block-size:44px; cursor:pointer;
  border:2px solid var(--hivis);
}
.consent-y{ background:var(--hivis); color:var(--ink); }
.consent-n{ background:transparent; color:var(--hivis); }
.consent button:hover{ background:var(--bone); color:var(--ink); border-color:var(--bone); }

@media (max-width:700px){
  .consent{ padding-block-end:calc(var(--s4) + env(safe-area-inset-bottom)); }
}
/* ⚠ There is deliberately NO `.product .consent` rule here. The notice is a
   body-level sibling of <main class="product">, so a descendant selector never
   matches it - one was written, looked right, and silently did nothing while
   the notice covered the buy button. app.js measures the sticky bar and sets
   inset-block-end directly, which also gets the height right instead of
   guessing 76px. */

/* ---------------------------------------------------------------- the bands */

.band{
  position:relative; z-index:var(--z-band);
  min-block-size:clamp(420px,66vh,760px);
  background:var(--crate);
  padding-block:var(--s7) var(--s6);
  display:flex; flex-direction:column; justify-content:center;
  border-block-end:2px solid var(--crate-deep);
  /* ⚠ NO content-visibility here, and that is deliberate. It used to carry
     `content-visibility:auto; contain-intrinsic-size:auto 640px`, which skips
     rendering a band while it is off-screen - and a skipped subtree is invisible
     to native lazy-loading too, so the rail's six photos were not even
     REQUESTED until the band was already on screen. On a phone that meant
     scrolling onto a band and watching an empty blue box while 350 KB started
     downloading from scratch. Without it the browser resumes its normal
     look-ahead and fetches the next band's strip before you reach it.
     13 sections is not a virtualisation problem; the filter hides bands with
     [hidden]/display:none, which never needed containment to work. */
}
.band[hidden]{ display:none; }

/* ⚠ direction:ltr belongs HERE, on the clipping window, not on the track.
   `@keyframes rail` translates by a PHYSICAL -50%, which only lands correctly if
   the track's own layout origin is the LEFT edge. Putting direction:ltr on the
   track itself does not do that: `direction` governs how an element lays out its
   CHILDREN, never where its own box is placed - that is decided by the parent.
   So under the page's dir="rtl" the over-wide track right-aligned and overflowed
   LEFT, and translating it a further one-copy-width left carried it clean out of
   the window. Measured on the live site at 375px: copy width 633px against a
   375px window, track at [-1526,-259], zero pixels of overlap. The rails were
   not slow, they were somewhere else. */
.rail{ position:relative; z-index:var(--z-rail); overflow:hidden; direction:ltr; }
.rail-track{
  display:flex; inline-size:max-content;
  animation:rail var(--dur) linear infinite;
  animation-play-state:paused;
}
.band.is-live .rail-track{ animation-play-state:running; will-change:transform; }
.band:hover .rail-track,.band:focus-within .rail-track{ animation-play-state:paused; }
.rail-track[data-drift="b"]{ animation-direction:reverse; }
.rail-run{ display:flex; }
.rail img{
  block-size:clamp(132px,17vw,224px); inline-size:auto;
  max-width:none; object-fit:cover;
  /* The width/height attributes already reserve the box, so a photo that has
     not arrived yet leaves a hole the exact colour of the band and the strip
     reads as missing rather than as loading. Tinting the reserved box makes an
     unfilled rail look like a rail. */
  background:var(--crate-deep);
}
/* --shift is 100%/copies, so it is exactly ONE copy width whatever the copy
   count. It cannot be hardcoded to -50%: render.mjs solves the copy count per
   band from the real photo aspect ratios, because two copies only tile the
   window while a single copy is at least as wide as the rail - false on every
   desktop band and false on the compact product-page rails even on a phone. */
@keyframes rail{ from{ transform:translate3d(calc(-1 * var(--shift, 50%)),0,0) } to{ transform:translate3d(0,0,0) } }

/* ⚠ THE SHADOW LIVES ON THE HOLDER, NOT ON THE PLATE, AND IT IS A FILTER.
   `clip-path` clips an element's OWN box-shadow, and every --cut polygon has all
   its vertices inside the border box, so a box-shadow on .plate was clipped away
   in full: measured 11,136 shadow pixels with clip-path removed, 0 with it on.
   The site shipped for days with its signature hard shadow silently dead, and
   the 620ms shadow transition animating nothing.
   `filter:drop-shadow()` on .plate itself does NOT fix it either - filter is
   applied BEFORE clip-path on the same element, so the shadow is generated and
   then clipped. It has to sit on a parent, and the payoff is that drop-shadow
   traces the CUT SHAPE rather than the rectangle, which is what the hand-drawn
   polygons wanted all along.
   ⚠ Never wrap `.hang` this way: filter creates a containing block for fixed
   descendants and .hang is position:fixed at every width. That bar has already
   lost its positioning twice. */
.plate-hold{
  position:absolute; z-index:var(--z-plate);
  inset-inline-end:var(--gutter);
  inline-size:min(440px,calc(100% - var(--gutter) * 2));
  filter:drop-shadow(var(--shadow-rest-x) var(--shadow-rest-x) 0 var(--shadow));
  transition:filter 620ms var(--ease-land);
}
.plate{
  display:block; inline-size:100%;
  background:var(--hivis); color:var(--ink);
  padding:var(--s5) var(--s5) var(--s4);
  text-decoration:none;
  clip-path:var(--cut);
  transform:rotate(calc(var(--tilt) - 5deg)) translate3d(0,26px,0);
  transition:transform 620ms var(--ease-land);
}
.band[data-side="start"] .plate-hold{ inset-inline-start:var(--gutter); inset-inline-end:auto; }
.band[data-side="end"] .plate-hold{ inset-block-start:var(--s7); }
.band[data-side="start"] .plate-hold{ inset-block-end:var(--s7); }
.band.is-in .plate{ transform:rotate(var(--tilt)); }
.band.is-in .plate-hold{ filter:drop-shadow(var(--shadow-land-x) var(--shadow-land-x) 0 var(--shadow)); }
.plate:hover{ background:var(--ink); color:var(--hivis); }

.plate-title{ font-size:var(--t-title); }
.plate-price{ font-size:var(--t-board); line-height:.9; margin:var(--s2) 0 0;
  clip-path:inset(0 0 100% 0); transition:clip-path 420ms 200ms var(--ease-land); }
.band.is-in .plate-price,.product .plate-price{ clip-path:inset(0 0 0 0); }
.plate-usd{ font-size:15px; margin:0; opacity:.72; }
.go{
  display:inline-flex; align-items:center; gap:var(--s2);
  font:800 var(--t-small)/1 Heebo,sans-serif; margin-block-start:var(--s3);
}
/* The document is rtl and the mark must point inline-end. */
.out{ transform:scaleX(-1); }

.ledger{
  position:relative; z-index:var(--z-ledger);
  margin:var(--s5) 0 0; padding:var(--s3) var(--gutter) 0;
  border-block-start:1px solid var(--rule);
  font-size:var(--t-data); color:rgb(242 239 224 / .72);
}

/* Sticky way home. Product pages only; the index hero is already the wordmark. */
.topbar{
  position:sticky; inset-block-start:0; z-index:var(--z-head);
  display:flex; align-items:center; justify-content:space-between; gap:var(--s4);
  padding:var(--s3) var(--gutter);
  background:var(--ink); color:var(--bone); text-decoration:none;
  border-block-end:2px solid var(--hivis);
}
/* The mark is the only multicolour thing on the site. It earns that by being
   the shop's actual logo, and it sits on ink so every facet stays legible. */
.mark{ inline-size:clamp(30px,4vw,40px); block-size:auto; flex:none; display:block; }
.topbar-name{
  font-family:Karantina,'Arial Hebrew',sans-serif; font-weight:700;
  font-size:clamp(24px,3vw,32px); line-height:1; color:var(--hivis);
  margin-inline-end:auto;
}
.topbar-back{
  display:inline-flex; align-items:center; gap:var(--s2);
  font:800 var(--t-small)/1 Heebo,sans-serif;
}
/* The bar is a <div> holding two links, not one link, because a language
   switch nested inside the home link would be an <a> inside an <a>. The home
   half keeps every pixel of the old behaviour; the switch sits at the end. */
.topbar-home{
  display:flex; align-items:center; gap:var(--s4); flex:1 1 auto;
  min-inline-size:0; color:inherit; text-decoration:none;
}
.topbar-home:hover{ background:var(--hivis); color:var(--ink); }
.topbar-home:hover .topbar-name{ color:var(--ink); }
.topbar-home:hover .topbar-back{ color:var(--ink); }

/* Deliberately small and plain. It is a way out for someone in the wrong
   language, not a feature to advertise, and the fluorescent board already has
   all the shouting the page can carry. */
.lang{
  flex:none; text-decoration:none; white-space:nowrap;
  font:800 var(--t-small)/1 Heebo,sans-serif;
  color:var(--bone); border:2px solid var(--hivis); padding:8px 12px;
}
.lang:hover{ background:var(--hivis); color:var(--ink); }
/* On the home page the switch sits in the top corner of the board rather than
   in the middle of it. A visitor who landed in the wrong language should not
   have to scroll past a masthead to get out of it, and the footer copy is too
   far down to count as an exit. */
/* Two other languages means two links, so they need a row of their own rather
   than one pill floated into a corner. */
.langs{ display:flex; gap:var(--s2); flex:none; }
.langs-board{
  position:absolute; inset-block-start:var(--s3); inset-inline-end:var(--gutter);
}
.lang-board{ margin:0; color:var(--ink); border-color:var(--ink); background:var(--bone); }
.lang-board:hover{ background:var(--ink); color:var(--hivis); }
.foot-lang{ text-decoration:underline; }

/* -------------------------------------------------------------- the product */

/* The banner photo is shown WHOLE, never as a cover-cropped background. A wide
   short strip crops a 3:4 product shot down to a slice of the midsole, which is
   what "it is cut" meant. It sits in its own column at its own aspect ratio, at
   full opacity, because a product photo is worth looking at. */
.head{
  background:var(--crate);
  padding:var(--s6) var(--gutter) var(--s7);
  border-block-end:2px solid var(--crate-deep);
  display:grid; gap:clamp(20px,3vw,48px);
  grid-template-columns:minmax(0,0.85fr) minmax(0,1fr);
  align-items:center;
}
/* Main photo and the colour-code sheet share the media column, side by side.
   The code sheet is what a buyer needs in order to pick a code, so it sits next
   to the product rather than at the end of a sixty-photo grid. */
.head-media{ display:grid; gap:var(--s4); grid-template-columns:minmax(0,1.35fr) minmax(0,1fr); align-items:start; }
.head-media:has(.head-shot:only-child){ grid-template-columns:1fr; }
.head-shot,.head-codes{ margin:0; }
.head-shot img,.head-codes img{ inline-size:100%; block-size:auto; }
.head-codes .shot{ display:block; inline-size:100%; padding:0; border:0; background:var(--crate-deep); cursor:zoom-in; }
.head-codes .shot + .shot{ margin-block-start:var(--s2); }
.head-codes figcaption{
  margin-block-start:var(--s2);
  font:800 var(--t-micro)/1.4 Heebo,sans-serif; color:var(--hivis);
}
.head-text{ min-inline-size:0; }
.head h1{ font-size:var(--t-title); max-inline-size:20ch; }

.plate-hold-lg{
  position:relative; inset:auto; margin-block-start:var(--s5);
  inline-size:min(460px,100%);
  filter:drop-shadow(var(--shadow-lg-x) var(--shadow-lg-x) 0 var(--shadow));
  transition:none;
}
.plate-lg{
  inline-size:100%;
  transform:rotate(var(--tilt));
  transition:background-color 90ms steps(2), color 90ms steps(2);
}

.grid-wrap{ padding:var(--s6) var(--gutter); }
.shots{
  list-style:none; margin:0; padding:0;
  display:grid; gap:6px;
  grid-template-columns:repeat(auto-fill,minmax(clamp(104px,15vw,176px),1fr));
}
.shots li[hidden]{ display:none; }
.shots .shot{
  display:block; inline-size:100%; padding:0; border:0;
  background:var(--crate); cursor:zoom-in;
  aspect-ratio:1;
}
/* The uniform frame is made here, not in the files. object-position is pulled
   down because the supplier burns a red style code into the top of the portrait
   shots; the lightbox still opens the whole uncropped photo. */
.shots img{ inline-size:100%; block-size:100%; object-fit:cover; object-position:50% 62%; }

.shots li{ transition:box-shadow 180ms linear; }
.shots li:hover,.shots li:focus-within{ box-shadow:0 0 0 3px var(--hivis); }

.more-shots{
  margin-block-start:var(--s4);
  padding:var(--s3) var(--s5);
  background:transparent; color:var(--bone);
  border:2px solid var(--rule); cursor:pointer;
  font:800 var(--t-small)/1 Heebo,sans-serif;
}
.more-shots:hover{ background:var(--hivis); color:var(--ink); border-color:var(--hivis); }
.more-shots[hidden]{ display:none; }

.slab{ padding:var(--s7) var(--gutter); border-block-start:1px solid var(--rule); }
.slab h2{ font-size:var(--t-h2); margin-block-end:var(--s4); }

.codes{ list-style:none; margin:0 0 var(--s4); padding:0;
  display:grid; grid-template-columns:repeat(auto-fill,minmax(112px,1fr)); gap:var(--s2); font-size:var(--t-data); }
.codes li{ border:1px solid var(--rule); padding:var(--s2) var(--s3); display:flex; flex-direction:column; gap:2px; }
.cc{ color:var(--bone); }
.cw{ color:var(--hivis); font-size:var(--t-micro); font-weight:800; }

.how{ background:var(--crate); }
.steps{ margin:0; padding-inline-start:var(--s5); max-inline-size:70ch; }
.steps li{ margin-block-end:var(--s3); font-size:var(--t-small); line-height:1.7; }
.steps li::marker{ color:var(--hivis); font-weight:800; }
.steps strong{ font-weight:800; color:var(--hivis); }

.note{ margin:0 0 var(--s3); font-size:var(--t-small); max-inline-size:68ch; color:rgb(242 239 224 / .82); }
.note strong{ font-weight:800; color:var(--bone); }

.sizes{ font-size:var(--t-data-lg); font-weight:700; margin:0 0 var(--s5); }

.chart{ margin:0; }
.chart figcaption{ font:800 var(--t-small)/1 Heebo,sans-serif; margin-block-end:var(--s3); }
.chart-zoom{ display:block; inline-size:100%; padding:0; border:0; background:none; cursor:zoom-in; }
.chart img{ inline-size:100%; block-size:auto; background:var(--bone); }

.more{ padding-block-start:var(--s7); border-block-start:1px solid var(--rule); }
.more > h2{ font-size:var(--t-h2); padding-inline:var(--gutter); margin-block-end:var(--s5); }
.more .band{ min-block-size:clamp(260px,38vh,420px); }
.more .rail img{ block-size:clamp(96px,11vw,150px); }
.more .plate-title{ font-size:clamp(22px,2.2vw,30px); }
.more .plate-price{ font-size:clamp(32px,5vw,74px); }

/* The only commercial action on the page, permanently in thumb reach. */
.hang{
  position:fixed; z-index:var(--z-sticky);
  inset-block-end:var(--s5); inset-inline-start:var(--s5); inset-inline-end:auto;
  inline-size:auto; padding:var(--s4) var(--s5);
  display:flex; align-items:center; gap:var(--s4);
  transform:rotate(var(--tilt));
  /* ⚠ No shadow, and no drop-shadow holder either. .hang is position:fixed at
     every width, and a filtered ancestor becomes its containing block, which
     would drop the bar out of the viewport-fixed layer. It also inherits
     .plate's clip-path, so a box-shadow here would be clipped to nothing
     anyway - it was, silently, and this is the honest version. */
  transition:background-color 90ms steps(2), color 90ms steps(2);
}
.hang-price{ font-size:34px; line-height:1; }
.hang .go{ margin:0; }

/* ------------------------------------------------------------------ dialog */

dialog{
  border:0; padding:0; max-inline-size:96vw; max-block-size:96svh;
  background:transparent; color:var(--bone);
}
dialog::backdrop{ background:rgb(3 45 102 / .94); }
dialog[open]{ animation:pop 160ms var(--ease-land); }
dialog::backdrop{ animation:fade 160ms linear; }
@keyframes pop{ from{ transform:scale(.965); opacity:0 } }
@keyframes fade{ from{ opacity:0 } }
#lb-img{ max-block-size:88svh; inline-size:auto; margin-inline:auto; }
/* ⚠ CHART MODE EXISTS BECAUSE A FITTED SIZE CHART IS NOT A ZOOM.
   The dialog is capped at 96vw and `img{max-width:100%}` fits the picture to
   it, so opening a 5.5:1 measurement table reproduced the exact 345x62 it
   already had on the page. Here it keeps its natural pixels and the DIALOG
   scrolls, which is how you read a wide table on a phone. max-width is used
   rather than max-inline-size on purpose: it is the same physical property the
   base img rule sets, so this unambiguously overrides it. */
#lb[data-mode="chart"]{ overflow:auto; overscroll-behavior:contain; }
#lb[data-mode="chart"] #lb-img{ max-width:none; max-block-size:none; inline-size:auto; block-size:auto; }
.lb-x{
  position:absolute; inset-block-start:0; inset-inline-end:0; z-index:1;
  inline-size:48px; block-size:48px; font-size:28px; line-height:1;
  background:var(--hivis); color:var(--ink); border:0; cursor:pointer;
}
.lb-n{ text-align:center; margin:var(--s3) 0 0; font-size:var(--t-data); }

/* ------------------------------------------------------------------- foot */

.foot{
  padding:var(--s7) var(--gutter) var(--s8);
  border-block-start:2px solid var(--hivis);
  background:var(--crate-deep);
}
.foot-name{
  margin:0 0 var(--s5);
  font-family:Karantina,'Arial Hebrew',sans-serif; font-weight:700;
  font-size:clamp(28px,4vw,44px); line-height:1; color:var(--hivis);
}
.foot nav{ display:flex; flex-wrap:wrap; gap:var(--s5); }
.foot nav a{ font:800 var(--t-small)/1 Heebo,sans-serif; text-decoration:none; }
.foot nav a:hover{ color:var(--hivis); }

/* ------------------------------------------------------------ small screens */

@media (max-width:700px){
  /* Scoped to band plates on purpose. A bare .plate here also matches the
     sticky buy bar, which carries both classes, and would drop it out of the
     fixed layer and out of thumb reach. */
  .band .plate-hold{
    position:static; inline-size:auto;
    margin:var(--s5) var(--gutter) 0;
  }
  .band{ justify-content:flex-start; }
  /* Photo above the title on a phone, still whole and still uncropped.
     The code sheet keeps its own row rather than shrinking to a thumbnail,
     because its whole job is that the codes stay readable. */
  .head{ grid-template-columns:1fr; padding-block:var(--s5) var(--s6); }
  .head-media{ grid-template-columns:1fr; }
  .hang{
    position:fixed;
    inset-inline:0; inset-block-end:0;
    inline-size:100%; justify-content:space-between;
    transform:none; clip-path:none; box-shadow:none;
    border-block-start:3px solid var(--ink);
  }
  .product{ padding-block-end:96px; }
}

/* --------------------------------------------------------- reduced motion */

@media (prefers-reduced-motion: reduce){
  /* Rails become swipeable shelves. ⚠ direction:rtl has to be restored on the
     RAIL, not only on the track: the rail is the scroll container here, and a
     scroller only exposes overflow on its inline-END side. With the rail left
     ltr (from line 173) and the track rtl, the strip laid out from the track's
     right edge and spilled LEFT - the one side an ltr scroller will not scroll
     to. Measured before this line existed: scrollWidth === clientWidth on all
     19 bands, scrollLeft clamped to 0 in both directions, and 37-68% of every
     strip permanently unreachable. It read as a shelf you could not push. */
  .rail{ direction:rtl; overflow-x:auto; scroll-snap-type:x mandatory; scroll-padding-inline-start:var(--gutter); }
  .rail-track{ animation:none; direction:rtl; inline-size:auto; }
  .rail-track [aria-hidden="true"]{ display:none; }
  .rail-run > *{ scroll-snap-align:start; }

  /* ⚠ `.band .plate`, never a bare `.plate`. The sticky mobile buy bar is
     class="hang plate", so a bare selector re-applies the tilt and the hard
     shadow that the <=700px rule deliberately zeroed on it - the same
     over-broad-selector mistake that once cost the bar its position:fixed. */
  .band .plate{ transform:rotate(var(--tilt)); transition:none; }
  .band .plate-hold{ filter:drop-shadow(var(--shadow-land-x) var(--shadow-land-x) 0 var(--shadow)); transition:none; }
  .plate-price{ clip-path:none; transition:none; }

  .shots li{ transition:none; }
  .shots li:hover,.shots li:focus-within{
    box-shadow:none;
    outline:3px solid var(--hivis); outline-offset:2px;
  }
  dialog[open],dialog::backdrop{ animation:none; }
}
