/* ============================================================
   INKSPOT — corrections to the concept
   inkspot.css is GENERATED verbatim from the approved concept and
   will be overwritten whenever the concept is regenerated. Any fix
   to a defect in the concept belongs here, not there.
   Every rule must carry a reason. Keep this file short: if it grows,
   the concept itself needs correcting instead.
   ============================================================ */

/* Sector tiles: the concept declares no colour on .tile h3. It worked while
   the sectors block sat inside the dark "on-ink" section and inherited
   --paper. The current concept promotes sectors to its own "band on-stock",
   so the titles inherit --ink and render black on a near-black tile,
   invisible. Tiles carry their own dark ground, so they must carry their own
   text colour rather than depend on the section they happen to sit in.
   The hover rule that flips text to --ink over the ink wash still wins on
   specificity, so the inversion is unaffected. */
.tile h3{color:var(--paper)}

/* Same reasoning for the step number: --grey-2 reads on dark, but state it
   rather than let it depend on ancestry. */
.tile span{color:var(--grey-2)}


/* ============================================================
   Footer — four columns over a legal bar.
   Not in the concept, which had a single-line footer. Built to
   Diarmuid's direction, 10 August 2026. Groupings come from the
   navigation data so footer and menus cannot diverge.
   ============================================================ */
.ftr{background:var(--ink);color:var(--paper);padding-block:64px 0}
.ftr__grid{
  display:grid;
  grid-template-columns:1.4fr 1fr 1fr 1fr;
  gap:48px 40px;
  align-items:start;
}
.ftr__brand img{display:block;height:36px;width:auto}
.ftr__brand .bar{margin-top:14px;max-width:64px}
.ftr__brand .bar span{height:5px}

.ftr__col{display:flex;flex-direction:column;gap:11px}
.ftr__col h4,.ftr__col .ftr__h{
  margin:0 0 6px;
  font-family:var(--dm-mono);
  font-size:11px;
  font-weight:400;
  letter-spacing:.16em;
  text-transform:uppercase;
  color:var(--grey-2);
}
.ftr__col a{
  color:var(--paper);
  text-decoration:none;
  font-size:15px;
  line-height:1.3;
  transition:opacity .2s;
}
.ftr__col a:hover,
.ftr__col a:focus-visible{opacity:.62}
.ftr__more{
  margin-top:14px;
  font-family:var(--dm-mono);
  font-size:12px;
  letter-spacing:.04em;
  color:var(--grey-2) !important;
  /* Keep the arrow on the same line as the label. Without this the
     column is narrow enough that the arrow wraps onto its own line and
     reads as a stray character. */
  display:inline-flex;
  align-items:baseline;
  gap:8px;
  text-wrap:balance;
}

.ftr__legal{
  display:flex;
  justify-content:space-between;
  align-items:center;
  gap:20px;
  flex-wrap:wrap;
  margin-top:56px;
  padding-block:22px 30px;
  border-top:1px solid rgba(247,245,241,.14);
  font-family:var(--dm-mono);
  font-size:12px;
  letter-spacing:.04em;
  color:var(--grey-2);
}
.ftr__legal-links{display:flex;align-items:center;gap:26px;flex-wrap:wrap}
.ftr__legal a{color:var(--grey-2);text-decoration:none}
.ftr__legal a:hover,
.ftr__legal a:focus-visible{color:var(--paper)}
.ftr__credit{
  display:inline-flex;
  align-items:baseline;
  gap:6px;
  padding-left:26px;
  border-left:1px solid rgba(247,245,241,.14);
}
.ftr__credit a{color:var(--paper) !important}
.ftr__credit a:hover,
.ftr__credit a:focus-visible{color:var(--ink-cyan) !important}

@media (max-width:980px){
  .ftr__grid{grid-template-columns:1fr 1fr;gap:38px 28px}
  .ftr__brand{grid-column:1 / -1}
}
@media (max-width:560px){
  .ftr__grid{grid-template-columns:1fr}
  .ftr__legal{flex-direction:column;align-items:flex-start;gap:14px}
  .ftr__legal-links{gap:18px}
  .ftr__credit{padding-left:0;border-left:none}
}


/* ============================================================
   Trust strip — accreditations and funders.
   Sits on paper above the dark footer. Greyscale by default so the
   marks read as a quiet credential row rather than a badge wall;
   colour returns on hover for anyone looking properly.
   Light ground is deliberate: the EU and LEO marks are boxed
   artwork on white and would reverse out as solid rectangles.
   ============================================================ */
.trust{background:var(--paper-2);border-top:1px solid rgba(22,19,15,.08)}
.trust__in{
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:22px;
  padding-block:34px;
}
.trust__label{
  margin:0;
  color:var(--grey);
  font-size:11px;
  letter-spacing:.16em;
}
.trust__marks{
  display:flex;
  align-items:center;
  gap:44px;
  flex-wrap:wrap;
}
.trust__marks img{
  display:block;
  width:auto;
  filter:grayscale(1);
  opacity:.55;
  transition:filter .3s,opacity .3s;
}
.trust__marks img:hover{filter:grayscale(0);opacity:1}

/* ISO 9001 set in type until the Amtivo mark is supplied. */
.trust__iso{
  display:flex;
  flex-direction:column;
  gap:2px;
  padding:9px 15px;
  border:1px solid rgba(22,19,15,.28);
  border-radius:4px;
  color:var(--grey);
  opacity:.72;
  transition:opacity .3s,color .3s,border-color .3s;
}
.trust__iso:hover{opacity:1;color:var(--ink);border-color:rgba(22,19,15,.5)}
.trust__iso b{
  font-family:var(--dm-display);
  font-size:15px;
  font-weight:700;
  letter-spacing:-.01em;
  line-height:1;
}
.trust__iso i{
  font-family:var(--dm-mono);
  font-style:normal;
  font-size:9px;
  letter-spacing:.11em;
  text-transform:uppercase;
  line-height:1;
}

@media (max-width:780px){
  .trust__in{gap:18px;padding-block:26px}
  .trust__marks{gap:28px}
  .trust__marks img{height:36px !important}
}


/* ============================================================
   Contact section colour bar.
   The four-ink rule ends on a paper blade, which is the point: on a
   dark ground it reads as the negative-space blade of the rosette.
   At the foot of the contact section, though, the cyan, magenta and
   yellow blades sit against near-black and effectively disappear,
   leaving the paper blade alone as a white line across the page.
   Removed here at Diarmuid's direction, 10 August 2026. The section
   already closes on the trust strip and the footer, so it needs no
   rule of its own. The device is untouched in the header, the hero
   and the testimonials, where all four blades read.
   ============================================================ */
.elementor-widget-inkspot_contact .bar--on{
  display:none;
}


/* ============================================================
   Inner page hero and body. Not in the concept, which covered the
   homepage only. Built for the nine solution pages, 10 August 2026.
   ============================================================ */
.phero{
  position:relative;
  display:flex;
  align-items:flex-end;
  min-height:clamp(560px,68vh,840px);
  background:var(--ink);
  overflow:hidden;
}
/* Specificity, not styling. Elementor ships `.elementor img{height:auto}`
   at (0,1,1), which beats a bare `.phero__img` at (0,1,0) — so the hero
   image quietly ignored height:100% and rendered at its own aspect ratio
   instead of covering the section. Wide photographs then came up short
   and left a band of bare --ink under them, which is what "the image is
   not fitting, see black area at base" was.

   Only printing.jpg (2.67:1) was wide enough to show it; the other nine
   heroes are tall enough to cover by accident. Doubling the selector to
   (0,2,0) fixes it for any image at any viewport, rather than waiting
   for the next wide crop to expose it again. Noted 11/08/2026. */
.phero .phero__img{
  position:absolute;inset:0;
  width:100%;
  height:100%;
  min-height:100%;
  object-fit:cover;
}

.phero__img{
  position:absolute;inset:0;
  width:100%;height:100%;
  object-fit:cover;
  /* Top-weighted crop. These photographs are overhead or bench shots and
     the subject sits in the upper half; a centred crop cut the hands off
     and left dead table in frame. */
  object-position:var(--focus,50% 22%);
  filter:grayscale(.35);
}
/* Phones: the hero is close to square, so a 3:1 photograph shows a third
   of its width. --focus-m picks which third; it falls back to --focus. */
@media (max-width:760px){
  .phero__img{object-position:var(--focus-m,var(--focus,50% 22%))}
}
.phero__scrim{
  position:absolute;inset:0;
  /* Two gradients, not one. The vertical band lifts the headline off the
     bottom of the frame; the horizontal one protects the text column on
     the left whatever photograph is dropped in behind it.

     Added 11/08/2026 when the licensed About hero replaced the darker
     preview: the new file is brighter through the middle and the
     standfirst fell to roughly AA-borderline over the machinery. Fixing
     the scrim rather than the image means the next swap is safe too. */
  background:
    linear-gradient(90deg,rgba(22,19,15,.58) 0%,rgba(22,19,15,.30) 44%,rgba(22,19,15,0) 74%),
    linear-gradient(180deg,rgba(22,19,15,.20) 0%,rgba(22,19,15,.40) 52%,rgba(22,19,15,.88) 100%);
}
.phero__in{
  position:relative;z-index:2;
  width:100%;
  padding-block:64px 52px;
  color:var(--paper);
}
.phero__in .spec{margin:0 0 14px;color:var(--ink-cyan)}
/* Display headings used to carry a hard <br> to force two lines. That only
   holds at one width: once the first line wraps on its own, the forced break
   lands mid-phrase and the heading reads as three ragged lines with a widow.
   The breaks are out of the copy now, so the browser splits them evenly at
   whatever width it is given. Applied to the display sizes only — balance is
   for headings, not body copy. */
