/* ------------------------------------------------------------------
   Studio — one-page site
   Local font
------------------------------------------------------------------- */
@font-face {
  font-family: "HelsinkiWeb";
  src:
    url("assets/HelsinkiWeb-Light.woff2") format("woff2"),
    url("assets/HelsinkiWeb-Light.woff") format("woff");
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}

/* ------------------------------------------------------------------
   Tokens
------------------------------------------------------------------- */
:root {
  --ink: #151515;
  --paper: #f0f0f0;
  --ink-dim: rgba(21, 21, 21, 0.55);

  --font-display: "HelsinkiWeb", "Helvetica Neue", Arial, sans-serif;
  --font-body: "HelsinkiWeb", "Helvetica Neue", Arial, sans-serif;
  --font-mono: "HelsinkiWeb", "Helvetica Neue", Arial, sans-serif;

  --edge: clamp(1rem, 3vw, 2.5rem);
  --slide-seconds: 5;      /* seconds each pair is fully visible */
  --slide-count: 6;        /* images stacked in each plate         */
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  min-height: 100%;
}

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
}

a { color: inherit; }

/* ------------------------------------------------------------------
   Header — solid band, centered wordmark
------------------------------------------------------------------- */
/* Both the logo and the language nav are positioned with the exact
   same `top` value below. That's the whole trick: grid/flex alignment
   (what was here before) aligns element BOXES, but text and images
   can still render slightly differently within their own box due to
   font metrics — so "aligned boxes" didn't mean "aligned pixels".
   Absolute positioning with one shared top value removes that
   ambiguity entirely; both start at literally the same coordinate. */
.mark {
  position: relative;
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  padding: 1.25rem var(--edge);
  min-height: 5rem;
}

.mark__name {
  margin: 0;
}

.mark__logo {
  position: absolute;
  top: 1.25rem;
  left: 50%;
  transform: translateX(-50%);
  display: block;
  height: clamp(1.6rem, 4vw, 2.4rem);
  width: auto;
}

/* ------------------------------------------------------------------
   Language switch
------------------------------------------------------------------- */
.lang-switch {
  position: absolute;
  top: 1.25rem;
  right: var(--edge);
  display: flex;
  align-items: center;
  gap: 0.4em;
  font-family: var(--font-mono);
  font-size: 1rem;
  letter-spacing: 0.06em;
}

.lang-switch__btn {
  font: inherit; /* buttons don't inherit font-size/family by default */
  background: none;
  border: none;
  padding: 0 0.15em;
  color: var(--ink);
  cursor: pointer;
  text-decoration: none;
  text-decoration-color: currentColor;
  text-underline-offset: 0.25em;
}

/* Active language: underlined at rest, hover removes it (reversed,
   since it's already there) */
.lang-switch__btn[aria-pressed="true"] {
  text-decoration: underline;
}

.lang-switch__btn[aria-pressed="true"]:hover,
.lang-switch__btn[aria-pressed="true"]:focus-visible {
  text-decoration: none;
}

/* Inactive language: no underline at rest, hover adds one */
.lang-switch__btn:not([aria-pressed="true"]):hover,
.lang-switch__btn:not([aria-pressed="true"]):focus-visible {
  text-decoration: underline;
}

.lang-switch__btn:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

.lang-switch__sep {
  color: var(--ink-dim);
}

/* ------------------------------------------------------------------
   Stage — the full-width 10:4 spread, flush against header and footer
------------------------------------------------------------------- */
.stage {
  flex: 0 0 auto;
}

.spread {
  position: relative;
  width: 100%;
  aspect-ratio: 10 / 4;
  display: flex;
  overflow: hidden;
}

.plate {
  position: relative;
  flex: 1 1 50%;
  height: 100%;
  overflow: hidden;
}

/* Slides in a plate stack directly on top of each other and cross-fade.
   Plain absolute positioning (rather than CSS grid stacking) is used
   here deliberately — it's the most broadly compatible technique across
   older mobile Safari versions. Each slide is a <picture> so a phone can
   be served a differently cropped file via the <source> inside it. */
.stage-slide {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  opacity: 0;
  animation-name: plate-cycle;
  animation-duration: calc(var(--slide-seconds) * var(--slide-count) * 1s);
  animation-iteration-count: infinite;
  animation-timing-function: ease-in-out;
}

