/* =============================================================================
   DRN Industriel — shared site stylesheet
   -----------------------------------------------------------------------------
   Conventions this file establishes, and that every page using it must follow:

   1. ONE type scale. --fs-1 .. --fs-9 on a 1.22 ratio. No page invents a size.
   2. ONE spacing scale. --sp-1 .. --sp-9, 4px quantum, 8pt-grid aligned.
   3. ONE breakpoint ladder. --bp-sm 640 / --bp-md 900 / --bp-lg 1200. Nothing else.
   4. ONE page inset. --page-inset is the single horizontal gutter for EVERY
      top-level container: header, section, footer. A container that adds its own
      left padding on top of this breaks site-level alignment.
   5. Anything inside a bounded component sizes off THE COMPONENT (cqi), never off
      the viewport. Viewport-keyed sizing inside a fixed-width box is what produces
      "correct at 1024 and 1440, broken at 1280".
   6. Content is never truncated to make a layout fit. No text-overflow:ellipsis.
   ========================================================================== */

:root{
  /* ---- colour ---- */
  --c-bg:#0b0b0d;
  --c-surface:#121216;
  --c-ink:#f4f4f4;
  --c-ink-dim:rgba(244,244,244,.68);
  --c-ink-faint:rgba(244,244,244,.4);
  --c-line:rgba(244,244,244,.1);
  --c-line-soft:rgba(244,244,244,.06);
  --c-primary:#539435;
  --c-primary-strong:#7cc653;
  --c-primary-ink:#0b0b0d;
  --c-primary-edge:rgba(83,148,53,.28);
  --c-plate:#f3f4f5;
  /* the tile field. --c-tile sits above --c-bg so a card reads as an object without a frame;
     --c-tile-hi is the hover step, far enough to be seen at a glance. */
  --c-tile:#151519;
  --c-tile-hi:#1d1d23;
  --c-foot-a:#0e1d0a;
  --c-foot-b:#1e4114;
  /* CTA panel: deep green ground with light ink. Title #e6f3dd on #17330f measures 12.4:1,
     and the primary button keeps its own dark-on-green pairing so it is unaffected. */
  --c-cta-panel:#17330f;
  --c-cta-panel-edge:#2c5c1e;
  --c-cta-panel-ink:#e6f3dd;

  /* ---- spacing: 4px quantum ---- */
  --sp-1:4px;  --sp-2:8px;  --sp-3:12px; --sp-4:16px; --sp-5:24px;
  --sp-6:32px; --sp-7:48px; --sp-8:64px; --sp-9:96px;

  /* ---- type: one modular scale, ratio 1.22 ---- */
  --fs-1:.6875rem; --fs-2:.75rem;  --fs-3:.875rem; --fs-4:1rem;
  --fs-5:1.22rem;  --fs-6:1.49rem; --fs-7:1.82rem; --fs-8:2.22rem; --fs-9:2.71rem;
  --fs-display:clamp(1.75rem, .35rem + 2.45vw, 3.05rem);

  /* ---- layout ---- */
  --page-max:1720px;
  --gutter:clamp(12px, 1.6vw, 24px);   /* tightened again: the sidebar reclaims the width */
  --page-inset:max(var(--gutter), calc((100% - var(--page-max)) / 2));
  --measure:68ch;

  /* ---- form ---- */
  --radius-sm:8px; --radius-md:14px; --radius-lg:26px; --radius-full:999px;
  --border-w:1px;
  --dur-fast:.18s; --dur-med:.32s;
  --ease-out:cubic-bezier(.16,1,.3,1);
  /* The hover gesture of a CARD-sized surface. Duration is Material 3 motion
     duration-medium4 (400ms) — the top of the Medium band, which is the band a
     transition covering 10-30% of the viewport belongs to. The curve is the
     symmetric easeInOutQuart spline: with y1 = 0 and y2 = 1 the velocity is zero
     at BOTH ends (Disney "Slow In and Slow Out"), and pushing x1 out to .76 and
     x2 back to .24 lengthens the flat run at each end, which is what reads as
     "softer" against the Material-2 standard (.4,0,.2,1) this replaces.
     One token, used by every property that moves on hover, so nothing can drift
     back into arriving on its own schedule. */
  --dur-card:400ms;
  --ease-card:cubic-bezier(.76,0,.24,1);
  --shadow-card:0 30px 70px -30px rgba(0,0,0,.6);

  --font-sans:'Inter',system-ui,-apple-system,'Segoe UI',Helvetica,Arial,sans-serif;
}

/* ---------- reset ---------- */
*,*::before,*::after{box-sizing:border-box;}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;}
body{
  margin:0;background:var(--c-bg);color:var(--c-ink);
  font-family:var(--font-sans);font-size:var(--fs-4);line-height:1.6;
  -webkit-font-smoothing:antialiased;
}
img{display:block;max-width:100%;height:auto;}
a{color:inherit;text-decoration:none;}
:where(a,button,input,textarea,select):focus-visible{
  outline:2px solid var(--c-primary-strong);outline-offset:3px;border-radius:var(--radius-sm);
}
::selection{background:var(--c-primary);color:var(--c-primary-ink);}
@media (prefers-reduced-motion:reduce){
  *{animation:none !important;transition:none !important;}
  html{scroll-behavior:auto;}
}

/* ---------- the one skip link ---------- */
.skip{
  position:absolute;left:-9999px;top:0;z-index:200;
  background:var(--c-primary);color:var(--c-primary-ink);
  padding:var(--sp-3) var(--sp-5);border-radius:0 0 var(--radius-sm) 0;font-weight:600;
}
.skip:focus{left:0;}

/* ---------- page shell: the single horizontal inset ---------- */
.shell{padding-inline:var(--page-inset);}
.shell-in{max-width:var(--page-max);margin-inline:auto;}

/* ---------- header ---------- */
/* Sticky. This reverses the earlier "do not make the top bar sticky", on a later instruction.
   It also forces the .has-hero treatment to change: that rule used position:absolute so the
   hero video ran under the bar, and absolute and sticky cannot both apply to one element.
   The bar is sticky and TRANSPARENT instead, and the hero simply starts under it. */
.site-head{
  position:sticky;top:0;z-index:120;
  display:flex;align-items:center;gap:var(--sp-4);
  padding:var(--sp-4) var(--page-inset);
  background:rgba(11,11,13,.82);
  -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
  border-bottom:0;
}
/* the wordmark retires once the reader is past the end of the results — the h1 and the
   controls stay, so the bar is still a bar and still navigable. */
.site-head__brand{display:inline-flex;align-items:center;flex:none;
  transition:opacity var(--dur-med) var(--ease-out),transform var(--dur-med) var(--ease-out);}
.site-head[data-past-end="true"] .site-head__brand{
  opacity:0;transform:translateX(-12px);pointer-events:none;
}
.site-head[data-past-end="true"] .site-head__title{padding-left:0;border-left:0;}
.site-head__brand img{height:clamp(30px,2.7vw,40px);width:auto;}  /* -20% */
/* the one h1 of every page. Visually it is a quiet label beside the mark, not a headline —
   the page's own title carries the visual weight and is an h2. */
.site-head__title{
  margin:0;font-size:var(--fs-6);font-weight:650;letter-spacing:.02em;
  color:var(--c-ink);line-height:1;padding-left:var(--sp-4);
  border-left:1px solid var(--c-line);white-space:nowrap;
}
@media (max-width:520px){ .site-head__title{font-size:var(--fs-4);padding-left:var(--sp-3);} }
.site-head__end{display:flex;align-items:center;gap:var(--sp-3);margin-left:auto;}
.head-cta{
  display:inline-flex;align-items:center;min-height:40px;padding:0 var(--sp-4);
  border-radius:var(--radius-full);border:1px solid var(--c-primary);
  color:var(--c-primary-strong);font-weight:600;font-size:var(--fs-2);white-space:nowrap;
  transition:background var(--dur-fast),color var(--dur-fast);
}
.head-cta:hover,.head-cta:focus-visible{background:var(--c-primary);color:var(--c-primary-ink);}

/* ---------- the hamburger ---------- */
.navburger{
  display:inline-flex;align-items:center;justify-content:center;flex:none;
  width:44px;height:44px;                      /* WCAG 2.2 SC 2.5.8 with room to spare */
  border:0;border-radius:var(--radius-sm);background:none;cursor:pointer;
  transition:background var(--dur-fast);
}
.navburger:hover{background:var(--c-tile-hi);}
.navburger:focus-visible{outline:2px solid var(--c-primary-strong);outline-offset:2px;}
.navburger__bars{display:grid;gap:5px;width:22px;}
.navburger__bars i{
  display:block;height:2px;border-radius:2px;background:var(--c-ink);
  transition:transform var(--dur-fast) var(--ease-out),opacity var(--dur-fast);
}
/* the bars become an X, so the control states what it will do next */
.navburger[aria-expanded="true"] i:nth-child(1){transform:translateY(7px) rotate(45deg);}
.navburger[aria-expanded="true"] i:nth-child(2){opacity:0;}
.navburger[aria-expanded="true"] i:nth-child(3){transform:translateY(-7px) rotate(-45deg);}

/* ---------- the menu panel ---------- */
/* Without JS the panel is a plain block under the bar and every link is reachable; nav.js
   removes `hidden` and switches to data-open, so the no-JS path is the working default. */
.site-nav{display:flex;flex-direction:column;gap:var(--sp-2);}
[data-nav-js="on"] .site-nav{
  position:absolute;top:100%;right:var(--page-inset);z-index:130;
  min-width:min(280px,72vw);
  padding:var(--sp-3);
  border-radius:var(--radius-md);
  background:var(--c-tile);box-shadow:0 24px 48px -14px rgba(0,0,0,.85);
  opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity var(--dur-fast),visibility var(--dur-fast),transform var(--dur-fast) var(--ease-out);
}
[data-nav-js="on"] .site-nav[data-open="true"]{opacity:1;visibility:visible;transform:none;}
.site-nav a{
  display:flex;align-items:center;min-height:40px;padding:0 var(--sp-3);
  border-radius:var(--radius-sm);
  font-size:var(--fs-2);letter-spacing:.09em;text-transform:uppercase;color:var(--c-ink-dim);
  transition:color var(--dur-fast),background var(--dur-fast);
}
.site-nav a:hover,.site-nav a:focus-visible{color:var(--c-primary-strong);background:var(--c-tile-hi);}
.site-nav a[aria-current="page"]{color:var(--c-ink);box-shadow:inset 2px 0 0 var(--c-primary);}
@media (max-width:640px){ .head-cta{display:none;} }

/* ---------- page head ---------- */
.page-head{padding-block:var(--sp-9) var(--sp-7);}
.eyebrow{
  margin:0 0 var(--sp-3);font-size:var(--fs-1);letter-spacing:.22em;
  text-transform:uppercase;color:var(--c-primary-strong);
}
/* the page's own title is a <p class="page-title"> now, not an h1: the shared header carries
   the single h1 of every page, and two h1s is exactly what the a11y sweep flags. It keeps the
   full display weight — this is a semantic change, not a visual one. */