.h1,.h2,.h3{text-wrap:balance}

.phero__in .h1{
  margin:0;
  max-width:18ch;
}
.phero__lede{
  margin:20px 0 0;
  max-width:56ch;
  color:rgba(247,245,241,.82);
}
.phero__bar{position:absolute;bottom:0;left:0;z-index:3}

.pbody .prose{max-width:64ch}
.pbody .prose p{margin:0 0 20px;font-size:17px;line-height:1.62}
.pbody .prose p:last-child{margin-bottom:0}
.pbody .prose p:first-child{
  font-size:19px;
  line-height:1.55;
  color:var(--ink);
}

.pbody--split{
  display:grid;
  grid-template-columns:minmax(0,1.55fr) minmax(210px,.75fr);
  gap:56px;
  align-items:start;
}
.pbody__aside .spec{
  margin:0 0 16px;
  padding-bottom:12px;
  border-bottom:2px solid var(--ink);
  color:var(--ink);
}
.pbody__aside ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:12px}
.pbody__aside li{
  position:relative;
  padding-left:20px;
  font-size:15px;
  line-height:1.42;
  color:var(--grey);
}
.pbody__aside li::before{
  content:"";
  position:absolute;left:0;top:.55em;
  width:8px;height:8px;border-radius:50%;
  background:var(--ink-cyan);
}
.pbody__aside li:nth-child(2)::before{background:var(--ink-magenta)}
.pbody__aside li:nth-child(3)::before{background:var(--ink-yellow)}
.pbody__aside li:nth-child(4)::before{background:var(--ink)}

@media (max-width:820px){
  .pbody--split{grid-template-columns:1fr;gap:38px}
  .phero__in{padding-block:40px 34px}
}


/* ============================================================
   Mega panel — make it reachable.
   The panel sits 16px below the button, and that gap is not part of
   .has, so moving the cursor down towards the panel fired mouseleave
   and closed it before a link could be clicked. An invisible bridge
   across the gap keeps the pointer inside the group.
   The header colour bar also painted over the panel, hence the
   z-index. .hdr is z-index 80, so the panel must clear it.
   ============================================================ */
.mega{z-index:90}
.mega::before{
  content:"";
  position:absolute;
  top:-18px;
  left:0;
  right:0;
  height:18px;
}
.hdr .bar{position:relative;z-index:1}

/* Panel links need a proper hit area: the concept styled the text but
   left the row itself only as tall as the type. */
.mega ul li a{
  display:flex;
  align-items:baseline;
  gap:14px;
  padding:9px 10px;
  margin-inline:-10px;
  border-radius:7px;
  text-decoration:none;
  color:var(--ink);
  transition:background .18s;
}
.mega ul li a:hover,
.mega ul li a:focus-visible{background:rgba(22,19,15,.06)}
.mega ul li a i{
  font-style:normal;
  font-family:var(--dm-mono);
  font-size:12px;
  color:var(--grey-2);
  min-width:20px;
}
.mega__ft a{
  display:inline-flex;
  align-items:center;
  gap:10px;
  padding:8px 10px;
  margin-inline:-10px;
  border-radius:7px;
  text-decoration:none;
  color:var(--ink);
  transition:background .18s;
}
.mega__ft a:hover,
.mega__ft a:focus-visible{background:rgba(22,19,15,.06)}


/* ============================================================
   Process chain steps as links.
   Each step now goes to its solution page. The arrow is the
   affordance: without it a step looks like a static caption and
   nobody discovers it is clickable.
   ============================================================ */
.step--link{
  display:block;
  position:relative;
  text-decoration:none;
  color:inherit;
  /* Was 26px, reserved for the arrow when it sat in the gutter. The
     arrow is in flow now, so this was only narrowing the copy. */
  padding-right:0;
  transition:transform .22s;
}
.step--link h3{transition:color .22s}
/* The arrow used to be absolutely positioned at right:2px, bottom:2px —
   which put it in the 30px column gutter, hard against the neighbouring
   step's copy, and floating at the bottom of a grid cell whose height is
   set by the tallest step in the row. It read as belonging to the step to
   its right rather than its own.

   It now sits in flow directly under the step's paragraph, left-aligned
   with the text it belongs to, which is the same language .fcard__go
   already uses on the sector cards. Space is reserved whether or not it
   is visible, so hovering never reflows the grid. Fixed 11/08/2026.

   Permanently visible as of 11/08/2026. It used to fade in on hover,
   which meant the affordance only existed for someone who had already
   guessed the step was clickable — and did not exist at all on touch,
   where there is no hover. The arrow is the only thing telling anyone
   these nine steps go somewhere, so it is always on and hover is now
   just emphasis: it travels and picks up cyan. */
.step__go{
  display:block;
  margin-top:16px;
  /* Was the &rarr; glyph at 17px, which is a stubby little arrow because
     the typeface draws it that way — the length is not ours to set. It is
     now the same 40x12 SVG used between pack-shot pairs, so the shaft can
     be as long as the design wants and the whole site draws one arrow.
     Lengthened 11/08/2026. */
  width:46px;
  color:var(--grey-2);
  transform:translateX(0);
  transition:transform .22s,color .22s;
}
.step__go svg{width:100%;height:auto;display:block}
.step--link:hover .step__go,
.step--link:focus-visible .step__go{
  transform:translateX(6px);
  color:var(--ink-cyan);
}
.step--link:hover h3,
.step--link:focus-visible h3{color:var(--ink-cyan)}
.step--link:focus-visible{
  outline:2px solid var(--ink-cyan);
  outline-offset:6px;
  border-radius:4px;
}

/* Touch has no hover, so the arrow must always be visible there. */
@media (hover:none){
  .step__go{transform:none;transition:color .22s}
}


/* ============================================================
   Accreditations block. Marks set typographically: FSC and PEFC
   artwork is trademark-controlled and must be generated through the
   certification body's portal against the holder's own licence code.
   Swap to official artwork when Inkspot supply it.
   ============================================================ */
.accs{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(230px,1fr));
  gap:2px;
  margin-top:48px;
  background:rgba(247,245,241,.14);
  border:1px solid rgba(247,245,241,.14);
}
.acc{
  display:flex;
  flex-direction:column;
  gap:14px;
  padding:28px 24px 24px;
  background:var(--ink);
}
/* The mark plate. Deliberately NOT a reproduction of the FSC tree, the
   PEFC trees or the NSAI eye — those are trademarks, issued as artwork by
   each scheme against the holder's own licence code. A traced copy would
   have to be thrown away the moment the real files arrive, and worse, it
   would read as a live claim if a preview ever reached the client.
   So the plate is typographic and visibly provisional until artwork lands
   in the repeater's Official mark artwork slot, at which point
   .acc__plate--real takes over and the dashed rule disappears. */
.acc__plate{
  display:flex;
  align-items:center;
  justify-content:center;
  flex-direction:column;
  gap:8px;
  aspect-ratio:1/1;
  width:100%;
  max-width:148px;
  padding:14px;
  text-align:center;
}
.acc__plate--hold{
  border:1px dashed rgba(247,245,241,.34);
  background:rgba(247,245,241,.04);
}
.acc__plate--hold .acc__plate-name{
  font-family:var(--dm-display);
  font-size:26px;
  font-weight:700;
  letter-spacing:-.02em;
  line-height:1;
  color:rgba(247,245,241,.5);
}
.acc__plate--hold .acc__plate-note{
  font-family:var(--dm-mono);
  font-size:9px;
  letter-spacing:.1em;
  text-transform:uppercase;
  line-height:1.5;
  color:rgba(247,245,241,.42);
}
.acc__plate--real{border:1px solid rgba(247,245,241,.14);background:var(--paper)}
.acc__plate--real img{width:100%;height:100%;object-fit:contain;display:block}

.acc__mark{display:flex;flex-direction:column;gap:6px}
.acc__mark b{
  font-family:var(--dm-display);
  font-size:23px;
  font-weight:700;
  letter-spacing:-.02em;
  line-height:1;
  color:var(--paper);
}
.acc__mark i{
  font-style:normal;
  font-size:13px;
  line-height:1.35;
  color:var(--grey-2);
}
.acc p{
  margin:0;
  font-size:14px;
  line-height:1.55;
  color:rgba(247,245,241,.72);
}
.acc__foot{
  margin-top:auto;
  padding-top:16px;
  border-top:1px solid rgba(247,245,241,.14);
  display:flex;
  flex-direction:column;
  gap:6px;
}
.acc__no{
  font-family:var(--dm-mono);
  font-size:12px;
  letter-spacing:.06em;
  color:var(--paper);
}
/* Deliberately conspicuous. An unverified certification claim is not a
   typo, it is a misrepresentation, and it should look wrong until fixed. */
.acc__status{
  align-self:flex-start;
  font-family:var(--dm-mono);
  font-size:10px;
  letter-spacing:.1em;
  text-transform:uppercase;
  padding:4px 8px;
  border-radius:3px;
  color:var(--ink);
  background:var(--ink-yellow);
}

@media (max-width:560px){
  .accs{grid-template-columns:1fr}
}

/* ============================================================
   Contact page: location strip, social, captcha. Not in the concept.
   Layout follows designminds.ie/contact: full-bleed row, grey map in
   one half, address on a dark panel in the other, no gutters.
   ============================================================ */
.locate{
  display:grid;
  grid-template-columns:1fr 1fr;
  min-height:440px;
  background:var(--ink);
}
.locate__map{
  position:relative;
  background:var(--paper-2);
  overflow:hidden;
}
.locate__map iframe{
  display:block;
  width:100%;
  height:100%;
  border:0;
  /* Desaturated to match the rest of the site. designminds.ie does the
     same with saturation -100 on the Maps JavaScript API; a filter gets
     there without a billed API key or a third-party script. */
  filter:grayscale(1) contrast(1.04);
}
.map__gate{
  position:absolute;inset:0;
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:18px;
  padding:28px;
  text-align:center;
}
.map__gate p{
  margin:0;
  max-width:40ch;
  font-size:14px;
  line-height:1.55;
  color:var(--grey);
}