.stage-slide img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.stage-slide:nth-child(1) { animation-delay: calc(var(--slide-seconds) * 0 * 1s); }
.stage-slide:nth-child(2) { animation-delay: calc(var(--slide-seconds) * 1 * 1s); }
.stage-slide:nth-child(3) { animation-delay: calc(var(--slide-seconds) * 2 * 1s); }
.stage-slide:nth-child(4) { animation-delay: calc(var(--slide-seconds) * 3 * 1s); }
.stage-slide:nth-child(5) { animation-delay: calc(var(--slide-seconds) * 4 * 1s); }
.stage-slide:nth-child(6) { animation-delay: calc(var(--slide-seconds) * 5 * 1s); }
/* Extend further (nth-child(7), *6, etc.) if a plate ever holds more
   than 6 images. */

/* Tuned for --slide-count: 4 (currently). Keyframe percentages can't
   read CSS custom properties — they have to be literal numbers — so
   this needs a manual recalculation any time --slide-count changes.
   Formula, where N = --slide-count:
     visible-end % = 80 / N
     fade-end   % = 100 / N
   e.g. N=2 → 40% / 50%   (the site's earlier setting)
        N=4 → 20% / 25%   (current)
        N=6 → 13.3% / 16.7% */
@keyframes plate-cycle {
  0%     { opacity: 0; }
  3.3%    { opacity: 1; }
  13.3%    { opacity: 1; }
  16.7%    { opacity: 0; }
  100%   { opacity: 0; }
}

/* WCAG 2.2.2 — user-triggered pause */
body.slideshow-paused .stage-slide {
  animation-play-state: paused;
}

/* WCAG 2.2.2 / 2.3.3 — respect OS-level reduced motion automatically */
@media (prefers-reduced-motion: reduce) {
  .stage-slide {
    animation: none;
    opacity: 0;
  }
  .stage-slide:first-child {
    opacity: 1;
  }
}

/* ------------------------------------------------------------------
   Pause control — overlaid on the image, bottom-right. mix-blend-mode
   makes it render white over dark photos and black over light ones,
   without needing to know each image's tone in advance.
------------------------------------------------------------------- */
.pause {
  position: absolute;
  right: 1rem;
  bottom: 1rem;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  color: #ffffff;
  mix-blend-mode: difference;
}

.pause__icon {
  width: 15px;
  height: 15px;
}

.pause__bar { fill: currentColor; display: block; }
.pause__tri { fill: currentColor; display: none; }

body.slideshow-paused .pause__bar { display: none; }
body.slideshow-paused .pause__tri { display: block; }

.pause:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

.contact__link:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

/* ------------------------------------------------------------------
   Footer — offering + legal on the left, phone + email on the right,
   arranged as an explicit 2x2 grid so the two lines on each side sit
   in the exact same row as their counterpart, rather than relying on
   matching line-heights to approximate it. The two wrapper elements
   from the markup (.site-footer__row, .site-footer__contact) are set
   to display:contents below — they still group the HTML for meaning,
   but hand their children directly to this grid for placement.
------------------------------------------------------------------- */
.site-footer {
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas:
    "offering phone"
    "legal    email";
  column-gap: 2rem;
  align-items: baseline;
  background: var(--paper);
  color: var(--ink);
  padding: 1.5rem var(--edge) 1.35rem;
}

.site-footer__row,
.site-footer__contact {
  display: contents;
}

.site-footer__offering {
  grid-area: offering;
  margin: 0;
  font-size: 1.25rem;
  line-height: 1.5;
}

.site-footer__legal {
  grid-area: legal;
  margin: 0;
  font-family: var(--font-mono);
  font-size: 1rem;
  color: var(--ink-dim);
}

.contact__link {
  font-size: 1.25rem;
  font-weight: 500;
  justify-self: end;
  text-decoration: underline;
  text-decoration-color: currentColor;
  text-underline-offset: 0.25em;
}

.contact__link:hover,
.contact__link:focus-visible {
  text-decoration: none;
}

.site-footer__contact a:first-of-type { grid-area: phone; }
.site-footer__contact a:last-of-type { grid-area: email; }

/* ------------------------------------------------------------------
   Small screens
------------------------------------------------------------------- */
@media (max-width: 640px) {
  .spread {
    flex-direction: column;
    aspect-ratio: auto; /* height now comes from the two stacked plates */
  }

  .plate {
    flex: 1 1 auto;
    height: auto;
    aspect-ratio: 5 / 4; /* each plate keeps its own 5:4 frame, stacked */
  }

  .site-footer {
    grid-template-columns: 1fr;
    grid-template-areas:
      "offering"
      "phone"
      "email"
      "legal";
    row-gap: 0.75rem;
  }

  .contact__link {
    justify-self: start;
  }

  .mark {
    padding: 1.1rem var(--edge) 1rem;
    min-height: 4.5rem;
  }

  .mark__logo,
  .lang-switch {
    top: 1.1rem;
  }
}