.page-head .page-title{
  margin:0 0 var(--sp-5);font-size:var(--fs-display);line-height:1.05;
  letter-spacing:-.025em;font-weight:700;text-wrap:balance;
}
.lede{margin:0;max-width:var(--measure);font-size:var(--fs-5);line-height:1.55;color:var(--c-ink-dim);}

/* ---------- sections ---------- */
/* minimalist: no rule between sections. The block rhythm separates them, and on the linecard
   the tile fields already draw the eye to where one group ends. */
.section{padding-block:var(--sp-8);border-top:0;}
.section:first-of-type{border-top:0;}
.section h2{
  margin:0 0 var(--sp-6);font-size:var(--fs-7);line-height:1.12;
  letter-spacing:-.02em;font-weight:700;text-wrap:balance;
}
.section h3{margin:0 0 var(--sp-3);font-size:var(--fs-5);font-weight:650;letter-spacing:-.01em;}

/* ---------- buttons ---------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:var(--sp-3);
  padding:var(--sp-4) var(--sp-6);border-radius:var(--radius-full);
  /* background:none and font:inherit are load-bearing: .btn is used on BOTH <a> and <button>,
     and a <button> with no background declared falls back to the UA buttonface grey. The print
     control rendered as a light grey pill next to a transparent phone link for exactly that. */
  background:none;font-family:inherit;
  font-size:var(--fs-3);font-weight:650;cursor:pointer;border:1px solid transparent;
  transition:transform var(--dur-fast) var(--ease-out),background var(--dur-fast);
}
.btn:active{transform:translateY(1px);}
.btn--primary{background:var(--c-primary);color:var(--c-primary-ink);}
.btn--primary:hover,.btn--primary:focus-visible{background:var(--c-primary-strong);}
.btn--ghost{border-color:var(--c-primary);color:var(--c-primary-strong);}
.btn--ghost:hover,.btn--ghost:focus-visible{background:var(--c-primary);color:var(--c-primary-ink);}

/* =============================================================================
   COMPONENT: supplier card (linecard)
   Sizes its own contents off the card, not the viewport — convention 5.
   ========================================================================== */
/* auto-fill, not fixed column counts: four of the seven categories hold a single supplier, and a
   lone card parked in a 3-column track leaves two dead cells. The track size decides the count. */
/* =============================================================================
   LINE CARD — one place controls the whole surface.
   Every spacing and column decision below reads from a token declared here, so a
   change is made once and cannot drift into per-card exceptions.
   ========================================================================== */
.lc{
  --lc-aside:232px;      /* sticky filter sheet width — +32, funded by the tighter page gutter */
  --lc-gap:var(--sp-4);  /* gap between tiles */
  --lc-pad:24px;         /* interior padding of one tile */
  --lc-cols:1;
  display:grid;grid-template-columns:1fr;gap:var(--lc-gap);
}
@media (min-width:600px){ .lc{--lc-cols:2;} }
@media (min-width:900px){                        /* the aside appears */
  .lc{grid-template-columns:var(--lc-aside) minmax(0,1fr);gap:var(--sp-7);}
}
@media (min-width:1100px){ .lc{--lc-cols:3;} }   /* three columns, laptop */
/* 1240, not 1400: a 1366 laptop is 1351 CSS px and a 1280 one is 1265, so a 1400-keyed step
   never fired on either — the operator was looking at 3 columns on a desktop and being told
   it was 4. The tile is 240px at 1280, which still holds the 260px mark box at 100%. */
@media (min-width:1240px){ .lc{--lc-cols:4;} }   /* four columns, desktop */

.linecard{
  display:grid;gap:var(--lc-gap);
  /* The track count is the LESSER of the breakpoint's column count and the number of suppliers
     the category actually holds. Four of the seven categories hold exactly one supplier, so a
     flat 4-track grid left 14 dead cells across the page and read as a half-empty catalogue.
     --n is emitted per section by the build; the max-width stops a lone card stretching to the
     full row instead. */
  grid-template-columns:repeat(min(var(--lc-cols),var(--n,99)),minmax(0,1fr));
  justify-content:start;
  align-items:stretch;           /* tiles match within a row; the capped list keeps them short */
}
.linecard > .supplier{max-width:420px;}
.supplier[hidden]{display:none;}

/* ---------- result toolbar: search + live count ---------- */
.u-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;}
.lc-tools{
  display:flex;align-items:center;gap:var(--sp-4);flex-wrap:wrap;
  margin-bottom:0;                 /* the first .section's own padding carries the gap */
}
/* the count belongs to the results, not floating 88px above them */
/* the sections sit inside [data-lc-view], not directly under #lc-results, so a child combinator
   matched nothing and the 64px band survived. */
#lc-results .section:first-of-type{padding-top:var(--sp-4);}
/* the count reads as a label on the results, seated on the heading it describes */
.lc-search{
  display:flex;align-items:center;gap:var(--sp-3);flex:1 1 16rem;min-width:0;
  padding:0 var(--sp-4);min-height:40px;
  border:0;border-radius:var(--radius-full);background:var(--c-tile);
  color:var(--c-ink-faint);
}
.lc-search:focus-within{background:var(--c-tile-hi);color:var(--c-primary-strong);}
.lc-search svg{width:16px;height:16px;flex:none;}
/* align-self:stretch, so the field's hit area is the whole 40px shell instead of the 22px the
   text line occupied — clicking the visible box's top or bottom edge now focuses it. */
.lc-search input{
  flex:1;min-width:0;align-self:stretch;border:0;background:none;color:var(--c-ink);
  font:inherit;font-size:var(--fs-3);padding:0;
}
.lc-search input::placeholder{color:var(--c-ink-faint);}
.lc-search input:focus{outline:none;}
.lc-tools__clear{
  border:0;background:none;cursor:pointer;font:inherit;font-size:var(--fs-2);
  color:var(--c-primary-strong);text-decoration:underline;padding:0;
}
.lc-empty{margin:0 0 var(--sp-6);color:var(--c-ink-dim);font-size:var(--fs-3);}
.section[hidden],.lc-empty[hidden],.lc-tools__clear[hidden]{display:none;}

/* ---------- filters: sticky left sheet (>=900) / bottom sheet (<900) ---------- */
.filters{ align-self:start; }
@media (min-width:900px){
  /* NO overflow:auto here. The dropdown panel is absolutely positioned and taller than the
     sidebar box, so a scroll container would CLIP it — the sidebar would grow a scrollbar and
     eat its own menu. Only the option list scrolls now, and it brands its own scrollbar. */
  /* clears the header. The bar is sticky at top:0 and 80px tall, so a 24px offset parked the
     panel's search and dropdown UNDERNEATH it the moment the page scrolled. --head-h is the
     same token the header sizes from, so the two cannot drift apart. */
  .filters{position:sticky;top:calc(var(--head-h) + var(--sp-4));
           padding-right:var(--sp-2);padding-left:0;}
}
/* =============================================================================
   COMPONENT: multi-select (.ms) — ONE component, used for suppliers AND categories.
   Collapsed it is a single row, so the option count no longer drives panel height:
   30 suppliers at 2-up cost the sidebar nothing until the user opens the dropdown.
   Only the option ROWS differ between the two instances; every behaviour is shared.
   ========================================================================== */