.locate__panel{
  display:flex;
  align-items:center;
  background:var(--ink);
  color:var(--paper);
}
.locate__inner{
  padding:clamp(34px,5vw,64px);
  max-width:44ch;
}
.locate__inner .spec{margin:0 0 16px;color:var(--grey-2)}
.locate__inner address{
  font-style:normal;
  font-family:var(--dm-display);
  font-size:clamp(21px,2.2vw,27px);
  font-weight:700;
  line-height:1.3;
  letter-spacing:-.02em;
  color:var(--paper);
}
.locate__contact{
  display:flex;
  flex-direction:column;
  gap:6px;
  margin-top:22px;
}
.locate__contact a{
  color:rgba(247,245,241,.82);
  text-decoration:none;
  font-size:16px;
}
.locate__contact a:hover,
.locate__contact a:focus-visible{color:var(--paper)}
.locate__link{margin-top:28px}

@media (max-width:820px){
  .locate{grid-template-columns:1fr;min-height:0}
  .locate__map{aspect-ratio:4/3}
}

.social__list{
  list-style:none;
  margin:14px 0 0;
  padding:0;
  display:flex;
  gap:12px;
}
.social__list a{
  display:grid;
  place-items:center;
  width:44px;
  height:44px;
  border:1px solid rgba(22,19,15,.22);
  border-radius:50%;
  color:var(--ink);
  transition:background .2s,color .2s,border-color .2s;
}
.social__list a:hover,
.social__list a:focus-visible{
  background:var(--ink);
  border-color:var(--ink);
  color:var(--paper);
}
.on-ink .social__list a{border-color:rgba(247,245,241,.28);color:var(--paper)}
.on-ink .social__list a:hover,
.on-ink .social__list a:focus-visible{background:var(--paper);color:var(--ink)}


@media (max-width:760px){
  .map{grid-template-columns:1fr;gap:28px}
  .map__frame{aspect-ratio:4/3}
}


/* ============================================================
   Form spam protection.
   Honeypot is positioned off-screen rather than display:none. Some bots
   skip hidden fields; almost none skip a field that is merely off-canvas.
   aria-hidden and tabindex -1 keep it away from screen readers and the
   keyboard, so nobody real ever meets it.
   ============================================================ */
.form__hp{
  position:absolute;
  left:-9999px;
  width:1px;
  height:1px;
  overflow:hidden;
}

/* reCAPTCHA v3 is invisible, so the badge is hidden and replaced with the
   attribution line Google's terms require. */
.grecaptcha-badge{visibility:hidden}
.form__legal{
  margin:16px 0 0;
  font-size:11px;
  line-height:1.5;
  color:var(--grey-2);
}
.form__legal a{color:inherit;text-decoration:underline}
.form__legal a:hover,
.form__legal a:focus-visible{color:var(--paper)}


/* ============================================================
   Contact form: outcome and error states. Not in the concept,
   because the concept's form did not submit anywhere.

   The form sits on the dark band, so these are tuned for --ink-2
   rather than paper. Magenta carries the errors: it is already a
   brand ink, so nothing foreign is introduced, and it clears AA
   against the panel. Red would have been a fifth colour.
   ============================================================ */

.form__alert{
  grid-column:1/-1;
  border-left:3px solid var(--ink-magenta);
  background:rgba(236,0,140,.10);
  border-radius:9px;
  padding:16px 18px;
  margin-bottom:4px;
}
.form__alert:focus-visible,
.form__done:focus-visible{outline:2px solid var(--ink-cyan);outline-offset:4px}
.form__alert p{margin:0;font-size:15.5px;color:var(--paper)}
.form__alert ul{margin:10px 0 0;padding-left:18px;font-size:15px}
.form__alert li+li{margin-top:5px}
.form__alert a{color:var(--paper);text-decoration:underline;text-underline-offset:3px}

.form__err{
  margin:0;
  font-family:var(--dm-mono);
  font-size:12.5px;
  letter-spacing:.04em;
  color:#ff7ac4;
}
.f--bad input,
.f--bad select,
.f--bad textarea{border-color:var(--ink-magenta)}

/* Success replaces the form rather than sitting above it. Nobody
   needs to look at empty fields they have just emptied. */
.form__done{
  display:block;
  align-content:center;
  background:var(--ink-2);
  border:1px solid var(--ink-3);
  border-radius:14px;
  padding:clamp(28px,4vw,44px);
}
.form__done-h{
  font-family:var(--dm-display);
  font-weight:800;
  font-stretch:104%;
  letter-spacing:-.025em;
  font-size:clamp(26px,3vw,36px);
  line-height:1.1;
  margin:14px 0 16px;
  color:var(--paper);
}
.form__done p{color:var(--grey-2);max-width:38ch}
.form__done .btn{margin-top:12px}


/* ============================================================
   Plain masthead and legal prose.

   A legal page is a reference document, not a pitch. Dressing
   one in a 68vh photograph is dressing up something nobody came
   to look at, and it pushes the actual text below the fold. So
   these pages get a short dark band instead, with the colour bar
   still closing it so the page is recognisably the same site.
   ============================================================ */

.phero--plain{
  min-height:0;
  padding-block:clamp(96px,13vh,150px) 0;
  background:var(--ink);
  color:var(--paper);
}
.phero--plain .phero__in{padding-block:0 clamp(44px,6vw,72px)}
.phero--plain .h1{max-width:22ch}

/* Prose in a body page. Only paragraphs were styled, because the
   solution pages only ever used paragraphs. Legal copy brings
   numbered sections and lists with it. */
.pbody .prose h2{
  font-family:var(--dm-display);
  font-weight:800;
  font-stretch:104%;
  letter-spacing:-.022em;
  font-size:clamp(21px,2.1vw,26px);
  line-height:1.18;
  margin:44px 0 16px;
  color:var(--ink);
}
.pbody .prose h2:first-child{margin-top:0}
.pbody .prose h3{
  font-family:var(--dm-body);
  font-weight:600;
  font-size:17.5px;
  margin:28px 0 10px;
  color:var(--ink);
}
.pbody .prose ul{margin:0 0 20px;padding:0;list-style:none}
.pbody .prose li{
  position:relative;
  padding-left:22px;
  margin-bottom:11px;
  font-size:17px;
  line-height:1.55;
}
.pbody .prose li::before{
  content:"";
  position:absolute;left:0;top:.62em;
  width:7px;height:7px;border-radius:50%;
  background:var(--ink-cyan);
}
.pbody .prose strong{font-weight:600;color:var(--ink)}
.pbody .prose a{color:var(--ink);text-decoration:underline;text-underline-offset:3px}
.pbody .prose a:hover,
.pbody .prose a:focus-visible{text-decoration-thickness:2px}

/* The first paragraph of a body page is set as a standfirst. A legal
   page opens on its effective date instead, which is a label, not a
   standfirst, so it opts out. */
.pbody .prose p.spec:first-child{
  font-size:11.5px;
  line-height:1.4;
  color:var(--grey-2);
  margin-bottom:34px;
  padding-bottom:14px;
  border-bottom:1px solid var(--rule,rgba(22,19,15,.14));
}

/* ============================================================
   Core values and figures. Not in the concept — added 11 August 2026.

   The reference the client brought was four stock leaf icons in four
   identical blue discs. That is the default every printer in the sector
   has already reached for. These use the Colour Bar instead: the four
   values cycle cyan, magenta, yellow, key, which ties the band to the
   rosette hook rather than to a generic sustainability palette. The
   marks are drawn from the press room and live in inc/icons.php.
   ============================================================ */
.vals{
  list-style:none;
  margin:56px 0 0;
  padding:0;
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(230px,1fr));
  gap:1px;
  background:rgba(22,19,15,.12);
  border-block:1px solid rgba(22,19,15,.12);
}
.val{
  position:relative;
  display:flex;
  flex-direction:column;
  gap:12px;
  padding:34px 26px 30px;
  background:var(--paper-2);
}
/* A 3px rule of the value's own colour, echoing the bar under the header. */
.val::before{
  content:"";
  position:absolute;
  inset:0 0 auto 0;
  height:3px;
  background:var(--c);
}
.val--0{--c:var(--ink-cyan)}
.val--1{--c:var(--ink-magenta)}
.val--2{--c:var(--ink-yellow)}
.val--3{--c:var(--ink)}
.val__mk{display:block;color:var(--c)}
.val__mk .mk{width:34px;height:34px;display:block}
.val__n{
  font-family:var(--dm-mono);
  font-size:11px;
  letter-spacing:.14em;
  color:var(--grey);
}
.val__t{
  margin:0;
  font-family:var(--dm-display);
  font-size:clamp(24px,2.4vw,30px);
  font-weight:700;
  letter-spacing:-.02em;
  line-height:1.02;
  color:var(--ink);
}
.val__l{
  margin:0;
  font-size:15px;
  line-height:1.55;
  color:var(--grey);
}

/* Figures. Reversed on ink so the band reads as a break in the page.
   A figure with nothing behind it renders as an em dash and dims: the
   gap is meant to be visible, to whoever is editing and to the client. */
