@charset "utf-8";

/* EDI Electronics Outlet
   The whole stylesheet. Sections 3 and 4 of BUILD-SPEC.md, in spec order.

   Reading order below: font faces, tokens, reset, base elements, utilities, focus,
   grid, motion, then every component in section 4.

   Three things a reader will otherwise trip over, all of them load-bearing:

   1. Colour. Nothing here uses a colour that is not already a token in 3.7, because a new
      colour without a measured luminance and a measured ratio is banned by rule 42. The one
      literal is #FFFFFF, and it is literal on purpose: on the green fill, the heading token
      measures 4.13 and fails, so the white is written out at every point where text can land
      on green rather than left to inherit.
   2. Motion. Only the 6 rows of the 3.13 table animate. Every transition below names its
      properties one at a time, so nothing new can ride in on a shorthand.
   3. Radius. Two values, 0 and 2px, plus 50% on the 2 counter-state dots and nothing else.

   Naming. Every selector here is written against the class the page generator actually emits.
   Where this file once carried a second private name for something the generator already
   named, the rule was renamed rather than copied, because 2 names for 1 thing is how the
   header, the certification row and the buy column came to render bare in the first place.
*/

/* ---------------------------------------------------------------------------
   FONT FACES, 3.8
   --------------------------------------------------------------------------- */

/* Archivo variable, weight axis only, latin subset, self-hosted. The width axis is not
   loaded: it costs 90,104 bytes for a variation this design uses twice. swap rather than
   optional because the fallback below is metric-matched, so the swap does not move text. */
@font-face{
  font-family:"Archivo";
  src:url("archivo.woff2") format("woff2");
  font-weight:100 900;
  font-style:normal;
  font-display:swap;
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,
    U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,
    U+FEFF,U+FFFD;
}

/* Metric override so nothing jumps when the real font lands. Archivo x-height is 0.5260 em
   against Arial at 0.5186, which is where 101.4% comes from. */
@font-face{
  font-family:"Archivo Fallback"; src:local("Arial");
  size-adjust:101.4%; ascent-override:92%; descent-override:24%; line-gap-override:0%;
}

/* ---------------------------------------------------------------------------
   TOKENS, 3.7 and 3.8
   --------------------------------------------------------------------------- */

:root{
  /* surfaces */
  --surface-page:#17191A; --surface-default:#26292A;
  --surface-raised:#2E3132; --surface-pressed:#383B3C;
  --plinth:#EDEEEA; --plinth-hover:#F3F4F1; --plinth-small:#E4E6E1;
  --plinth-ink:#2C2D2D;

  /* text */
  --text-heading:#F2F3F1; --text-body:#F2F3F1; --text-muted:#AEB6B2;

  /* green, split into 2 roles. The split is not optional. */
  --accent-fill:#0C8566;     /* fills only, #FFFFFF hardcoded on it */
  --accent-on-dark:#12B88C;  /* text and information only */
  --focus-ring:#4CC9A3;
  --accent-rgb:12,133,102;

  /* state */
  --state-closed:#E8B14C;    /* 9.09 / 7.55 / 6.76. Counter rail only */
  --stamp:#E8C46A;           /* review builds only, never ships live */
  --stamp-ink:#17191A;

  /* structure */
  --hairline:rgb(255 255 255 / .08);
  --hairline-strong:rgb(255 255 255 / .14);
  --edge:#808282;

  /* radii */
  --r-0:0;    /* panels, tiles, photographs, plinths, tables, sheets */
  --r-1:2px;  /* buttons, inputs, chips, tags */

  /* layout */
  --wrap:1440px;
  --gutter:clamp(1rem,3.2vw,3rem);
  --header-h:108px; /* overwritten at runtime by ResizeObserver */
}

:root{
  --ff-sans:"Archivo","Archivo Fallback","Segoe UI",system-ui,Arial,sans-serif;
  --ff-mono:ui-monospace,"Cascadia Mono","SF Mono",Menlo,Consolas,monospace;

  /* The floor is 2.125rem, not the 2.75rem the specification names. At 320px, 2.75rem sets
     "WORKSTATIONS," at about 370px inside 288px of content, so the page scrolled sideways on a
     phone, which acceptance item 18 forbids outright. Nothing above 531px changes, and the cap
     is untouched. A headline that overflows is worse than a headline that is 10px smaller. */
  --t-display:clamp(2.125rem,6.4vw,4.5rem);  --lh-display:0.95; --ls-display:-0.022em;
  --t-h1:clamp(2.25rem,4.4vw,3.25rem);      --lh-h1:1.00;      --ls-h1:-0.018em;
  --t-h2:clamp(1.75rem,3.0vw,2.25rem);      --lh-h2:1.06;      --ls-h2:-0.012em;
  --t-h3:1.5rem;      --lh-h3:1.15;   --ls-h3:-0.006em;
  --t-h4:1.25rem;     --lh-h4:1.25;   --ls-h4:0;
  --t-lede:1.125rem;  --lh-lede:1.55; --ls-lede:0;
  --t-body:1rem;      --lh-body:1.60; --ls-body:0;
  --t-small:0.875rem; --lh-small:1.50;--ls-small:0;
  --t-caption:0.8125rem; --lh-caption:1.45; --ls-caption:0;
  --t-eyebrow:0.6875rem; --lh-eyebrow:1.20; --ls-eyebrow:0.14em;
  --t-price:2rem;        --lh-price:1.00;   --ls-price:-0.012em;
  --t-price-2:1.125rem;  --lh-price-2:1.20;
  --t-cell-price:1.25rem;--lh-cell-price:1.00; --ls-cell-price:-0.012em;
  --t-cell-name:0.875rem;--lh-cell-name:1.35;
  --t-list-name:0.9375rem; --lh-list-name:1.30;
  --t-ref:0.8125rem;     --lh-ref:1.20;     --ls-ref:0.04em;
}

/* ---------------------------------------------------------------------------
   RESET
   --------------------------------------------------------------------------- */

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

/* The search field filters by toggling hidden on cells that are display:flex, so this has to
   win outright or a filtered-out product stays on screen. */
[hidden]{ display:none !important; }

html{
  color-scheme:dark;
  -webkit-text-size-adjust:100%;
  text-size-adjust:100%;
}

body{
  margin:0;
  background:var(--surface-page);
  color:var(--text-body);
  font-family:var(--ff-sans);
  font-size:var(--t-body);
  line-height:var(--lh-body);
  font-weight:400;
  font-synthesis-weight:none;
}

h1,h2,h3,h4,h5,h6,p,figure,blockquote,dl,dd{ margin:0; }
ul,ol{ margin:0; padding:0; }
li{ list-style:none; }

img,picture,svg,video{ display:block; max-width:100%; }
img{ height:auto; }

button,input,select,textarea{
  font:inherit; color:inherit; letter-spacing:inherit; margin:0;
}
button{ background:none; border:0; padding:0; cursor:pointer; }

fieldset{ margin:0; padding:0; border:0; min-inline-size:0; }
legend{ padding:0; }

table{ border-collapse:collapse; inline-size:100%; }

/* Archivo ships no slanted file and nothing on this site is ever slanted. Without this the
   browser synthesises a slant for these elements, which is the exact thing 3.8 rules out.
   Emphasis is carried by weight instead. */
em,i,cite,dfn,var,address{ font-style:normal; }
em,i{ font-weight:600; }

/* ---------------------------------------------------------------------------
   BASE ELEMENTS
   --------------------------------------------------------------------------- */

h1{ font-size:var(--t-h1); line-height:var(--lh-h1); letter-spacing:var(--ls-h1);
    font-weight:700; color:var(--text-heading); text-wrap:balance; }
h2{ font-size:var(--t-h2); line-height:var(--lh-h2); letter-spacing:var(--ls-h2);
    font-weight:700; color:var(--text-heading); text-wrap:balance; }
h3{ font-size:var(--t-h3); line-height:var(--lh-h3); letter-spacing:var(--ls-h3);
    font-weight:600; color:var(--text-heading); }
h4{ font-size:var(--t-h4); line-height:var(--lh-h4); letter-spacing:var(--ls-h4);
    font-weight:600; color:var(--text-heading); }

strong,b{ font-weight:700; color:var(--text-heading); }
small{ font-size:var(--t-small); line-height:var(--lh-small); }

/* A stray link still has to read as a link, because the pages are written by a script and an
   unstyled anchor on a dark ground is invisible. Components that are not prose links turn the
   underline off again below.

   :where() so this carries no specificity at all. Without it, a:hover would beat .btn-primary
   and paint the mint over the green fill at 1.45, which is exactly the silent failure rule 38
   is written about. Every component rule below now wins on its own. */
:where(a){
  color:var(--text-heading);
  text-decoration:underline;
  text-decoration-thickness:1px;
  text-underline-offset:.18em;
}
:where(a:hover){ color:var(--accent-on-dark); }

::placeholder{ color:var(--text-muted); opacity:1; }
::selection{ background:var(--surface-pressed); color:var(--text-heading); }

/* ---------------------------------------------------------------------------
   UTILITIES
   --------------------------------------------------------------------------- */

.vh{
  position:absolute; inline-size:1px; block-size:1px;
  padding:0; margin:-1px; overflow:hidden;
  clip-path:inset(50%); white-space:nowrap; border:0;
}

/* One of the 3 permitted monospace uses: item references, manufacturer model codes, and the
   4 ordinals on /testing/. Never on prose and never on a price. */
.mono{
  font-family:var(--ff-mono);
  font-size:var(--t-ref); line-height:var(--lh-ref); letter-spacing:var(--ls-ref);
}

.num{ font-variant-numeric:tabular-nums; }