.ms{position:relative;margin-bottom:var(--sp-3);}
.ms[hidden]{display:none;}
.ms__trigger{
  display:flex;align-items:center;justify-content:space-between;gap:var(--sp-2);
  width:100%;min-height:38px;padding:0 var(--sp-3);
  border:0;border-radius:var(--radius-sm);
  background:var(--c-tile);color:var(--c-ink);font:inherit;font-size:var(--fs-2);
  text-align:left;cursor:pointer;
  transition:border-color var(--dur-fast),color var(--dur-fast);
}
.ms__value{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
/* the picked marks, ON the collapsed field. A count alone made the visitor reopen the panel to
   recall their own answer; the logos ARE the answer, and they read at a glance. */
.ms__marks{display:flex;align-items:center;gap:3px;flex:none;}
.ms__marks[hidden]{display:none;}
.ms__marks img{
  width:22px;height:16px;object-fit:contain;flex:none;
  background:var(--c-plate);border-radius:3px;padding:1px 2px;
}
.ms__marks img[data-dark]{filter:invert(1) hue-rotate(180deg);}
.ms__marks-more{font-size:var(--fs-1);font-weight:700;color:var(--c-primary-strong);}
.ms__chev{display:flex;flex:none;color:var(--c-ink-faint);transition:transform var(--dur-fast);}
.ms__chev svg{width:16px;height:16px;}
.ms__trigger:hover{background:var(--c-tile-hi);color:var(--c-primary-strong);}
.ms__trigger:focus-visible{outline:2px solid var(--c-primary-strong);outline-offset:2px;}
.ms__trigger:active{transform:translateY(1px);}
.ms__trigger[aria-expanded="true"]{background:var(--c-tile-hi);color:var(--c-primary-strong);}
.ms__trigger[aria-expanded="true"] .ms__chev{transform:rotate(180deg);}
.ms__trigger[data-count]:not([data-count="0"]) .ms__value{color:var(--c-primary-strong);font-weight:650;}

/* the panel is absolutely positioned so opening it never resizes the sidebar */
.ms__panel{
  position:absolute;z-index:60;left:0;top:calc(100% + 4px);
  /* wider than the 200px aside: at 2-up an option row was 87px, and a 26px mark plus a name
     does not fit that. Overhanging the results is what a dropdown is for. */
  width:max(100%, 340px);
  display:grid;gap:var(--sp-2);padding:var(--sp-2);
  border:0;border-radius:var(--radius-md);
  background:var(--c-tile);box-shadow:0 24px 48px -14px rgba(0,0,0,.85);
}
.ms__panel[hidden]{display:none;}
.ms__search{
  display:flex;align-items:center;gap:var(--sp-2);
  padding:0 var(--sp-2);min-height:32px;
  border:0;border-radius:var(--radius-sm);background:var(--c-bg);color:var(--c-ink-faint);
}
.ms__search:focus-within{color:var(--c-primary-strong);}
.ms__search svg{width:14px;height:14px;flex:none;}
.ms__search input{
  flex:1;min-width:0;align-self:stretch;border:0;background:none;color:var(--c-ink);
  font:inherit;font-size:var(--fs-2);padding:0;
}
.ms__search input:focus{outline:none;}

/* two columns for the marks — three made them unreadable. The panel, not the sidebar,
   absorbs the height, and only the option list scrolls. */
.ms__opts{
  display:grid;grid-template-columns:repeat(var(--ms-cols,1),minmax(0,1fr));gap:2px;
  max-height:min(46dvh,320px);overflow:auto;
  scrollbar-width:thin;scrollbar-color:var(--c-primary) transparent;
}
.ms__opts::-webkit-scrollbar{width:6px;}
.ms__opts::-webkit-scrollbar-track{background:transparent;}
.ms__opts::-webkit-scrollbar-thumb{background:var(--c-primary);border-radius:var(--radius-full);}

/* logo AND name side by side — the mark alone was not identifiable at this size */
.ms__opt{
  display:flex;align-items:center;gap:var(--sp-2);width:100%;min-height:30px;text-align:left;
  padding:var(--sp-1) var(--sp-2);
  border:1px solid transparent;border-radius:var(--radius-sm);
  background:none;color:var(--c-ink-dim);font:inherit;font-size:var(--fs-1);
  text-align:left;cursor:pointer;
  transition:border-color var(--dur-fast),color var(--dur-fast),background var(--dur-fast);
}
.ms__opt[hidden]{display:none;}
.ms__mark{
  flex:none;width:26px;height:16px;object-fit:contain;object-position:left center;
  filter:grayscale(1) brightness(1.15) invert(1);opacity:.65;
  transition:opacity var(--dur-fast);
}
/* wraps rather than truncates — convention 6 of this stylesheet. Grouped lines like
   "WEMCO · Hidrostal · Warman" are the whole point of the option; an ellipsis hides which
   brands the row actually covers. */
.ms__name{flex:1 1 auto;min-width:0;line-height:1.2;}
.ms__opt .count{flex:none;}
.ms__opt:hover{background:var(--c-tile-hi);color:var(--c-primary-strong);}
.ms__opt:hover .ms__mark{opacity:1;}
.ms__opt:focus-visible{outline:2px solid var(--c-primary-strong);outline-offset:-1px;}
.ms__opt:active{transform:translateY(1px);}
.ms__opt[aria-selected="true"]{
  border-color:var(--c-primary);background:var(--c-primary-edge);color:var(--c-primary-strong);
  font-weight:650;
}
.ms__opt[aria-selected="true"] .ms__mark{opacity:1;}
.ms__empty{padding:var(--sp-3);color:var(--c-ink-faint);font-size:var(--fs-1);text-align:center;}
.ms__clear{
  border:0;background:none;cursor:pointer;font:inherit;font-size:var(--fs-1);
  color:var(--c-primary-strong);text-decoration:underline;padding:var(--sp-1);
}
.ms__clear[hidden]{display:none;}
.ms__clear:hover{color:var(--c-ink);}
.ms__clear:focus-visible{outline:2px solid var(--c-primary-strong);outline-offset:2px;}

/* search moved out of the results toolbar and into the panel */
.lc-search--panel{min-height:36px;margin-bottom:var(--sp-3);border-radius:var(--radius-sm);}

/* the CTA and print sit BELOW the filters */
.filters__foot{margin-top:var(--sp-5);display:grid;gap:var(--sp-3);}

/* ---------- map card ---------- */
.mapcard{
  display:block;overflow:hidden;border-radius:var(--radius-md);
  background:var(--c-tile);
  transition:background var(--dur-fast),transform var(--dur-fast) var(--ease-out);
}
.mapcard__img{display:block;width:100%;height:96px;object-fit:cover;object-position:center;
  transition:transform var(--dur-med) var(--ease-out);}
.mapcard__body{display:block;padding:var(--sp-3);}
.mapcard__label{
  display:block;font-size:var(--fs-1);letter-spacing:.14em;text-transform:uppercase;
  color:var(--c-primary-strong);font-weight:650;margin-bottom:2px;
}
.mapcard__addr{display:block;font-size:var(--fs-1);line-height:1.35;color:var(--c-ink-dim);}
.mapcard:hover{background:var(--c-tile-hi);transform:translateY(-2px);}
.mapcard:hover .mapcard__img{transform:scale(1.06);}
.mapcard:focus-visible{outline:2px solid var(--c-primary-strong);outline-offset:2px;}
.mapcard:active{transform:translateY(0);}

/* Inside the mobile sheet the panel goes back IN FLOW. The sheet is a scroll container, so an
   absolutely-positioned panel would be clipped by it — the same trap that made the desktop
   sidebar grow a scrollbar and swallow its own menu. */
@media (max-width:899px){
  .ms__panel{position:static;width:auto;box-shadow:none;margin-top:var(--sp-2);}
  .ms__opts{max-height:none;}
}
/* mobile: the sheet is hidden until the sticky bar's filter button opens it */
@media (max-width:899px){
  .filters{
    position:fixed;left:0;right:0;bottom:0;z-index:120;
    max-height:76dvh;overflow:auto;
    padding:var(--sp-5) var(--page-inset) calc(var(--sp-8) + env(safe-area-inset-bottom));
    border-top:1px solid var(--c-line);border-radius:var(--radius-lg) var(--radius-lg) 0 0;
    background:var(--c-bg);
    transform:translateY(101%);transition:transform var(--dur-med) var(--ease-out);
  }
  .filters[data-open="true"]{transform:translateY(0);}
  .filters__grab{
    display:block;width:44px;height:4px;margin:0 auto var(--sp-4);
    border-radius:var(--radius-full);background:var(--c-line);
  }
}
.lc-scrim{
  position:fixed;inset:0;z-index:110;background:rgba(0,0,0,.55);
  opacity:0;visibility:hidden;transition:opacity var(--dur-med),visibility var(--dur-med);
}
.lc-scrim[data-open="true"]{opacity:1;visibility:visible;}

/* mobile sticky bottom bar */
.lc-bar{
  position:fixed;left:0;right:0;bottom:0;z-index:100;
  display:flex;align-items:center;justify-content:space-between;gap:var(--sp-4);
  padding:var(--sp-3) var(--page-inset) calc(var(--sp-3) + env(safe-area-inset-bottom));
  border-top:1px solid var(--c-line);background:var(--c-bg);
}
/* the bar's three controls are .btn .btn--primary / .btn--ghost — box, radius, hover, focus
   and active all come from there. This block adds ONLY what the bar changes: a tap target,
   a tighter fit, and the expanded state the generic button has no concept of. */
.lc-bar .btn{min-height:44px;padding:0 var(--sp-5);font-size:var(--fs-2);}
.lc-bar .btn svg{width:16px;height:16px;flex:none;}
.lc-bar__filter[aria-expanded="true"]{background:var(--c-primary);color:var(--c-primary-ink);}
/* The bar must not sit on top of the last card or the footer — but only on the page that HAS a
   bar. Unconditional, this put 96px of dead padding under the copyright on the four pages that
   never render one, which is the only bottom padding the footer had left. */
@media (max-width:899px){
  body:has(.lc-bar) .site-foot{padding-bottom:calc(var(--sp-9) + env(safe-area-inset-bottom));}
}
/* declared LAST so it beats the display:flex above — order, not specificity, decides here.
   The bar is removed from the box tree on laptop/desktop, not merely hidden. */
@media (min-width:900px){ .filters__grab,.lc-bar,.lc-scrim{display:none !important;} }

/* ---------- compact hero with the drone video behind ----------
   On .has-hero pages the header is lifted out of flow so the footage runs to the very top of
   the page and the nav sits over it. Scoped to >=900 because the mobile header wraps to a
   second row and would collide with the hero copy. */
/* On a hero page the bar has NO field of its own — the footage runs behind it. The header stays
   sticky and in flow; the hero is pulled up by the header's own height and pads that height back,
   so the video occupies the band the bar sits on without either leaving the flow. --head-h is
   the one number both sides read. */
:root{ --head-h:80px; }
.has-hero .site-head{background:transparent;-webkit-backdrop-filter:none;backdrop-filter:none;}
.has-hero .phero{margin-top:calc(var(--head-h) * -1);padding-top:var(--head-h);}
/* with no copy inside it, the hero has no intrinsic height — it collapsed to its own padding.
   min-height makes it a real band; 34vh capped so it never eats the results. */
.phero{position:relative;isolation:isolate;overflow:hidden;padding-block:0;
       min-height:clamp(200px,34vh,320px);}
.phero__media{position:absolute;inset:0;z-index:-1;}
.phero__video{
  position:absolute;inset:0;
  width:100%;height:100%;min-width:100%;min-height:100%;
  /* .38 over a near-black field read as a black strip — the band was paying 289px and showing
     nothing. Raised; the scrim below carries the legibility the low opacity used to. */
  object-fit:cover;object-position:center 58%;opacity:.95;
}
/* the scrim is what keeps the copy at AA over moving footage. It is now a LEFT wedge rather than
   a flat wash: opaque behind the copy, clearing to almost nothing on the right so the plant is
   actually visible there. */
/* Much lighter: no copy sits over the footage any more, so the scrim only has to hold the
   sticky bar's own links and the fade into the page below. */
/* Held dark across the top band and then cleared fast: the sticky bar's wordmark, h1, CTA and
   hamburger all sit over the footage now, and at .12 by 22% they were washing out against the
   bright plant signage. The hold is the height of the header, not a guess. */
.phero__scrim{
  position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(11,11,13,.72) 0%,rgba(11,11,13,.6) 12%,
             rgba(11,11,13,.14) 34%,rgba(11,11,13,.06) 70%,var(--c-bg) 100%);
}
  margin:0 0 var(--sp-3);font-size:clamp(1.6rem,.9rem + 1.6vw,2.4rem);
  line-height:1.06;letter-spacing:-.025em;font-weight:700;
}
@media (prefers-reduced-motion:reduce){ .phero__video{display:none;} }

/* ---------- CTA box, BELOW the filters in the left panel ---------- */
/* No outer border and no heading: the buttons are the whole message. The dark green field
   still carries them, so the panel reads as one block without a frame around it. */
.lc-cta{
  display:flex;flex-direction:column;gap:var(--sp-2);
  padding:var(--sp-4);          /* 12 -> 16: the box now holds a form, not two buttons */
  background:var(--c-cta-panel);border:0;
  border-radius:var(--radius-md);
}
.lc-cta .btn{width:100%;justify-content:center;padding:2px var(--sp-3);font-size:var(--fs-2);min-height:32px;}

/* ---------- the header utilities: call, print, download ----------
   They were three controls inside the green box competing with the ask. They are page-level
   actions, so they sit with the chrome instead. */
/* Shown from 900 up — the same width the mobile bar stops carrying its own actions at, so no
   band is left without print and download. Between 900 and 1100 they are icon-only: the labels
   are what does not fit, not the controls. */
.site-head__tools{display:none;align-items:center;gap:var(--sp-2);}
@media (min-width:900px){ .site-head__tools{display:flex;} }
@media (min-width:900px) and (max-width:1099px){
  .headtool span{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);}
  .headtool{padding:0 var(--sp-2);}
  .headtool--call span{position:static;width:auto;height:auto;clip-path:none;}
}
.headtool{
  display:inline-flex;align-items:center;gap:var(--sp-2);
  min-height:36px;padding:0 var(--sp-3);
  background:none;border:1px solid transparent;border-radius:var(--radius-full);
  color:var(--c-ink-dim);font:inherit;font-size:var(--fs-1);font-weight:600;
  text-decoration:none;cursor:pointer;white-space:nowrap;
  transition:color var(--dur-fast),border-color var(--dur-fast),background var(--dur-fast);
}
.headtool svg{width:15px;height:15px;flex:none;}
.headtool:hover{color:var(--c-ink);border-color:var(--c-line);background:rgba(244,244,244,.05);}
.headtool:focus-visible{outline:2px solid var(--c-primary-strong);outline-offset:2px;}
.headtool--call{color:var(--c-primary-strong);}
.headtool--call:hover{color:var(--c-primary-strong);border-color:var(--c-primary);}
.headtool[aria-expanded="true"]{color:var(--c-ink);border-color:var(--c-line);background:rgba(244,244,244,.08);}
/* in the header the menu drops DOWN, not up as it did from the panel's foot */
.site-head__tools .dl__menu{top:calc(100% + 8px);bottom:auto;right:0;left:auto;}