.figs{
  margin-top:52px;
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(210px,1fr));
  gap:2px;
  background:rgba(247,245,241,.14);
  border:1px solid rgba(247,245,241,.14);
}
.fig{
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:10px;
  padding:30px 24px 26px;
  background:var(--ink);
}
.fig__mk{color:var(--ink-cyan)}
.fig__mk .mk{width:28px;height:28px;display:block}
.fig__n{margin:4px 0 0;display:flex;align-items:baseline;gap:2px}
.fig__n b{
  font-family:var(--dm-display);
  font-size:clamp(52px,6vw,74px);
  font-weight:700;
  letter-spacing:-.04em;
  line-height:.86;
  color:var(--paper);
}
.fig__n i{
  font-style:normal;
  font-family:var(--dm-display);
  font-size:clamp(26px,3vw,34px);
  font-weight:700;
  color:var(--ink-cyan);
}
.fig__t{
  margin:6px 0 0;
  font-size:16px;
  font-weight:600;
  line-height:1.25;
  color:var(--paper);
}
.fig__l{margin:0;font-size:13.5px;line-height:1.5;color:rgba(247,245,241,.66)}
.fig--hold .fig__n b{color:rgba(247,245,241,.34)}
.fig--hold .fig__mk{color:rgba(247,245,241,.34)}
.fig .acc__status{margin-top:12px}

@media (max-width:560px){
  .vals,.figs{grid-template-columns:1fr}
}

/* Figures: the correct mark, and the entrance.
   The tick is stroke-drawn on a dash offset rather than faded in, which
   reads as something being written rather than something appearing —
   the same logic as a QC sheet being signed off. Numerals are tabular so
   the count-up does not jitter the layout while it runs. */
.fig__c{font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}
.fig__tick{
  display:block;
  color:var(--ink-cyan);
  width:clamp(52px,6vw,74px);
  height:clamp(52px,6vw,74px);
}
.fig__tick svg{width:100%;height:100%;display:block;overflow:visible}
.fig__tick path{
  stroke-dasharray:44;
  stroke-dashoffset:44;
}
.figs--go .fig__tick path{
  animation:inkspot-tick .62s cubic-bezier(.2,.7,.3,1) .28s forwards;
}
@keyframes inkspot-tick{to{stroke-dashoffset:0}}

/* Each card lifts in turn, left to right, so the band resolves as a
   sequence rather than a block. */
.figs--go .fig{animation:inkspot-fig .62s cubic-bezier(.2,.7,.3,1) both}
.figs--go .fig:nth-child(1){animation-delay:.02s}
.figs--go .fig:nth-child(2){animation-delay:.10s}
.figs--go .fig:nth-child(3){animation-delay:.18s}
.figs--go .fig:nth-child(4){animation-delay:.26s}
@keyframes inkspot-fig{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}

@media (prefers-reduced-motion:reduce){
  .fig__tick path{stroke-dashoffset:0}
  .figs--go .fig,
  .figs--go .fig__tick path{animation:none}
}

/* ============================================================
   History rail — about page. Added 11 August 2026.

   A vertical dated list is the default and it buries the length of the
   story in a scroll. This runs the milestones along a horizontal rule
   instead, so thirty-five years reads as distance travelled. A register
   mark runs along the rule as the reader scrolls, swelling as it reaches
   each milestone and leaving a printed dot behind it. Falls back to a
   vertical rail under 860px, where a horizontal scroll would be worse
   than honest stacking, and where the mark is dropped entirely.
   ============================================================ */
.tl{
  list-style:none;
  /* 10px of top padding is load-bearing, not spacing. overflow-x:auto
     forces the block axis to compute to auto as well, so the rail clips
     anything sitting above its content box — which is where the rule,
     the travelling mark and every station dot live. Without the padding
     they are cut in half. Margin drops by the same amount so the rail
     has not moved. */
  margin:46px 0 0;
  padding:10px 0 18px;
  position:relative;          /* anchors the travelling head and its rule */
  display:grid;
  grid-auto-flow:column;
  /* 180px min rather than 210px. Six milestones then fit inside a
     1200px wrap without scrolling at all, which is the state most
     desktop visitors see. The scroller below is for narrower windows
     and for a client who adds a seventh. */
  grid-auto-columns:minmax(180px,1fr);
  gap:0;
  overflow-x:auto;
  overscroll-behavior-x:contain;
  scroll-snap-type:x proximity;
  -webkit-overflow-scrolling:touch;

  /* macOS hides overlay scrollbars until you actually scroll, so a
     horizontal scroller with no affordance reads as clipped text —
     reported as "text on the right is missing", which is exactly what
     it looks like. Forcing a slim permanent bar makes the overflow
     legible instead of looking like a bug. */
  scrollbar-width:thin;
  scrollbar-color:var(--ink-cyan) rgba(22,19,15,.10);
}
.tl::-webkit-scrollbar{height:4px}
.tl::-webkit-scrollbar-track{background:rgba(22,19,15,.10)}
.tl::-webkit-scrollbar-thumb{background:var(--ink-cyan);border-radius:4px}
.tl__i{
  position:relative;
  scroll-snap-align:start;
  padding:34px 26px 4px 0;
  border-top:1px solid rgba(22,19,15,.16);
}
/* Colour on the rail was cycling C/M/Y/K one milestone after another,
   which is a rainbow rather than a device and breaks the site rule that
   cyan is the only accent. Colour now appears in one place only: the
   moment each year comes into register. Cyan holds the rail. */
.tl__i{--c:var(--ink-cyan)}