.prose p,.prose li{ font-size:var(--t-body); line-height:var(--lh-body); max-inline-size:68ch; }
.prose p + p{ margin-block-start:1rem; }
.prose h2{ margin-block:3rem 1rem; }
.prose h3{ margin-block:2rem .75rem; }

/* 3.12. On a dark ground a drop shadow does almost nothing, the 1px top highlight is what
   sells elevation. Exactly 3 things carry this: the sticky header with its rail, the mobile
   drawer and the mobile action bar. The drawer and the bar carry the class in the markup; the
   header is named here so a 4th thing cannot quietly acquire the treatment. */
.floating,
.hdr{
  background:var(--surface-default);
  box-shadow:inset 0 1px 0 rgb(255 255 255 / .08), 0 24px 48px -12px rgb(0 0 0 / .70);
}

/* ---------------------------------------------------------------------------
   FOCUS, and SC 2.4.11
   --------------------------------------------------------------------------- */

:where(a,button,input,select,summary,[tabindex]):focus-visible{
  outline:3px solid var(--focus-ring); outline-offset:2px; border-radius:inherit;
}

/* outline-offset puts the ring on the dark ground rather than on the green fill, where the
   mint measures 2.23 and disappears. The shadow fills that 2px gap with the page colour so
   the ring never touches the green. */
.btn-primary:focus-visible{ box-shadow:0 0 0 2px var(--surface-page); }

/* The mint ring against the light plinth measures 1.81 and is not usable, so anything
   focusable that lands on the certification band takes the plinth ink instead, at 11.85. */
.certs :focus-visible{ outline-color:var(--plinth-ink); }

/* The browser's own scroll-into-view for a newly focused element honours scroll-padding, which
   is what makes keyboard focus pass 2.4.11 and not just anchor jumps. --header-h is measured
   at runtime because the header changes height at 320px and at 200% zoom, which is exactly
   when this value matters. */
html{ scroll-padding-top: calc(var(--header-h) + 1rem); }
:target,[id],#main,h1,h2,h3{ scroll-margin-top: calc(var(--header-h) + 1rem); }
@media (max-height:450px){
  .hdr{ position:static; }
  html{ scroll-padding-top:1rem; }
}

/* ---------------------------------------------------------------------------
   GRID, 3.10
   --------------------------------------------------------------------------- */

.wrap{ max-width:var(--wrap); margin-inline:auto; padding-inline:var(--gutter); }

/* THE SHEET. Borders on children right and bottom, container top and left.

   minmax(0,1fr) and not a bare 1fr, for the same reason 4.2 puts minmax(0,auto) on the
   counter rail. A bare 1fr floors every track at the cell's own min-content, and a cell whose
   footer holds a 15 character reference on one unbreakable line measures 422px, so 4 tracks
   came to 1,692px inside a 1,425px page and the home page scrolled sideways at 1440 by 253px.
   With the floor removed the tracks are 356px at 1440, which is the cell size 3.10 states in
   its own arithmetic, and nothing inside a cell overflows it. */
.sheet{
  display:grid; gap:0; grid-template-columns:repeat(2,minmax(0,1fr));
  border-top:1px solid var(--hairline);
  border-left:1px solid var(--hairline);
}
.sheet > *{
  border-right:1px solid var(--hairline);
  border-bottom:1px solid var(--hairline);
}
@media (min-width:700px){  .sheet{ grid-template-columns:repeat(3,minmax(0,1fr)); } }
@media (min-width:1040px){ .sheet{ grid-template-columns:repeat(4,minmax(0,1fr)); } }

.sheet--gallery{ grid-template-columns:minmax(0,1fr); }
@media (min-width:700px){ .sheet--gallery{ grid-template-columns:repeat(2,minmax(0,1fr)); } }
.sheet--list{ grid-template-columns:minmax(0,1fr); }

.cell--wide{ grid-column:span 2; }
.cell--full{ grid-column:1 / -1; }

/* ITEM AND MODEL PAGES */
.item{
  display:grid; grid-template-columns:repeat(12,minmax(0,1fr));
  column-gap:clamp(1.5rem,3vw,3rem); row-gap:2rem;
}
.item__media{ grid-column:1 / span 7; }
.item__buy{
  grid-column:8 / span 5;
  position:sticky; top:calc(var(--header-h) + 1.5rem); align-self:start;
}
@media (max-width:900px){
  .item__media,.item__buy{ grid-column:1 / -1; }
  .item__buy{ position:static; }
}

/* SHOP: fixed rail plus sheet */
@media (min-width:1040px){
  .shop{ display:grid; grid-template-columns:240px minmax(0,1fr); column-gap:0; }
  .shop__rail{ position:sticky; top:calc(var(--header-h) + 1.5rem); align-self:start;
               border-right:1px solid var(--hairline); padding-right:1.5rem; }
  .shop__sheet{ padding-left:1.5rem; }
}

/* At 1440 with a 48px gutter, 4 columns gives 336px cells, a plinth of 336 by 252 and a cell
   about 390px tall. That is where contain-intrinsic-size comes from, further down. */

/* ---------------------------------------------------------------------------
   THE 8 PAGE CLASSES, on <body>
   --------------------------------------------------------------------------- */

/* These carry the 3 differences the specification actually asks for and nothing else.

   1. Two page types, home and visit, open with a full bleed band that has to meet the counter
      rail with no gap, so only those two carry no separation above <main>. Every other type
      opens with a breadcrumb inside .wrap and needs the air.
   2. 3.9 permits 2 section values and no others, 4rem and 6rem. That is what closes every
      page above the certification band, which is a light band and needs the dark page to
      finish before it starts.
   3. The item page is the only one carrying the fixed mobile bar, so it is the only one that
      has to reserve room under the last thing on the page. */
.page-home main,.page-visit main{ padding-block:0 4rem; }
.page-404 main,.page-shop main,.page-item main,
.page-model main,.page-business main,.page-prose main{ padding-block:1rem 4rem; }
@media (min-width:900px){
  .page-home main,.page-visit main{ padding-block:0 6rem; }
  .page-404 main,.page-shop main,.page-item main,
  .page-model main,.page-business main,.page-prose main{ padding-block:1rem 6rem; }
}

/* ---------------------------------------------------------------------------
   MOTION, 3.13. Nothing outside this inventory animates.
   --------------------------------------------------------------------------- */

/* .01ms and never none. none stops transitionend firing, and the drawer's close handler
   waits on that event, so none leaves the drawer stuck open. */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important; animation-iteration-count:1 !important;
    transition-duration:.01ms !important; scroll-behavior:auto !important;
  }
}
html{ scroll-behavior:smooth; }
@media (prefers-reduced-motion:reduce){ html{ scroll-behavior:auto; } }

/* ---------------------------------------------------------------------------
   REVIEW BUILD ONLY
   --------------------------------------------------------------------------- */

/* Neither of these reaches a live deploy set: the publish guard fails the build on the
   [CONFIRM string. They exist so a review build shows the tag where the fact would sit, and
   shows at a glance that it is a review build. --stamp measures 10.53 on the page ground and
   its ink measures 10.53 the other way, on the tag. */
.reviewbar{
  padding:.5rem var(--gutter);
  background:var(--stamp); color:var(--stamp-ink);
  font-size:var(--t-small); line-height:var(--lh-small); font-weight:600;
}
.stamp{
  display:inline-block;
  padding:.125rem .375rem;
  background:var(--stamp); color:var(--stamp-ink);
  border-radius:var(--r-1);
  font-size:var(--t-eyebrow); line-height:var(--lh-eyebrow); letter-spacing:var(--ls-eyebrow);
  text-transform:uppercase; font-weight:700;
}

/* The blocks that hold nothing but unanswered questions. They are set as quietly as the rest
   of the page: rule 43 forbids marking an unknown with red or amber, and the yellow above is
   on the tag itself, which is a build marker and not a warning about the fact. */
.confirm{
  margin-block-start:3rem; padding-block-start:1rem;
  border-block-start:1px solid var(--hairline-strong);
  font-size:var(--t-small); line-height:var(--lh-small); color:var(--text-muted);
}
.confirm h2{
  font-size:var(--t-h4); line-height:var(--lh-h4); letter-spacing:var(--ls-h4);
  font-weight:700; margin-block:0 .75rem;
}
.confirm p + p{ margin-block-start:.75rem; }

/* ---------------------------------------------------------------------------
   4.1 HEADER
   --------------------------------------------------------------------------- */

.hdr{
  position:sticky; inset-block-start:0; z-index:100;
}

/* Row A, 64px. The logo and the nav are hard left, in that order, and the phone is the only
   thing on the right. No cart, no account, no search glyph. */
.hdr__row{
  display:flex; align-items:center; gap:1.5rem;
  min-block-size:64px; padding-inline:var(--gutter);
}

.skip{
  position:absolute; inline-size:1px; block-size:1px;
  padding:0; margin:-1px; overflow:hidden; clip-path:inset(50%); white-space:nowrap;
}
.skip:focus{
  position:fixed; inset-block-start:0; inset-inline-start:0; z-index:300;
  inline-size:auto; block-size:auto; margin:0; padding:.75rem 1rem;
  clip-path:none; overflow:visible;
  background:var(--accent-fill);
  border-radius:var(--r-1);
  font-size:var(--t-small); font-weight:700; text-decoration:none;
}

.hdr__logo{ display:flex; align-items:center; flex:0 0 auto; text-decoration:none; }
.hdr__logo img{ inline-size:182px; block-size:35px; }