/* ---------- the inventory request, embedded on the green field ----------
   The panel used to carry a button that promised a form. The form IS the panel now: step one
   asks what they came to ask, and nothing personal, so the first interaction costs nothing.
   The pickers are the SAME .ms component the filter above uses — the visitor has already
   learned this control by the time they reach it. */
.ivf{display:flex;flex-direction:column;gap:var(--sp-2);}
/* one tight rhythm: the fields read as a single block, not four separate controls */
.ivf__step{border:0;margin:0;padding:0;min-width:0;display:flex;flex-direction:column;gap:4px;}
.ivf__step[hidden]{display:none;}
.ivf__step legend{padding:0;float:left;width:100%;}
.ivf__step legend b{display:block;font-size:var(--fs-5);font-weight:700;color:var(--c-cta-panel-ink);letter-spacing:-.01em;}
.ivf__step legend span{display:block;margin-top:2px;font-size:var(--fs-1);line-height:1.35;
  color:rgba(230,243,221,.7);}
/* the rail is two ticks, not a percentage: two steps do not need a progress bar */
.ivf__rail{display:flex;gap:4px;margin:0 0 2px;padding:0;list-style:none;}
.ivf__rail li{height:3px;flex:1;border-radius:2px;background:rgba(230,243,221,.2);transition:background var(--dur-fast);}
.ivf__rail li.is-on{background:var(--c-primary-strong);}
.ivf__rail[hidden]{display:none;}

.ivf .ms{width:100%;}
.ivf .ms__trigger{background:rgba(11,11,13,.34);border-color:rgba(230,243,221,.22);color:var(--c-cta-panel-ink);}
.ivf .ms__trigger:hover{border-color:var(--c-primary-strong);}
.ivf .ms__panel{background:var(--c-bg);border-color:var(--c-line);}

.ivf__fld{min-width:0;}
.ivf__fld label{display:block;margin:0 0 2px;font-size:var(--fs-1);font-weight:600;
  color:rgba(230,243,221,.78);}
.ivf__step > legend + .ivf__fld{margin-top:2px;}
.ivf__opt{font-weight:400;color:rgba(230,243,221,.5);}
.ivf__fld input{
  display:block;width:100%;min-height:34px;padding:6px var(--sp-3);
  background:rgba(11,11,13,.34);color:var(--c-cta-panel-ink);
  border:1px solid rgba(230,243,221,.22);border-radius:var(--radius-sm);
  font:inherit;font-size:var(--fs-2);
  transition:border-color var(--dur-fast),box-shadow var(--dur-fast);
}
.ivf__fld input::placeholder{color:rgba(230,243,221,.34);}
.ivf__fld input:focus{outline:none;border-color:var(--c-primary-strong);
  box-shadow:0 0 0 3px rgba(124,198,83,.22);}