/* The dot sits on the rule, not beside it. */
.tl__dot{
  position:absolute;
  top:-5px;left:0;
  width:9px;height:9px;
  border-radius:50%;
  background:var(--c);
}
.tl__i--pivot .tl__dot{
  top:-7px;
  width:13px;height:13px;
  box-shadow:0 0 0 4px var(--paper,#f7f5f1);
}

/* --- year: misregistration, then register -------------------------
   Three separations sit behind the black plate, offset by a few pixels
   and multiplied so the overlaps read as ink rather than as coloured
   type. On reveal they close on zero and the black lands last. It is
   the one piece of motion a printer is entitled to use, and it is the
   argument the whole site makes — everything in one place, in register.
   Kept off the paint path: transform and opacity only. */
.tl__y{
  position:relative;
  /* The pivot year is larger, so the year box is sized to the largest
     of them and every year hangs from the same baseline. Without this
     the pivot shoves its own title down the page and the row reads as
     broken rather than as emphasis. */
  display:flex;
  align-items:flex-end;
  min-height:clamp(44px,5vw,64px);
  margin:0;
  font-family:var(--dm-display);
  font-size:clamp(34px,3.6vw,46px);
  font-weight:700;
  letter-spacing:-.03em;
  line-height:1;
  color:var(--ink);
  isolation:isolate;
}
.tl__i--pivot .tl__y{font-size:clamp(44px,5vw,64px)}
/* Emphasis by contrast, not by scale alone. Six equally black numbers
   with one of them larger reads as a sizing error; the pivot only reads
   as a decision once it is the single full-strength year on the rail.
   Two-thirds ink on the rest is a clear step down without washing them
   out — at half they fell behind their own titles and the hierarchy
   inside each column inverted. Titles hold full ink throughout: they
   carry the meaning, and muting them buys nothing. */
.tl__i:not(.tl__i--pivot) .tl__y__k{color:rgba(22,19,15,.66)}
.tl__y__k{position:relative}
.tl__y__s{
  position:absolute;
  inset:auto 0 0 0;          /* bottom-aligned, same baseline as the K plate */
  mix-blend-mode:multiply;
  pointer-events:none;
}
.tl__y__s--c{color:var(--ink-cyan)}
.tl__y__s--m{color:var(--ink-magenta)}
.tl__y__s--y{color:var(--ink-yellow)}
.tl__t{
  margin:14px 0 0;
  font-size:17px;
  font-weight:600;
  line-height:1.25;
  color:var(--ink);
}
.tl__b{
  margin:8px 0 0;
  font-size:14.5px;
  line-height:1.55;
  color:var(--grey);
  max-width:34ch;
}
.tl .acc__status{margin-top:12px}

/* --- scroll room for the mark ---------------------------------------
   A rail on a page that simply scrolls past has one viewport of travel
   to spend, whatever the thresholds are set to — roughly 80px of scroll
   per milestone, which is why it kept reading as too fast. So the block
   is held in place while the reader scrolls past it and .tl__scope
   supplies the distance. Nothing is jacked: the page scrolls at its
   normal rate, the rail just stays put while it does.

   --tl-run is the tuning dial. 260vh gives roughly 400px of scroll per
   milestone, about five times the old pace. Raise it to slow the mark
   further, lower it to speed up. Nothing else needs touching.

   Stacked under 860px this is all inert — the block is short, the
   milestones reveal against their own position, and holding anything
   in place on a phone would only steal the screen. */
.tl__scope{--tl-run:260vh}
@media (min-width:861px){
  .tl__scope--run{height:var(--tl-run)}
  .tl__scope--run .tl__stick{position:sticky;top:16vh}
}

/* --- the travelling register mark -----------------------------------
   Built by initRail(), so it exists only where there is JavaScript to
   drive it. Position and scale are written straight onto the element
   from the scroll handler — no transitions, because the reader's wheel
   is the timing function. Anything eased here would lag behind the
   scroll and read as sticky.

   The mark sits on the rule, swells as it arrives at a milestone and
   thins again as it moves off, and the cyan rule is drawn to wherever
   it has reached. Each station it has passed keeps its own small dot,
   so the rail records where the mark has been. */
.tl__head,
.tl__rule{
  position:absolute;
  top:10px;                   /* the rail's top padding — see .tl above */
  pointer-events:none;
  will-change:transform;
}
.tl__rule{
  left:0;
  width:100%;
  height:1px;
  background:var(--ink-cyan);
  transform-origin:left;
  transform:scaleX(0);
}
.tl__head{
  left:0;
  width:11px;
  height:11px;
  margin:-5px 0 0 -5.5px;
  border-radius:50%;
  background:var(--ink-cyan);
  transform:translateX(0) scale(0);
}

/* --- milestones: revealed by the mark, not by a timer ----------------
   Each milestone gets .is-reg from initRail() as the mark reaches it,
   so the stagger is the reader's scroll rather than a delay chain.

   The copy only fades. It used to rise as well, but with a mark
   travelling the rule, a line drawing behind it and six years snapping
   into register, one more moving part was noise. The register snap is
   the idea; everything else gets out of its way.

   Scoped to .tl--anim, which only JavaScript adds, so with JS off or
   under reduced motion none of it applies and the rail renders exactly
   as PHP wrote it. There is no state in which the history is invisible. */
.tl--anim .tl__i > *{opacity:0;transition:opacity .55s ease}
.tl--anim .tl__dot{transform:scale(0);transition:transform .45s cubic-bezier(.34,1.4,.64,1)}
.tl--anim .tl__y__s{transition:transform .95s cubic-bezier(.16,1,.3,1), opacity .3s ease .6s}
/* Offsets in em, not px, so the throw scales with the year — the pivot
   gets a proportionally wider miss and reads as the loudest snap on the
   rail. Roughly 10px at 46px, which is legible without tipping into
   cartoon. */
.tl--anim .tl__y__s--c{transform:translate(-.22em,.13em)}
.tl--anim .tl__y__s--m{transform:translate(.2em,-.15em)}
.tl--anim .tl__y__s--y{transform:translate(.11em,.23em)}
.tl--anim .tl__y__k{opacity:0;transition:opacity .5s ease .25s}

/* The copy waits for the year — the mark arrives, the year registers,
   then the milestone reads. In that order, or the snap is upstaged. */
.tl--anim .tl__i.is-reg > *{opacity:1;transition-delay:.35s}
.tl--anim .tl__i.is-reg .tl__y{transition-delay:0s}
.tl--anim .tl__i.is-reg .tl__dot{transform:scale(1);transition-delay:0s}
.tl--anim .tl__i.is-reg .tl__y__s{transform:translate(0,0);opacity:0}
.tl--anim .tl__i.is-reg .tl__y__k{opacity:1}

/* The static rule. Unscoped, so it exists whether or not the rail
   animates — without it the milestones have nothing to hang from. Where
   the mark is running it draws the cyan itself, so the per-item segment
   stands down and only the hairline stays. */
.tl__i::before{
  content:"";
  position:absolute;
  top:-1px;left:0;right:0;
  height:1px;
  background:var(--ink-cyan);
}
.tl--anim .tl__i::before{display:none}

/* The separations are a motion device. With nothing to animate they
   would only sit as a permanent colour fringe, so they go. The cyan
   rule stays in every state — it is structure, not motion. */
@media (prefers-reduced-motion:reduce){
  .tl__y__s{display:none}
}
.tl:not(.tl--anim) .tl__y__s{display:none}

@media (max-width:860px){
  .tl{
    padding-bottom:0;
    scrollbar-width:auto;
    grid-auto-flow:row;
    grid-auto-columns:auto;
    overflow-x:visible;
    border-left:1px solid rgba(22,19,15,.16);
    padding:0 0 0 26px;
  }
  .tl__i{border-top:0;padding:0 0 34px}
  .tl__i:last-child{padding-bottom:0}
  .tl__dot{top:6px;left:-31px}
  .tl__i--pivot .tl__dot{top:4px;left:-33px}
  .tl__b{max-width:46ch}
  /* Vertical rail on mobile — the horizontal draw has nothing to draw
     along, so it goes rather than turning into a stray cyan line. */
  .tl__i::before{display:none}
  .tl__i--pivot .tl__y{font-size:clamp(40px,11vw,52px)}
}

/* Compact accreditations — a credential row for pages where the full
   argument lives elsewhere. Four across on light ground, smaller plates,
   no body copy, and a route through to the page that evidences them. */
.accs-c__head{max-width:46ch}
.accs--c{
  margin-top:44px;
  background:rgba(22,19,15,.12);
  border:1px solid rgba(22,19,15,.12);
}
.acc--c{
  background:var(--paper-2);
  gap:16px;
  padding:26px 22px 24px;
}
.acc--c .acc__plate{max-width:128px}
.acc--c .acc__plate--hold{
  border-color:rgba(22,19,15,.26);
  background:rgba(22,19,15,.03);
}
.acc--c .acc__plate--real{
  border:1px solid rgba(22,19,15,.14);
  background:#fff;
  box-shadow:0 1px 3px rgba(22,19,15,.08);
}
.acc--c .acc__plate--hold .acc__plate-name{font-size:22px;color:rgba(22,19,15,.44)}
.acc--c .acc__plate--hold .acc__plate-note{color:rgba(22,19,15,.42)}
.acc--c .acc__mark b{font-size:20px;color:var(--ink)}
.acc--c .acc__mark i{color:var(--grey)}
.acc--c .acc__no{color:var(--ink)}
.accs-c__more{margin:32px 0 0}

/* ============================================================
   Client logos — rolling strip and static grid. 11 August 2026.

   Black and white as asked: grayscale(1) with a slight knock-down in
   opacity, so a wall of competing brand colours reads as one calm row
   and Inkspot's own Colour Bar stays the only colour on the page.
   Colour returns on hover for anyone looking properly.

   The roll is CSS only — no library, no JS. Two identical sets sit side
   by side and the pair translates by exactly -50%, so the seam never
   shows. It pauses on hover and on keyboard focus, and it does not run
   at all under prefers-reduced-motion, where it becomes a static grid.
   An endless unpausable marquee is a genuine accessibility failure, not
   a style choice.
   ============================================================ */
.cl{--tile:150px}
.cl__label{margin:0 0 26px;color:var(--grey)}

.cl__set{
  list-style:none;
  margin:0;padding:0;
  display:flex;
  align-items:center;
  gap:clamp(38px,5vw,72px);
}
.cl__i{
  flex:0 0 auto;
  width:var(--tile);
  height:64px;
  display:flex;
  align-items:center;
  justify-content:center;
}
.cl__i img{
  max-width:100%;max-height:100%;
  width:auto;height:auto;
  display:block;
  filter:grayscale(1);
  opacity:.62;
  transition:opacity .3s ease,filter .3s ease;
}
.cl__i:hover img{filter:grayscale(0);opacity:1}

/* Placeholder wordmarks. No dashed box: at mock-up stage the wall needs
   to read as a wall so spacing and greyscale balance can be judged. The
   honesty lives in one caption under the strip instead. Three treatments
   give the row the uneven rhythm a real logo wall has. */
.cl__i--hold{width:var(--w,150px)}
.cl__nm{
  display:flex;
  align-items:center;
  gap:8px;
  width:var(--w,150px);
  color:rgba(22,19,15,.55);
  text-align:center;
  justify-content:center;
}
.cl__nm i{font-style:normal}
/* 0 — tight display bold, the commonest wordmark shape */
.cl__nm--0 i{
  font-family:var(--dm-display);
  font-weight:700;
  font-size:19px;
  letter-spacing:-.03em;
  line-height:1.05;
}
/* 1 — light, wide-tracked caps, the "premium retail" treatment */
.cl__nm--1 i{
  font-family:var(--dm-body);
  font-weight:400;
  font-size:13px;
  letter-spacing:.22em;
  text-transform:uppercase;
  line-height:1.25;
}
/* 2 — monogram lock-up beside the name */
.cl__nm--2{justify-content:flex-start;text-align:left}
.cl__nm--2 i{
  font-family:var(--dm-display);
  font-weight:700;
  font-size:15px;
  letter-spacing:-.01em;
  line-height:1.05;
}
.cl__mono{
  flex:0 0 auto;
  display:grid;
  place-items:center;
  width:30px;height:30px;
  font-family:var(--dm-display);
  font-size:13px;
  font-weight:700;
  letter-spacing:.02em;
  color:var(--paper-2);
  background:rgba(22,19,15,.55);
}
.on-ink .cl__nm{color:rgba(247,245,241,.6)}
.on-ink .cl__mono{color:var(--ink);background:rgba(247,245,241,.6)}

/* The one honest line. Quiet, but not hidden. */
.cl__note{
  margin:26px 0 0;
  font-family:var(--dm-mono);
  font-size:11px;
  letter-spacing:.06em;
  color:var(--grey);
}
.on-ink .cl__note{color:rgba(247,245,241,.55)}

/* Rolling */
.cl__vp{
  position:relative;
  display:flex;
  overflow:hidden;
  /* Fade the ends so logos enter and leave rather than being clipped. */
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);
}
.cl--roll .cl__set{
  padding-right:clamp(38px,5vw,72px);
  animation:inkspot-roll var(--lap,46s) linear infinite;
  will-change:transform;
}
.cl__vp:hover .cl__set,
.cl__vp:focus-within .cl__set{animation-play-state:paused}
@keyframes inkspot-roll{from{transform:translateX(0)}to{transform:translateX(-100%)}}

/* Static grid, for the clients page */
.cl--grid .cl__set{
  flex-wrap:wrap;
  gap:clamp(28px,3.4vw,46px);
}

@media (prefers-reduced-motion:reduce){
  .cl--roll .cl__set{animation:none}
  .cl__vp{overflow:visible;-webkit-mask-image:none;mask-image:none;flex-wrap:wrap}
  .cl__set--b{display:none}
  .cl--roll .cl__set{flex-wrap:wrap}
}

/* ============================================================
   Capability columns — sector pages. 11 August 2026.
   Three or four columns of formats and finishes. The reference sets
   these under stock icons on a white card; the card adds nothing, so
   the columns sit on rules instead and the type does the work.
   ============================================================ */