.hdr__nav ul{ display:flex; align-items:center; gap:.25rem; flex-wrap:wrap; }
.hdr__nav a{
  display:inline-flex; align-items:center;
  min-block-size:44px; padding-inline:.625rem;
  border-block-end:2px solid transparent;
  color:var(--text-body); text-decoration:none;
  font-size:var(--t-small); line-height:var(--lh-small); font-weight:500;
  transition:background-color 120ms linear, border-color 120ms linear;
}
.hdr__nav a:hover{ background:var(--surface-raised); color:var(--text-body); }
/* State is never colour alone: the active link carries a rule and a weight as well. */
.hdr__nav a[aria-current="page"]{
  color:var(--text-heading); font-weight:700;
  border-block-end-color:var(--accent-on-dark);
}

.hdr__tel{
  margin-inline-start:auto;
  display:inline-flex; align-items:center;
  min-block-size:44px; padding-inline:.75rem; margin-inline-end:-.75rem;
  border-radius:var(--r-1);
  color:var(--text-heading); text-decoration:none;
  font-size:var(--t-small); font-weight:600; font-variant-numeric:tabular-nums;
  white-space:nowrap;
  transition:background-color 120ms linear;
}
.hdr__tel:hover{ background:var(--surface-raised); color:var(--text-heading); }

.hdr__burger{
  display:none;
  align-items:center; gap:.5rem;
  min-block-size:44px; min-inline-size:44px; padding-inline:.75rem;
  border:1px solid var(--edge); border-radius:var(--r-1);
  background:var(--surface-default); color:var(--text-heading);
  font-size:var(--t-small); font-weight:600;
  transition:background-color 120ms linear, border-color 120ms linear;
}
.hdr__burger:hover{ background:var(--surface-raised); }

/* 3 rules drawn in the control's own text colour, never a drawn line icon from a set, and
   never on its own: the word Menu sits beside it and is the accessible name. */
.hdr__glyph{
  flex:0 0 auto;
  inline-size:16px; block-size:2px;
  background:currentColor;
  box-shadow:0 -5px 0 currentColor, 0 5px 0 currentColor;
}

/* The logo is 182px, the phone is 123px and the burger with its word is 72px. Those 3 do not
   fit one 288px line at 320px and they never will, so the row is allowed to take a second
   line rather than squeezing the word out of the burger or pushing the phone off the page.
   The header measures its own height at runtime, so the sticky offsets follow it. */
@media (max-width:900px){
  .hdr__nav{ display:none; }
  .hdr__row{ flex-wrap:wrap; gap:.5rem 1rem; padding-block:.5rem; }
  .hdr__burger{ display:inline-flex; flex:0 0 auto; margin-inline-start:auto;
                white-space:nowrap; }
  .hdr__tel{ margin-inline-start:0; }
}

/* ---------------------------------------------------------------------------
   4.2 COUNTER RAIL
   --------------------------------------------------------------------------- */

.rail{
  display:grid; grid-template-columns:minmax(0,auto) minmax(0,1fr) auto;
  align-items:center; column-gap:1.5rem; min-height:44px;
  padding-inline:var(--gutter);
  background:var(--surface-default);
  border-block:1px solid var(--hairline);
  font-size:var(--t-caption); line-height:var(--lh-caption);
}
/* minmax(0,auto) on the first track and min-width:0 here. The original auto 1fr auto with
   nowrap pushed the phone number out of the gutter between roughly 701px and 850px, which
   includes portrait tablets and a laptop at 200% zoom. */
.rail__state,
.rail__where{ margin:0; display:flex; align-items:baseline; gap:.5rem; min-width:0; }
.rail__dot{ flex:0 0 auto; align-self:center; width:8px; height:8px; border-radius:50%;
            background:var(--text-muted); }
.rail[data-state="open"]   .rail__dot{ background:var(--accent-on-dark); }
.rail[data-state="closed"] .rail__dot{ background:var(--state-closed); }
.rail__word{ font-weight:700; text-transform:uppercase; letter-spacing:var(--ls-eyebrow);
             color:var(--text-muted); white-space:nowrap; }
.rail[data-state="open"]   .rail__word{ color:var(--accent-on-dark); }
.rail[data-state="closed"] .rail__word{ color:var(--state-closed); }
.rail__detail,.rail__addr{ color:var(--text-muted); font-variant-numeric:tabular-nums;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0; }
.rail__where{ justify-self:start; }
.rail__dir{ color:var(--text-heading); text-decoration:underline;
            text-underline-offset:.18em; white-space:nowrap; flex:0 0 auto; }
.rail__dir:hover{ color:var(--accent-on-dark); }
.rail__tel{
  justify-self:end; display:inline-flex; align-items:center;
  min-height:44px; padding-inline:.75rem; margin-inline-end:-.75rem;
  border-radius:var(--r-1);
  font-size:var(--t-small); font-weight:600; font-variant-numeric:tabular-nums;
  color:var(--text-heading); text-decoration:none; white-space:nowrap;
  transition:background-color 120ms linear;
}
.rail__tel:hover{ background:var(--surface-raised); }
@media (max-width:900px){ .rail__detail{ display:none; } }
@media (max-width:700px){
  .rail{ grid-template-columns:minmax(0,1fr) auto; min-height:52px; column-gap:1rem; }
  .rail__where{ display:none; }
}
@media (max-width:360px){ .rail__word{ letter-spacing:0; } }

/* ---------------------------------------------------------------------------
   4.3 MOBILE DRAWER
   --------------------------------------------------------------------------- */

/* The handshake with the script: the drawer carries hidden while shut. The script removes
   hidden with data-state="closed" still set, forces a reflow, then sets data-state="open",
   which is what gives the panel something to transition from. On close it sets
   data-state="closed" and waits for transitionend before putting hidden back, which is why
   reduced motion uses .01ms and never none.

   The generator ships the panel itself as .drawer with the scrim as its next sibling, not as
   a child, so the sliding element and the scrim are addressed in that shape. site.js watches
   transitionend on .drawer__panel where one exists and on the drawer itself where one does
   not, so this arrangement is the one it already expects. */
.drawer{
  position:fixed; inset-block:0; inset-inline-end:0; z-index:200;
  inline-size:min(88vw,22rem);
  padding:1rem var(--gutter) 2rem;
  overflow-y:auto; overscroll-behavior:contain;
  transform:translateX(0);
  transition:transform 180ms cubic-bezier(.2,0,0,1);
}
.drawer[data-state="closed"]{ transform:translateX(100%); }

.drawer__scrim{
  position:fixed; inset:0; z-index:190;
  background:var(--surface-page);
  opacity:.86;
  transition:opacity 180ms linear;
}
.drawer[data-state="closed"] + .drawer__scrim{ opacity:0; }

.drawer__close{
  display:inline-flex; align-items:center;
  min-block-size:44px; padding-inline:.75rem;
  border:1px solid var(--edge); border-radius:var(--r-1);
  background:var(--surface-default); color:var(--text-heading);
  font-size:var(--t-small); font-weight:600;
  transition:background-color 120ms linear, border-color 120ms linear;
}
.drawer__close:hover{ background:var(--surface-raised); }

.drawer nav{ margin-block:1.5rem; }
.drawer nav a{
  display:flex; align-items:center;
  min-block-size:52px;
  border-block-end:1px solid var(--hairline);
  color:var(--text-heading); text-decoration:none;
  font-size:var(--t-lede); font-weight:600;
  transition:background-color 120ms linear;
}
.drawer nav a:hover{ background:var(--surface-raised); color:var(--text-heading); }
.drawer nav a[aria-current="page"]{ box-shadow:inset 3px 0 0 var(--accent-on-dark); }

/* 3.2.6, consistent help. The phone and the address sit at the foot of the drawer in the same
   order as they sit at the foot of every page. */
.drawer__tel{
  font-size:var(--t-lede); font-weight:700; font-variant-numeric:tabular-nums;
}
.drawer__addr{
  margin-block-start:.75rem;
  font-size:var(--t-small); line-height:var(--lh-small); color:var(--text-muted);
}

/* ---------------------------------------------------------------------------
   4.4 HERO
   --------------------------------------------------------------------------- */

.hero{
  /* minmax(0,1fr) and not 1fr. A bare 1fr track will not shrink below the widest unbreakable
     thing inside it, and the headline is one long uppercase word, so at 320px the column
     resolved to 408px and pushed the whole page sideways. Same floor the sheet hit. */
  display:grid; grid-template-columns:minmax(0,1fr); background:var(--surface-page);
  border-bottom:0;                     /* the sheet's own top rule provides the joint */
}
.hero__text{ padding:2rem var(--gutter) 3rem; }
.hero__h1{
  font-size:var(--t-display); line-height:var(--lh-display); letter-spacing:var(--ls-display);
  font-weight:500; text-transform:uppercase; color:var(--text-heading);
  max-width:16ch; margin:0 0 1.5rem;
  margin-block-start:calc(var(--t-display) * -0.157);
  text-wrap:balance;
}
.hero__h1 b{ font-weight:800; }
.hero__lede{
  font-size:var(--t-lede); line-height:var(--lh-lede); color:var(--text-body);
  max-width:46ch; margin:0 0 2rem;
}
.hero__fig{ margin:0; position:relative; }
.hero__fig img{
  display:block; width:100%; height:100%; object-fit:cover;
  object-position:62% 58%;
  filter:saturate(.86) contrast(1.04);
}
.hero__cap{
  position:absolute; inset-block-end:0; inset-inline:0;
  padding:.5rem .75rem;
  background:var(--surface-page);      /* solid, never a translucent plate */
  border-top:1px solid var(--hairline);
  font-size:var(--t-caption); color:var(--text-muted);
}
@media (min-width:900px){
  .hero{ grid-template-columns:42fr 58fr; align-items:stretch; }
  .hero__text{
    padding:4rem 3rem 6rem var(--gutter);
    border-right:1px solid var(--hairline-strong);
    display:flex; flex-direction:column; justify-content:flex-end;
  }
  .hero__fig{ min-height:clamp(480px,64vh,720px); }
  .hero__fig img{ position:absolute; inset:0; }
}