.ivf__fld input[aria-invalid="true"]{border-color:#ff8a8a;box-shadow:0 0 0 3px rgba(255,138,138,.2);}
.ivf__err{display:block;margin:3px 0 0;font-size:var(--fs-1);color:#ff9b9b;}
.ivf__err[hidden]{display:none;}
.ivf__err--step{margin:0;}
.ivf__hp{position:absolute;left:-9999px;width:1px;height:1px;opacity:0;}

/* ---------- the ask, emphasised ----------
   A continuous breath plus a sheen that crosses it. Motion is the cheapest way to say "this is
   the control" on a panel where everything else is quiet — and it is the ONLY moving thing here,
   so it does not compete. Both loops stop under prefers-reduced-motion; the states below do not,
   because a state is information and a preference about motion is not a preference about feedback. */
/* 3.4s on a symmetric ease-in-out, not 2.6s on ease-out. Slower and eased at BOTH ends is what
   reads as smooth: ease-out alone snaps into the pass and then coasts, so the loop drew the eye
   as a flicker instead of a breath. The sheen is softer (.28 over a wider band) and rests longer
   between passes, so it registers as light moving over the surface rather than a wipe. */
.ivf__go{
  width:100%;justify-content:center;position:relative;overflow:hidden;
  animation:ivf-breathe 3.4s cubic-bezier(.4,0,.2,1) infinite;
  transition:transform var(--dur-med),box-shadow var(--dur-med),filter var(--dur-med);
}
.ivf__go::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(105deg,transparent 28%,rgba(255,255,255,.28) 50%,transparent 72%);
  transform:translateX(-130%);
  animation:ivf-sheen 3.4s cubic-bezier(.4,0,.2,1) infinite;
}
@keyframes ivf-breathe{
  0%,100%{ box-shadow:0 0 0 0 rgba(124,198,83,.34); }
  58%    { box-shadow:0 0 0 9px rgba(124,198,83,0); }
}
@keyframes ivf-sheen{
  0%,60%{ transform:translateX(-130%); }
  94%,100%{ transform:translateX(130%); }
}
.ivf__go:hover{transform:translateY(-1px);filter:brightness(1.06);}
.ivf__go:active{transform:translateY(0) scale(.985);filter:brightness(.96);}
.ivf__go:focus-visible{outline:2px solid var(--c-ink);outline-offset:3px;}
.ivf__go:disabled{animation:none;filter:grayscale(.35);opacity:.7;cursor:progress;}
.ivf__go:disabled::after{animation:none;opacity:0;}
@media (prefers-reduced-motion:reduce){
  .ivf__go{animation:none;}
  .ivf__go::after{animation:none;opacity:0;}
}
/* column-reverse: the primary sits first and full width, Back beneath it as the quiet escape.
   Side by side, "Request Inventory" wrapped to two lines inside a 250px panel. */
.ivf__acts{display:flex;flex-direction:column-reverse;gap:var(--sp-2);}
.ivf .ivf__back{background:none;border:1px solid rgba(230,243,221,.24);color:var(--c-cta-panel-ink);
  padding:2px var(--sp-3);font-size:var(--fs-1);min-height:28px;}
.ivf .ivf__back:hover{border-color:var(--c-cta-panel-ink);}

.ivf__done{padding:var(--sp-3) 0;}
.ivf__done[hidden]{display:none;}
.ivf__doneT{margin:0 0 2px;font-size:var(--fs-3);font-weight:700;color:var(--c-primary-strong);}
.ivf__doneM{margin:0;font-size:var(--fs-1);line-height:1.4;color:rgba(230,243,221,.78);}
/* The panel's whole job after a send is to hand the visitor the next move, so the one control
   here inherits .ivf__go — same breathing loop, same states, one definition. text-decoration
   is the only thing an anchor needs that the shared .btn does not already give it. */
.ivf__doneGo{margin-top:var(--sp-3);text-decoration:none;}
/* The two-segment rail is still frozen at "step 1 of 2" when the done block appears, which sits
   directly above a line saying access is granted and contradicts it. There is no progress left
   to report once the panel is no longer a form, so the rail goes rather than being re-filled. */
.ivf:has([data-ivf-done]:not([hidden])) .ivf__rail{display:none;}

/* ---------- download format menu ---------- */
.dl{position:relative;}
.dl__menu{
  /* anchored LEFT and overhanging to the right, over the results. right:0 on a 244px menu
     inside a ~95px half-column pushed it clean off the viewport's left edge. */
  position:absolute;z-index:70;left:0;right:auto;bottom:calc(100% + 6px);
  display:grid;gap:2px;padding:var(--sp-2);
  width:max(100%, 244px);
  border-radius:var(--radius-md);
  background:var(--c-tile);box-shadow:0 24px 48px -14px rgba(0,0,0,.85);
}
.dl__menu[hidden]{display:none;}
.dl__opt{
  display:flex;align-items:center;gap:var(--sp-2);width:100%;min-height:36px;
  padding:var(--sp-1) var(--sp-2);
  border:0;border-radius:var(--radius-sm);background:none;
  color:var(--c-ink-dim);font-family:inherit;font-size:var(--fs-1);
  text-align:left;cursor:pointer;
  transition:background var(--dur-fast),color var(--dur-fast);
}
.dl__opt svg{width:18px;height:18px;flex:none;}
.dl__opt:hover{background:var(--c-tile-hi);color:var(--c-primary-strong);}
.dl__opt:focus-visible{outline:2px solid var(--c-primary-strong);outline-offset:-1px;}
.dl__opt:active{transform:translateY(1px);}
/* the open state marks the control without shouting — the near-white panel ink rendered as a
   loud white pill inside the dark green box. */
.lc-cta__dl[aria-expanded="true"]{background:rgba(230,243,221,.16);color:var(--c-cta-panel-ink);}
/* print is a sibling of the phone and shares its treatment exactly — no separate rule set. */
.lc-cta .btn svg{width:14px;height:14px;flex:none;}
/* the ghost button loses its outline too — it reads as the secondary action by weight alone */
.lc-cta .btn--ghost{border-color:transparent;color:var(--c-cta-panel-ink);}
.lc-cta .btn--ghost:hover{background:var(--c-cta-panel-ink);color:var(--c-cta-panel);}

/* the Products | Suppliers toggle is gone: one view, so the control and its styles
   are removed rather than hidden. */

/* the products view is gone with its toggle; .productgrid/.product/.product__* removed. */

/* ---------- mobile bar: three one-tap actions ---------- */
.lc-bar .btn{flex:1 1 0;min-width:0;min-height:46px;padding:0 var(--sp-3);
  font-size:var(--fs-1);gap:var(--sp-2);justify-content:center;}
.lc-bar .btn svg{width:16px;height:16px;flex:none;}
.lc-bar .btn span{white-space:nowrap;overflow:hidden;text-overflow:clip;}
.count{
  display:inline-block;min-width:1.6em;padding:0 .4em;border-radius:var(--radius-full);
  background:var(--c-primary-edge);color:var(--c-primary-strong);
  font-size:var(--fs-1);font-weight:650;text-align:center;vertical-align:middle;
}
.section h2 .count{margin-left:var(--sp-2);}
/* the sticky header must not cover the heading a jump link lands on */
[id]{scroll-margin-top:calc(var(--sp-9) + var(--sp-4));}

/* Copy left, product photo right. flex-wrap + flex-basis does the responsive work intrinsically:
   the shot drops below the copy the moment the card is too narrow to hold both, at whatever width
   that happens to be. No media query, so there is no band where it is wrong. */
/* Source spec, reproduced: 1px solid #28712A, radius 48px 8px 48px 8px, 20px padding,
   transparent background, copy left and product photo right. */
/* No border, no radius. With the frame gone the only thing separating one tile from the next is
   rhythm, so the row gap carries that job and a hairline rule marks the baseline of each tile. */
/* tile: photo on top, body beneath. A dark grey FIELD separates one tile from the next, so
   there is no border and no baseline rule anywhere on the card — the surface does the work a
   hairline used to. */
.supplier{
  container-type:inline-size;
  position:relative;
  display:flex;flex-direction:column;gap:var(--sp-3);
  border:0;border-radius:var(--radius-md);
  padding:var(--lc-pad) var(--lc-pad) calc(var(--lc-pad) + var(--sp-2));
  background:var(--c-tile);
  /* ONE token for every property that moves on hover — see --dur-card / --ease-card.
     transform used to run --dur-fast/ease-out while the rest ran --dur-med, so the lift
     arrived before the shadow and the card read as two events instead of one. opacity and
     filter join the list because the SIBLING dim below rides them. */
  transition:background var(--dur-card) var(--ease-card),
             transform  var(--dur-card) var(--ease-card),
             box-shadow var(--dur-card) var(--ease-card),
             opacity    var(--dur-card) var(--ease-card),
             filter     var(--dur-card) var(--ease-card);
}
/* Hover is a real change of state, not just the action bar arriving: the field lifts, brightens
   and casts, and the product photo scales a touch inside its box. focus-within gets the SAME
   treatment so a keyboard reaches it — /design scores the state set by its weakest member. */
.supplier:hover,.supplier:focus-within{
  background:var(--c-tile-hi);
  transform:translateY(-8px);
  box-shadow:0 26px 44px -20px rgba(0,0,0,.9);
  /* the ring is an OUTER shadow, so the card's own overflow:hidden cannot clip it */
  animation:card-pulse 2.6s var(--ease-card) infinite;
}
/* The ring travels 10px from a .5 alpha — one step up from 6px/.34, which was close to
   invisible against the cast shadow underneath it. It stays a RING that expands and fades,
   never a standing glow: at every keyframe the alpha is either falling or zero, so there is
   no frame where the card is wearing a halo. */
@keyframes card-pulse{
  0%,100%{ box-shadow:0 26px 44px -20px rgba(0,0,0,.9), 0 0 0 0 rgba(124,198,83,.5); }
  70%    { box-shadow:0 26px 44px -20px rgba(0,0,0,.9), 0 0 0 10px rgba(124,198,83,0); }
}

/* ---------- one card lit, the rest stood down ----------
   Hovering a card dims every OTHER card in the result set, so the grid resolves to a single
   subject. This is a HIERARCHY device, which is the justification /taste requires before any
   motion ships — it is not decoration.
   Scoped to #lc-results so a card in the category above also stands down, with .linecard as
   the fallback scope for a standalone grid (the contact page carries one). Both share one
   declaration block rather than repeating it.
   :not(:focus-within) is load-bearing: a keyboard user parked inside one card and then moving
   the mouse over another should not have their own card go dark under them.
   @media (hover:hover) keeps it off touch entirely — there is no hover there, so the whole
   grid would sit dimmed or flash on tap. */
@media (hover:hover){
  #lc-results:has(.supplier:hover) .supplier:not(:hover):not(:focus-within),
  .linecard:has(.supplier:hover) .supplier:not(:hover):not(:focus-within){
    opacity:.38;
    filter:saturate(.45);
  }
}
@media (prefers-reduced-motion:reduce){
  /* The pulse and the lift are the two vestibular-triggering pieces and both go. The dim and
     the brighten stay: an opacity cross-fade is what WCAG 2.3.3 asks a slide or scale to be
     REPLACED BY, so removing it would be the wrong direction. transform is overridden rather
     than left to snap — killing the transition alone would keep the 8px jump, instantly. */
  .supplier:hover,.supplier:focus-within{animation:none;transform:none;}
  .supplier{transition:opacity var(--dur-med) linear,filter var(--dur-med) linear;}
}
.supplier:focus-within{outline:2px solid var(--c-primary-strong);outline-offset:2px;}
/* the shot-scale pair used to be declared here AND again at .supplier__shot below — one of the
   two was dead weight. It lives with the shot now, on the card's own curve. */
.supplier__body{
  min-width:0;
  display:flex;flex-direction:column;align-items:flex-start;gap:var(--sp-2);
}
/* the source scales each mark individually (24%-100%); --logo-w carries that per supplier.
   The box bounds the absolute size so a 100% mark cannot run away on a wide row, while the
   relative weights the original author chose are preserved inside it. */
/* fixed-height box: logo intrinsic heights vary, which pushed every brand name to a different
   baseline across a row. The box holds the row rhythm; --logo-w still sets relative weight. */
/* No plate behind the mark — the field is the card. */
.supplier__logobox{
  display:flex;align-items:center;
  width:100%;height:58px;
}
/* No blanket grayscale: a mark keeps its own colours. But 24 of the 30 are drawn for light
   backgrounds — mean opaque luminance under 105, measured per file — and on a #151519 field
   they vanish. Those 24 carry data-dark from the build and get invert + hue-rotate(180deg),
   which flips LIGHTNESS while preserving HUE, so a navy wordmark reads as pale blue rather
   than as grey. The 6 light marks are left exactly as their owners drew them. */
.supplier__logo{
  display:block;width:var(--logo-w,72%);max-width:100%;max-height:100%;height:auto;object-fit:contain;object-position:left center;
  opacity:.92;
  transition:opacity var(--dur-card) var(--ease-card);
}
.supplier__logo[data-dark]{filter:invert(1) hue-rotate(180deg);}
.supplier:hover .supplier__logo,.supplier:focus-within .supplier__logo{opacity:1;}
/* demoted so the mark leads the tile, not the wordmark under it.
   h3 qualifier is load-bearing: .section h3 is (0,1,1) and would otherwise win. */
/* one step above the capability list, so the brand reads as the heading of its own list rather
   than the first bullet. Weight stays at 500 — the LOGO still leads the tile. */
h3.supplier__name{
  margin:0;font-size:var(--fs-3);font-weight:500;letter-spacing:.01em;
  line-height:1.25;color:var(--c-ink);
}
.supplier__list{margin:0;padding-left:1em;display:grid;gap:var(--sp-1);}
.supplier__list li{font-size:var(--fs-2);line-height:1.4;color:var(--c-ink-dim);}
/* No cap: every capability is shown. Tiles in one ROW still match via align-items:stretch;
   heights differ BETWEEN rows now, which is correct once the list is the card's content. */
/* The `+N more` toggle this comment used to sit above was deleted by J2 — but only its
   SELECTOR was, and the orphaned body stayed. A declaration body with no selector is not
   inert: the parser reads it as a prelude and keeps consuming until the next `{`, so it ate
   `.lc-search:hover` whole. Measured absent from document.styleSheets before this deletion. */

/* search: hover / focus-within / filled are three distinct states, not one */
.lc-search:hover{background:var(--c-tile-hi);}
.lc-search input:not(:placeholder-shown){color:var(--c-ink);}
.lc-tools__clear:hover{color:var(--c-ink);}
.lc-tools__clear:focus-visible{outline:2px solid var(--c-primary-strong);outline-offset:3px;}
.lc-tools__clear:active{transform:translateY(1px);}
/* hover / focus-visible / active on the bar's controls come from .btn and .btn--ghost;
   only the focus ring is restated, because the shared button relies on the browser default. */
.lc-bar .btn:focus-visible{outline:2px solid var(--c-primary-strong);outline-offset:3px;}

/* ---------- tile hover action bar ----------
   Reserved by padding-bottom on the tile so revealing it shifts nothing. focus-within carries
   it to the keyboard, and a coarse pointer gets it permanently since hover never fires there. */
/* No reserved strip. The bar was costing every card 30px of height for a control only visible
   on hover; it is absolute OVER the content now, with a scrim so the text beneath stays legible. */
/* THE WHOLE CARD IS THE TARGET.
   The stretched-::before trick does NOT work here and it is worth recording why: a pseudo-element
   resolves inset:0 against its nearest POSITIONED ancestor, and that is .supplier__act, not the
   card — so it covered the bar only. Measured: a click at the card's centre landed on
   .supplier__logo and opened nothing. The click is forwarded in JS instead (linecard.js), and the
   real button keeps the name, the role and the keyboard path. */
.supplier{cursor:pointer;}
.supplier__act-btn{width:100%;justify-content:center;}
.supplier__act{
  position:absolute;left:0;right:0;bottom:0;
  padding:var(--sp-5) var(--lc-pad) var(--lc-pad);
  background:linear-gradient(180deg,rgba(29,29,35,0),var(--c-tile-hi) 46%);
  border-radius:0 0 var(--radius-md) var(--radius-md);
  display:flex;justify-content:stretch;align-items:center;
  opacity:0;transform:translateY(4px);pointer-events:none;
  transition:opacity var(--dur-card) var(--ease-card),transform var(--dur-card) var(--ease-card);
}
.supplier:hover .supplier__act,
.supplier:focus-within .supplier__act{opacity:1;transform:none;pointer-events:auto;}
@media (hover:none){ .supplier__act{opacity:1;transform:none;pointer-events:auto;} }

/* the DRN symbol, bottom centre — a branded graphic that arrives with the bar. Decorative, so
   it is a pseudo-element and carries no markup, no alt and nothing for a screen reader. */
/* The signature. A large DRN mark anchored to the card's bottom edge and translated down by
   half its own height, so the card's own overflow clips it: what shows is the top half rising
   out of the bottom. Sized off the CARD (cqi) so it is the same gesture in a 223px tile and a
   356px one. z-index 0 keeps it BEHIND the copy — it is a mark on the card's back, not a badge
   over its front — while still sitting above the field. */
.supplier{overflow:hidden;}
.supplier::after{
  content:"";position:absolute;z-index:0;
  left:50%;bottom:0;transform:translate(-50%,60%) scale(.94);
  /* 178cqi — wider than the card itself, so the card clips it on BOTH sides as well as along
     the bottom. The vector carries the mark's own box, so the declared size is the MARK's size
     rather than a file's padded canvas — and at 178cqi the old 433px raster was resampled up. */
  width:178cqi;aspect-ratio:2048/1991;
  color:var(--c-ink);background:currentColor;
  -webkit-mask:url("/assets/brand/drn-symbol-mono.svg") center/contain no-repeat;
          mask:url("/assets/brand/drn-symbol-mono.svg") center/contain no-repeat;
  opacity:0;pointer-events:none;
  transition:opacity var(--dur-card) var(--ease-card),transform var(--dur-card) var(--ease-card);
}
.supplier:hover::after,.supplier:focus-within::after{opacity:.3;transform:translate(-50%,50%) scale(1);}
@media (hover:none){ .supplier::after{opacity:.2;transform:translate(-50%,50%) scale(1);} }
/* the copy and the bar both stay above the signature */
.supplier__logobox,.supplier__shot,.supplier__body{position:relative;z-index:1;}
.supplier__act{z-index:2;}
.supplier__act-btn{
  display:inline-flex;align-items:center;justify-content:center;
  border:0;border-radius:var(--radius-full);cursor:pointer;font-family:inherit;
  background:var(--c-primary);color:var(--c-primary-ink);
  font-size:var(--fs-2);font-weight:650;letter-spacing:.01em;
  min-height:34px;padding:0 var(--sp-5);
  transition:background var(--dur-fast),transform var(--dur-fast) var(--ease-out);
}
.supplier__act-btn:hover{background:var(--c-primary-strong);}
.supplier__act-btn:focus-visible{outline:2px solid var(--c-primary-strong);outline-offset:3px;}
.supplier__act-btn:active{transform:translateY(1px);}

/* The standalone print button moved into the nav's icon bar at T1. Its selector went with it
   and its body did not — the same orphan defect as above, and this one ate
   `.linecard[data-loading="true"] .supplier`, so the loading state dimmed nothing. */

/* loading state: the grid can show skeletons before data paints, and is announced politely */
.linecard[data-loading="true"] .supplier{opacity:.35;pointer-events:none;}
.linecard[data-loading="true"]{cursor:progress;}

/* no plate: all 30 product shots are keyed transparent, so they sit directly on the field.
   The shot LEADS the tile: it bleeds to the card's edges instead of sitting inside the padding,
   and it sizes off the CARD (cqi) rather than the viewport, so it stays proportionate in the
   261px 4-column tile and the 356px 2-column one alike — convention 5.
   The cap is still what stops a wider tile growing a taller hero; without it adding columns
   buys no density because each card grows to cancel it. It is just a higher cap now. */
/* the mark needs more air beneath it than the card's uniform gap gives */
.supplier__logobox + .supplier__shot{margin-top:var(--sp-4);}
.supplier__shot{
  /* still edge-to-edge left and right, but NOT to the top: the mark is above it now, so a
     top bleed would run the photo under the logo. */
  width:calc(100% + var(--lc-pad) * 2);
  margin:0 calc(var(--lc-pad) * -1);
  aspect-ratio:4/3;
  height:clamp(200px, 86cqi, 280px);   /* larger again: the shot is the card's subject */
  position:relative;background:none;overflow:hidden;
}
/* The shot is a STACK of frames, not one image. Every frame occupies the same box; exactly one
   carries .is-on and is opaque, and the rest sit at zero. Advancing the carousel is therefore a
   cross-fade between two stacked images rather than a src swap, which would flash.
   A supplier with only one frame gets this identical rule set and simply never changes frame —
   there is no second code path for the 21 cards that have no alternate view. */
.supplier__frame{
  position:absolute;inset:var(--sp-2);
  width:calc(100% - var(--sp-2) * 2);height:calc(100% - var(--sp-2) * 2);
  object-fit:contain;object-position:center;
  opacity:0;
  transition:opacity var(--dur-card) var(--ease-card),transform var(--dur-card) var(--ease-card);
}
/* .is-on is emitted on frame 0 by the build, so the stack renders correctly with JS off. */
.supplier__frame.is-on{opacity:1;}
.supplier:hover .supplier__frame{transform:scale(1.05);}
@media (prefers-reduced-motion:reduce){
  /* the scale is movement and goes; the cross-fade stays, but the carousel never starts —
     linecard.js checks the same media query before it sets an interval. */
  .supplier:hover .supplier__frame{transform:none;}
}

/* =============================================================================
   COMPONENT: definition rows (contact, sitemap)
   ========================================================================== */
.rows{display:grid;gap:var(--sp-5);margin:0;}
.row{display:flex;gap:var(--sp-4);align-items:flex-start;color:var(--c-ink-dim);line-height:1.5;
  transition:color var(--dur-fast);}
a.row:hover,a.row:focus-visible{color:var(--c-primary-strong);}
.row__ico{
  flex:none;width:28px;height:28px;display:grid;place-items:center;border-radius:50%;
  border:1px solid var(--c-line);color:var(--c-primary-strong);font-size:var(--fs-3);
}
.row__label{display:block;font-size:var(--fs-1);letter-spacing:.14em;text-transform:uppercase;
  color:var(--c-ink-faint);margin-bottom:2px;}

/* sitemap tree */
.tree{list-style:none;margin:0;padding:0;display:grid;gap:var(--sp-3);}
.tree ul{list-style:none;margin:var(--sp-3) 0 0;padding-left:var(--sp-6);display:grid;gap:var(--sp-3);
  border-left:1px solid var(--c-line);}
/* inline-block + a padded box, so the target is the 24px WCAG 2.2 SC 2.5.8 minimum rather than
   the 22px the line-height alone produced. These are a navigation list, not links inside a
   sentence, so the SC's inline exception does not cover them. */
.tree a{display:inline-block;min-height:24px;padding-block:1px;
        color:var(--c-ink-dim);border-bottom:1px solid transparent;transition:color var(--dur-fast),border-color var(--dur-fast);}
.tree a:hover,.tree a:focus-visible{color:var(--c-primary-strong);border-bottom-color:var(--c-primary);}
.tree .u{font-size:var(--fs-1);color:var(--c-ink-faint);letter-spacing:.04em;}

/* two-column split */
.split{display:grid;gap:var(--sp-8);}
@media (min-width:900px){.split{grid-template-columns:1fr 1fr;gap:var(--sp-9);}}

/* =============================================================================
   SECTION TYPE: convert-proof-team-slide (.tsl)
   The face is the only element that gets scale here; everything else is quiet, because the
   claim being made is "a person answers" and a person is the evidence.
   /design reactivity scores the ten css states on a FLOOR, not an average — so rest, hover,
   focus-visible, active, disabled and the two data-states below are each authored, and the
   component is only as good as the state it forgot.
   ============================================================================= */
/* the section is emitted OUTSIDE the page wrapper, so it carries the page inset itself —
   without this it ran full-bleed to x=0 while every other block sat on the gutter */
.tsl{padding:var(--sp-9) var(--page-inset) var(--sp-8);max-width:var(--page-max);margin-inline:auto;}
.tsl__title{margin:var(--sp-2) 0 0;font-size:clamp(1.6rem,.9rem + 1.7vw,2.4rem);
  line-height:1.08;letter-spacing:-.025em;font-weight:700;max-width:20ch;text-wrap:balance;}
.tsl__lede{margin:var(--sp-3) 0 0;max-width:52ch;}
.tsl__grid{display:grid;gap:var(--sp-5);margin-top:var(--sp-7);
  grid-template-columns:repeat(auto-fit,minmax(min(240px,100%),1fr));}
/* auto-fill with a max, not auto-fit: a two-person team must not stretch two cards across a
   1720px row, and must not leave the row looking truncated either. The cap holds the card at a
   portrait's natural size and the row simply ends. */
@media (min-width:900px){ .tsl__grid{grid-template-columns:repeat(auto-fill,minmax(260px,300px));} }

.tsl__card{
  position:relative;display:flex;flex-direction:column;min-width:0;
  background:var(--c-tile);border-radius:var(--radius-md);overflow:hidden;
  transition:transform var(--dur-med) var(--ease-out),box-shadow var(--dur-med) var(--ease-out),
             background var(--dur-fast);
}
.tsl__card[data-on],.tsl__card:hover{
  background:var(--c-tile-hi);transform:translateY(-4px);
  box-shadow:0 22px 44px -22px rgba(0,0,0,.9);
}
.tsl__card:focus-visible{outline:2px solid var(--c-primary-strong);outline-offset:3px;}
.tsl__card:active{transform:translateY(-1px);}

/* the two stills are stacked, not swapped in the src — a src swap flashes white on first hover */
.tsl__face{position:relative;aspect-ratio:1;background:#97948f;overflow:hidden;}
.tsl__still{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;
  transition:opacity var(--dur-med) var(--ease-out),transform 1.2s var(--ease-out);}
.tsl__still--hover{opacity:0;}
.tsl__card[data-on] .tsl__still--rest{opacity:0;}
.tsl__card[data-on] .tsl__still--hover{opacity:1;transform:scale(1.03);}
[data-tsl-reduce] .tsl__still{transition:none;}
[data-tsl-reduce] .tsl__card[data-on] .tsl__still--hover{transform:none;}

/* the voice meter — present only when the member carries a clip */
.tsl__vo{position:absolute;left:var(--sp-3);bottom:var(--sp-3);z-index:2;
  display:inline-flex;align-items:center;gap:5px;height:26px;padding:0 10px;
  border-radius:var(--radius-full);background:rgba(11,11,13,.72);backdrop-filter:blur(6px);
  color:var(--c-primary-strong);font-size:var(--fs-1);font-weight:700;}
.tsl__vo i{width:2px;height:8px;border-radius:1px;background:currentColor;opacity:.55;}
.tsl__card[data-playing] .tsl__vo i{animation:tsl-vo .9s var(--ease-out) infinite;opacity:1;}
.tsl__card[data-playing] .tsl__vo i:nth-child(2){animation-delay:.15s;}
.tsl__card[data-playing] .tsl__vo i:nth-child(3){animation-delay:.3s;}
@keyframes tsl-vo{0%,100%{height:6px}50%{height:15px}}
.tsl__card[data-playing] .tsl__vo-txt{color:var(--c-primary-strong);}
[data-tsl-reduce] .tsl__vo i{animation:none!important;}
/* the autoplay refusal, stated on the surface rather than swallowed */
[data-tsl-locked] .tsl__vo-txt::after{content:" — tap once";font-weight:400;opacity:.8;}

.tsl__body{padding:var(--sp-4);display:flex;flex-direction:column;gap:2px;}
.tsl__name{margin:0;font-size:var(--fs-3);font-weight:700;letter-spacing:-.01em;}
.tsl__role{margin:0 0 var(--sp-3);font-size:var(--fs-1);color:var(--c-ink-dim);}
.tsl__ctas{display:flex;flex-wrap:wrap;gap:var(--sp-2);}
.tsl__cta{
  display:inline-flex;align-items:center;gap:6px;min-height:36px;padding:0 var(--sp-3);
  border:1px solid var(--c-line);border-radius:var(--radius-full);
  color:var(--c-ink);font-size:var(--fs-1);font-weight:600;text-decoration:none;
  transition:border-color var(--dur-fast),color var(--dur-fast),background var(--dur-fast);
}
.tsl__cta svg{width:14px;height:14px;flex:none;}
.tsl__cta:hover{border-color:var(--c-primary);color:var(--c-primary-strong);background:rgba(83,148,53,.1);}
.tsl__cta:focus-visible{outline:2px solid var(--c-primary-strong);outline-offset:2px;}
/* the number is the primary act of this block, so it carries the primary treatment — filled, not
   outlined — and the SAME breathing + sheen loop the Request Inventory button uses. The keyframes
   are reused, not restated: two copies of one motion drift apart on the first edit. */
.tsl__cta--call{
  border-color:transparent;color:var(--c-primary-ink);font-weight:700;
  background:linear-gradient(180deg,var(--c-primary-strong),var(--c-primary));
  position:relative;overflow:hidden;
  animation:ivf-breathe 3.4s cubic-bezier(.4,0,.2,1) infinite;
  transition:transform var(--dur-med),filter var(--dur-med),box-shadow var(--dur-med);
}
.tsl__cta--call::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(105deg,transparent 28%,rgba(255,255,255,.28) 50%,transparent 72%);
  transform:translateX(-130%);
  animation:ivf-sheen 3.4s cubic-bezier(.4,0,.2,1) infinite;
}
.tsl__cta--call svg{color:var(--c-primary-ink);}
.tsl__cta--call:hover{background:linear-gradient(180deg,var(--c-primary-strong),var(--c-primary));
  color:var(--c-primary-ink);transform:translateY(-1px);filter:brightness(1.06);}
.tsl__cta--call:active{transform:translateY(0) scale(.985);filter:brightness(.96);}
.tsl__cta--call:focus-visible{outline:2px solid var(--c-ink);outline-offset:3px;}
@media (prefers-reduced-motion:reduce){
  .tsl__cta--call{animation:none;}
  .tsl__cta--call::after{animation:none;opacity:0;}
}
.tsl__more{
  align-self:flex-start;margin-top:var(--sp-3);padding:0;
  background:none;border:0;border-bottom:1px solid var(--c-line);
  color:var(--c-ink-dim);font:inherit;font-size:var(--fs-1);cursor:pointer;
  transition:color var(--dur-fast),border-color var(--dur-fast);
}
.tsl__more:hover{color:var(--c-primary-strong);border-color:var(--c-primary);}
.tsl__more:focus-visible{outline:2px solid var(--c-primary-strong);outline-offset:3px;}

/* the profile — in the served HTML, so the credibility marks are crawlable and survive JS off */
.tsl__profile{position:relative;margin-top:var(--sp-6);padding:var(--sp-6);
  background:var(--c-tile);border-radius:var(--radius-md);}
.tsl__profile[hidden]{display:none;}
.tsl__x{position:absolute;top:var(--sp-3);right:var(--sp-3);width:36px;height:36px;
  border-radius:50%;border:1px solid var(--c-line);background:none;color:var(--c-ink);
  font-size:1.1rem;line-height:1;cursor:pointer;}
.tsl__x:hover{border-color:var(--c-primary);color:var(--c-primary-strong);}
.tsl__profile-head{display:flex;align-items:center;gap:var(--sp-4);}
.tsl__profile-head img{width:72px;height:72px;border-radius:50%;object-fit:cover;flex:none;}
.tsl__bio{margin:var(--sp-4) 0 0;max-width:62ch;color:var(--c-ink-dim);}
.tsl__h{margin:var(--sp-6) 0 var(--sp-3);font-size:var(--fs-1);letter-spacing:.1em;
  text-transform:uppercase;color:var(--c-ink-faint);font-weight:700;}
.tsl__exp{list-style:none;margin:0;padding:0;display:grid;gap:var(--sp-3);}
.tsl__exp li{display:flex;align-items:center;gap:var(--sp-3);}
/* the third-party mark is the credibility transfer — it gets a plate so it reads as a real logo */
.tsl__exp img{width:64px;height:34px;object-fit:contain;flex:none;
  background:var(--c-plate);border-radius:var(--radius-sm);padding:4px 6px;}
.tsl__exp-mark{width:64px;height:34px;flex:none;border-radius:var(--radius-sm);
  border:1px dashed var(--c-line);}
.tsl__exp i{display:block;font-style:normal;font-size:var(--fs-1);color:var(--c-ink-faint);}
.tsl__folio{display:grid;gap:var(--sp-3);grid-template-columns:repeat(auto-fit,minmax(180px,1fr));}
.tsl__folio figure{margin:0;}
.tsl__folio img{width:100%;height:auto;border-radius:var(--radius-sm);display:block;}
.tsl__folio figcaption{margin-top:6px;font-size:var(--fs-1);color:var(--c-ink-faint);}

/* ---------- the slot variant: the sidebar container that changes the human ----------
   The track holds every member side by side and slides; nothing is fetched or src-swapped on
   advance, so the transition cannot flash and JS-off still shows the first person. */
.tsl--slot{padding:0;margin:0;max-width:none;overflow:hidden;
  background:var(--c-tile);border-radius:var(--radius-md);}
.tsl__slot-eyebrow{margin:0;padding:var(--sp-3) var(--sp-3) 0;}
.tsl__track{display:flex;width:100%;
  transition:transform .6s cubic-bezier(.4,0,.2,1);will-change:transform;}
[data-tsl-reduce] .tsl__track{transition:none;}
.tsl__card--slot{flex:0 0 100%;min-width:0;background:none;border-radius:0;transform:none!important;
  box-shadow:none!important;}
.tsl__card--slot .tsl__face{aspect-ratio:4/3;}
.tsl__card--slot .tsl__body{padding:var(--sp-3);}
.tsl__card--slot .tsl__name{font-size:var(--fs-2);}
.tsl__card--slot .tsl__role{margin-bottom:var(--sp-2);}
.tsl__card--slot .tsl__cta{min-height:32px;padding:0 var(--sp-2);font-size:var(--fs-1);}
.tsl__card--slot .tsl__vo{left:var(--sp-2);bottom:var(--sp-2);height:22px;padding:0 8px;}
.tsl__card--slot .tsl__body{padding:var(--sp-3) var(--sp-3) var(--sp-2);}

/* ---------- the icon bar: search · print · download ----------
   Three boxes, three icons, one row. The label lives in .u-sr and in title=, so the control is
   named for assistive tech and on hover without spending width on it. */
/* ---------- the action bar: ONE container, ONE radius ----------
   The radius belongs to the bar and to nothing inside it. overflow:hidden makes the container
   the only thing that can round a corner, so a hovered end cell is clipped by the bar rather
   than carrying a matching radius of its own — no item can drift out of agreement with the
   container, because no item has a corner to get wrong. */
.lctools{position:relative;display:grid;gap:var(--sp-2);}
.lctools__bar{
  display:grid;grid-template-columns:repeat(3,1fr);   /* 1fr x3 — every cell the same width */
  background:var(--c-tile);border:1px solid var(--c-line);
  border-radius:var(--radius-sm);overflow:hidden;
}
.lctools__bar > *{min-width:0;border-radius:0;}
.lctools .dl{display:grid;border-radius:0;}
.lctools__btn{
  display:grid;place-items:center;width:100%;min-height:40px;padding:0;
  background:none;border:0;border-radius:0;
  color:var(--c-ink-dim);cursor:pointer;
  transition:color var(--dur-fast),background var(--dur-fast);
}
/* declared AFTER the border reset, or the reset wins on equal specificity and the second cell
   silently loses its divider. Inset shadow, not border: a border takes a pixel out of the cell's
   content box and the third icon measured 73 against 74. */
.lctools__bar > * + * > .lctools__btn,
.lctools__bar > .lctools__btn + .lctools__btn{box-shadow:inset 1px 0 0 var(--c-line);}
.lctools__btn svg{width:17px;height:17px;}
.lctools__btn:hover{color:var(--c-primary-strong);background:var(--c-tile-hi);}
.lctools__btn:focus-visible{outline:2px solid var(--c-primary-strong);outline-offset:-2px;}
.lctools__btn:active{background:rgba(83,148,53,.16);}
.lctools__btn[aria-expanded="true"]{color:var(--c-primary-strong);background:var(--c-tile-hi);}
.lctools .lc-search--panel[hidden]{display:none;}
/* anchored to .lctools, so it escapes the bar's clip */
.lctools > .dl__menu{position:absolute;top:44px;right:0;left:auto;bottom:auto;z-index:70;}

/* ---------- the slot, laid out to the reference ----------
   Map on top, place, invitation, faces, who, the number. Values are taken from the screenshot
   rather than from the token ladder where the two disagree, because the reference IS the spec. */
.tsl__map{display:block;overflow:hidden;}
.tsl__map img{display:block;width:100%;height:104px;object-fit:cover;
  filter:grayscale(1) contrast(.92) brightness(.85);
  transition:filter var(--dur-med) var(--ease-out),transform var(--dur-med) var(--ease-out);}
.tsl__map:hover img{filter:grayscale(1) contrast(1) brightness(1);transform:scale(1.04);}
.tsl__map:focus-visible{outline:2px solid var(--c-primary-strong);outline-offset:-2px;}

.tsl--slot .tsl__body{padding:16px;display:block;}
.tsl__place-label{margin:0;font-size:10.5px;font-weight:700;letter-spacing:.12em;
  text-transform:uppercase;color:var(--c-primary-strong);}
.tsl__invite{margin:10px 0 0;padding:0;font-size:19px;line-height:1.2;font-weight:700;
  letter-spacing:-.02em;color:var(--c-ink);text-wrap:balance;}

.tsl__avatars{display:flex;flex-wrap:wrap;gap:10px;padding:0;margin:14px 0 0;border:0;}
.tsl__av{
  width:46px;height:46px;padding:0;flex:none;cursor:pointer;
  border-radius:50%;border:2px solid transparent;background:none;opacity:.5;
  transition:border-color var(--dur-fast),transform var(--dur-fast),opacity var(--dur-fast);
}
.tsl__av img{width:100%;height:100%;border-radius:50%;object-fit:cover;display:block;
  background:var(--c-plate);}
.tsl__av:hover{opacity:.8;transform:translateY(-1px);}
.tsl__av[aria-selected="true"]{opacity:1;border-color:var(--c-primary-strong);}
.tsl__av:focus-visible{outline:2px solid var(--c-primary-strong);outline-offset:2px;}
.tsl__av:active{transform:translateY(0) scale(.96);}

.tsl__now{padding:0;margin:14px 0 0;}
.tsl--slot .tsl__name{margin:0;font-size:15px;font-weight:700;letter-spacing:-.01em;}
.tsl--slot .tsl__role{margin:2px 0 0;font-size:12px;color:var(--c-ink-dim);}

/* full-width pills, stacked. The reference shows one; a second action takes the same shape below
   it rather than halving the first, so the number never shrinks when an action is added. */
.tsl--slot .tsl__actions{display:grid;gap:8px;padding:0;margin:16px 0 0;}
.tsl--slot .tsl__cta{width:100%;justify-content:center;min-height:42px;
  border-radius:var(--radius-full);font-size:13px;}

.tsl__av{
  width:44px;height:44px;padding:0;flex:none;cursor:pointer;
  border-radius:50%;border:2px solid transparent;background:none;
  transition:border-color var(--dur-fast),transform var(--dur-fast),opacity var(--dur-fast);
  opacity:.55;
}
.tsl__av img{width:100%;height:100%;border-radius:50%;object-fit:cover;display:block;
  background:var(--c-plate);}
.tsl__av:hover{opacity:.85;transform:translateY(-1px);}
.tsl__av[aria-selected="true"]{opacity:1;border-color:var(--c-primary-strong);}
.tsl__av:focus-visible{outline:2px solid var(--c-primary-strong);outline-offset:2px;}
.tsl__av:active{transform:translateY(0) scale(.96);}

/* the container WITHIN the container — the profile gets its own frame inside the slot */
.tsl__slotbox{margin:0 var(--sp-3);border-radius:var(--radius-sm);overflow:hidden;
  background:var(--c-bg);}

/* ONE action row for the whole carousel, re-pointed at the active slide. Its position never
   moves between people, so the control does not have to be re-found on every change. */
.tsl__actions{display:flex;flex-wrap:wrap;gap:var(--sp-2);padding:var(--sp-3);}
.tsl__actions .tsl__cta{flex:1 1 auto;justify-content:center;min-height:36px;}
.tsl__actions .tsl__cta[hidden]{display:none;}

/* the place and the number that reaches it */
.tsl__loc{display:grid;gap:var(--sp-4);margin-top:var(--sp-7);align-items:center;}
@media (min-width:700px){ .tsl__loc{grid-template-columns:240px 1fr;} }
.tsl__loc-map{display:block;overflow:hidden;border-radius:var(--radius-md);}
.tsl__loc-map img{width:100%;height:auto;display:block;filter:grayscale(1) contrast(.9) brightness(.85);
  transition:filter var(--dur-med) var(--ease-out),transform var(--dur-med) var(--ease-out);}
.tsl__loc-map:hover img{filter:none;transform:scale(1.03);}
.tsl__loc-map:focus-visible{outline:2px solid var(--c-primary-strong);outline-offset:3px;}
.tsl__loc address{font-style:normal;margin:var(--sp-2) 0 var(--sp-3);color:var(--c-ink-dim);
  line-height:1.5;}
.tsl__loc-tel{display:inline-flex;align-items:center;gap:var(--sp-2);
  font-size:var(--fs-4);font-weight:700;color:var(--c-primary-strong);text-decoration:none;
  letter-spacing:-.01em;}
.tsl__loc-tel svg{width:18px;height:18px;flex:none;}
.tsl__loc-tel:hover{text-decoration:underline;text-underline-offset:4px;}
.tsl__loc-tel:focus-visible{outline:2px solid var(--c-primary-strong);outline-offset:3px;}

/* ---------- the quote popup ----------
   It began as a 680x760 box inside the homepage's own stylesheet, then became a 960x880 panel.
   Both were still a WIDGET sitting on a page. It is the page now: the overlay is the viewport,
   the iframe fills it edge to edge, and there is no frame, no radius, no shadow and no scrim
   blur left to render — the form's own field is the background.
   The single piece of chrome is the close control, which floats over the surface at the same
   position and size the marketplace funnel puts its own. */
.qmodal{
  position:fixed;inset:0;z-index:200;
  background:var(--c-bg);
  animation:qmodal-in .22s var(--ease-out) both;
}
.qmodal[hidden]{display:none;}
@keyframes qmodal-in{from{opacity:0}to{opacity:1}}
/* dvh over vh: on iOS vh counts the space behind the URL bar, which would push the
   form's primary control off the bottom of the screen it is measured against. */
.qmodal__box{position:absolute;inset:0;height:100dvh;overflow:hidden;}
.qmodal__box iframe{width:100%;height:100%;border:0;display:block;}
/* The iframe carries its OWN close button (form.html), which is the one a visitor
   inside the form reaches. This one is the host's escape hatch and sits above it,
   so the two must not collide — the frame's own sits at 20px, this at 20px too, and
   only ONE of them is rendered: the host's is hidden once the frame reports ready.
   Until then it is the only way out if the frame fails to load at all. */
.qmodal__close{
  position:absolute;top:20px;right:20px;z-index:2;
  width:44px;height:44px;border-radius:50%;display:grid;place-items:center;
  border:1px solid var(--c-line);background:rgba(244,244,244,.04);
  color:var(--c-ink);font-size:1.25rem;line-height:1;cursor:pointer;
  transition:background var(--dur-fast),transform var(--dur-fast);
}
.qmodal__close:hover{background:rgba(244,244,244,.1);transform:rotate(90deg);}
.qmodal__close:focus-visible{outline:none;box-shadow:0 0 0 3px rgba(124,198,83,.5);}
.qmodal[data-frame-ready] .qmodal__close{display:none;}
@media (prefers-reduced-motion:reduce){ .qmodal{animation:none;} .qmodal__close:hover{transform:none;} }

/* ---------- footer ---------- */
.site-foot{
  margin-top:var(--sp-9);
  padding:var(--sp-9) var(--page-inset) 0;
  border-top:0;
  /* eleven stops rather than five: the old ramp banded visibly across the first third, where
     the steps between #0b0b0d, #0e1d0a and #14290d are large enough to read as edges. */
  /* Two layers, and the split is the whole point: the gradient is SIZED to stop exactly one
     viewport short of the footer's bottom, and the solid --c-foot-b sits under it. So the
     fully-saturated green the reader lands on at the page bottom is exactly 100vh — not a
     gradient that happens to look finished. */
  background:
    linear-gradient(180deg,
      var(--c-bg) 0%, #0c0f0b 6%, #0d140a 12%, #0f1c0a 19%,
      var(--c-foot-a) 26%, #12240c 34%, #14290d 42%,
      #17300f 52%, #1a3711 66%, #1c3c12 82%, var(--c-foot-b) 100%)
      top left / 100% calc(100% - 30svh) no-repeat,
    var(--c-foot-b);
  position:relative;
}
/* the coordinate rows sit closer together */
/* the drone film as GROUND. z-index 0 puts it under every child of .site-foot, and the gradient
   background already painted on .site-foot sits on top of it — which is what keeps the coordinates
   readable over moving footage instead of hoping the frames stay dark. */
.site-foot > *{position:relative;z-index:1;}
.site-foot__film{
  position:absolute;inset:0;z-index:0;
  width:100%;height:100%;object-fit:cover;
  opacity:.14;pointer-events:none;
  filter:grayscale(.35) contrast(1.05);
  mask-image:linear-gradient(180deg,#000 0%,#000 55%,transparent 92%);
  -webkit-mask-image:linear-gradient(180deg,#000 0%,#000 55%,transparent 92%);
}
/* the poster still carries the image when motion is refused; the film simply stops */
@media (prefers-reduced-motion:reduce){ .site-foot__film{display:none;} }

.site-foot .rows{gap:var(--sp-3);}

/* ---------- footer CTA, directly under the last coordinate row ---------- */
.foot-cta{display:flex;align-items:center;gap:var(--sp-2);margin-top:var(--sp-5);}
.foot-cta__btn{white-space:nowrap;}

/* the nudge, reused from pcania's NudgeArrow — same path, same bob, DRN's green.
   It loops TOWARD the button (translateX negative would point away here, since the arrow
   sits to the button's LEFT and its head points right). */
.nudge{display:inline-flex;align-items:center;flex:none;color:var(--c-primary-strong);
       animation:nudge-bob 1.6s var(--ease-out) infinite;}
/* the arrow now sits to the RIGHT of the button, so the glyph keeps pcania's own orientation
   (head pointing left) and the bob runs LEFT — toward the control, never away from it. */
.nudge svg{width:4.2rem;height:3.2rem;display:block;overflow:visible;}
@keyframes nudge-bob{
  0%,100%{transform:translateX(0);opacity:.65;}
  50%    {transform:translateX(-.4rem);opacity:1;}
}
@media (prefers-reduced-motion:reduce){ .nudge{animation:none;opacity:1;} }

/* ---------- the signature at the footer's foot ---------- */
/* Uses the page's OWN .rise reveal, so there is one observer on the page and no second
   mechanism to keep in step. Without JS .rise never gets opacity:0, so it is simply visible. */
/* ---------- the immersive band ---------- */
/* Exactly one viewport tall, which is what makes the solid-green region above measure 100vh. */
/* Exactly one viewport tall — that is what makes the solid-green region measure 100vh — and
   it now COMPOSES rather than sitting empty: the watermark rises through it and the legal line
   is seated at its foot, centred. */
/* Exactly one viewport tall — that is what makes the solid-green region measure 100vh.
   A column: the mark's own box takes the space above, the legal line sits beneath it. The
   two were previously both anchored to the band's bottom edge and the copyright printed
   straight over the symbol. */
/* 50svh, halved. This SUPERSEDES the earlier "exactly 100 view height" instruction — the band
   is where the footer's height actually lives, and the content block above it is real content
   that cannot be halved. Revert this one value to restore the full-viewport band. */
.foot-immersive{
  position:relative;height:30svh;
  display:flex;flex-direction:column;
  padding:0 var(--page-inset);
}
/* the mark is clipped by THIS box, so its half-cut edge is a line above the legal, not the
   page's bottom edge */
.foot-markwrap{position:relative;flex:1 1 auto;min-height:0;overflow:hidden;}

/* The symbol is absolutely positioned and pushed down by half its own height, so the band
   clips it and only the TOP HALF is ever visible. Double the previous 200px. A thin
   translucent white rather than a solid one — it is a watermark in the field, not a logo
   sitting on it. */
/* Vector, and painted rather than pictured. drn-symbol-mono.svg is the traced silhouette of the
   mark (VTracer via the /logo pipeline's own tracer); as a mask it takes `color`, so the same one
   file serves a white watermark here and any other tint elsewhere. The 433px raster it replaces
   was resampled 2.65x on a retina screen at this size — the softness was in the source. */
.foot-mark{
  position:absolute;left:50%;bottom:0;
  width:min(575px,92vw);aspect-ratio:2048/1991;   /* +25% */
  color:var(--c-ink);background:currentColor;
  -webkit-mask:url(/assets/brand/drn-symbol-mono.svg) no-repeat center / contain;
          mask:url(/assets/brand/drn-symbol-mono.svg) no-repeat center / contain;
  transform:translate(-50%,62%);
  opacity:.18;
  will-change:transform;
}
/* Scroll-driven where the browser supports it: the mark rises as the band enters the viewport,
   tied to the scroll position itself rather than to a timer, which is what makes it read as
   parallax instead of as an animation that happens to play. */
@supports (animation-timeline: view()) {
  .foot-mark{
    animation:foot-mark-rise linear both;
    animation-timeline:view();
    animation-range:entry 0% cover 40%;
  }
  @keyframes foot-mark-rise{
    from{ transform:translate(-50%,104%); opacity:.05; }
    to  { transform:translate(-50%,62%);  opacity:.22; }
  }
}
@media (prefers-reduced-motion:reduce){
  .foot-mark{animation:none;transform:translate(-50%,62%);opacity:.18;}
}

/* The reveal for the SHARED pages. .rise only existed in the homepage's own inline CSS and
   observer, so on /en/* the mark would simply have been static — the ease-in was asked for on
   every page. Gated on data-rise-js: the class is inert until the script announces itself, so
   with JS off the content is visible rather than stuck at opacity 0. */
[data-rise-js="on"] .rise{opacity:0;transform:translateY(14px);}
[data-rise-js="on"] .rise.is-in{
  opacity:1;transform:none;
  transition:opacity .7s var(--ease-out),transform .7s var(--ease-out);
}
@media (prefers-reduced-motion:reduce){
  [data-rise-js="on"] .rise{opacity:1;transform:none;}
  [data-rise-js="on"] .rise.is-in{transition:none;}
}
/* start, not center: centring measured the short column against the tall one and pushed the ask
   93px below the wordmark, so the two blocks shared no edge. They now begin on the same line. */
.site-foot__in{max-width:var(--page-max);margin-inline:auto;display:grid;gap:var(--sp-8);
  align-items:start;padding-top:32px;}
/* one column: the second held the Request-for-information block, which is gone. A 1fr .9fr
   grid with one child leaves a dead column the reader reads as a missing thing. */
.site-foot__logo{height:clamp(78px,7.2vw,108px);width:auto;object-fit:contain;margin-bottom:var(--sp-5);}  /* +50% */
.site-foot h2{margin:0 0 var(--sp-5);font-size:clamp(1.7rem,.9rem + 1.8vw,2.6rem);
  line-height:1.06;letter-spacing:-.025em;font-weight:700;max-width:18ch;text-wrap:balance;}
.site-foot .lede{font-size:var(--fs-4);max-width:44ch;}
.foot-legal{
  position:relative;z-index:1;flex:none;margin:0;padding:0;
  border-top:0;font-size:var(--fs-1);text-align:center;
  color:rgba(230,243,221,.72);   /* .5 measured 3.76:1 at 11px, below the 4.5 AA floor */
}
