/* PrinterHero
   Palette sampled directly from the photograph so the section and the image
   share one black; nothing here recolours the machine. */

.printer-hero {
  --ph-ink: #030304;          /* photo background */
  --ph-ink-raised: #0c0c0f;
  --ph-red: #dd4039;          /* brightest red on the top cover */
  --ph-accent: #ff5a0a;       /* the brand orange, same as the nav and buttons */
  --ph-red-deep: #a2333a;
  --ph-steel: #9aa0a6;        /* rail aluminium */
  --ph-paper: #f2f1ee;        /* vinyl */
  --ph-muted: #8e8b88;

  --ph-display: 'Archivo Narrow', 'Oswald', 'Helvetica Neue Condensed',
    'Arial Narrow', ui-sans-serif, system-ui, sans-serif;
  --ph-body: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --ph-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;

  position: relative;
  isolation: isolate;
  min-height: 100svh;
  background: var(--ph-ink);
  color: var(--ph-paper);
  font-family: var(--ph-body);
  overflow: clip;
}

/* ---------- the machine ---------- */

/* The photograph fills the viewport the way `object-fit: cover` would, except
   the whole layered stage is scaled as one unit — so the sprites keep their
   percentage positions and the head stays on its rail. Overflow is cropped
   evenly from the top and bottom, which is empty room and floor. */
.printer-hero__stage {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: max(100%, calc(100svh * 1536 / 1024));
  /* Reserves the box before the image lands: no layout shift. */
  aspect-ratio: var(--ph-aspect);
  /* Applied to the group so the layers composite together first and the result
     is faded once. On the layers individually it would break the composite. */
  opacity: var(--ph-stage-opacity, 1);
}

.printer-hero__base {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.printer-hero__carriage,
.printer-hero__smear {
  position: absolute;
  top: var(--ph-carriage-top);
  margin: 0;
  pointer-events: none;
  user-select: none;
  transform: translate3d(var(--ph-rest), 0, 0);
  animation: var(--ph-animation-name) var(--ph-cycle) infinite;
  /* Promote once; the browser keeps both layers on the compositor. */
  will-change: transform;
  backface-visibility: hidden;
}

.printer-hero__carriage {
  left: var(--ph-carriage-left);
  width: var(--ph-carriage-width);
  height: var(--ph-carriage-height);
  --ph-travel: var(--ph-carriage-travel);
  --ph-rest: var(--ph-rest-travel);
}

/* Pre-blurred duplicate running a few milliseconds behind the sharp head.
   The blur is baked into the asset, so no filter runs at paint time. */
.printer-hero__smear {
  left: var(--ph-smear-left);
  width: var(--ph-smear-width);
  height: var(--ph-smear-height);
  --ph-travel: var(--ph-smear-travel);
  --ph-rest: var(--ph-rest-smear-travel);
  opacity: var(--ph-smear-opacity);
  animation-delay: var(--ph-smear-lag);
}

/* The vinyl in front of the rail, re-laid over the sprites. Same pixels as the
   base underneath, so it is invisible except where it hides the head's foot. */
.printer-hero__roll {
  position: absolute;
  left: var(--ph-roll-left);
  top: var(--ph-roll-top);
  width: var(--ph-roll-width);
  height: var(--ph-roll-height);
  margin: 0;
  pointer-events: none;
  user-select: none;
}

/* Paused while the hero is off-screen; set by the component. */
.printer-hero__stage[data-ph-paused='true'] .printer-hero__carriage,
.printer-hero__stage[data-ph-paused='true'] .printer-hero__smear {
  animation-play-state: paused;
}

/* ---------- tagline ---------- */

/* The tagline is anchored to the viewport and the photograph is cover-cropped,
   so what sits behind the text changes with the ratio — at some sizes it is the
   vinyl, which is white, and white type measured 4.2:1 against it. Anchoring
   the scrim to the viewport as well means the two move together and the
   contrast stops depending on the crop. */
.printer-hero::after {
  content: '';
  position: absolute;
  /* Over the stage, under the tagline and the actions, which are z-index 2. */
  z-index: 1;
  inset: auto 0 0 0;
  height: 45%;
  pointer-events: none;
  /* Shallower and lighter than it was, so the machine's base keeps its
     detail — the scrim only has to protect the bottom-left corner the
     headline sits in, not the whole width. Measured over the photo at six
     ratios: white 13.5:1, orange 4.8:1, with the base 2.5x brighter than
     under the old scrim. Four stops rather than two, because a straight ramp
     bands visibly over this height on a near-black photograph. */
  background: linear-gradient(
    to top,
    rgba(3, 3, 4, 0.62) 0%,
    rgba(3, 3, 4, 0.38) 30%,
    rgba(3, 3, 4, 0.12) 65%,
    transparent 100%
  );
}

/* Bottom left, on the content column. Measured over the photograph at eight
   viewport ratios, this corner is the steadiest place on it: the left of the
   frame is dark at every crop, so white lands at 17.2:1 and the orange at
   6.1:1 in the worst case, varying by less than a point across all of them.
   The centre could not manage that — the vinyl moves through it as the crop
   changes. */
.printer-hero__tagline {
  position: absolute;
  z-index: 2;
  left: max(1.25rem, calc((100% - 1200px) / 2));
  /* The diagonal cut is gone, so this is no longer clearing anything — it is
     just the headline's seat above a straight edge. */
  bottom: clamp(2.5rem, 7vh, 4.5rem);
  margin: 0;
  max-width: min(92vw, 40ch);
  font-family: var(--ph-display);
  font-weight: 700;
  font-size: clamp(1.35rem, 3vw, 2.5rem);
  line-height: 1.05;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  text-wrap: balance;
  color: var(--ph-paper);
  text-shadow: 0 2px 24px rgba(0, 0, 0, 0.55);
}

.printer-hero__tagline em {
  font-style: normal;
  color: var(--ph-accent);
}

/* ---------- actions ---------- */

/* Over the floor, where the photograph is darkest and evenly lit. */
.printer-hero__actions {
  position: absolute;
  z-index: 2;
  left: 50%;
  bottom: clamp(1.5rem, 6vh, 4rem);
  transform: translateX(-50%);
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(0.75rem, 2vw, 1.25rem);
  width: max-content;
  max-width: min(92vw, 46rem);
}

/* The button ships with its own type; this is the only thing the hero imposes,
   so the labels match the machine's own stencilled lettering. */
.printer-hero .specular-button {
  font-family: var(--ph-mono);
  font-size: clamp(0.78rem, 1.1vw, 0.9rem);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 1.05rem 2.1rem;
}

/* The question is the viewport's shape, not its width: a 3:2 photograph can
   only fill a viewport that is itself landscape. Anything squarer or taller
   would have to crop the ends off the machine, so there the hero collapses to
   the photograph's own height and the page continues underneath it. */
@media (max-aspect-ratio: 11 / 10) {
  .printer-hero {
    min-height: 0;
  }

  .printer-hero__stage {
    position: static;
    transform: none;
    width: 100%;
  }

  .printer-hero__actions {
    bottom: clamp(0.9rem, 4vw, 1.75rem);
  }

  .printer-hero__tagline {
    bottom: clamp(1rem, 4vw, 1.75rem);
  }
}

/* Small screens, whichever way up. */
@media (max-width: 640px) {
  .printer-hero .specular-button {
    padding: 0.85rem 1.4rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .printer-hero__carriage,
  .printer-hero__smear {
    animation: none;
    will-change: auto;
  }
  .printer-hero__smear {
    display: none;
  }
}