/* The stock readout. Every figure in it is written by the nightly script. */
.hero__stock{
  display:flex; flex-wrap:wrap; gap:.5rem 1.5rem;
  font-size:var(--t-eyebrow); line-height:var(--lh-eyebrow);
  letter-spacing:var(--ls-eyebrow); text-transform:uppercase;
  font-variant-numeric:tabular-nums;
}
.hero__pair{ display:flex; align-items:baseline; gap:.5rem; }
.hero__stock dt{ color:var(--text-muted); }
.hero__stock dd{ margin:0; color:var(--text-heading); font-weight:700; }

/* ---------------------------------------------------------------------------
   THE PLINTH, 3.1 and section 9
   --------------------------------------------------------------------------- */

/* The product photographs were shot over months by different people, on white or near-white,
   at widths from 333px to 500px. One fixed box with contain and 12% padding is what makes
   them read as one collection rather than as 197 pasted cutouts on charcoal.

   The plinth is #EDEEEA and not #FFFFFF because seller white is rarely pure, and near-white
   on pure white shows up as a faint grey rectangle around every product.

   isolation:isolate is mandatory and is not an optimisation. mix-blend-mode resolves against
   the nearest stacking context, and without this the blend falls through to the charcoal page
   and the photographs disappear. It must not depend on content-visibility, which is a
   performance property somebody will one day remove. */
.cell__plinth{
  --plinth-c:var(--plinth);
  position:relative; aspect-ratio:4 / 3;
  background:var(--plinth-c);
  display:grid; place-items:center; padding:12%;
  /* minmax(0,1fr) is load bearing. Without it the implicit row track sizes to the image's
     own height, the img's height:100% resolves against that grown track instead of the
     aspect-locked box, and overflow:hidden then cuts the bottom off the product. It clipped
     more than half the catalogue, some photographs through the middle of the item, which is
     the exact outcome the contain rule below exists to prevent. */
  grid-template-rows:minmax(0,1fr);
  overflow:hidden;
  border-radius:var(--r-0);
  box-shadow:inset 0 0 0 1px rgb(0 0 0 / .10);
  isolation:isolate;
  transition:background-color 120ms linear;
}

/* contain, never cover. A cover crop on a product photograph cuts the product. */
.cell__plinth img{
  width:100%; height:100%;
  object-fit:contain;
  mix-blend-mode:multiply;
}

/* ---------------------------------------------------------------------------
   4.5 PRODUCT CARD, THE SHEET CELL
   --------------------------------------------------------------------------- */

.cell{
  position:relative; display:flex; flex-direction:column; padding:1rem;
  background:var(--surface-page);
  transition:background-color 120ms linear;
  content-visibility:auto; contain-intrinsic-size:auto 390px;
  isolation:isolate;                 /* keeps the blend honest, see the plinth note above */
}
.cell:hover,.cell:focus-within{ background:var(--surface-raised); }
.cell:has(a:focus-visible){ background:var(--surface-raised); }
.cell:hover .cell__plinth{ --plinth-c:var(--plinth-hover); }

/* Exactly 1 link per cell. The hit area comes from this overlay and never from a wrapping
   anchor, which would swallow the whole cell into one unreadable link name. */
.cell__name{
  margin-block:.75rem 0;
  font-size:var(--t-cell-name); line-height:var(--lh-cell-name); font-weight:500;
  color:var(--text-body);
  display:-webkit-box; -webkit-box-orient:vertical;
  -webkit-line-clamp:2; line-clamp:2;
  overflow:hidden;
}
.cell__name a{ color:inherit; text-decoration:none; }
.cell__name a::after{ content:""; position:absolute; inset:0; }

.cell__model{
  margin-block-start:.25rem;
  font-family:var(--ff-mono); font-size:var(--t-ref); line-height:var(--lh-ref);
  letter-spacing:var(--ls-ref); color:var(--text-muted);
}
.cell__spec{
  margin-block-start:.25rem;
  font-size:var(--t-caption); line-height:var(--lh-caption);
  color:var(--text-muted); font-variant-numeric:tabular-nums;
}
.cell__cond{
  margin-block-start:.5rem;
  font-size:var(--t-eyebrow); line-height:var(--lh-eyebrow); letter-spacing:var(--ls-eyebrow);
  text-transform:uppercase; color:var(--text-muted);
}

/* The footer row makes a real edge on both sides. Nothing in the cell is centred. */
.cell__foot{
  display:flex; align-items:baseline; justify-content:space-between; gap:.75rem;
  margin-block-start:auto; padding-block-start:.75rem;
}
/* Fields 6, 7 and 8 travel together on the left of that row, so they are one column and the
   reference stays baseline-aligned with the price and not with the shipped line. */
.cell__prices{ min-inline-size:0; }
.cell__price{
  font-size:var(--t-cell-price); line-height:var(--lh-cell-price);
  letter-spacing:var(--ls-cell-price); font-weight:700;
  color:var(--text-heading);            /* the price is never green */
  font-variant-numeric:tabular-nums;
}
.cell__pricelab{
  margin-block-start:.25rem;
  font-size:var(--t-eyebrow); line-height:var(--lh-eyebrow); letter-spacing:var(--ls-eyebrow);
  text-transform:uppercase; color:var(--text-muted);
}
.cell__shipped{
  margin-block-start:.25rem;
  font-size:var(--t-caption); line-height:var(--lh-caption);
  color:var(--text-muted); font-variant-numeric:tabular-nums;
}
/* Promoted to body weight because this is the string you read down the phone. */
.cell__ref{
  font-family:var(--ff-mono); font-size:var(--t-ref); line-height:var(--lh-ref);
  letter-spacing:var(--ls-ref); color:var(--text-body); white-space:nowrap;
}
.cell__group{
  font-size:var(--t-eyebrow); line-height:var(--lh-eyebrow); letter-spacing:var(--ls-eyebrow);
  text-transform:uppercase; font-weight:600; color:var(--accent-on-dark); white-space:nowrap;
}

/* A group cell prints a range opener rather than a single price, and "From C$1,235" must not
   break across 2 lines in a 336px cell. */
.cell--group .cell__price{ white-space:nowrap; }

/* The wide prose cell. It is prose inside a grid of objects, so it gets 1.5rem. */
.cell--fact{
  padding:1.5rem;
  background:var(--surface-default);
  font-size:var(--t-small); line-height:var(--lh-small); color:var(--text-muted);
}
.fact__h{
  font-size:var(--t-h4); line-height:var(--lh-h4); letter-spacing:var(--ls-h4);
  font-weight:700; text-transform:uppercase; color:var(--text-heading);
  margin-block-end:.75rem;
}
.fact__p{ font-size:var(--t-small); line-height:var(--lh-small); color:var(--text-muted); }
.fact__p + .fact__p{ margin-block-start:.75rem; }

/* The 374px board crop, used inside a wide fact cell on the home page and at the head of
   /testing/. Capped at its own intrinsic width so it is never upscaled. */
.floorfig,
.testing__fig{ margin:0 0 1.5rem; max-inline-size:374px; }

/* The 7 categories as real links, ordered by count. A row is a target, and a target is 44px
   minimum, which is where 1.25rem of block padding comes from. */
.shelf{ margin-block:1rem; }
.shelf__row{ border-block-end:1px solid var(--hairline); }
.shelf__row a{
  display:flex; align-items:baseline; justify-content:space-between; gap:1rem;
  padding-block:1.25rem;
  color:var(--text-heading); text-decoration:none;
  font-size:var(--t-small); font-weight:600;
  transition:background-color 120ms linear;
}
.shelf__row a:hover{ background:var(--surface-raised); color:var(--text-heading); }
.shelf__name{ min-inline-size:0; }
.shelf__n{ font-variant-numeric:tabular-nums; flex:0 0 auto; }

/* The last cell of the home sheet, spanning the full row. It is the only cell in the sheet
   with no photograph and no price, so it says what it is and gets out of the way. */
.cell--seeall{ background:var(--surface-default); }
.cell--seeall a{
  display:inline-flex; align-items:center; min-block-size:44px;
  color:var(--text-heading); text-decoration:none;
  font-size:var(--t-small); font-weight:700;
  transition:color 120ms linear;
}
.cell--seeall a:hover{ color:var(--accent-on-dark); }

/* List density. 56px rows, 24 to a laptop screen, which is why cables are readable here and
   not in a photograph grid. */
.sheet--list .cell{
  flex-direction:row; align-items:center; gap:1rem;
  padding-block:.375rem; min-block-size:56px;
  contain-intrinsic-size:auto 56px;
}
.sheet--list .cell__plinth{
  flex:0 0 44px; inline-size:44px; block-size:44px;
  aspect-ratio:1 / 1; padding:3px;
  --plinth-c:var(--plinth-small);
}
.sheet--list .cell:hover .cell__plinth{ --plinth-c:var(--plinth); }
.sheet--list .cell__name{
  margin:0; flex:1 1 auto;
  font-size:var(--t-list-name); line-height:var(--lh-list-name);
  -webkit-line-clamp:1; line-clamp:1;
}
.sheet--list .cell__model,
.sheet--list .cell__spec,
.sheet--list .cell__pricelab,
.sheet--list .cell__shipped{ display:none; }
.sheet--list .cell__cond{ margin:0; flex:0 0 auto; }
.sheet--list .cell__foot{
  margin:0; padding:0; flex:0 0 auto; gap:1rem; align-items:baseline;
}
/* Prose does not belong in a table. */
.sheet--list .cell--fact,
.sheet--list .cell--photo{ display:none; }

/* ---------------------------------------------------------------------------
   HOME, THE MODEL GROUP STRIP
   --------------------------------------------------------------------------- */

