@layer components {
  /* ===
     Header · nav · mega-menu · buttons · cards · footer · forms · overlays
     === */

  /* === preloader
     Shown by an inline <head> script on the first view of a session only; the
     `display:none` default and the `html.is-loading` reveal both live inline, so
     this block only carries the choreography. */

  .preloader {
    background: transparent;
    color: var(--d-text);
    pointer-events: none;
  }

  /* Two halves that split at the cut line on exit. Transform-only. */
  .preloader::before,
  .preloader::after {
    content: '';
    position: absolute;
    inset-inline: 0;
    height: 50.2%; /* a hair over half, so no seam shows at fractional DPRs */
    background: var(--d-bg);
    transition: transform var(--d-base) var(--e-in-out);
  }

  .preloader::before { inset-block-start: 0; }
  .preloader::after { inset-block-end: 0; }

  .preloader.is-done::before { transform: translateY(-100%); }
  .preloader.is-done::after { transform: translateY(100%); }

  .preloader__inner {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: grid;
    place-content: center;
    transition: opacity 200ms linear;
  }

  .preloader.is-done .preloader__inner { opacity: 0; }

  .preloader__logo { position: relative; width: 160px; }
  .preloader__logo svg { width: 160px; height: auto; }

  /* The colour copy sits exactly over the dim one and is revealed left to right,
     behind the line — the cut exposing the metal. */
  .preloader__logo-full {
    position: absolute;
    inset: 0;
    clip-path: inset(0 100% 0 0);
    animation: pre-reveal 700ms var(--e-in-out) 120ms forwards;
  }

  .preloader__line {
    position: absolute;
    inset-block: -18px;
    inset-inline-start: 0;
    width: 2px;
    background: var(--red);
    box-shadow: 0 0 18px 1px var(--red-glow);
    opacity: 0;
    animation: pre-cut 700ms var(--e-in-out) 120ms;
  }

  @keyframes pre-reveal { to { clip-path: inset(0 0 0 0); } }

  @keyframes pre-cut {
    0% { transform: translateX(0); opacity: 0; }
    10% { opacity: 1; }
    88% { opacity: 1; }
    100% { transform: translateX(160px); opacity: 0; }
  }

  .preloader__pct {
    position: absolute;
    z-index: 2;
    inset-block-end: var(--s7);
    inset-inline-start: var(--gutter);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.18em;
    color: var(--d-muted);
    transition: opacity 200ms linear;
  }

  .preloader.is-done .preloader__pct { opacity: 0; }

  /* Reduced motion: one plain fade. No line, no split, no counter animation. */
  @media (prefers-reduced-motion: reduce) {
    .preloader {
      background: var(--d-bg);
      opacity: 1;
      transition: opacity 250ms linear;
    }

    .preloader::before,
    .preloader::after { display: none; }
    .preloader__logo-full { clip-path: none; animation: none; }
    .preloader__line { display: none; }
    .preloader.is-done { opacity: 0; }
  }

  .scroll-progress {
    position: fixed;
    inset-block-start: 0;
    inset-inline: 0;
    z-index: 120;
    height: 2px;
    background: var(--red);
    transform: scaleX(0);
    transform-origin: left center;
    pointer-events: none;
    will-change: transform;
  }

  .site-header {
    position: sticky;
    inset-block-start: 0;
    z-index: 100;
    height: var(--header-h);
    background: transparent;
    transition: background var(--d-base) var(--e-out),
                border-color var(--d-base) var(--e-out);
    border-block-end: 1px solid transparent;
  }

  /* Every page opens with a dark hero or a dark catalog band, and the header sits on
     top of it. So while it is transparent it must use the dark token set regardless of
     the page's own theme — otherwise the nav on a light catalog page renders near-black
     text on the near-black band. Once solidified it takes the page theme. */
  .site-header:not(.is-stuck) {
    --text: var(--d-text);
    --muted: var(--d-muted);
    --line: var(--d-line);
    --surface: var(--d-surface);
    --raise: var(--d-raise);
    --accent-text: var(--red-hot);

    color: var(--d-text);
  }

  /* Solidifies after 40px of scroll — nav.js toggles .is-stuck. */
  .site-header.is-stuck {
    background: color-mix(in srgb, var(--surface) 92%, transparent);
    backdrop-filter: blur(14px) saturate(1.1);
    border-block-end-color: var(--line);
  }

  /* Three zones. Below 1100px the nav is display:none and drops out of the grid
     entirely, leaving [logo][actions]; from 1100px the `1fr auto 1fr` template puts
     the link group in the exact centre of the wrapper, because two equal fr tracks
     always leave the auto track centred between them. */
  .site-header__inner {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    gap: var(--s4);
    height: 100%;
  }

  @media (min-width: 1100px) {
    .site-header__inner { grid-template-columns: 1fr auto 1fr; gap: var(--s5); }
  }

  .brand {
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;
    justify-self: start;
    text-decoration: none;
    color: var(--text);
  }

  /* Height-only scaling. `aspect-ratio` rather than the SVG's own width attribute:
     the attribute is a rounded integer, so at 40px tall it resolved to 149px instead
     of 149.49px and the box was 0.3% out of ratio. Declaring the ratio makes the
     lockup exact at any height. */
  .brand svg,
  .brand img { width: auto; height: 32px; aspect-ratio: 583 / 156; }

  @media (min-width: 1100px) {
    .brand svg,
    .brand img { height: 40px; }
  }

  .site-footer .brand svg { height: 34px; }

  /* The logo geometry, defined once and referenced by <use>. Takes no space. */
  .sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

  /* Wordmark takes the context colour; the geometric mark stays red. */
  .brand__mark { color: var(--red); }
  .brand__word { color: currentColor; }

  .nav {
    display: none;
    align-items: center;
    gap: 32px;
  }

  @media (min-width: 1100px) {
    .nav { display: flex; }
  }

  .nav__link {
    position: relative;
    padding-block: var(--s2);
    font-size: 16px;
    font-weight: 500;
    letter-spacing: -0.005em;
    text-decoration: none;
    white-space: nowrap;
    background: none;
    border: 0;
    color: inherit;
  }

  /* Underline draws from the left — the cut motif at link scale.
     2px, offset 6px below the link box. */
  .nav__link::after {
    content: '';
    position: absolute;
    inset-block-end: -6px;
    inset-inline: 0;
    height: 2px;
    background: var(--red);
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform var(--d-base) var(--e-out);
  }

  .nav__link:hover::after,
  .nav__link:focus-visible::after,
  .nav__link[aria-expanded='true']::after,
  .nav__link[aria-current='page']::after { transform: scaleX(1); }

  .nav__link[aria-current='page'] { color: var(--text); }

  .nav__caret {
    display: inline-block;
    width: 0.5em;
    margin-inline-start: 0.4em;
    transition: transform var(--d-fast) var(--e-out);
  }

  .nav__link[aria-expanded='true'] .nav__caret { transform: rotate(180deg); }

  .header-actions {
    display: flex;
    align-items: center;
    justify-self: end;
    gap: var(--s3);
  }

  .btn {
    --btn-bg: transparent;
    --btn-fg: var(--text);
    --btn-line: var(--line);

    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--s2);
    padding: var(--s3) var(--s5);
    min-height: 44px;
    background: var(--btn-bg);
    color: var(--btn-fg);
    border: 1px solid var(--btn-line);
    border-radius: var(--radius);
    font-family: var(--f-mono);
    font-size: var(--t-sm);
    font-weight: 500;
    letter-spacing: 0.08em;
    line-height: 1;
    text-transform: uppercase;
    text-decoration: none;
    white-space: nowrap;
    transition: background var(--d-fast) var(--e-out),
                color var(--d-fast) var(--e-out),
                border-color var(--d-fast) var(--e-out),
                transform var(--d-fast) var(--e-out);
  }

  .btn:hover { color: var(--btn-fg); }

  /* Filled red: white bold text at ≥16px only — never body copy. */
  .btn--primary {
    --btn-bg: var(--red-ui);
    --btn-fg: #fff;
    --btn-line: var(--red-ui);

    font-size: 16px;
    font-weight: 600;
  }

  .btn--primary:hover { --btn-bg: #c60500; --btn-line: #c60500; }

  .btn--outline { --btn-line: var(--red); --btn-fg: var(--text); }

  .btn--outline:hover { --btn-bg: var(--red-ui); --btn-fg: #fff; --btn-line: var(--red-ui); }

  .btn--ghost:hover { --btn-line: var(--text); }

  .btn--sm { padding: var(--s2) var(--s3); min-height: 34px; font-size: var(--t-xs); }
  .btn--lg { padding: var(--s4) var(--s6); min-height: 54px; }
  .btn--block { display: flex; width: 100%; }

  /* Header CTA. Red outline on the dark band; on hover the fill sweeps in from the
     left rather than cross-fading — the same left-origin gesture as every cut line.
     `min-height` holds the 44px tap target without touching the specified padding. */
  .btn--cta {
    display: none;
    padding: 12px 22px;
    min-height: 44px;
    font-size: 13px;
    letter-spacing: 0.14em;
    overflow: hidden;
    isolation: isolate;
    --btn-line: var(--red);
  }

  @media (min-width: 560px) {
    .btn--cta { display: inline-flex; }
  }

  .btn--cta::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    background: var(--red-ui);
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform 180ms var(--e-out);
  }

  .btn--cta:hover,
  .btn--cta:focus-visible { --btn-fg: #fff; --btn-line: var(--red-ui); color: #fff; }
  .btn--cta:hover::before,
  .btn--cta:focus-visible::before { transform: scaleX(1); }

  /* Pressed: 1px down with an inset edge. Machined, not bouncy. */
  .btn:active { transform: translateY(1px); box-shadow: inset 0 1px 0 rgb(0 0 0 / 0.28); }
  .btn[data-magnetic]:active { transform: translate3d(var(--mx, 0), calc(var(--my, 0px) + 1px), 0); }

  .btn[disabled],
  .btn[aria-disabled='true'] { opacity: 0.5; pointer-events: none; }

  /* Magnetic hover — nav.js writes --mx/--my. Pointer-coarse never gets it. */
  @media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
    .btn[data-magnetic] {
      transform: translate3d(var(--mx, 0), var(--my, 0), 0);
      transition: transform var(--d-base) var(--e-out),
                  background var(--d-fast) var(--e-out),
                  color var(--d-fast) var(--e-out),
                  border-color var(--d-fast) var(--e-out);
    }
  }

  /* Loading state on form submit. */
  .btn.is-loading { pointer-events: none; color: transparent; }

  .btn.is-loading::after {
    content: '';
    position: absolute;
    width: 16px;
    height: 16px;
    border: 2px solid rgb(255 255 255 / 0.35);
    border-top-color: #fff;
    border-radius: 50%;
    animation: spin 620ms linear infinite;
  }

  @keyframes spin { to { transform: rotate(360deg); } }

  /* === mega-menu
     A designed panel, not a floating set of lists. Five equal columns divided by
     hairlines, each with a tint bar, a one-line family name, its computed dimension
     count and a red "Sve o …" tail link. The hairlines and the tail links are what
     stop the short families (Bakar, Bronza) from reading as dead space.

     Opacity + translate rather than a clip-path: a clip would cut the 2px cut line
     that draws across the top edge, which is the panel's opening gesture. */
  .mega {
    --mega-pad: 28px;

    position: absolute;
    inset-inline: 0;
    inset-block-start: var(--header-h);
    z-index: 99;
    background: var(--d-surface);
    color: var(--d-text);
    border-block-start: 1px solid var(--d-line);
    border-block-end: 1px solid var(--d-line);
    box-shadow: 0 24px 60px rgb(0 0 0 / 0.55);

    visibility: hidden;
    opacity: 0;
    transform: translateY(-10px);
    /* Closing is the fast direction and carries no stagger. */
    transition: opacity 140ms var(--e-out), transform 140ms var(--e-out), visibility 0s linear 140ms;
  }

  .mega[data-open='true'] {
    visibility: visible;
    opacity: 1;
    transform: translateY(0);
    transition: opacity 200ms var(--e-out), transform 200ms var(--e-out), visibility 0s;
  }

  /* Desktop only, and `display: none` rather than merely hidden.
     The panel this replaced was closed with `clip-path: inset(0 0 100% 0)`, which
     clipped it in both axes; opacity and visibility do not, so it stayed fully laid
     out. At 390px its five `white-space: nowrap` columns pushed the document to
     488px wide and every page scrolled sideways. It is `inert`, its trigger is hidden
     below 1100px and the mobile overlay covers materials there, so nothing is lost by
     not laying it out at all. */
  .mega { display: none; }

  @media (min-width: 1100px) {
    .mega { display: block; }
  }

  /* The cut: 2px of red drawn left→right across the panel's top edge as it opens. */
  .mega__cut {
    position: absolute;
    inset-block-start: -1px;
    inset-inline: 0;
    height: 2px;
    background: var(--red);
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform 260ms var(--e-out);
  }

  .mega[data-open='true'] .mega__cut { transform: scaleX(1); }

  /* Bleeding the grid out by one column padding keeps the first column's text on the
     page grid while every column still gets the same 28px of breathing room. */
  .mega__grid {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    margin-inline: calc(var(--mega-pad) * -1);
    padding-block: var(--s7) var(--s6);
  }

  .mega__col {
    min-width: 0;
    padding-inline: var(--mega-pad);
    display: flex;
    flex-direction: column;
  }

  .mega__col + .mega__col { border-inline-start: 1px solid var(--d-line); }

  /* Between 1100px (where the panel first appears) and 1200px the full 28px of column
     padding would leave "Industrijska plastika" 2.5px of clearance on one nowrap line.
     Trimming the padding here buys it 15px instead. */
  @media (max-width: 1199px) {
    .mega { --mega-pad: 20px; }
  }

  /* Columns arrive in sequence on open only — closing is a single 140ms fade. */
  .mega[data-open='true'] .mega__col {
    animation: mega-col 200ms var(--e-out) both;
    animation-delay: calc(var(--i, 0) * 30ms);
  }

  @keyframes mega-col {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
  }

  /* The head is a block, not a baseline row: the count sits under the name, so a long
     family name can never push it out of line with the other four columns. */
  .mega__head {
    padding-block-end: var(--s4);
    margin-block-end: var(--s3);
    border-block-end: 1px solid var(--d-line);
  }

  .mega__bar {
    display: block;
    width: 20px;
    height: 4px;
    margin-block-end: var(--s3);
    background: var(--mega-tint, var(--m-alu));
  }

  .mega__name {
    display: block;
    font-family: var(--f-display);
    font-size: 17px;
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1.1;
    color: var(--d-text);
    white-space: nowrap;
  }

  .mega__count {
    display: block;
    margin-block-start: 6px;
    font-size: 11px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--d-muted);
  }

  .mega__list { list-style: none; margin: 0; padding: 0; }

  /* One shared row treatment: 40px tall, muted, with a red tick that slides in from
     the left edge on hover, focus and for the page you are on. */
  .mega__link,
  .mega__all {
    position: relative;
    display: flex;
    align-items: center;
    padding-inline-start: 0;
    text-decoration: none;
    transition: color 140ms var(--e-out), padding-inline-start 140ms var(--e-out);
  }

  .mega__link {
    min-height: 40px;
    font-size: 14.5px;
    color: var(--d-muted);
  }

  .mega__link::before,
  .mega__all::before {
    content: '';
    position: absolute;
    inset-inline-start: -8px;
    inset-block: 25%;
    width: 2px;
    background: var(--red);
    transform: scaleY(0);
    transform-origin: center;
    transition: transform 140ms var(--e-out);
  }

  .mega__link:hover,
  .mega__link:focus-visible { color: var(--d-text); padding-inline-start: 4px; }

  .mega__link:hover::before,
  .mega__link:focus-visible::before,
  .mega__link[aria-current='page']::before,
  .mega__all[aria-current='page']::before { transform: scaleY(1); }

  .mega__link[aria-current='page'] { color: var(--d-text); padding-inline-start: 4px; }

  /* The tail link. `margin-block-start: auto` pins it to the bottom of the column, so
     all five end on the same line however many products the family has. */
  .mega__all {
    margin-block-start: auto;
    padding-block-start: var(--s4);
    min-height: 40px;
    /* Flex collapses the whitespace between the label and the arrow, so the gap has
       to be declared rather than typed. */
    gap: 0.6em;
    font-size: 11px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--red);
  }

  .mega__all:hover,
  .mega__all:focus-visible { color: var(--d-text); padding-inline-start: 4px; }

  .mega__all:hover::before,
  .mega__all:focus-visible::before { transform: scaleY(1); }

  .mega__foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--s4);
    padding-block: var(--s5);
    border-block-start: 1px solid var(--d-line);
  }

  /* Reduced motion: the panel is simply there or not. No slide, no stagger, no draw. */
  @media (prefers-reduced-motion: reduce) {
    .mega,
    .mega[data-open='true'] { transform: none; transition: opacity 0s, visibility 0s; }
    .mega__cut { transition: none; }
    .mega[data-open='true'] .mega__col { animation: none; }
    .mega__link,
    .mega__all,
    .mega__link::before,
    .mega__all::before { transition: none; }
  }

  .menu-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    background: none;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    color: inherit;
  }

  @media (min-width: 1100px) {
    .menu-toggle { display: none; }
  }

  .menu-toggle__bars,
  .menu-toggle__bars::before,
  .menu-toggle__bars::after {
    display: block;
    width: 18px;
    height: 1.5px;
    background: currentColor;
    transition: transform var(--d-base) var(--e-out), opacity var(--d-fast) linear;
  }

  .menu-toggle__bars::before,
  .menu-toggle__bars::after { content: ''; position: absolute; }

  .menu-toggle__bars::before { transform: translateY(-6px); }
  .menu-toggle__bars::after { transform: translateY(6px); }

  .menu-toggle[aria-expanded='true'] .menu-toggle__bars { background: transparent; }
  .menu-toggle[aria-expanded='true'] .menu-toggle__bars::before { transform: rotate(45deg); background: var(--red); }
  .menu-toggle[aria-expanded='true'] .menu-toggle__bars::after { transform: rotate(-45deg); background: var(--red); }

  .mobile-menu {
    position: fixed;
    inset: 0;
    z-index: 98;
    display: flex;
    flex-direction: column;
    background: var(--d-bg);
    color: var(--d-text);
    padding-block-start: var(--header-h);
    overflow-y: auto;
    overscroll-behavior: contain;
    clip-path: inset(0 0 100% 0);
    visibility: hidden;
    transition: clip-path 380ms var(--e-out), visibility 0s linear 380ms;
  }

  .mobile-menu[data-open='true'] {
    clip-path: inset(0 0 0 0);
    visibility: visible;
    transition: clip-path 380ms var(--e-out), visibility 0s;
  }

  .mobile-menu__list { list-style: none; margin: 0; padding: var(--s5) 0 var(--s8); }

  .mobile-menu__item {
    border-block-end: 1px solid var(--d-line);
    /* Staggered entrance — nav.js sets --i per item. */
    opacity: 0;
    transform: translateY(14px);
    transition: opacity var(--d-base) var(--e-out), transform var(--d-base) var(--e-out);
    transition-delay: calc(var(--i, 0) * 42ms);
    margin: 0;
  }

  .mobile-menu[data-open='true'] .mobile-menu__item { opacity: 1; transform: none; }

  .mobile-menu__link {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--s4);
    width: 100%;
    padding-block: var(--s5);
    background: none;
    border: 0;
    color: inherit;
    font-family: var(--f-display);
    font-size: clamp(24px, 6vw, 34px);
    font-weight: 700;
    letter-spacing: -0.03em;
    text-align: left;
    text-decoration: none;
  }

  /* The same computed dimension count the desktop panel shows, at a size that reads as
     an annotation next to a 34px family name rather than competing with it. */
  .mobile-menu__count {
    flex: none;
    font-size: 11px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--d-muted);
  }

  .mobile-menu__sub { list-style: none; margin: 0; padding: 0 0 var(--s5); display: grid; gap: var(--s1); }

  .mobile-menu__sub[hidden] { display: none; }
  .mobile-menu__sub li { margin: 0; }

  .mobile-menu__sublink {
    display: block;
    padding-block: var(--s2);
    color: var(--d-muted);
    font-size: var(--t-sm);
    text-decoration: none;
  }

  body.is-locked { overflow: hidden; }

  .card {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    overflow: hidden;
    text-decoration: none;
    color: inherit;
    isolation: isolate;
    transition: border-color var(--d-base) var(--e-out),
                transform var(--d-base) var(--e-out);
  }

  .card:hover { border-color: color-mix(in srgb, var(--tint) 55%, var(--line)); }

  /**
   * Catalog product photography (P4). Deliberately *not* graded: a buyer choosing
   * between brass and bronze is reading the hue, and a house filter that flattens the
   * two together would be actively misleading. What they get instead is consistency of
   * frame — one hairline border and one 3:2 crop for every product, so the set looks
   * ordered without any of the colours being touched.
   */
  .card__media {
    position: relative;
    aspect-ratio: 3 / 2;
    overflow: hidden;
    background: var(--raise);
    box-shadow: inset 0 0 0 1px var(--line);
  }

  .card__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform var(--d-cine) var(--e-out);
  }

  .card:hover .card__media img { transform: scale(1.035); }

  /* Material tint bleeds in from the top edge on hover — never a fill. */
  .card__media::after {
    content: '';
    position: absolute;
    inset-block-start: 0;
    inset-inline: 0;
    height: 2px;
    background: var(--tint);
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform var(--d-base) var(--e-out);
  }

  .card:hover .card__media::after { transform: scaleX(1); }

  .card__body { display: flex; flex-direction: column; gap: var(--s3); flex: 1; padding: var(--s5); }

  .card__title {
    font-family: var(--f-display);
    font-size: var(--t-h3);
    font-weight: 700;
    letter-spacing: -0.02em;
  }

  .card__desc { color: var(--muted); font-size: var(--t-sm); flex: 1; }

  .card__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s2) var(--s4);
    padding-block-start: var(--s3);
    border-block-start: 1px solid var(--line);
    font-family: var(--f-mono);
    font-size: var(--t-xs);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted);
  }

  .card__tags { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--s2); }
  .card__tags li { margin: 0; }

  .tag {
    display: inline-block;
    padding: 3px var(--s2);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    font-family: var(--f-mono);
    font-size: var(--t-xs);
    letter-spacing: 0.06em;
    color: var(--muted);
  }

  /* Specular tilt — only with a fine pointer and motion allowed. */
  @media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
    .card[data-tilt] {
      transform: perspective(900px)
                 rotateX(var(--rx, 0deg))
                 rotateY(var(--ry, 0deg))
                 translateZ(0);
      transition: transform var(--d-base) var(--e-out), border-color var(--d-base) var(--e-out);
    }

    .card[data-tilt]::before {
      content: '';
      position: absolute;
      inset: 0;
      z-index: 2;
      pointer-events: none;
      opacity: 0;
      background: radial-gradient(
        420px circle at var(--px, 50%) var(--py, 50%),
        color-mix(in srgb, var(--tint) 22%, transparent),
        transparent 62%
      );
      transition: opacity var(--d-base) var(--e-out);
    }

    .card[data-tilt]:hover::before { opacity: 1; }
  }

  /* === crop marks (P2)
     8px registration ticks in the four corners, the way a technical drawing is
     trimmed. One implementation, one class. Each pseudo-element paints two corners
     with four solid-colour gradient images, so no extra markup is needed anywhere.
     `.related__item` opts in from here rather than from the generator, because it is
     produced in three different places.

     They go on card-shaped surfaces only. On the full-bleed service rows they drew a
     frame around something that has no frame, which reads as a mistake rather than as
     a registration mark — those keep the plain hairline rule instead. */

  .ticks,
  .related__item { position: relative; }

  .ticks::before,
  .ticks::after,
  .related__item::before,
  .related__item::after {
    content: '';
    position: absolute;
    inset: 5px;
    z-index: 4;
    pointer-events: none;
    background-repeat: no-repeat;
    --tick: color-mix(in srgb, currentColor 38%, transparent);
  }

  .ticks::before,
  .related__item::before {
    background-image:
      linear-gradient(var(--tick) 0 0), linear-gradient(var(--tick) 0 0),
      linear-gradient(var(--tick) 0 0), linear-gradient(var(--tick) 0 0);
    background-size: 8px 1px, 1px 8px, 8px 1px, 1px 8px;
    background-position: left top, left top, right top, right top;
  }

  .ticks::after,
  .related__item::after {
    background-image:
      linear-gradient(var(--tick) 0 0), linear-gradient(var(--tick) 0 0),
      linear-gradient(var(--tick) 0 0), linear-gradient(var(--tick) 0 0);
    background-size: 8px 1px, 1px 8px, 8px 1px, 1px 8px;
    background-position: left bottom, left bottom, right bottom, right bottom;
  }

  .ticks:hover::before,
  .ticks:hover::after,
  .ticks:focus-within::before,
  .ticks:focus-within::after,
  .related__item:hover::before,
  .related__item:hover::after,
  .related__item:focus-visible::before,
  .related__item:focus-visible::after { --tick: var(--red); }

  .chip {
    display: inline-flex;
    align-items: center;
    gap: var(--s2);
    padding: 2px var(--s2);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    font-family: var(--f-mono);
    font-size: var(--t-xs);
    letter-spacing: 0.06em;
    white-space: nowrap;
    color: var(--muted);
    background: none;
  }

  .chip::before { content: ''; width: 6px; height: 6px; background: currentColor; flex: 0 0 auto; }

  .chip--ok { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 40%, transparent); }
  .chip--wait { color: var(--wait); border-color: color-mix(in srgb, var(--wait) 40%, transparent); }

  /* Toggleable filter chip. */
  .chip--toggle { cursor: pointer; transition: all var(--d-fast) var(--e-out); }
  .chip--toggle:hover { border-color: var(--text); color: var(--text); }

  .chip--toggle[aria-pressed='true'] {
    color: var(--text);
    border-color: var(--red);
    background: color-mix(in srgb, var(--red) 10%, transparent);
  }

  .chip--toggle[aria-pressed='true']::before { background: var(--red); }

  .field { display: flex; flex-direction: column; gap: var(--s2); }

  .field__label {
    font-family: var(--f-mono);
    font-size: var(--t-xs);
    font-weight: 500;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--muted);
  }

  .field__label .req { color: var(--accent-text); }

  .input,
  .select,
  .textarea {
    width: 100%;
    padding: var(--s3) var(--s4);
    min-height: 48px;
    background: var(--raise);
    color: var(--text);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    font-size: var(--t-body);
    transition: border-color var(--d-fast) var(--e-out), background var(--d-fast) var(--e-out);
  }

  .input::placeholder,
  .textarea::placeholder { color: color-mix(in srgb, var(--muted) 75%, transparent); }

  .input:hover, .select:hover, .textarea:hover { border-color: color-mix(in srgb, var(--text) 35%, var(--line)); }
  .input:focus, .select:focus, .textarea:focus { border-color: var(--red); }

  .textarea { min-height: 152px; line-height: 1.55; }

  .select {
    appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                      linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: calc(100% - 20px) center, calc(100% - 14px) center;
    background-size: 6px 6px, 6px 6px;
    background-repeat: no-repeat;
    padding-inline-end: var(--s8);
  }

  /**
   * === form finish (P10)
   *
   * Floating labels, scoped to `.field--float` so the calculator and the catalog
   * filters keep their boxed data controls — those are instruments, not a form.
   *
   * `:has()` does the work because the label precedes its input in the DOM, which no
   * sibling combinator can walk backwards from. Where `:has()` is unsupported the
   * label simply stays above the field: the same layout this had before, still
   * perfectly usable. Every floatable control carries `placeholder=" "` so
   * `:placeholder-shown` has something to report on.
   */
  .field--float {
    position: relative;
    padding-block-start: 18px;
    gap: 0;
  }

  .field--float .input,
  .field--float .textarea {
    padding-inline: 0;
    background: none;
    border: 0;
    border-block-end: 1px solid var(--line);
    border-radius: 0;
  }

  .field--float .input { min-height: 44px; }
  .field--float .textarea { min-height: 132px; padding-block-start: var(--s2); }

  .field--float .input:hover,
  .field--float .textarea:hover { border-block-end-color: color-mix(in srgb, var(--text) 40%, var(--line)); }

  /* The underline draws in from the left on focus — the cut, at field scale. */
  .field--float::after {
    content: '';
    position: absolute;
    inset-block-end: 0;
    inset-inline: 0;
    height: 2px;
    background: var(--red);
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform var(--d-fast) var(--e-out);
  }

  .field--float:focus-within::after { transform: scaleX(1); }

  .field--float .field__label {
    position: absolute;
    inset-block-start: 30px;
    inset-inline-start: 0;
    transform-origin: left top;
    pointer-events: none;
    transition: transform 180ms var(--e-out), color 180ms var(--e-out);
  }

  /* Placeholders stay invisible until the label has moved out of their way. */
  .field--float .input::placeholder,
  .field--float .textarea::placeholder { opacity: 0; transition: opacity 180ms linear; }
  .field--float:focus-within .input::placeholder,
  .field--float:focus-within .textarea::placeholder { opacity: 1; }

  @supports selector(:has(*)) {
    .field--float:has(.input:focus) .field__label,
    .field--float:has(.textarea:focus) .field__label,
    .field--float:has(.input:not(:placeholder-shown)) .field__label,
    .field--float:has(.textarea:not(:placeholder-shown)) .field__label {
      transform: translateY(-26px) scale(0.92);
    }

    .field--float:has(:focus) .field__label { color: var(--accent-text); }
  }

  /* The textarea's label sits at its top edge, not vertically centred in 132px. */
  .field--float:has(.textarea) .field__label { inset-block-start: 26px; }

  .field__error {
    display: none;
    margin-block-start: var(--s2);
    font-family: var(--f-mono);
    font-size: var(--t-xs);
    letter-spacing: 0.04em;
    color: var(--accent-text);
  }

  .field.has-error .input,
  .field.has-error .select,
  .field.has-error .textarea { border-color: var(--red); }
  .field--float.has-error .input,
  .field--float.has-error .textarea { border-block-end-color: var(--red); }

  /* Validation messages slide in rather than appearing, so a message that changes
     while you are typing reads as one element moving, not two flickering. */
  .field.has-error .field__error {
    display: block;
    animation: field-error 160ms var(--e-out);
  }

  @keyframes field-error {
    from { opacity: 0; transform: translateY(-4px); }
    to { opacity: 1; transform: none; }
  }

  /* Checkbox — square, 2px radius, red check. */
  .check {
    display: grid;
    grid-template-columns: 20px 1fr;
    gap: var(--s3);
    align-items: start;
    font-size: var(--t-sm);
    color: var(--muted);
    cursor: pointer;
  }

  .check input {
    appearance: none;
    width: 20px;
    height: 20px;
    margin: 0;
    background: var(--raise);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    display: grid;
    place-content: center;
    cursor: pointer;
  }

  .check input::after {
    content: '';
    width: 10px;
    height: 6px;
    border-inline-start: 2px solid #fff;
    border-block-end: 2px solid #fff;
    transform: rotate(-45deg) scale(0);
    transition: transform var(--d-fast) var(--e-out);
  }

  .check input:checked { background: var(--red-ui); border-color: var(--red-ui); }
  .check input:checked::after { transform: rotate(-45deg) scale(1); }

  /* File input — native control styled as a drop plate. */
  .filefield {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--s4);
    padding: var(--s4);
    background: var(--raise);
    border: 1px dashed var(--line);
    border-radius: var(--radius);
    transition: border-color var(--d-fast) var(--e-out);
  }

  .filefield:hover,
  .filefield:focus-within { border-color: var(--red); }

  /* Dragover: the dashed hairline tightens to a solid 2px edge — the plate is armed. */
  .filefield.is-dragover {
    border-style: solid;
    border-width: 2px;
    border-color: var(--red);
    padding: calc(var(--s4) - 1px);
    background: color-mix(in srgb, var(--red) 6%, var(--raise));
  }

  .filefield input[type='file'] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
  }

  .filefield__text { font-size: var(--t-sm); color: var(--muted); min-width: 0; }
  .filefield__name { color: var(--text); word-break: break-all; }

  /* Honeypot — visually hidden AND aria-hidden, never a labelled field.
     The legacy form exposed a visible "UKPP" input; that is the bug this fixes. */
  .hp {
    position: absolute !important;
    left: -9999px !important;
    width: 1px !important;
    height: 1px !important;
    opacity: 0 !important;
    pointer-events: none !important;
  }

  .form-status {
    padding: var(--s4) var(--s5);
    border: 1px solid var(--line);
    border-inline-start: 2px solid var(--red);
    border-radius: var(--radius);
    background: var(--raise);
    font-size: var(--t-sm);
  }

  .form-status--ok { border-inline-start-color: var(--ok); }

  /* === floating widget docks
     Two fixed flex columns, one per bottom corner. Because the buttons are laid out
     by the dock rather than each positioning itself, they cannot overlap at any
     viewport — which is exactly what happened when the inquiry counter and a second
     bottom-right button both anchored themselves to the same corner. */

  .dock {
    position: fixed;
    z-index: 96;
    inset-block-end: calc(var(--dock-block) + env(safe-area-inset-bottom, 0px));
    display: flex;
    flex-direction: column;
    gap: var(--dock-gap);
    pointer-events: none;
  }

  .dock > * { pointer-events: auto; }

  .dock--right { inset-inline-end: calc(var(--dock-inline) + env(safe-area-inset-right, 0px)); align-items: flex-end; }
  .dock--left { inset-inline-start: calc(var(--dock-inline) + env(safe-area-inset-left, 0px)); align-items: flex-start; }

  @media (max-width: 560px) {
    .dock { --dock-inline: 14px; --dock-block: 14px; }
  }

  /* Square machined button — back-to-top and the assistant launcher share it. */
  .widget-btn {
    position: relative;
    display: inline-grid;
    place-content: center;
    width: var(--dock-size);
    height: var(--dock-size);
    background: var(--d-surface);
    color: var(--d-text);
    border: 1px solid var(--d-line);
    border-radius: var(--radius);
    box-shadow: 0 18px 44px rgb(0 0 0 / 0.5);
    transition: color var(--d-fast) var(--e-out),
                border-color var(--d-fast) var(--e-out),
                opacity 180ms var(--e-out),
                transform 180ms var(--e-out);
  }

  .widget-btn:hover,
  .widget-btn:focus-visible { border-color: var(--red); color: var(--red-hot); }

  /* Reserved space, so revealing it never nudges the inquiry counter. */
  .widget-btn[data-visible='false'] { opacity: 0; transform: translateY(8px); visibility: hidden; }
  .widget-btn[data-visible='true'] { opacity: 1; transform: none; visibility: visible; }

  .widget-btn__dot {
    position: absolute;
    inset-block-start: 7px;
    inset-inline-end: 7px;
    width: 6px;
    height: 6px;
    background: var(--red);
  }

  .widget-btn__tip {
    position: absolute;
    inset-inline-start: calc(100% + var(--s3));
    inset-block-end: 50%;
    transform: translateY(50%);
    padding: 5px var(--s3);
    background: var(--d-raise);
    border: 1px solid var(--d-line);
    color: var(--d-text);
    font-size: var(--t-xs);
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--d-fast) var(--e-out);
  }

  .widget-btn:hover .widget-btn__tip,
  .widget-btn:focus-visible .widget-btn__tip { opacity: 1; }

  @media (pointer: coarse) {
    .widget-btn__tip { display: none; }
  }

  .inquiry-fab {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: var(--s2);
    padding: var(--s3) var(--s5);
    min-height: var(--dock-size);
    background: var(--d-raise);
    color: var(--d-text);
    border: 1px solid var(--red);
    border-radius: var(--radius);
    box-shadow: 0 18px 44px rgb(0 0 0 / 0.5);
    font-family: var(--f-mono);
    font-size: var(--t-xs);
    font-weight: 500;
    letter-spacing: 0.1em;
    text-transform: uppercase;
  }

  /* Removed from the dock entirely when empty, so the back-to-top button drops into
     the corner instead of hovering over a gap. */
  .inquiry-fab[data-visible='false'] { display: none; }
  .inquiry-fab[data-visible='true'] { animation: dock-in var(--d-base) var(--e-out); }

  @keyframes dock-in {
    from { opacity: 0; transform: translateY(14px); }
    to { opacity: 1; transform: none; }
  }

  .inquiry-fab__count {
    display: inline-grid;
    place-content: center;
    min-width: 22px;
    height: 22px;
    padding-inline: 5px;
    background: var(--red-ui);
    color: #fff;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
  }

  /* One red ring pulse when an item is added. */
  .inquiry-fab.is-pulse::after {
    content: '';
    position: absolute;
    inset: -4px;
    border: 1px solid var(--red);
    border-radius: var(--radius);
    animation: ring 620ms var(--e-out) forwards;
    pointer-events: none;
  }

  @keyframes ring {
    from { opacity: 1; transform: scale(1); }
    to { opacity: 0; transform: scale(1.28); }
  }

  .inquiry-drawer {
    position: fixed;
    inset-block: 0;
    inset-inline-end: 0;
    z-index: 97;
    width: min(460px, 100vw);
    display: flex;
    flex-direction: column;
    background: var(--d-surface);
    color: var(--d-text);
    border-inline-start: 1px solid var(--d-line);
    box-shadow: -30px 0 80px rgb(0 0 0 / 0.6);
    transform: translateX(101%);
    visibility: hidden;
    transition: transform var(--d-base) var(--e-out), visibility 0s linear var(--d-base);
  }

  .inquiry-drawer[data-open='true'] {
    transform: none;
    visibility: visible;
    transition: transform var(--d-base) var(--e-out), visibility 0s;
  }

  .inquiry-drawer__head,
  .inquiry-drawer__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--s4);
    padding: var(--s5);
    flex: 0 0 auto;
  }

  .inquiry-drawer__head { border-block-end: 1px solid var(--d-line); }
  .inquiry-drawer__foot { border-block-start: 1px solid var(--d-line); flex-wrap: wrap; }

  .inquiry-drawer__body { flex: 1; overflow-y: auto; overscroll-behavior: contain; padding: var(--s3) var(--s5); }

  .inquiry-item {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: var(--s2) var(--s3);
    padding-block: var(--s4);
    border-block-end: 1px solid var(--d-line);
  }

  .inquiry-item__name { font-size: var(--t-sm); font-weight: 500; }
  .inquiry-item__dim { font-family: var(--f-mono); font-size: var(--t-xs); letter-spacing: 0.06em; color: var(--d-muted); }
  .inquiry-item__qty { display: flex; align-items: center; gap: var(--s2); }

  .qty {
    width: 74px;
    padding: var(--s1) var(--s2);
    min-height: 34px;
    background: var(--raise);
    color: inherit;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    font-family: var(--f-mono);
    font-size: var(--t-sm);
    text-align: right;
  }

  .icon-btn {
    display: inline-grid;
    place-content: center;
    width: 34px;
    height: 34px;
    background: none;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    color: var(--muted);
    font-size: 15px;
    line-height: 1;
    transition: color var(--d-fast) var(--e-out), border-color var(--d-fast) var(--e-out);
  }

  .icon-btn:hover { color: var(--red-hot); border-color: var(--red); }

  /* === Nikoma asistent
     Answers come from the catalogue and data/site.js only. The panel is dark-themed
     on every page so it reads as one consistent surface, light pages included. */

  .assistant {
    position: fixed;
    z-index: 97;
    inset-block-end: calc(var(--dock-block) + var(--dock-size) + var(--dock-gap) + env(safe-area-inset-bottom, 0px));
    inset-inline-start: calc(var(--dock-inline) + env(safe-area-inset-left, 0px));
    width: 380px;
    height: min(560px, calc(100svh - var(--dock-size) - 72px));
    display: flex;
    flex-direction: column;
    background: var(--d-surface);
    color: var(--d-text);
    border: 1px solid var(--d-line);
    border-block-start: 2px solid var(--red);
    border-radius: var(--radius);
    box-shadow: 0 30px 80px rgb(0 0 0 / 0.6);
    opacity: 0;
    transform: translateY(12px) scale(0.98);
    transform-origin: bottom left;
    visibility: hidden;
    transition: opacity var(--d-base) var(--e-out),
                transform var(--d-base) var(--e-out),
                visibility 0s linear var(--d-base);
  }

  .assistant[data-open='true'] {
    opacity: 1;
    transform: none;
    visibility: visible;
    transition: opacity var(--d-base) var(--e-out), transform var(--d-base) var(--e-out), visibility 0s;
  }

  /* Full-screen sheet on small viewports. */
  @media (max-width: 560px) {
    .assistant {
      inset: 0;
      width: auto;
      height: auto;
      border-inline: 0;
      border-block-end: 0;
      transform-origin: bottom center;
    }

    body.is-assistant-open { overflow: hidden; }
  }

  .assistant__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--s4);
    padding: var(--s5);
    border-block-end: 1px solid var(--d-line);
    flex: 0 0 auto;
  }

  .assistant__title { font-family: var(--f-display); font-size: 1.05rem; font-weight: 700; letter-spacing: -0.02em; }
  .assistant__sub { margin-block-start: 3px; color: var(--d-muted); letter-spacing: 0.08em; }

  .assistant__log {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: var(--s4);
    padding: var(--s5);
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
  }

  .msg { max-width: 92%; font-size: var(--t-sm); line-height: 1.55; }

  .msg--user {
    align-self: flex-end;
    padding: var(--s3) var(--s4);
    background: var(--d-raise);
    border: 1px solid var(--d-line);
    border-inline-end: 2px solid var(--red);
    border-radius: var(--radius);
  }

  .msg--bot { align-self: flex-start; padding-inline-start: var(--s4); border-inline-start: 2px solid var(--red); }

  .msg__cards { display: grid; gap: var(--s2); margin-block-start: var(--s3); }
  .msg__actions { display: flex; flex-wrap: wrap; gap: var(--s2); margin-block-start: var(--s3); }

  .msg-card {
    padding: var(--s3) var(--s4);
    background: var(--d-raise);
    border: 1px solid var(--d-line);
    border-radius: var(--radius);
  }

  .msg-card__dim { font-family: var(--f-mono); font-size: var(--t-sm); font-variant-numeric: tabular-nums; }
  .msg-card__meta { margin-block-start: 2px; font-size: var(--t-xs); color: var(--d-muted); }
  .msg-card__acts { display: flex; flex-wrap: wrap; gap: var(--s2); margin-block-start: var(--s3); }

  /* Typing indicator. Three dots, and never a claim to be a person. */
  .msg--typing { display: flex; gap: 5px; align-items: center; min-height: 20px; }

  .msg--typing span {
    width: 5px;
    height: 5px;
    background: var(--d-muted);
    animation: typing 1s var(--e-in-out) infinite;
  }

  .msg--typing span:nth-child(2) { animation-delay: 140ms; }
  .msg--typing span:nth-child(3) { animation-delay: 280ms; }

  @keyframes typing {
    0%, 60%, 100% { opacity: 0.3; transform: translateY(0); }
    30% { opacity: 1; transform: translateY(-3px); }
  }

  .assistant__chips { display: flex; flex-wrap: wrap; gap: var(--s2); padding: 0 var(--s5) var(--s4); }

  .assistant__chip {
    padding: 6px var(--s3);
    background: none;
    border: 1px solid var(--d-line);
    border-radius: var(--radius);
    color: var(--d-muted);
    font-size: var(--t-xs);
    text-align: left;
    transition: color var(--d-fast) var(--e-out), border-color var(--d-fast) var(--e-out);
  }

  .assistant__chip:hover,
  .assistant__chip:focus-visible { color: var(--d-text); border-color: var(--red); }

  .assistant__form {
    display: flex;
    gap: var(--s2);
    padding: var(--s4) var(--s5) calc(var(--s5) + env(safe-area-inset-bottom, 0px));
    border-block-start: 1px solid var(--d-line);
    flex: 0 0 auto;
  }

  .assistant__input {
    flex: 1;
    min-width: 0;
    padding: var(--s3) var(--s4);
    min-height: 44px;
    background: var(--d-raise);
    color: var(--d-text);
    border: 1px solid var(--d-line);
    border-radius: var(--radius);
    font-size: var(--t-sm);
  }

  .assistant__input:focus { border-color: var(--red); }
  .assistant__input::placeholder { color: color-mix(in srgb, var(--d-muted) 78%, transparent); }

  .assistant__send {
    display: inline-grid;
    place-content: center;
    width: 44px;
    height: 44px;
    flex: 0 0 auto;
    background: var(--red-ui);
    color: #fff;
    border: 1px solid var(--red-ui);
    border-radius: var(--radius);
    transition: background var(--d-fast) var(--e-out);
  }

  .assistant__send:hover { background: #c60500; }

  .drawer-scrim {
    position: fixed;
    inset: 0;
    z-index: 96;
    background: rgb(0 0 0 / 0.6);
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--d-base) var(--e-out), visibility 0s linear var(--d-base);
  }

  .drawer-scrim[data-open='true'] { opacity: 1; visibility: visible; transition: opacity var(--d-base) var(--e-out), visibility 0s; }

  /* Custom cursor — fine pointers only, never hides the native cursor on touch. */
  .cursor-ring {
    position: fixed;
    inset-block-start: 0;
    inset-inline-start: 0;
    z-index: 150;
    width: 26px;
    height: 26px;
    margin: -13px 0 0 -13px;
    border: 1px solid var(--red);
    border-radius: 50%;
    pointer-events: none;
    opacity: 0;
    transform: translate3d(-100px, -100px, 0) scale(1);
    transition: opacity var(--d-fast) linear, transform 90ms linear, border-color var(--d-fast) linear;
    will-change: transform;
  }

  .cursor-ring.is-on { opacity: 1; }
  .cursor-ring.is-hot { transform: translate3d(var(--cx), var(--cy), 0) scale(1.7); background: var(--red-glow); }

  @media (pointer: coarse), (prefers-reduced-motion: reduce) {
    .cursor-ring { display: none; }
  }

  /* === page transitions (P8)
     Where the browser supports cross-document view transitions, navigation snaps
     through dark — 140 ms out, 180 ms in. The at-rule is simply ignored elsewhere,
     and nav.js feature-tests for it before deciding whether to install the red-line
     wipe instead, so the two paths can never both run. */

  @view-transition { navigation: auto; }

  ::view-transition-old(root) {
    animation: vt-out 140ms var(--e-in-out) both;
  }

  ::view-transition-new(root) {
    animation: vt-in 180ms var(--e-out) both;
  }

  @keyframes vt-out { to { opacity: 0; filter: brightness(0.35); } }
  @keyframes vt-in { from { opacity: 0; filter: brightness(0.35); } }

  @media (prefers-reduced-motion: reduce) {
    ::view-transition-old(root),
    ::view-transition-new(root) { animation: none; }
  }

  /* Page transition — a red line wipes across before navigating. */
  .page-wipe {
    position: fixed;
    inset: 0;
    z-index: 160;
    pointer-events: none;
    display: grid;
    place-items: center;
    visibility: hidden;
  }

  .page-wipe::before {
    content: '';
    width: 100%;
    height: 2px;
    background: var(--red);
    transform: scaleX(0);
    transform-origin: left center;
  }

  .page-wipe.is-out { visibility: visible; }
  .page-wipe.is-out::before { animation: wipe-out 220ms var(--e-in-out) forwards; }
  .page-wipe.is-in { visibility: visible; }
  .page-wipe.is-in::before { animation: wipe-in 260ms var(--e-out) forwards; }

  @keyframes wipe-out { from { transform: scaleX(0); } to { transform: scaleX(1); } }
  @keyframes wipe-in { from { transform: scaleX(1); transform-origin: right center; } to { transform: scaleX(0); transform-origin: right center; } }

  @media (prefers-reduced-motion: reduce) {
    .page-wipe { display: none; }
  }

  [data-reveal] { will-change: transform, opacity, clip-path; }

  [data-reveal='up'] {
    opacity: 0;
    transform: translateY(24px);
    transition: opacity var(--d-slow) var(--e-out), transform var(--d-slow) var(--e-out);
    transition-delay: calc(var(--rd, 0) * 1ms);
  }

  /* The wipe clips the *contents*, never the observed element itself: an element
     clipped to `inset(100%)` has an empty intersection rect, so IntersectionObserver
     would never fire for it and the reveal could never start. */
  [data-reveal='mask'] > * {
    clip-path: inset(100% 0 0 0);
    transition: clip-path var(--d-cine) var(--e-out);
    transition-delay: calc(var(--rd, 0) * 1ms);
  }

  [data-reveal='mask'].is-in > * { clip-path: inset(0 0 0 0); }

  [data-reveal].is-in { opacity: 1; transform: none; }

  /* Split headline — words stagger in. The readable copy stays in the DOM
     as an sr-only sibling; the visible spans are aria-hidden. */
  .split__w {
    display: inline-block;
    opacity: 0;
    transform: translateY(0.42em);
    transition: opacity var(--d-base) var(--e-out), transform var(--d-base) var(--e-out);
    transition-delay: calc(var(--wi, 0) * 32ms);
  }

  [data-reveal='chars'].is-in .split__w { opacity: 1; transform: none; }

  @media (prefers-reduced-motion: reduce) {
    [data-reveal] { opacity: 1 !important; transform: none !important; }
    [data-reveal='mask'] > * { clip-path: none !important; }
    .split__w { opacity: 1 !important; transform: none !important; }
  }

  .site-footer { background: var(--d-bg); color: var(--d-text); border-block-start: 1px solid var(--d-line); }

  .site-footer a { color: var(--d-muted); text-decoration: none; }
  .site-footer a:hover { color: var(--d-text); }

  .footer-top { display: grid; grid-template-columns: 1fr; gap: var(--s7); padding-block: var(--s8); }

  @media (min-width: 900px) {
    .footer-top { grid-template-columns: minmax(0, 1.35fr) repeat(3, minmax(0, 1fr)); gap: var(--s6); }
  }

  .footer-col__title {
    font-family: var(--f-mono);
    font-size: var(--t-xs);
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--d-muted);
    padding-block-end: var(--s3);
    margin-block-end: var(--s3);
    border-block-end: 1px solid var(--d-line);
  }

  .footer-col ul { list-style: none; margin: 0; padding: 0; }
  .footer-col li { margin: 0; }
  .footer-col li + li { margin-top: var(--s1); }
  .footer-col a { display: block; padding-block: 3px; font-size: var(--t-sm); }

  /* Outlined wordmark, clipped by the footer edge. Stroke text is not universally
     supported, so the fallback below paints a solid low-opacity fill instead. */
  .footer-mark {
    margin-block-start: var(--s6);
    margin-block-end: calc(var(--s6) * -1);
    font-family: var(--f-display);
    font-size: 14vw;
    font-weight: 800;
    letter-spacing: -0.045em;
    line-height: 0.78;
    text-align: center;
    color: color-mix(in srgb, var(--d-text) 6%, transparent);
    user-select: none;
    overflow: hidden;
    opacity: 0.06;
    transition: opacity var(--d-cine) var(--e-out);
  }

  .footer-mark.is-in { opacity: 0.12; }

  @supports (-webkit-text-stroke: 1px currentColor) {
    .footer-mark {
      color: transparent;
      -webkit-text-stroke: 1px var(--d-text);
      opacity: 0.06;
    }
  }

  .footer-bottom {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--s4);
    padding-block: var(--s5);
    border-block-start: 1px solid var(--d-line);
    font-family: var(--f-mono);
    font-size: var(--t-xs);
    letter-spacing: 0.06em;
    color: var(--d-muted);
  }

  .footer-credit { margin-inline-start: auto; }
  .footer-credit a { text-decoration: none; }
  .site-footer .footer-credit a:hover { color: var(--red-hot); }

  .faq { border-block-start: 1px solid var(--line); }

  .faq__item { border-block-end: 1px solid var(--line); }

  .faq__q {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--s5);
    padding-block: var(--s5);
    cursor: pointer;
    list-style: none;
    font-family: var(--f-display);
    font-size: clamp(17px, 2vw, 21px);
    font-weight: 600;
    letter-spacing: -0.02em;
    line-height: 1.25;
  }

  .faq__q::-webkit-details-marker { display: none; }

  .faq__q::after {
    content: '';
    flex: 0 0 auto;
    width: 13px;
    height: 13px;
    margin-block-start: 0.35em;
    background:
      linear-gradient(currentColor, currentColor) center / 100% 1px no-repeat,
      linear-gradient(currentColor, currentColor) center / 1px 100% no-repeat;
    color: var(--accent-text);
    transition: transform var(--d-base) var(--e-out);
  }

  .faq__item[open] .faq__q::after { transform: rotate(45deg); }

  .faq__a { padding-block-end: var(--s5); max-width: 72ch; color: var(--muted); }

  .crumbs {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s2);
    list-style: none;
    margin: 0;
    padding: 0;
    font-family: var(--f-mono);
    font-size: var(--t-xs);
    letter-spacing: 0.06em;
    color: var(--muted);
  }

  /* Every breadcrumb trail on the site sits at the very top of a dark band, which
     since iteration 3 is a photograph — the thinnest part of the overlay. Plain
     `--muted` measured 3.2:1 there against the brightest region it covers. Halfway to
     full text colour takes it to 5.3:1 without making 12px mono compete with the H1.
     The deepened overlay alone could not close this: reaching 4.5:1 with muted grey
     needed roughly 0.93 alpha at the top edge, which erases the photograph. */
  .band .crumbs { color: color-mix(in srgb, var(--d-text) 50%, var(--d-muted)); }

  .crumbs li { margin: 0; display: flex; align-items: center; gap: var(--s2); }
  .crumbs li + li::before { content: '/'; color: color-mix(in srgb, currentColor 55%, transparent); }
  .crumbs a { text-decoration: none; }
  .crumbs a:hover { color: var(--accent-text); }
  .crumbs [aria-current='page'] { color: var(--text); }
}