.spx{
  margin-top:48px;
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(210px,1fr));
  gap:0 clamp(28px,3.6vw,52px);
}
.spx__c{
  padding-top:26px;
  border-top:1px solid rgba(22,19,15,.16);
}
.on-ink .spx__c{border-top-color:rgba(247,245,241,.2)}
.spx__mk{display:block;color:var(--ink-cyan);margin-bottom:16px}
.spx__mk .mk{width:30px;height:30px;display:block}
.spx__t{
  margin:0 0 8px;
  font-family:var(--dm-display);
  font-size:clamp(21px,2.1vw,26px);
  font-weight:700;
  letter-spacing:-.02em;
  line-height:1.05;
  color:var(--ink);
}
.on-ink .spx__t{color:var(--paper)}
.spx__n{
  margin:0 0 16px;
  font-size:14px;
  line-height:1.55;
  color:var(--grey);
  max-width:34ch;
}
.on-ink .spx__n{color:rgba(247,245,241,.7)}
.spx__l{list-style:none;margin:0;padding:0}
.spx__l li{
  padding:7px 0;
  border-bottom:1px solid rgba(22,19,15,.09);
  font-size:14px;
  line-height:1.45;
  color:var(--ink);
}
.on-ink .spx__l li{border-bottom-color:rgba(247,245,241,.12);color:var(--paper)}
.spx__l li:last-child{border-bottom:0}
.spx__q{color:var(--grey)}
.spx__l .acc__status{margin-left:8px;display:inline-block;vertical-align:1px}

@media (max-width:560px){
  .spx{grid-template-columns:1fr;gap:0}
  .spx__c{margin-bottom:26px}
}

/* ============================================================
   Pack shots — mock-up beside finished. Rebuilt 11 August 2026.

   The first attempt was a flat four-column grid of six squares, which
   did two things wrong: six items in a four-wide grid orphans a row,
   and nothing grouped the mock-up with the pack it became. The pairing
   is the entire argument, so it is now the unit of layout: one job per
   row, two frames, an arrow between them.

   Frames are 4:3 rather than square. The source photographs are 800px
   squares with the carton small in a lot of empty sweep; cropping to
   landscape throws away the dead space top and bottom and roughly
   doubles how big the carton reads.
   ============================================================ */
.pks{margin-top:52px;display:flex;flex-direction:column;gap:clamp(34px,4vw,56px)}

.pkp{display:grid;grid-template-columns:minmax(180px,1fr) minmax(0,2.6fr);gap:clamp(20px,3vw,44px);align-items:start}
.pkp__hd{padding-top:4px}
.pkp__j{
  margin:0 0 8px;
  font-family:var(--dm-display);
  font-size:clamp(20px,2vw,25px);
  font-weight:700;
  letter-spacing:-.02em;
  line-height:1.08;
  color:var(--ink);
}
.on-ink .pkp__j{color:var(--paper)}
.pkp__n{margin:0;font-size:14px;line-height:1.55;color:var(--grey);max-width:30ch}
.on-ink .pkp__n{color:rgba(247,245,241,.68)}

/* The pair itself: two frames and the arrow that earns its place. */
.pkp__pair{display:grid;grid-template-columns:1fr auto 1fr;gap:clamp(12px,1.6vw,22px);align-items:center}
.pkp__arw{display:block;width:40px;color:rgba(22,19,15,.32)}
.on-ink .pkp__arw{color:rgba(247,245,241,.4)}
.pkp__arw svg{width:100%;height:auto;display:block}

.pk{margin:0}
.pk__f{
  aspect-ratio:4/3;
  overflow:hidden;
  background:var(--paper-2);
  border:1px solid rgba(22,19,15,.1);
}
.on-ink .pk__f{background:rgba(247,245,241,.06);border-color:rgba(247,245,241,.14)}
.pk__f img{width:100%;height:100%;object-fit:cover;object-position:50% 46%;display:block}
.pk__c{
  margin:10px 0 0;
  font-family:var(--dm-mono);
  font-size:10px;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--grey);
}
.on-ink .pk__c{color:rgba(247,245,241,.55)}
/* Second frame in each pair is the outcome, so it gets the ink dot. */
.pk:last-of-type .pk__c{color:var(--ink)}
.on-ink .pk:last-of-type .pk__c{color:var(--ink-cyan)}

@media (max-width:900px){
  .pkp{grid-template-columns:1fr;gap:16px}
}
@media (max-width:560px){
  .pkp__pair{grid-template-columns:1fr;gap:16px}
  .pkp__arw{width:22px;transform:rotate(90deg);justify-self:center}
}

/* Sector cards: give them somewhere to go, and say so.
   The cards were reading as decoration because nothing signalled they
   were links. An arrow that travels on hover is the same language the
   process chain already uses, so the site behaves consistently. */
.fcard__go{
  display:inline-flex;
  align-items:center;
  gap:10px;
  margin-top:18px;
  font-family:var(--dm-mono);
  font-size:11px;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--ink-cyan);
}
.fcard__go i{font-style:normal}
.fcard__go svg{width:26px;height:12px;display:block;transition:transform .32s cubic-bezier(.2,.7,.3,1)}
a.fcard:hover .fcard__go svg,
a.fcard:focus-visible .fcard__go svg{transform:translateX(6px)}

/* The whole card is the target, so it should read as one. */
a.fcard{display:block;text-decoration:none}
a.fcard img{transition:transform .6s cubic-bezier(.2,.7,.3,1)}
a.fcard:hover img{transform:scale(1.035)}
a.fcard:focus-visible{outline:2px solid var(--ink-cyan);outline-offset:3px}

/* A job with no blank mock-up shows one frame, held to the width the
   left-hand frame would have had so the column edge stays true down the
   page rather than the single image stretching to fill the pair. */
.pkp__pair--solo{grid-template-columns:minmax(0,1fr) auto minmax(0,1fr)}
.pkp__pair--solo .pk{grid-column:1 / 2}
@media (max-width:560px){ .pkp__pair--solo .pk{grid-column:1 / -1} }

/* The solo frame is portrait, not 4:3. The paired frames crop landscape
   because those source shots are squares with the carton small in a lot
   of empty sweep. The Durex shot is the opposite — a tall pack shot,
   already tight, with the tear-out fronts at the bottom of the frame.
   A landscape crop guillotines the pack tops and cuts the tear-outs in
   half, which is precisely the structure the note beside it describes.
   9:10 matches the supplied file, so nothing is cropped at all. */
.pkp__pair--solo .pk__f{aspect-ratio:9/10}
.pkp__pair--solo .pk__f img{object-position:50% 50%}


/* ============================================================
   Process chain — phases layout. Added 11 August 2026.

   This welds two blocks that were saying overlapping things: the
   "what we offer" tiles from the intro band, and the nine-step
   chain. Both were already a three-column grid coloured C/M/Y, so
   the join is along a seam that already existed.

   The tiles supply the treatment — 1px dividers over a hairline
   ground, a 4px ink rule capping each column. The chain supplies
   the content. What changes is reading direction: steps now run
   DOWN each column in threes rather than across in rows, which is
   what lets a column be headed at all. Three arbitrary rows become
   three named phases, and the ink stops being decoration: cyan is
   everything before the press, magenta is the press, yellow is
   everything after it.

   Left alone, .chain__grid on the homepage is untouched.
   ============================================================ */
.chain--phases{margin-top:clamp(40px,5vw,62px)}

.chain__cols{
  display:grid;
  grid-template-columns:repeat(3,1fr);
  grid-template-rows:auto auto;
  gap:1px;
  background:rgba(0,0,0,.14);
  border-block:1px solid rgba(0,0,0,.14);
}
.on-ink .chain__cols{background:rgba(247,245,241,.16);border-block-color:rgba(247,245,241,.16)}

/* Heads are different lengths, so without this the divider rule under
   each one sits at a different height and step 07 starts above step 01.
   Subgrid makes the three columns share the parent's rows, which lines
   the rules up on one line across the band. Browsers without it fall
   back to the ragged version rather than breaking. */
.phase{background:var(--paper);padding:26px clamp(20px,2vw,28px) clamp(28px,3vw,36px);position:relative}
@supports (grid-template-rows:subgrid){
  .phase{display:grid;grid-template-rows:subgrid;grid-row:span 2}
}
.on-ink .phase{background:var(--ink)}

/* The cap rule, straight off the offer tiles. */
.phase::before{content:"";position:absolute;top:0;left:0;right:0;height:4px;background:var(--f,var(--ink-cyan))}
.chain__cols>.phase:nth-child(1){--f:var(--ink-cyan)}
.chain__cols>.phase:nth-child(2){--f:var(--ink-magenta)}
.chain__cols>.phase:nth-child(3){--f:var(--ink-yellow)}
.chain__cols>.phase:nth-child(4){--f:var(--ink)}

.phase__hd{padding-bottom:22px;margin-bottom:26px;border-bottom:1px solid rgba(0,0,0,.14)}
@supports (grid-template-rows:subgrid){
  .phase__hd{margin-bottom:0}
  .phase__steps{padding-top:26px}
}
.on-ink .phase__hd{border-bottom-color:rgba(247,245,241,.16)}
.phase__hd h3{
  font-family:var(--dm-display);
  font-weight:700;
  font-stretch:106%;
  font-size:19px;
  letter-spacing:-.015em;
  margin:0 0 9px;
}
.on-ink .phase__hd h3{color:var(--paper)}
.phase__hd p{margin:0;font-size:15px;line-height:1.5;color:var(--grey);max-width:34ch}

/* Steps stack rather than grid, so a phase with two or four still
   sits correctly instead of tearing the row height apart. */
.phase__steps{display:flex;flex-direction:column;gap:clamp(26px,3vw,36px)}
.phase__steps .step{padding-right:0}
.phase__steps .step__tick{background:var(--f,var(--ink-cyan));margin-bottom:22px}
.phase__steps .step::before{background:var(--paper-2)}
.on-ink .phase__steps .step::before{background:rgba(247,245,241,.14)}