/* The home page's <main> holds no .wrap of its own, because the hero and the sheet are both
   full bleed by design. The 3 bands that follow the sheet are prose and controls, so each one
   carries the wrap measure and the gutter itself. */
.groups{
  max-inline-size:var(--wrap); margin-inline:auto;
  padding:4rem var(--gutter) 0;
}
.groups__h{ margin-block-end:.75rem; }
.groups__p{
  font-size:var(--t-lede); line-height:var(--lh-lede); color:var(--text-body);
  max-inline-size:68ch;
}
.sheet--groups{ margin-block-start:1.5rem; }

/* ---------------------------------------------------------------------------
   HOME, THE eBAY REPUTATION STRIP
   --------------------------------------------------------------------------- */

/* No stars, no avatars, no quotes, and none of it marked up as a rating. It is 2 sentences
   and the date they were read, which is the whole of what the ground truth supports. */
.rep{
  max-inline-size:var(--wrap); margin-inline:auto;
  padding:4rem var(--gutter) 0;
}
.rep__h{
  font-size:var(--t-h3); line-height:var(--lh-h3); letter-spacing:var(--ls-h3);
  font-weight:700; color:var(--text-heading);
  font-variant-numeric:tabular-nums;
  max-inline-size:34ch;
}
.rep__p{
  margin-block-start:.75rem;
  font-size:var(--t-small); line-height:var(--lh-small); color:var(--text-muted);
  max-inline-size:68ch;
}

/* ---------------------------------------------------------------------------
   HOME, THE QUIET BUSINESS CHIP
   --------------------------------------------------------------------------- */

/* One line, one control, last on the page. It carries 2 real figures, so it is not an eyebrow
   pill with nothing in it. */
.bizchip{
  max-inline-size:var(--wrap); margin-inline:auto;
  padding:4rem var(--gutter) 0;
}
.bizchip a{
  display:block; max-inline-size:68ch;
  padding:1.25rem;
  border:1px solid var(--hairline-strong); border-radius:var(--r-1);
  color:var(--text-body); text-decoration:none;
  font-size:var(--t-small); line-height:var(--lh-small);
  font-variant-numeric:tabular-nums;
  transition:background-color 120ms linear, border-color 120ms linear;
}
.bizchip a:hover{
  background:var(--surface-raised); border-color:var(--edge); color:var(--text-body);
}

/* ---------------------------------------------------------------------------
   4.6 FILTER CHIPS
   --------------------------------------------------------------------------- */

/* The flex container has to be the list, not the nav. The markup is nav.chips > ul > li > a,
   so putting the row on .chips gives it exactly one flex child, the block level ul, and the
   chips stack into a vertical staircase beside an empty page. They fit one line with room
   to spare. */
.chips{ display:block; }
.chips ul{
  display:flex; flex-wrap:wrap; gap:.5rem;
  list-style:none; margin:0; padding:0;
}
.chip{
  display:inline-flex; align-items:center;
  min-block-size:44px; padding-inline:.875rem;
  background:var(--surface-default);
  border:1px solid var(--edge); border-radius:var(--r-1);
  color:var(--text-body); text-decoration:none;
  font-size:var(--t-small); line-height:var(--lh-small); white-space:nowrap;
  transition:background-color 120ms linear;
}
.chip:hover{ background:var(--surface-raised); color:var(--text-body); }
/* Selected is 2 channels, a fill and a 3px rule, because colour alone fails SC 1.4.1. The
   mint fill with the page colour as its label measures 8.56. White on this mint is 2.06 and
   is banned, so the label is dark and stays dark. */
.chip[aria-current="page"]{
  background:var(--focus-ring);
  border-color:var(--focus-ring);
  color:var(--surface-page);
  font-weight:700;
  box-shadow:inset 0 -3px 0 var(--surface-page);
}
.chip[aria-current="page"]:hover{ background:var(--focus-ring); color:var(--surface-page); }
/* The count needs its own space and its own weight, or every chip reads as "Gaming12". */
.chip__n{
  font-variant-numeric:tabular-nums;
  margin-inline-start:.4em; color:var(--text-muted); font-weight:400;
}
.chip[aria-current="page"] .chip__n{ color:var(--surface-page); }

/* ---------------------------------------------------------------------------
   SHOP AND BUSINESS PAGE HEADS
   --------------------------------------------------------------------------- */

/* Both of these headlines carry a live count written by the nightly script, so both set their
   figures on the tabular axis and neither is ever typed by hand. */
.shop__h1,
.biz__h1{
  font-variant-numeric:tabular-nums;
  max-inline-size:28ch;
  margin-block-end:.75rem;
}
.shop__sub{
  font-size:var(--t-small); line-height:var(--lh-small); color:var(--text-muted);
  max-inline-size:68ch;
  margin-block-end:1.5rem;
}
.biz__lede,
.model__lede{
  font-size:var(--t-lede); line-height:var(--lh-lede); letter-spacing:var(--ls-lede);
  color:var(--text-body); max-inline-size:68ch;
}
.biz__lede{ margin-block-end:1.5rem; }
.model__lede + .model__lede{ margin-block-start:1rem; }

/* ---------------------------------------------------------------------------
   4.7 SEARCH, 4.8 SORT AND DENSITY
   --------------------------------------------------------------------------- */

.controls{
  display:flex; flex-wrap:wrap; align-items:flex-end; gap:1rem;
  padding-block:1rem;
  border-block-end:1px solid var(--hairline-strong);
}

.sortwrap{ display:flex; flex-direction:column; gap:.25rem; }
.sortwrap > label{
  font-size:var(--t-eyebrow); line-height:var(--lh-eyebrow); letter-spacing:var(--ls-eyebrow);
  text-transform:uppercase; color:var(--text-muted);
}

.search{ display:flex; align-items:center; gap:.5rem; flex:1 1 16rem; }
input[type="search"],
input[type="text"],
select{
  min-block-size:44px;
  padding:.5rem .75rem;
  background:var(--surface-raised);
  color:var(--text-body);
  border:1px solid var(--edge);          /* 3.39 on the raised ground, clears SC 1.4.11 */
  border-radius:var(--r-1);
  font-size:var(--t-small); line-height:var(--lh-small);
  transition:border-color 120ms linear;
}
input[type="search"]{ inline-size:100%; }
input[type="search"]:hover,select:hover{ border-color:var(--text-muted); }

/* The native cancel glyph is a sub-24px target sitting next to a real 44px Clear button, so
   only the real button ships. */
input[type="search"]::-webkit-search-cancel-button{ display:none; }

/* Clear and Search are the same control class of thing: a 44px labelled button beside the
   field. Search is the no-script submit path and must look like a real control, because with
   the script off it is the only way to run a query. */
.search__clear,
.search__go{
  display:inline-flex; align-items:center;
  min-block-size:44px; min-inline-size:44px; padding-inline:.75rem;
  background:var(--surface-default); color:var(--text-body);
  border:1px solid var(--edge); border-radius:var(--r-1);
  font-size:var(--t-small);
  transition:background-color 120ms linear, border-color 120ms linear;
}
.search__clear:hover,
.search__go:hover{ background:var(--surface-raised); }

/* The 2px inner padding keeps the pressed fill off the group's own boundary, so --edge always
   sits against --surface-default at 3.79 and never against --surface-pressed at 2.92. */
.density{
  display:inline-flex; align-items:stretch; gap:0;
  padding:2px;
  background:var(--surface-default);
  border:1px solid var(--edge); border-radius:var(--r-1);
}
.density__btn{
  display:inline-flex; align-items:center;
  min-block-size:44px; min-inline-size:44px; padding-inline:.75rem;
  background:var(--surface-default); color:var(--text-body);
  font-size:var(--t-eyebrow); line-height:var(--lh-eyebrow); letter-spacing:var(--ls-eyebrow);
  text-transform:uppercase; font-weight:600;
  transition:background-color 120ms linear;
}
.density__btn + .density__btn{ border-inline-start:1px solid var(--hairline-strong); }
.density__btn:hover{ background:var(--surface-raised); }
/* A fill plus weight 700, so the pressed state survives a greyscale filter. */
.density__btn[aria-pressed="true"]{
  background:var(--surface-pressed); color:var(--text-heading); font-weight:700;
}

/* The single permanent status region. Visible on the pages that filter, visually hidden
   elsewhere, and it is always the same element in the same place. */
.resultline{
  font-size:var(--t-small); line-height:var(--lh-small);
  color:var(--text-muted); font-variant-numeric:tabular-nums;
  padding-block:.75rem;
}

.empty{
  padding-block:3rem;
  font-size:var(--t-body); line-height:var(--lh-body); color:var(--text-muted);
  max-inline-size:56ch;
}
.empty__h{
  font-size:var(--t-h4); line-height:var(--lh-h4); letter-spacing:var(--ls-h4);
  font-weight:700; color:var(--text-heading);
  margin-block-end:.75rem;
}

/* ---------------------------------------------------------------------------
   4.9 TYPE FACET RAIL
   --------------------------------------------------------------------------- */

.facet legend{
  font-size:var(--t-eyebrow); line-height:var(--lh-eyebrow); letter-spacing:var(--ls-eyebrow);
  text-transform:uppercase; font-weight:600; color:var(--text-muted);
  padding-block-end:.5rem;
}
.facet__list li{
  display:flex; align-items:center; gap:.5rem;
  min-block-size:44px;
  font-size:var(--t-small); line-height:var(--lh-small);
}
.facet__list label{ flex:1 1 auto; cursor:pointer; }
.facet__n{ color:var(--text-muted); font-variant-numeric:tabular-nums; margin-inline-start:.4em; }

/* The tail of the 47 types, behind a native disclosure. summary is focusable and toggles on
   Enter and Space on its own, so neither behaviour is re-implemented. */
.facet__more{ margin-block-start:.5rem; }

/* The accent is the heading colour and not the brand green on purpose. A rail can hold 8
   checked boxes at once, and 8 green marks would blow the 2-green budget on its own. A near
   white box with a dark tick reads as checked, and the boundary measures 11.78 on the raised
   ground. */
.facet input[type="checkbox"]{
  inline-size:1.125rem; block-size:1.125rem; flex:0 0 auto;
  accent-color:var(--text-heading);
  cursor:pointer;
}

summary{
  cursor:pointer;
  padding-block:.75rem;
  font-size:var(--t-small); line-height:var(--lh-small); color:var(--text-heading);
}
details > summary{ list-style-position:inside; }

@media (max-width:1039px){
  .shop__rail{ border-block-end:1px solid var(--hairline-strong); padding-block-end:1rem; }
}

/* ---------------------------------------------------------------------------
   BUTTONS
   --------------------------------------------------------------------------- */

/* Rule 38, made impossible by construction. Every descendant of anything sitting on the green
   fill takes white explicitly, so nothing can inherit --text-heading and land on 4.13.
   #FFFFFF on #0C8566 measures 4.60 and is the only permitted text on the green. */
.btn-primary,.btn-primary *,
.btn-primary:hover,.btn-primary:focus,.btn-primary:active,
.callstrip,.callstrip *,
.callstrip a:hover,.callstrip a:focus,
.skip:focus,.skip:focus *{ color:#FFFFFF; }

.btn-primary{
  display:flex; align-items:center;
  inline-size:100%; min-block-size:52px; padding-inline:1rem;
  background:var(--accent-fill);
  border:1px solid var(--accent-fill);
  border-radius:var(--r-1);
  font-size:var(--t-body); line-height:var(--lh-small); font-weight:700;
  text-decoration:none;
  font-variant-numeric:tabular-nums;
  transition:background-color 120ms linear, border-color 120ms linear;
}
/* The hover has to be a border change and not a darker green, because a second green is not a
   token and rule 42 forbids inventing one. White on the green is already a measured pair. */
.btn-primary:hover{ border-color:#FFFFFF; }
.btn-primary:active{ border-color:var(--surface-page); }

/* The outlined control. The reveal button is the same object under the name the generator and
   the script both give it, so it is named here rather than styled twice. */
.btn-outline,
.reveal{
  display:inline-flex; align-items:center;
  min-block-size:52px; padding-inline:1rem;
  background:transparent;
  border:1px solid var(--hairline-strong);
  border-radius:var(--r-1);
  color:var(--text-heading); text-decoration:none;
  font-size:var(--t-small); font-weight:600;
  transition:background-color 120ms linear, border-color 120ms linear;
}
.btn-outline:hover,
.reveal:hover{
  background:var(--surface-raised); border-color:var(--edge); color:var(--text-heading);
}

/* aria-disabled and never disabled, so the reveal control keeps focus on its final press. */
[aria-disabled="true"]{ color:var(--text-muted); cursor:default; }

/* ---------------------------------------------------------------------------
   4.10 REVEAL AND PAGINATION
   --------------------------------------------------------------------------- */

.revealwrap{ padding-block:2rem; }
/* On the last press the button is replaced by this paragraph, which takes the focus, so focus
   never falls to the body. */
.reveal__done{
  font-size:var(--t-small); line-height:var(--lh-small); color:var(--text-muted);
  font-variant-numeric:tabular-nums;
}

.pager{ padding-block:2rem; }
.pager ul{ display:flex; flex-wrap:wrap; align-items:center; gap:.25rem; }
/* 1.25rem of inline padding puts a single digit over 44px without centring anything. */
.pager a{
  display:inline-flex; align-items:center;
  min-block-size:44px; padding-inline:1.25rem;
  border:1px solid var(--edge); border-radius:var(--r-1);
  color:var(--text-body); text-decoration:none;
  font-size:var(--t-small); font-variant-numeric:tabular-nums;
  transition:background-color 120ms linear, border-color 120ms linear;
}
.pager a:hover{ background:var(--surface-raised); color:var(--text-body); }
.pager a[aria-current="page"]{
  background:var(--surface-pressed); color:var(--text-heading); font-weight:700;
  border-color:var(--hairline-strong);
}
.pager__pos{
  font-size:var(--t-small); color:var(--text-muted); font-variant-numeric:tabular-nums;
  padding-block-end:.75rem;
}

/* ---------------------------------------------------------------------------
   BREADCRUMB
   --------------------------------------------------------------------------- */

.crumb{ padding-block:1rem; font-size:var(--t-small); line-height:var(--lh-small); }
.crumb ol{ display:flex; flex-wrap:wrap; align-items:center; gap:.5rem; }
.crumb li{ color:var(--text-muted); }
.crumb li + li::before{ content:"/"; margin-inline-end:.5rem; color:var(--text-muted); }
.crumb a{ color:var(--text-muted); }
.crumb a:hover{ color:var(--accent-on-dark); }

/* ---------------------------------------------------------------------------
   4.11 ITEM PAGE, MEDIA COLUMN
   --------------------------------------------------------------------------- */

/* The mirror holds 1 file per item, 333px to 500px wide, and there is no second width to
   offer. The media column runs to roughly 800px at --wrap, so an uncapped plinth would
   upscale every photograph by half again and soften it. The cap goes on the figure so the
   caption travels with the picture. */
.item__fig{ margin:0; max-inline-size:560px; }
/* Same plinth as the sheet cell with more room around the product, because this is the one
   photograph on the page and the first thing 56% of visitors go to. */
.item__plinth{ padding:8%; }
.item__cap{
  padding-block:.75rem;
  font-size:var(--t-caption); line-height:var(--lh-caption); color:var(--text-muted);
}

/* ---------------------------------------------------------------------------
   4.11 ITEM PAGE, BUY MODULE
   --------------------------------------------------------------------------- */

.item__eyebrow{
  font-size:var(--t-eyebrow); line-height:var(--lh-eyebrow); letter-spacing:var(--ls-eyebrow);
  text-transform:uppercase; color:var(--text-muted);
}
.item__eyebrow a{ color:inherit; text-decoration:none; }
.item__eyebrow a:hover{ color:var(--accent-on-dark); }

.item__h1{
  margin-block:.5rem .75rem;
  font-size:var(--t-h3); line-height:var(--lh-h3); letter-spacing:var(--ls-h3);
  font-weight:600; color:var(--text-heading);
  text-transform:none;                 /* sentence case, never uppercase */
}
/* Printed only when the title already carries the code. Never derived, never invented. */
.item__model{ margin-block-end:.75rem; color:var(--text-muted); }

.price{
  font-size:var(--t-price); line-height:var(--lh-price); letter-spacing:var(--ls-price);
  font-weight:700; color:var(--text-heading);   /* never green */
  font-variant-numeric:tabular-nums;
}
.price__lab{
  margin-block-start:.25rem;
  font-size:var(--t-caption); line-height:var(--lh-caption); color:var(--text-muted);
}
.price__two{
  margin-block-start:.75rem;
  font-size:var(--t-price-2); line-height:var(--lh-price-2);
  font-weight:500; color:var(--text-muted); font-variant-numeric:tabular-nums;
}
/* The difference is stated in dollars as plain text. No badge, no strikethrough, no
   percentage, ever: on one-of-a-kind stock neither ordinary-price test can be met. */
.price__diff{
  margin-block-start:.5rem;
  font-size:var(--t-caption); line-height:var(--lh-caption); color:var(--text-muted);
}

.factband{
  display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:.75rem;
  margin-block:1.5rem;
  padding-block:.75rem; min-block-size:48px;
  border-block:1px solid var(--hairline);
}
/* A reference is 15 characters of monospace in a third of a 5-column track, so the cell has to
   be allowed to be narrower than its content rather than widening the band. */
.factband__cell{ min-inline-size:0; }
.factband dt{
  font-size:var(--t-eyebrow); line-height:var(--lh-eyebrow); letter-spacing:var(--ls-eyebrow);
  text-transform:uppercase; color:var(--text-muted);
}
.factband dd{
  margin:0; font-size:var(--t-small); line-height:var(--lh-small); color:var(--text-body);
}

/* One of the approved scarcity lines. It is a fact about the stock, not a countdown. */
.noholds{
  font-size:var(--t-small); line-height:var(--lh-small); color:var(--text-muted);
}

/* Field 10, the same clock as the rail read a second time where it is load-bearing.
   It carries no state colour of its own: 3.6 counts the rail's dot as 1 of the 2 greens a
   viewport may hold and the call button's fill is the other, and 3.7 confines --state-closed
   to the rail and nowhere else, ever. The words themselves change, so the state is not being
   carried by colour in the first place. */
.cstate{
  display:flex; align-items:center; gap:.5rem;
  min-block-size:40px;
  margin-block-start:1rem;
  border-block-end:1px solid var(--hairline);
  font-size:var(--t-caption); line-height:var(--lh-caption); color:var(--text-muted);
}
.cstate__dot{
  flex:0 0 auto; align-self:center;
  inline-size:8px; block-size:8px; border-radius:50%;
  background:var(--text-muted);
}

.item__cta{ margin-block-start:1.5rem; }
.item__who{
  margin-block-start:.5rem;
  font-size:var(--t-caption); line-height:var(--lh-caption); color:var(--text-muted);
}
.item__cta2{ margin-block-start:.75rem; }

/* Printed only on a unit that belongs to a group. It says the units are separate machines,
   which is the one thing a duplicate listing makes people doubt. */
.grouped{
  margin-block-start:1.5rem;
  font-size:var(--t-small); line-height:var(--lh-small); color:var(--text-muted);
}

/* No icon, no coloured box. It is the best 40 words in the project and it does not need one. */
.script{
  margin-block-start:2rem;
  font-size:var(--t-small); line-height:var(--lh-small); color:var(--text-muted);
}
.script p + p{ margin-block-start:.75rem; }

.wipe{ margin-block-start:2rem; font-size:var(--t-small); line-height:var(--lh-small);
       color:var(--text-muted); }
.provenance{ margin-block-start:1.5rem; font-size:var(--t-small); line-height:var(--lh-small);
             color:var(--text-muted); }

/* The 3 module headings in the buy column, set alike so the column reads as one object. */
.script__h,
.wipe__h,
.spec__h{
  font-size:var(--t-h4); line-height:var(--lh-h4); letter-spacing:var(--ls-h4);
  font-weight:700; color:var(--text-heading);
  margin-block-end:.75rem;
}
.spec__h{ margin-block-start:2rem; }

/* The specification list is a table, and a table is read down a column, so 0.5rem. */
.spec{ border-block-start:1px solid var(--hairline); }
.spec__row{
  display:flex; align-items:baseline; justify-content:space-between; gap:1rem;
  padding-block:.5rem;
  border-block-end:1px solid var(--hairline);
}
.spec dt{ font-size:var(--t-small); line-height:var(--lh-small); color:var(--text-muted); }
.spec dd{
  margin:0; text-align:end;
  font-size:var(--t-small); line-height:var(--lh-small); color:var(--text-body);
  font-variant-numeric:tabular-nums;     /* digits stack down the column */
}

/* SC 3.2.6. The address, the hours and the phone close every one of the 17 page types in the
   same relative position. */
.addrstrip{
  margin-block-start:2rem; padding-block-start:1rem;
  border-block-start:1px solid var(--hairline);
  font-size:var(--t-caption); line-height:var(--lh-caption); color:var(--text-muted);
}

/* ---------------------------------------------------------------------------
   4.12 THE THREE QUESTIONS
   --------------------------------------------------------------------------- */

/* No red, no amber, no warning icon, no border box. Colouring an unknown as a warning says
   we are embarrassed by it, and every row here promises an answer on the phone. */
.ask{ margin-block-start:2rem; }
.ask__h{
  font-size:var(--t-h4); line-height:var(--lh-h4); letter-spacing:var(--ls-h4);
  font-weight:600; color:var(--text-heading); margin-block-end:.75rem;
}
.ask__list{ border-block-start:1px solid var(--hairline); }
.ask__row{ padding-block:.75rem; border-block-end:1px solid var(--hairline); }
.ask__row dt{
  font-size:var(--t-small); line-height:var(--lh-small); font-weight:600;
  color:var(--text-body);
}
.ask__row dd{
  margin:0; font-size:var(--t-small); line-height:var(--lh-small); color:var(--text-muted);
}

/* ---------------------------------------------------------------------------
   MOBILE ACTION BAR, 4.11
   --------------------------------------------------------------------------- */

.mbar{ display:none; }

@media (max-width:900px){
  /* Exactly 2 controls, CALL and DIRECTIONS, or 1 control while the maps URL is unconfirmed.
     Never 3. */
  .mbar{
    position:fixed; inset-inline:0; inset-block-end:0; z-index:150;
    display:flex; align-items:center; gap:.5rem;
    min-block-size:56px;
    /* 0.375rem above and below a 44px target is exactly 56px, which is the height 4.11 asks
       for and the height reserved at the foot of the page. It is the same pair of numbers as
       the 56px list density row in 3.9. */
    padding:.375rem var(--gutter);
    padding-block-end:calc(.375rem + env(safe-area-inset-bottom));
  }
  .mbar > *{ flex:1 1 0; }
  /* .btn-primary is 52px, which does not fit a 56px bar once the bar's own padding is
     counted, so the call control drops to the 44px minimum target inside the bar. */
  .mbar__call{ min-block-size:44px; }

  /* The bar is fixed, so the last thing on an item page needs somewhere to sit. 56px is the
     floor from 4.11; site.js publishes the bar's measured height, which is what matters at
     320px and at 200% zoom where the bar wraps, and the larger of the 2 wins. Keep the max():
     if the script never runs, the fallback still reserves the full 56px. */
  .page-item{
    padding-block-end:calc(max(56px,var(--actionbar-h,56px)) + env(safe-area-inset-bottom));
  }
}

/* ---------------------------------------------------------------------------
   TABLES: sibling units, and the business list
   --------------------------------------------------------------------------- */

.tablewrap{ overflow-x:auto; margin-block:1.5rem; }
table caption{
  text-align:start; padding-block:.75rem;
  font-size:var(--t-small); line-height:var(--lh-small); color:var(--text-muted);
}
th{
  text-align:start; padding-block:.5rem; padding-inline-end:1rem;
  border-block-end:1px solid var(--hairline-strong);
  font-size:var(--t-eyebrow); line-height:var(--lh-eyebrow); letter-spacing:var(--ls-eyebrow);
  text-transform:uppercase; font-weight:600; color:var(--text-muted);
  white-space:nowrap;
}
td{
  padding-block:.75rem; padding-inline-end:1rem;
  border-block-end:1px solid var(--hairline);
  font-size:var(--t-small); line-height:var(--lh-small); color:var(--text-body);
}
tbody tr{ transition:background-color 120ms linear; }
tbody tr:hover{ background:var(--surface-raised); }
/* Money reads down a column, so it is set on the trailing edge and on the tabular axis. */
td.num{ text-align:end; font-variant-numeric:tabular-nums; }
td.mono{ white-space:nowrap; }

/* Left to itself a table will squeeze 6 columns into 320px and wrap every cell to 3 lines.
   A floor on the table sends the wrapper sideways instead, which is what it is for. */
.units{ min-inline-size:34rem; }
.biztable{ min-inline-size:48rem; }
/* 100 rows is faster to read than to look at, so the business list is dense and unphotographed. */
.biztable td{ padding-block:.5rem; }

/* ---------------------------------------------------------------------------
   MODEL GROUP PAGE
   --------------------------------------------------------------------------- */

/* A 90 character feed title plus the live unit count is 4 lines at --t-h1 on a laptop, and
   the page's job is the unit table under it, so the model headline takes the next step down. */
.model__h1{
  font-size:var(--t-h2); line-height:var(--lh-h2); letter-spacing:var(--ls-h2);
  font-variant-numeric:tabular-nums;
  max-inline-size:34ch;
}
.model__code{ margin-block:.5rem 1rem; color:var(--text-muted); }

/* One photograph per unit, on its own plinth, because these are separate machines and the
   whole point of the page is that they are not one listing repeated. */
.strip{
  display:grid; grid-template-columns:repeat(auto-fill,minmax(160px,1fr)); gap:1rem;
  padding-block:1.5rem;
}
.strip__fig{ margin:0; }
.strip__fig figcaption{ margin-block-start:.5rem; color:var(--text-body); }

/* ---------------------------------------------------------------------------
   /testing/ CHAIN OF CUSTODY
   --------------------------------------------------------------------------- */

.chain{ border-block-start:1px solid var(--hairline); max-inline-size:68ch; }
.chain__row{
  display:flex; align-items:baseline; gap:1rem;
  padding-block:1rem;
  border-block-end:1px solid var(--hairline);
}
/* One of the 3 permitted monospace uses, and the one permitted numeral centring. */
.chain__n{
  flex:0 0 2.5rem;
  font-family:var(--ff-mono); font-size:var(--t-ref); letter-spacing:var(--ls-ref);
  text-align:center; color:var(--text-muted);
}
.chain__t{ flex:1 1 auto; font-size:var(--t-body); line-height:var(--lh-body); }

/* ---------------------------------------------------------------------------
   4.13 CERTIFICATION ROW
   --------------------------------------------------------------------------- */

/* The badges are dark ink. Two of them vanish on a dark ground, so the whole row sits on the
   plinth band with the plinth ink at 11.85. Never recoloured, never tinted, never made
   monochrome, never forced to a common width: the mismatched widths are what make them read
   as real third-party marks.

   The section sits outside .wrap in the markup, so it carries the gutter and the wrap measure
   itself rather than running its text into the edge of the viewport. */
.certs{
  background:var(--plinth);
  color:var(--plinth-ink);
  padding-block:3rem;
  padding-inline:var(--gutter);
}
.certs__h{
  max-inline-size:var(--wrap); margin-inline:auto;
  color:var(--plinth-ink);
  font-size:var(--t-h4); line-height:var(--lh-h4); letter-spacing:var(--ls-h4);
  font-weight:700; text-transform:uppercase;
  margin-block-end:2rem;
}
.certs__list{
  max-inline-size:var(--wrap); margin-inline:auto;
  display:flex; flex-wrap:wrap; gap:2rem;
}
.certs__item{ flex:1 1 13rem; max-inline-size:18rem; }
/* Height only. Setting a width here is the same act as normalising them. */
.certs__badge{
  block-size:44px; inline-size:auto; max-inline-size:100%;
  margin-block-end:.75rem;
}
.certs__line{
  font-size:var(--t-small); line-height:var(--lh-small); color:var(--plinth-ink);
}
/* The lead-in of each line is bold, and the base rule paints bold text with the heading token,
   which is #F2F3F1 on a #EDEEEA band. That is the one place on this site where a colour lands
   on top of itself, so the ink is restated. */
.certs__line b,
.certs__line strong{ color:var(--plinth-ink); }

/* ---------------------------------------------------------------------------
   4.14 FOOTER
   --------------------------------------------------------------------------- */

/* 2 plain sentences. No logos, no bar. Outside .wrap in the markup, so it carries its own. */
.siblings{
  max-inline-size:var(--wrap); margin-inline:auto;
  padding:2rem var(--gutter);
  font-size:var(--t-small); line-height:var(--lh-small); color:var(--text-muted);
}
.siblings a{ color:var(--text-muted); }
.siblings a:hover{ color:var(--accent-on-dark); }

/* .callstrip is on the <footer> itself. Left aligned, and every colour in it is written out
   rather than inherited, because inheriting the heading token here measures 4.13. */
.callstrip{
  background:var(--accent-fill);
  padding-block:3rem;
}
.callstrip__inner{
  max-inline-size:var(--wrap); margin-inline:auto;
  padding-inline:var(--gutter);
}
.callstrip__h{
  font-size:var(--t-h4); line-height:var(--lh-h4); letter-spacing:var(--ls-h4);
  font-weight:700; text-transform:uppercase;
  margin-block-end:.75rem;
}
/* The phone number is the conversion control on this site, so it is the only thing in the
   strip at --t-h1. The hours that follow it in the same paragraph are not. */
.callstrip__tel{
  font-size:var(--t-small); line-height:var(--lh-small);
  font-variant-numeric:tabular-nums;
}
.callstrip__tel a{
  display:inline-flex; align-items:center;
  min-block-size:44px;
  font-size:var(--t-h1); line-height:var(--lh-h1); letter-spacing:var(--ls-h1);
  font-weight:800; font-variant-numeric:tabular-nums;
}
.callstrip__addr{
  margin-block-start:.75rem;
  font-size:var(--t-small); line-height:var(--lh-small);
}
.callstrip a{ text-decoration:underline; text-underline-offset:.18em; }

/* A mint ring on a green ground measures 2.23, so the ring gets a dark plate under it. */
.callstrip :focus-visible{
  outline:3px solid var(--focus-ring); outline-offset:2px;
  box-shadow:0 0 0 2px var(--surface-page);
}

/* ---------------------------------------------------------------------------
   SECTION 9. THE FACILITY DRONE PHOTOGRAPH
   --------------------------------------------------------------------------- */

/* 4 places on the whole site and never a fifth. No scrim, no duotone, no overlay, no
   parallax, and no text over it anywhere. The crops are chosen to push the trailer's own web
   address and toll-free number out of frame, so every one of them is checked at 1280, 1440,
   1920 and 21:9 before ship. */

/* Use 2, /visit/, full bleed 21:9. */
/* The directions control, or the line standing in for it while there is no maps URL to point
   at. There is never a placeholder href here. */
.visit__dir{
  margin-block:1.5rem;
  font-size:var(--t-small); line-height:var(--lh-small); color:var(--text-muted);
}

/* Use 3, one wide cell in the sheet. No caption and no words on it, which is the most
   confident thing the site does. */
.cell--photo{
  padding:0; position:relative; background:var(--surface-page); isolation:isolate;
}
.cell--photo img{
  display:block; width:100%; height:100%;
  aspect-ratio:21 / 9; object-fit:cover; object-position:52% 56%;
  filter:saturate(.86) contrast(1.04);
}

/* The duotone belongs to the 374 x 374 board crops only, and never to the drone photograph.
   The house green wash measures 4.05 over the white wall and 3.10 at the worst pixels, so it
   fails as a contrast device, and it flattens the green trailer into the green building trim,
   which is the one object in the frame that identifies the company. */
.duotone{ filter:url(#edi-duotone); }
@supports not (filter: url(#edi-duotone)){ .duotone{ filter:grayscale(1) sepia(.3); } }

/* ---------------------------------------------------------------------------
   PRINT
   The whole buying model on this site is: find the machine, write the reference
   down, ring the counter, drive to Orillia and quote it. So the item page is the
   most printed page here, and until now it printed as near white ink on white
   paper at 1.11:1, because browsers do not print backgrounds by default and this
   page is light text on charcoal. Six reviewers looked at this site and none of
   them tried to print it.
   --------------------------------------------------------------------------- */

@media print{
  /* Ink on paper, not the screen palette. Set on the tokens so every component
     follows without needing its own print rule. */
  :root{
    --surface-page:#FFFFFF; --surface-default:#FFFFFF;
    --surface-raised:#FFFFFF; --surface-pressed:#FFFFFF;
    --plinth:#FFFFFF; --plinth-hover:#FFFFFF; --plinth-small:#FFFFFF;
    --text-heading:#000000; --text-body:#000000; --text-muted:#333333;
    --accent-on-dark:#000000; --plinth-ink:#000000;
    --hairline:#BBBBBB; --hairline-strong:#888888; --edge:#666666;
  }
  html,body{ background:#FFFFFF; color:#000000; }

  /* Navigation, filters and anything that only makes sense with a pointer.
     .mbar is position:fixed, and a fixed element repeats on every printed page
     and lands on top of the content, so it has to go first. */
  .skip,.reviewbar,.hdr,.rail,.drawer,.drawer__scrim,.mbar,
  .chips,.controls,.facet,.search,.sortwrap,.density,
  .revealwrap,.reveal,.resultline,.pager,.callstrip,.siblings,
  .cell--photo,.floorfig,.testing__fig,.strip__fig{
    display:none !important;
  }

  /* The logo is white on transparent, so on paper it is nothing at all. Print the
     name instead, once, at the top. */
  .hdr__logo img{ display:none; }
  main::before{
    content:"EDI Electronics Outlet, 35 Progress Drive, Orillia, Ontario L3V 0T7. (705) 327-8691.";
    display:block; font-weight:700; font-size:11pt; margin-block-end:1rem;
    padding-block-end:.5rem; border-block-end:1px solid #888888;
  }

  /* The reference is the thing being carried to the counter, so it is the one
     item that gets bigger on paper rather than smaller. */
  .item__ref,.mono,.factband__cell dd,.units td:first-child{
    font-family:var(--ff-mono); font-weight:700;
  }
  .factband__cell dd{ font-size:12pt; }

  /* Keep what a person needs at the counter together on one sheet. */
  .price__two,.price__diff,.factband,.script,.ask,.spec,.addrstrip,.noholds{
    break-inside:avoid; page-break-inside:avoid;
  }
  .item__h1,h1,h2{ break-after:avoid; page-break-after:avoid; }

  /* One photograph is useful for recognising the machine on the shelf. The rest
     of the catalogue imagery is not worth the toner. */
  .item__plinth img{ max-width:70mm; height:auto; }
  .cell__plinth{ display:none; }

  a{ text-decoration:underline; }
  /* Print the phone number and the address a link points at, since a printed page
     cannot be clicked. Nothing else, or every reference turns into a URL. */
  .item__cta a[href^="tel:"]::after,.addrstrip a[href^="tel:"]::after{ content:""; }

  @page{ margin:14mm; }
}

/* ---------------------------------------------------------------------------
   SOLD. Reached by somebody who followed a link to a machine that has gone.
   --------------------------------------------------------------------------- */

.page-gone .wrap{ padding-block:2rem 4rem; }
.gone__h1{
  font-size:var(--t-h1); line-height:var(--lh-h1); letter-spacing:var(--ls-h1);
  font-weight:800; text-transform:uppercase; color:var(--text-heading);
  max-width:22ch; margin:0 0 1.5rem;
}
.gone__p{
  font-size:var(--t-lede); line-height:var(--lh-lede); color:var(--text-muted);
  max-width:62ch; margin:0 0 1rem;
}
.gone__p:last-of-type{ margin-block-end:2rem; }

/* ---------------------------------------------------------------------------
   PHOTO RAIL. Every photograph EDI took of this exact unit, 2 to 19 of them.
   The main photo swaps in place; each thumbnail is a real button, so the rail
   is reachable by Tab and needs no dragging (SC 2.5.7). 44px targets (SC 2.5.8).
   --------------------------------------------------------------------------- */

.thumbs{
  display:flex; flex-wrap:wrap; gap:.5rem;
  list-style:none; margin:.75rem 0 0; padding:0;
  max-inline-size:560px;
}
.thumb{
  display:block; inline-size:64px; block-size:64px; padding:0;
  background:var(--plinth-small); border:1px solid var(--hairline-strong);
  border-radius:var(--r-1); cursor:pointer; overflow:hidden; isolation:isolate;
  transition:border-color 120ms linear;
}
.thumb img{
  display:block; inline-size:100%; block-size:100%;
  object-fit:contain; mix-blend-mode:multiply;
}
.thumb:hover{ border-color:var(--edge); }
.thumb[aria-pressed="true"]{
  border-color:var(--text-heading);
  box-shadow:inset 0 0 0 1px var(--text-heading);
}
.thumb:focus-visible{ outline:3px solid var(--focus-ring); outline-offset:2px; }
.item__count{
  margin:.5rem 0 0; font-size:var(--t-caption); line-height:var(--lh-caption);
  color:var(--text-muted);
}

/* ---------------------------------------------------------------------------
   LISTING NOTES. What EDI's own technician typed into the listing for this unit.
   Quoted, not paraphrased, because it is the only per-unit description we hold.
   --------------------------------------------------------------------------- */

.notes{ margin-block:2rem 0; padding-block-start:1.5rem; border-block-start:1px solid var(--hairline-strong); }
.notes__h{ margin:0 0 .75rem; font-size:var(--t-h4); line-height:var(--lh-h4); font-weight:700; color:var(--text-heading); }
.notes__p{ margin:0 0 .75rem; font-size:var(--t-body); line-height:var(--lh-body); color:var(--text-body); white-space:pre-line; }
.notes__src{ margin:0; font-size:var(--t-caption); line-height:var(--lh-caption); color:var(--text-muted); }
.returns{ margin:1rem 0 0; font-size:var(--t-small); line-height:var(--lh-small); color:var(--text-muted); }

/* The web checkout button, second in weight to the phone. Outlined, same height. */
.btn-outline--checkout{ inline-size:100%; justify-content:center; }
.item__ship{ margin:.5rem 0 0; font-size:var(--t-caption); line-height:var(--lh-caption); color:var(--text-muted); }