/* Closing line and button, carried over from the intro band so the
   section still ends on somewhere to go. */
.chain__end{display:flex;align-items:center;gap:20px;flex-wrap:wrap;margin-top:clamp(34px,4vw,50px)}

@media (max-width:900px){
  .chain__cols{grid-template-columns:1fr}
  .phase{padding-top:24px}
}


/* Shot slot — video ------------------------------------------------------
   The .shot slot took an <img> only. It now optionally takes silent looping
   footage, so the video needs the same box the image had: full width, 4/3,
   cropped to fill. Matches .shot img at inkspot.css:139. */
.shot video{width:100%;aspect-ratio:4/3;object-fit:cover;display:block}
.shot--tall video{aspect-ratio:3/3.4}
.stack .shot:first-child video{aspect-ratio:16/9}
.stack .shot:last-child video{aspect-ratio:21/9}


/* Gallery — metro ---------------------------------------------------------
   Twelve pack shots in a repeating three-item block: one large tile at
   2x2, two single tiles stacked beside it. Twelve divides by three, so the
   grid tiles exactly with no orphan cells. The large tile alternates left
   and right each block so the eye zig-zags down rather than marching.
   Cells stay square because the singles set their own height from the
   column width, and the large tile spans two of both. */
.gal{display:grid;grid-template-columns:repeat(3,1fr);
     gap:clamp(10px,1.1vw,18px);grid-auto-flow:dense;
     margin-top:clamp(34px,4vw,52px)}
.gal__i{margin:0;position:relative;overflow:hidden;border-radius:12px;
        background:var(--paper)}
.gal__i img{width:100%;height:100%;aspect-ratio:1/1;object-fit:cover;display:block}

/* Large tiles: items 1, 4, 7, 10 — alternating side. */
.gal__i:nth-child(6n+1){grid-column:1 / span 2;grid-row:span 2}
.gal__i:nth-child(6n+4){grid-column:2 / span 2;grid-row:span 2}
.gal__i:nth-child(6n+1) img,
.gal__i:nth-child(6n+4) img{aspect-ratio:auto}

/* Caption sits on the shot itself. Every one of these is photographed on a
   pale studio ground, so it reads without a heavy scrim — the gradient is
   only there to protect the few that carry product into the lower left. */
.gal__i figcaption{position:absolute;left:0;right:0;bottom:0;
     padding:26px 14px 12px;color:var(--ink);
     background:linear-gradient(to top,rgba(247,245,240,.92) 38%,rgba(247,245,240,0));
     font-size:11px}

.gal__note{margin-top:clamp(26px,3vw,38px);color:var(--grey);max-width:70ch}

@media (max-width:900px){
  .gal{grid-template-columns:repeat(2,1fr)}
  /* Two columns cannot hold a 2-wide tile beside anything, so every tile
     goes square and the rhythm comes back on wider screens. */
  .gal__i:nth-child(6n+1),
  .gal__i:nth-child(6n+4){grid-column:auto;grid-row:auto}
  .gal__i:nth-child(6n+1) img,
  .gal__i:nth-child(6n+4) img{aspect-ratio:1/1}
}
@media (max-width:560px){
  .gal{grid-template-columns:1fr}
}

/* Tile call to action -----------------------------------------------------
   Same device as .fcard__go so a linked tile and a linked card read as the
   same promise. Two differences the tile forces: the h3 sits on `margin:auto
   0 0` to push itself to the bottom, so the CTA has to come after it without
   fighting that, and the tile fills with a process ink on hover — so the
   cyan CTA has to flip to ink alongside the heading or it vanishes into the
   fill. */
.tile__go{
  position:relative;z-index:2;
  display:inline-flex;align-items:center;gap:10px;
  margin-top:14px;
  font-family:var(--dm-mono);
  font-size:11px;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--ink-cyan);
  transition:color .25s;
}
.tile__go i{font-style:normal}
.tile__go svg{width:26px;height:12px;display:block;
              transition:transform .32s cubic-bezier(.2,.7,.3,1)}
a.tile:hover .tile__go,
a.tile:focus-visible .tile__go{color:var(--ink)}
a.tile:hover .tile__go svg,
a.tile:focus-visible .tile__go svg{transform:translateX(6px)}

/* "Our commitment to quality": client asked for it slightly bigger and
   bolder than the standard spec label. 24/09/2026. */
.intro__lbl{
  font-family:var(--dm-display);
  font-size:20px;
  font-weight:700;
  letter-spacing:-.01em;
  text-transform:none;
  color:var(--ink);
  margin:38px 0 12px;
}
.on-ink .intro__lbl{color:var(--paper)}

/* Capability lines inside the commitment block: tight stack, bold lead-in. */
.intro__body .intro__cap{margin:0 0 10px}
.intro__body .intro__cap b{font-weight:600;color:var(--ink)}
.intro__body .intro__cap b::after{content:'. '}

/* Accessibility: mobile touch targets at least 24px tall (WCAG 2.2 2.5.8).
   Desktop dropdown links get a little more vertical padding too. */
.nav .has ul a{display:block;padding-block:6px}

/* Skip link: hidden until focused by keyboard, then shown top-left.
   It had no styles at all and sat visibly above the header. */
.skip{position:absolute;left:12px;top:-60px;z-index:10000;padding:10px 16px;background:var(--paper);color:var(--ink);font:600 14px/1 var(--dm-sans,sans-serif);border-radius:4px;text-decoration:none;transition:top .15s}
.skip:focus{top:12px}

/* CLS: the hero headline measure was 13ch, and ch is the width of "0" in
   whichever font is showing. Archivo's zero is wider than any fallback's,
   so the box widened by 36px when Archivo arrived and the headline dropped
   from three lines to two, jolting everything below. 8.125em is exactly
   13ch in Archivo 800, so the settled layout is unchanged. */
.hero h1{max-width:8.125em}

/* Intro: the right column now runs to six paragraphs, which left a long
   empty strip under the headline on desktop. The headline holds its place
   while the text scrolls past it. */
@media (min-width:901px){
  .intro__hd{position:sticky;top:124px}
}

/* Section rhythm: intro and "Nine steps" are both plain bands, so their
   padding stacked into a 280px blank at desktop. Halve the join. */
.elementor-widget-inkspot_intro .band{padding-bottom:calc(var(--dm-sec)*.5)}
.elementor-widget-inkspot_process_chain .band{padding-top:calc(var(--dm-sec)*.5)}


/* ============================================================
   UX pass, 30/09/2026
   ============================================================ */

/* --- header: phone, quote button, shrink on scroll --------------------
   The Contact button was meant to be cyan all along, but .nav>a (0,1,1)
   out-ranked .btn--go (0,1,0) and flattened it to a text link. */
.nav>a.nav__cta{background:var(--ink-cyan);color:#062634;padding:10px 19px;margin-left:6px;font-weight:600}
.nav>a.nav__cta:hover{background:#31C0F5;transform:translateY(-1px)}
.nav>a.nav__tel{font-variant-numeric:tabular-nums;white-space:nowrap;margin-left:8px;border:1px solid var(--ink-3)}
.nav>a.nav__tel:hover{border-color:var(--grey)}
.nav__tel-k{font-family:var(--dm-mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--grey-2);margin-right:2px}
@media (max-width:1320px){ .nav__tel-k{display:none} }
@media (max-width:1180px){ .nav>a.nav__tel{display:none} }

.hdr__in{transition:height .25s cubic-bezier(.2,.7,.3,1)}
.brand img{transition:height .25s cubic-bezier(.2,.7,.3,1)}
html.is-scrolled .hdr__in{height:70px}
html.is-scrolled .brand img{height:42px}

.hdr__call{display:none;align-items:center;justify-content:center;width:44px;height:44px;border-radius:100px;
  color:var(--paper);border:1px solid var(--ink-3);margin-left:auto}
.hdr__call:hover,.hdr__call:focus-visible{border-color:var(--ink-cyan);color:var(--ink-cyan)}
@media (max-width:1040px){
  .hdr__call{display:inline-flex}
  .hdr__call + .burger{margin-left:6px}
  html.is-scrolled .hdr__in{height:62px}
  html.is-scrolled .brand img{height:38px}
}

/* --- reveal: shorter, and landed before it is seen (see inkspot.js) --- */
.rv{transition:opacity .35s ease,transform .35s cubic-bezier(.2,.7,.3,1)}

/* --- accreditations: certified vs supported --------------------------- */
.trust__in--split{flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:flex-end;gap:28px 56px}
.trust__grp{display:flex;flex-direction:column;gap:16px}
.trust__cert{margin:0;display:flex;flex-direction:column;align-items:flex-start;gap:8px}
.trust__cert figcaption{font-size:10px;letter-spacing:.12em;color:var(--grey)}
.trust__grp--cert .trust__marks img{filter:none;opacity:1}
/* Sector tiles: eight since 30/09/2026 (Veterinary, Braille added), so four
   across on desktop and two on tablets; phones stay single column. */
@media (max-width:1100px) and (min-width:781px){.tiles{grid-template-columns:repeat(2,1fr)}}
/* Certification marks: equal visible marks (84px body), tops and captions aligned.
   FSC panel is 400/490 of its artwork; Amtivo badge 93% of its file; PEFC is a
   white square. Bottom margins make every image 103px tall overall. */
.trust__grp--cert .trust__marks{align-items:flex-end}
.trust__m{width:auto;display:block}
.trust__m--fsc{height:103px}
.trust__m--pefc{height:84px;margin-bottom:19px}
.trust__m--iso{height:90px;margin-bottom:13px}
@media (max-width:780px){
  .trust__marks img.trust__m--fsc{height:78px !important}
  .trust__marks img.trust__m--pefc{height:64px !important;margin-bottom:14px}
  .trust__marks img.trust__m--iso{height:69px !important;margin-bottom:9px}
}
.trust__grp--fund .trust__marks{gap:28px}
.trust__grp--fund .trust__marks img{filter:grayscale(1);opacity:.6}
.trust__grp--fund .trust__marks img:hover{filter:none;opacity:1}
@media (max-width:780px){
  .trust__in--split{flex-direction:column;align-items:flex-start}
  .trust__grp--fund .trust__marks img{height:28px !important}
}

/* --- footer contact block -------------------------------------------- */
.ftr__addr{font-style:normal;margin-top:22px;line-height:1.65;color:var(--grey-2);font-size:14px}
.ftr__contact{margin:14px 0 0;line-height:1.9;font-size:14px}
.ftr__contact a{color:var(--paper);text-decoration:none;border-bottom:1px solid var(--ink-3)}
.ftr__contact a:hover{border-color:var(--ink-cyan)}

/* --- mobile action bar ------------------------------------------------
   Bottom of the screen is where a thumb is. Two equal targets, 52px
   tall, with the safe-area inset so it clears the iPhone home bar. */
.actbar{display:none}
@media (max-width:1040px){
  .actbar{position:fixed;left:0;right:0;bottom:0;z-index:90;display:grid;grid-template-columns:1fr 1.35fr;gap:8px;
    padding:10px var(--dm-gut) calc(10px + env(safe-area-inset-bottom));background:rgba(22,19,15,.94);
    -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border-top:1px solid var(--ink-3);
    transform:translateY(110%);transition:transform .28s cubic-bezier(.2,.7,.3,1)}
  .actbar[data-show="true"]{transform:none}
  .actbar__btn{display:flex;align-items:center;justify-content:center;gap:9px;min-height:52px;border-radius:100px;
    font-family:var(--dm-body);font-weight:600;font-size:15.5px;text-decoration:none}
  .actbar__btn--call{color:var(--paper);border:1.5px solid var(--ink-3)}
  .actbar__btn--quote{background:var(--ink-cyan);color:#062634}
  /* Keep the footer's last line clear of the bar. */
  .ftr{padding-bottom:calc(34px + 72px + env(safe-area-inset-bottom))}
}
@media (prefers-reduced-motion:reduce){ .actbar{transition:none} }
@media print{ .actbar,.hdr__call{display:none !important} }

/* --- enquiry form: file field ---------------------------------------- */
.f--file input[type=file]{padding:12px;cursor:pointer;color:var(--grey-2);font-size:14.5px}
.f--file input[type=file]::file-selector-button{font-family:var(--dm-body);font-weight:600;font-size:14px;
  margin-right:14px;padding:9px 16px;border-radius:100px;border:1.5px solid var(--ink-3);background:transparent;color:var(--paper);cursor:pointer}
.f--file input[type=file]:hover::file-selector-button{border-color:var(--ink-cyan)}
.f__hint{margin:0;font-size:13px;line-height:1.5;color:var(--grey-2)}

/* --- homepage nine steps in phases: the phase heads are the grouping
   the flat 3x3 grid lacked. Same component as the About page. */
.home .elementor-widget-inkspot_process_chain .chain--phases{margin-top:clamp(36px,5vw,56px)}

/* Sector tiles with a darkened photograph behind each (Scolly 30/09/2026).
   Layers: photo, then a scrim dark at top and bottom, then the ink wipe on
   hover, then the text. */
.tile{min-height:170px}
.tile__img{position:absolute;inset:0;z-index:0;width:100%;height:100%;object-fit:cover;filter:grayscale(35%) brightness(.8);transition:transform .6s cubic-bezier(.2,.7,.3,1)}
.tile::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;background:linear-gradient(180deg,rgba(22,19,15,.9) 0%,rgba(22,19,15,.62) 32%,rgba(22,19,15,.55) 55%,rgba(22,19,15,.92) 100%)}
.tile::before{z-index:2}
.tile span,.tile h3,.tile .tile__go{z-index:3}
a.tile:hover .tile__img,a.tile:focus-visible .tile__img{transform:scale(1.05)}
@media (max-width:780px){.tile{min-height:120px}}
@media (prefers-reduced-motion:reduce){.tile__img{transition:none}}

/* Healthcare card (hc-sleep-aid): the carton photo is pale at the top and
   the headline sits there, so this card gets a scrim dark at both ends.
   Scolly 30/09/2026. */
.fcard:has(img[src*="hc-sleep-aid"])::after{background:linear-gradient(180deg,rgba(22,19,15,.9) 0%,rgba(22,19,15,.72) 28%,rgba(22,19,15,.42) 55%,rgba(22,19,15,.7) 78%,rgba(22,19,15,.95) 100%)}
.fcard img[src*="hc-sleep-aid"]{filter:brightness(.72)}
.fcard:has(img[src*="hc-sleep-aid"])::after{background:linear-gradient(180deg,rgba(22,19,15,.96) 0%,rgba(22,19,15,.8) 30%,rgba(22,19,15,.5) 58%,rgba(22,19,15,.78) 80%,rgba(22,19,15,.97) 100%)}



/* WordPress gives lazy images with sizes="auto" contain:size and a 3000x1500
   placeholder; outside the old square grid that set every tile 1500px tall.
   Proportions come from an inline aspect-ratio set in class-gallery.php. */
.gal .gal__i img{contain:none;contain-intrinsic-size:none}


/* Gallery: metro, no crop (Scolly 30/09/2026) -----------------------------
   Cells take the gallery's own proportions (--gal-ar, set per gallery in
   class-gallery.php from the shape most of its shots share), so those shots
   fill their cells uncut. A shot of another shape (.gal__i--fit) is shown
   whole on a ground matched to its own background. */
.gal__i img{aspect-ratio:var(--gal-ar,1)}
.gal__i--fit img{object-fit:contain}
@media (max-width:900px){
  .gal__i:nth-child(6n+1) img,
  .gal__i:nth-child(6n+4) img{aspect-ratio:var(--gal-ar,1)}
}

/* Large metro tiles: the image fills the 2x2 cell outright. A percentage
   height does not resolve against a spanned grid cell. */
@media (min-width:901px){
  .gal__i:nth-child(6n+1) img,
  .gal__i:nth-child(6n+4) img{position:absolute;inset:0;height:100%}
}

/* Gallery: incomplete last block (Scolly 30/09/2026) ----------------------
   A large tile needs two singles beside it to give its two rows height.
   When the gallery does not divide by three, the last large tile has one
   single or none, its second row collapses and the square shot is cut to
   a letterbox. A large tile in the last two places is set as a single. */
.gal .gal__i:is(:nth-child(6n+1),:nth-child(6n+4)):is(:nth-last-child(1),:nth-last-child(2)){grid-column:auto;grid-row:auto}
.gal .gal__i:is(:nth-child(6n+1),:nth-child(6n+4)):is(:nth-last-child(1),:nth-last-child(2)) img{position:static;inset:auto;height:auto;aspect-ratio:var(--gal-ar,1)}

/* Contact widget: team block (08/10/2026) */
.team{margin-top:34px;max-width:52ch}
.team__h{font-weight:700;font-size:1.25rem;line-height:1.3;margin:0}
.team__list{list-style:none;margin:20px 0 0;padding:0;display:grid;gap:18px}
.team__m{margin:0;padding-top:16px;border-top:1px solid currentColor;border-top-color:color-mix(in srgb,currentColor 22%,transparent)}
.team__n{margin:0;font-size:1rem;line-height:1.4}
.team__n strong{font-weight:700}
.team__r{display:block;opacity:.75;font-size:.875rem;letter-spacing:.02em;margin-top:2px}
.team__t{margin:8px 0 0;font-size:.9375rem;line-height:1.55;opacity:.85}

.team__c{margin:10px 0 0;display:flex;flex-wrap:wrap;gap:4px 20px;font-size:.9375rem;line-height:1.5}
.team__c a{color:inherit;text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:1px;padding:6px 0}
.team__c a:hover,.team__c a:focus-visible{text-decoration-thickness:2px}

.team__n strong{color:var(--ink-cyan)}

/* Accreditation plates (08/10/2026): equal visible marks, 93% of the plate.
   FSC panel is 400/490 of its artwork, so the file runs taller and its
   caption sits in the plate padding; PEFC label is full bleed; Amtivo badge
   is 93% of its file. */
.acc__plate--real img{flex-shrink:0}
.acc__plate--real img[src*="fsc-mark"]{height:114%}
.acc__plate--real img[src*="pefc-label"]{height:93%}


/* Gallery: mixed shapes as even rows (Scolly 09/10/2026) ------------------
   Set by class-gallery.php when a gallery's shots are not all one shape.
   Each tile grows in proportion to its own ratio (--ar), so every tile in a
   row ends the same height and every shot shows whole: no crop, no fill.
   The filler keeps a short last row at natural size instead of stretching. */
.gal.gal--rows{display:flex;flex-wrap:wrap;--rh:clamp(180px,19vw,260px)}
.gal.gal--rows::after{content:"";flex:999 1 0}
.gal.gal--rows > .gal__i.gal__i.gal__i{flex:var(--ar,1) 1 calc(var(--ar,1) * var(--rh));
     grid-column:auto;grid-row:auto;background:none}
.gal.gal--rows > .gal__i.gal__i.gal__i > img{position:static;inset:auto;width:100%;height:auto;
     aspect-ratio:var(--ar,1);object-fit:cover}
@media (max-width:560px){
  .gal.gal--rows > .gal__i.gal__i.gal__i{flex:1 1 100%}
}
