/* AP Design — theme glue.
   1) Adds the --font-mono token kit.css references but doesn't define.
   2) A minimal reset scoped to .site (the prototype relied on one).
   3) WordPress / Elementor-header integration. */

/* ---- 1) Missing token (IBM Plex Mono per the handoff) ---- */
.site {
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

/* ---- 2) Base reset, scoped to the design wrapper ---- */
.site *,
.site *::before,
.site *::after { box-sizing: border-box; }

.site {
  margin: 0;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-family: var(--font-sans);
  font-size: var(--text-base);
}

.site h1, .site h2, .site h3, .site h4, .site h5, .site h6,
.site p, .site figure, .site blockquote, .site dl, .site dd { margin: 0; }

.site img,
.site svg,
.site video,
.site iframe { display: block; max-width: 100%; }

.site a { color: inherit; text-decoration: none; }

.site button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  cursor: pointer;
}

.site ul, .site ol { margin: 0; padding: 0; list-style: none; }

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

/* Screen-reader-only text (visually hidden, announced by AT) */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Skip-to-content — hidden until focused, then a clear pill top-left */
.skip-link {
  position: fixed;
  top: -100px; left: 1rem;
  z-index: 100001;
  padding: 0.8em 1.4em;
  background: var(--ink);
  color: var(--bg);
  font-family: var(--font-display);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transition: top 0.2s ease;
}
.skip-link:focus { top: 1rem; }

/* Logo link: no boxy focus outline — use a subtle underline indicator instead. */
.nav__brand:focus-visible { outline: none; }
.nav__brand:focus-visible span { text-decoration: underline; text-underline-offset: 5px; text-decoration-thickness: 1px; }

/* ---- 3) WordPress / Elementor integration ---- */

/* When the Elementor header renders above the content, give the first
   full-bleed hero a touch of breathing room only on inner pages. The home
   project-stack stays edge-to-edge. */
.ap-main { display: block; }

/* Full-bleed utility for sections that must escape the content width. */
.ap-bleed {
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  width: 100vw;
}

/* WordPress core image/caption defaults inside project galleries & content. */
.site .wp-caption,
.site figure { max-width: 100%; }

/* ---- Branded page loader — rotating circle seal ----
   Invisible for the first 0.4s so instant page loads never flash it;
   only slow loads fade the spinner in. Never intercepts clicks. */
.ap-loader {
  position: fixed;
  inset: 0;
  z-index: 100000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  opacity: 0;
  visibility: visible;
  pointer-events: none;
  animation: ap-loader-appear 0.25s ease 0.4s forwards;
}
@keyframes ap-loader-appear { to { opacity: 1; } }
.admin-bar .ap-loader { top: 32px; }
@media screen and (max-width: 782px) { .admin-bar .ap-loader { top: 46px; } }
.ap-loader__mark {
  width: clamp(96px, 12vw, 144px);
  height: clamp(96px, 12vw, 144px);
  background: var(--ink);
  -webkit-mask: var(--ap-loader-mask) center / contain no-repeat;
  mask: var(--ap-loader-mask) center / contain no-repeat;
  animation: ap-loader-spin 10s linear infinite;
  will-change: transform;
}
@keyframes ap-loader-spin { to { transform: rotate(-360deg); } }
/* hidden once the page has finished loading */
body.is-loaded .ap-loader {
  animation: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.4s var(--ease), visibility 0.4s var(--ease);
}
@media (prefers-reduced-motion: reduce) {
  .ap-loader__mark { animation-duration: 16s; }
}

/* ---- Fullscreen sigill (home, above project stack) — admin-configurable ---- */
.sigill {
  position: relative;
  height: 100svh;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--sig-bg, #0a0a0a);
  overflow: hidden;
}
.sigill--grain::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(circle at 50% 42%, transparent 30%, rgba(0, 0, 0, 0.55) 100%);
}
/* effect wrapper (scale / opacity / float) */
.sigill__fx {
  display: block;
  width: var(--sig-size, 42vw);
  aspect-ratio: 1 / 1;
  will-change: transform, opacity;
}
/* the masked, colour-fillable shape (rotation) */
.sigill__mark {
  display: block;
  width: 100%;
  height: 100%;
  background: var(--sig-ink, #f4f1ea);
  -webkit-mask: var(--sig-mask) center / contain no-repeat;
  mask: var(--sig-mask) center / contain no-repeat;
  will-change: transform;
}
/* rotation on the shape */
.sigill[data-spin="slow"]   .sigill__mark { animation: sigill-spin 48s linear infinite; }
.sigill[data-spin="medium"] .sigill__mark { animation: sigill-spin 24s linear infinite; }
.sigill[data-spin="fast"]   .sigill__mark { animation: sigill-spin 10s linear infinite; }
/* effect on the wrapper */
.sigill[data-effect="pulse"]   .sigill__fx { animation: sigill-pulse 3.6s ease-in-out infinite; }
.sigill[data-effect="breathe"] .sigill__fx { animation: sigill-breathe 4.5s ease-in-out infinite; }
.sigill[data-effect="float"]   .sigill__fx { animation: sigill-float 5s ease-in-out infinite; }

@keyframes sigill-spin    { to { transform: rotate(360deg); } }
@keyframes sigill-pulse   { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.06); } }
@keyframes sigill-breathe { 0%, 100% { opacity: 0.72; } 50% { opacity: 1; } }
@keyframes sigill-float   { 0%, 100% { transform: translateY(-2%); } 50% { transform: translateY(2%); } }

@media (prefers-reduced-motion: reduce) {
  .sigill__mark, .sigill__fx { animation: none !important; }
}

/* ---- Opening hero: street-art wall (and optional corner logo) ---- */
.hero-wall {
  position: relative;
  height: 100svh;
  width: 100%;
  overflow: hidden;
  background: var(--ink);
}
.hero-wall__img { position: absolute; inset: 0; }
.hero-wall__img img {
  width: 100%; height: 100%; object-fit: cover;
  object-position: center top;
  filter: grayscale(1) contrast(1.05) brightness(0.82);
}
/* readability scrim, mirrors the project-stack treatment */
.hero-wall::after {
  content: "";
  position: absolute; inset: 0; z-index: 1;
  /* The wall is black line-art on WHITE, so it reads as a light image and white
     nav text needs help. Strong but short scrim over the nav band only, cleared
     by 30% so the artwork itself stays bright. */
  background: linear-gradient(to bottom, rgba(8,8,8,0.72), rgba(8,8,8,0.30) 13%, rgba(8,8,8,0) 30%, rgba(8,8,8,0) 55%, rgba(8,8,8,0.66));
  pointer-events: none;
}
/* Circle seal, lower-right corner (logo_corner mode) — doubled per request.
   One continuous clamp instead of a mobile/desktop pair: the old two-tier rule
   left a flat "dead zone" between 620-1095px (so iPads got the SMALLEST size),
   and a literal x2 of the old mobile numbers would have put the mark at ~45-50%
   of a phone's width. This curve hits exactly 2x the old max (168px -> 336px)
   at large desktop widths, and ~1.7-1.8x at phone widths — clearly bigger
   everywhere, but still reads as a corner mark rather than taking over a small
   screen. Tune the 336 / 0.134 / 95 constants below if a different balance is
   wanted; see /tmp/ap.css.bak-logo for the pre-change values. */
.hero-wall__logo {
  position: absolute; z-index: 2;
  right: clamp(1.25rem, 0.75rem + 3.5vw, 4.5rem);
  bottom: clamp(1.25rem, 0.75rem + 3.5vw, 4.5rem);
  width: clamp(120px, 95px + 13.4vw, 336px);
  height: auto;
  aspect-ratio: 1 / 1;
  /* white seal, with a soft halo so it still reads where the wall goes bright —
     shadow scaled up to match the larger mark */
  filter: brightness(0) invert(1)
          drop-shadow(0 3px 22px rgba(0, 0, 0, 0.55))
          drop-shadow(0 0 5px rgba(0, 0, 0, 0.35));
  opacity: 0.97;
}
.hero-wall .phero__scroll { color: rgba(255, 255, 255, 0.72); z-index: 2; }

/* ---- Word banner (PERSONALITY · TRUST · CONFIDENCE) ---- */
.wordbanner { background: var(--ink); color: var(--bg); padding-block: clamp(1.6rem, 1rem + 2vw, 3rem); }
.wordbanner__track {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.35em 0.9em;
  text-align: center;
}
.wordbanner__word {
  font-family: var(--font-display);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  line-height: 1;
  font-size: clamp(1.4rem, 0.9rem + 2.6vw, 3.4rem);
  color: var(--bg);
}
.wordbanner__dot {
  font-family: var(--font-accent);
  font-style: italic;
  font-weight: 300;
  color: var(--faint);
  font-size: clamp(1.4rem, 0.9rem + 2.6vw, 3.4rem);
  line-height: 1;
}

/* ---- Home stats — vinyl image backdrop, light text, subtle scrim for balance ---- */
/* Gentle dark scrim so the numbers read clearly while the record colours show through. */
.stats-section::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  /* Lighter than before so the vinyl records stay readable as records; the
     figures keep their contrast via the text-shadow below. */
  background: linear-gradient(180deg, rgba(12, 10, 8, 0.24), rgba(12, 10, 8, 0.38));
  pointer-events: none;
}
.stats-section .stats { border-top: 0; }
.stats-section .stat + .stat { border-left: 0; }
.stats-section .stat__fig { color: var(--bg); text-shadow: 0 2px 18px rgba(0,0,0,0.55), 0 1px 3px rgba(0,0,0,0.4); }
.stats-section .stat__fig .suffix { color: rgba(255, 255, 255, 0.82); }
.stats-section .stat__label { color: rgba(255, 255, 255, 0.92); text-shadow: 0 1px 10px rgba(0,0,0,0.6); }
@media (max-width: 760px) {
  .stats-section .stat:nth-child(even) { border-left: 0; }
}

/* gallery image frames should fill their aspect-ratio box */
.ncard__frame img,
.sv-block__media img,
.sv-hero img,
.wcard__frame img,
.ptile__frame img,
.phero__img img,
.contact2__img img { width: 100%; height: 100%; object-fit: cover; }

/* Vimeo background hero — fullscreen (full viewport width & height) */
.ap-video-hero { position: relative; width: 100%; height: 100svh; overflow: hidden; background: var(--paper-3); }
/* 16:9 video scaled to cover the whole viewport, both ways */
.ap-video-hero iframe {
  position: absolute; top: 50%; left: 50%;
  width: 100vw; height: 56.25vw;          /* 16:9 by width */
  min-height: 100%; min-width: 177.78vh;  /* cover in both directions */
  transform: translate(-50%, -50%);
  border: 0; pointer-events: none;
  z-index: 1;                              /* above the poster */
  transition: opacity 0.6s var(--ease);    /* fade in once the player is ready */
}
/* Poster still shown behind the player until the film loads (no empty flash). */
.ap-video-poster {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; object-fit: cover;
}
/* Mobile portrait: a full-height 16:9 cover would crop ~75% of the frame —
   reduce the hero height so far more of the film stays visible (still cover, no bars). */
@media (max-width: 760px) {
  .ap-video-hero { height: 60svh; }
  .ap-video-hero .pd__scroll-hint { display: none; }
}
/* visible "Watch film ↗" chip — the only link out to the stream */
.pd__watch {
  position: absolute;
  z-index: 4;
  left: clamp(1.25rem, 1rem + 1.5vw, 2.25rem);
  bottom: clamp(1.25rem, 1rem + 1.5vw, 2.25rem);
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  padding: 0.85em 1.3em;
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 999px;
  background: rgba(10, 10, 10, 0.42);
  backdrop-filter: blur(6px);
  color: #fff;
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  transition: background 0.3s var(--ease), border-color 0.3s var(--ease);
}
.pd__watch:hover { background: rgba(10, 10, 10, 0.7); border-color: rgba(255, 255, 255, 0.7); }
.pd__watch svg { transition: transform 0.3s var(--ease); }
.pd__watch:hover svg { transform: translate(2px, -2px); }
/* unmute control — circular icon button, sits above the cover, animated to invite a tap */
.pd__unmute {
  position: absolute;
  z-index: 4;
  right: clamp(1.25rem, 1rem + 1.5vw, 2.25rem);
  bottom: clamp(1.25rem, 1rem + 1.5vw, 2.25rem);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: clamp(58px, 4vw + 2.5rem, 76px);
  height: clamp(58px, 4vw + 2.5rem, 76px);
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 50%;
  background: rgba(10, 10, 10, 0.42);
  backdrop-filter: blur(6px);
  color: #fff;
  cursor: pointer;
  transition: background 0.3s var(--ease), border-color 0.3s var(--ease), transform 0.3s var(--ease);
}
.pd__unmute:hover { background: rgba(10, 10, 10, 0.7); border-color: rgba(255, 255, 255, 0.7); transform: scale(1.06); }
.pd__unmute__icon { display: inline-flex; }
/* Film autoplays muted, so show the muted icon by default and swap to the
   sound icon only once the viewer has turned audio on (JS sets aria-pressed). */
.pd__unmute .pd__icon--sound { display: none; }
.pd__unmute[aria-pressed="true"] .pd__icon--muted { display: none; }
.pd__unmute[aria-pressed="true"] .pd__icon--sound { display: block; }
.pd__unmute__icon svg { display: block; }
/* pulsing ring to draw the eye while still muted */
.pd__unmute::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: 1px solid rgba(255, 255, 255, 0.55);
  animation: pd-unmute-pulse 2.4s ease-out infinite;
  pointer-events: none;
}
@keyframes pd-unmute-pulse {
  0%   { transform: scale(1);    opacity: 0.6; }
  70%  { transform: scale(1.35); opacity: 0; }
  100% { transform: scale(1.35); opacity: 0; }
}
/* unmuted state — stop the attention pulse once sound is on */
.pd__unmute[aria-pressed="true"]::before { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .pd__unmute::before { animation: none; }
}

/* Hero-stack Vimeo fallback (film-only projects, e.g. Spotify): cover the slide.
   Films play CONSTANTLY IN COLOUR (no B&W→colour hover swap) — the still photos
   keep the editorial grayscale, the moving film does not. A mild brightness keeps
   the overlaid title legible; the .phero::after scrim handles the rest.
   Fades in from opacity 0 once the player is ready (JS adds inline opacity). */
.phero__video {
  position: absolute; top: 50%; left: 50%;
  width: 100vw; height: 56.25vw;          /* 16:9 */
  min-height: 100%; min-width: 177.78vh;  /* cover both ways */
  transform: translate(-50%, -50%) scale(1.15);
  border: 0; pointer-events: none;
  z-index: 1;
  filter: contrast(1.02) brightness(0.86);
  transition: opacity 0.6s var(--ease);
}

/* Contact page: zero top padding so the hero sits flush under the header. */
.ap-contact { padding-top: 0; }

/* Design nav: fixed so it overlays the dark hero like the old Elementor header did. */
.nav { position: fixed; top: 0; left: 0; right: 0; }
/* Admin bar is also fixed at top — push our nav below it. */
.admin-bar .nav { top: 32px; }
@media screen and (max-width: 782px) {
  .admin-bar .nav { top: 46px; }
}

/* Adaptive nav: slide away on scroll-down, return on scroll-up */
.nav                  { transition: transform 0.35s var(--ease-out), background 0.25s ease; }
.nav--hidden          { transform: translateY(-150%); }
.nav .nav__brand span { transition: color 0.35s var(--ease); }
.nav .nav__link       { transition: opacity var(--dur) var(--ease), color 0.35s var(--ease); }
.nav .nav__link::after { transition: transform var(--dur) var(--ease), background-color 0.35s var(--ease); }
.nav .nav__burger span { transition: background-color 0.35s var(--ease); }

/* White text by default and when over a dark section.
   data-theme="light" is the only explicit override (set by JS when scrolled over a light section). */
.nav { background: transparent; }
.nav:not([data-theme="light"]) .nav__brand span,
.nav:not([data-theme="light"]) .nav__link {
  color: var(--bg);
  /* holds up over light patches of the street-art wall */
  text-shadow: 0 1px 14px rgba(0, 0, 0, 0.6), 0 1px 3px rgba(0, 0, 0, 0.45);
}
.nav:not([data-theme="light"]) .nav__link::after { background: var(--bg); }
.nav:not([data-theme="light"]) .nav__burger span { background: var(--bg); }

/* Scrolled state: white bg + dark text — must come last to win the specificity tie */
.nav.nav--scrolled { background: var(--bg); }
.nav.nav--scrolled .nav__brand span,
.nav.nav--scrolled .nav__link { color: var(--ink); text-shadow: none; }
.nav.nav--scrolled .nav__link::after { background: var(--ink); }
.nav.nav--scrolled .nav__burger span { background: var(--ink); }
/* Overlay text inherits white so .site button { color: inherit } picks it up too */
.nav__overlay { color: var(--bg); }

/* News excerpt spacing — .site .ncard__excerpt (0-2-0) beats .site p margin reset (0-1-1) */
.site .ncard__excerpt { margin-top: 0.5rem; }
/* News card title spacing — .site .ncard__title (0-2-0) beats .site h2 margin reset (0-1-1) */
.site .ncard__title { margin: 0 0 0.7rem; }
/* Footer column headings — .site .footer__col h4 (0-2-1) beats .site h4 reset (0-1-1) */
.site .footer__col h4 { margin-bottom: 2rem; }

/* Buttons — .site .btn--solid (0-2-0) beats .site a color:inherit (0-1-1) */
.site .btn--solid { color: var(--bg); }
.site .btn--solid:hover { color: var(--ink); }
.site .btn--outline:hover { color: var(--bg); }

/* Solid button placed on a dark section — inverted resting state, inverts back on hover.
   Must be declared after .btn--solid: same specificity (0-2-0), later rule wins the tie. */
.site .btn--invert { background: var(--bg); color: var(--ink); }
.site .btn--invert:hover { background: var(--ink); color: var(--bg); }

/* Irresistibly clickable CTA — idle bounce+wiggle+glow, unhinged hover/press */
.site .btn--bounce {
  position: relative;
  white-space: normal;
  text-align: center;
  max-width: min(90vw, 30ch);
  animation: btn-idle-bounce 1.6s ease-in-out infinite, btn-idle-glow 1.6s ease-in-out infinite;
  transition: transform 0.2s cubic-bezier(.34,1.56,.64,1), background 0.2s var(--ease), color 0.2s var(--ease), box-shadow 0.2s var(--ease);
  overflow: hidden;
}
.site .btn--bounce::after {
  content: "";
  position: absolute;
  top: 0; bottom: 0; left: -60%;
  width: 40%;
  background: linear-gradient(115deg, transparent, rgba(255,255,255,0.55), transparent);
  transform: skewX(-20deg);
  pointer-events: none;
  opacity: 0;
}
.site .btn--bounce:hover {
  animation: btn-hover-wobble 0.5s ease-in-out infinite;
  box-shadow: 0 14px 30px -8px rgba(0,0,0,0.4);
}
.site .btn--bounce:hover::after {
  opacity: 1;
  animation: btn-shimmer 0.9s ease-in-out infinite;
}
.site .btn--bounce:active {
  animation: none !important;
  transform: scale(0.92) rotate(0deg) !important;
  transition-duration: 0.06s;
}
.site .btn--bounce:hover svg {
  animation: btn-arrow-nudge 0.5s ease-in-out infinite;
}
@keyframes btn-idle-bounce {
  0%, 100% { transform: translateY(0) scale(1) rotate(0deg); }
  25%      { transform: translateY(-7px) scale(1.03) rotate(-2deg); }
  50%      { transform: translateY(0) scale(1) rotate(0deg); }
  75%      { transform: translateY(-4px) scale(1.02) rotate(2deg); }
}
@keyframes btn-idle-glow {
  0%   { box-shadow: 0 4px 10px -4px rgba(0,0,0,0.2), 0 0 0 0 rgba(20,20,20,0.35); }
  70%  { box-shadow: 0 12px 26px -6px rgba(0,0,0,0.4), 0 0 0 14px rgba(20,20,20,0); }
  100% { box-shadow: 0 4px 10px -4px rgba(0,0,0,0.2), 0 0 0 0 rgba(20,20,20,0); }
}
@keyframes btn-hover-wobble {
  0%, 100% { transform: scale(1.15) rotate(-3deg); }
  50%      { transform: scale(1.18) rotate(3deg); }
}
@keyframes btn-shimmer {
  0%   { left: -60%; }
  100% { left: 120%; }
}
@keyframes btn-arrow-nudge {
  0%, 100% { transform: translateX(4px) rotate(6deg); }
  50%      { transform: translateX(10px) rotate(-6deg); }
}
@media (prefers-reduced-motion: reduce) {
  .site .btn--bounce,
  .site .btn--bounce::before,
  .site .btn--bounce::after,
  .site .btn--bounce:hover,
  .site .btn--bounce:hover svg { animation: none; }
  .site .btn--bounce:hover { transform: none; }
}

/* Filter pills — .site .pill (0-2-0) beats .site button (0-1-1) reset */
.site .pill {
  font-size: var(--text-2xs);
  padding: 0.75em 1.6em;
  letter-spacing: 0.14em;
  border: 1.5px solid var(--line-strong);
}
.site .pill[data-active="true"] { border-color: var(--ink); }
.site .pill:hover { border-color: var(--ink); }

/* Client grid — aligned grid (was CSS multi-column masonry). A real grid keeps
   every tile on the same baseline (images "linjera") and preserves left-to-right
   reading order, so chronological ordering reads correctly. Uniform frame aspect
   below forces equal image heights; the title is line-clamped so a long headline
   can no longer push a card taller and knock the row out of alignment. */
.tiles--mosaic {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(2.5rem, 1.5rem + 3vw, 4rem) clamp(1.5rem, 1rem + 2vw, 2.5rem);
  align-items: start;
}
@media (max-width: 1024px) { .tiles--mosaic { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px)  { .tiles--mosaic { grid-template-columns: 1fr; } }
/* Uniform tile image box so every card lines up */
.tiles--mosaic .ptile__frame { aspect-ratio: 4 / 3; }
/* Keep the title to two lines so wrapping can't misalign the row */
.tiles--mosaic .ptile__title {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Clients — Residential "top secret" message */
.clients-secret[hidden] { display: none; }
.clients-secret { padding-block: clamp(2rem, 1rem + 5vw, 6rem); max-width: 40ch; }
.clients-secret__lead {
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(1.8rem, 1rem + 3.5vw, 3.8rem);
  line-height: 1.02;
  letter-spacing: -0.03em;
  color: var(--ink);
  margin: 0;
}
.clients-secret__lead .it {
  font-family: var(--font-accent);
  font-weight: 300;
  font-style: italic;
  text-transform: none;
  letter-spacing: 0;
}
.clients-secret__note {
  margin-top: clamp(1.5rem, 1rem + 2vw, 2.5rem);
  font-family: var(--font-sans);
  font-size: clamp(1rem, 0.9rem + 0.4vw, 1.2rem);
  line-height: 1.55;
  color: var(--ink-2);
  max-width: 34ch;
}

/* Project tile text lockup — category / title / disciplines */
.ptile__meta {
  margin-top: 1.5rem;
  letter-spacing: 0.18em;
}
.ptile__title {
  margin-top: 0.4rem;
  font-size: clamp(1.05rem, 0.8rem + 1vw, 1.45rem);
  line-height: 1.08;
  letter-spacing: -0.02em;
}
/* Single project — still-image hero wrapper (matches ap-video-hero proportions) */
.pd__hero-wrap {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 8;
  overflow: hidden;
  background: var(--paper-3);
}
.pd__hero-wrap .pd__hero-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Scroll hint — centred on hero bottom, slow bounce */
.pd__scroll-hint {
  position: absolute;
  bottom: clamp(1.5rem, 1rem + 2vw, 2.5rem);
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.65);
  white-space: nowrap;
  animation: pd-scroll-bounce 2.4s ease-in-out infinite;
  pointer-events: none;
}
@keyframes pd-scroll-bounce {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50%       { transform: translateX(-50%) translateY(7px); }
}
@media (prefers-reduced-motion: reduce) {
  .pd__scroll-hint { animation: none; }
}
/* Contact hero — dark scroll hint (image bottom is light pavement) */
.contact2__img .pd__scroll-hint { color: rgba(10, 10, 10, 0.72); }

/* Single project — standalone quote section */
.pd__quote-section {
  border-top: 1.5px solid var(--ink);
  padding-block: clamp(5rem, 4rem + 7vw, 11rem);
}
.pd__quote-text {
  font-family: var(--font-accent);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(2rem, 0.5rem + 4.5vw, 5.5rem);
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin: 0;
  max-width: 24ch;
  text-wrap: balance;
}
.pd__quote-cite {
  display: block;
  margin-top: clamp(2rem, 1rem + 2vw, 3.5rem);
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  font-style: normal;
}

/* ---- Colour reveal + zoom on hover — all image contexts ---- */

/* Shared transition on all hoverable image frames */
.phero__img img,
.wcard__frame img,
.ptile__frame img,
.ncard__frame img,
.sv-block__media img {
  transition: filter 0.65s var(--ease), transform 0.75s var(--ease);
}

/* Home — hero stack still images */
.phero:hover .phero__img img {
  filter: grayscale(0) contrast(1.02) brightness(0.85);
  transform: scale(1.03);
}
/* Home — hero stack video: NO hover swap (films stay constant colour). */
/* Home — selected work cards */
.wcard:hover .wcard__frame img {
  filter: grayscale(0) contrast(1.02) brightness(0.9);
  transform: scale(1.04);
}

/* Clients — project tiles */
.ptile:hover .ptile__frame img {
  filter: grayscale(0) contrast(1.02) brightness(0.9);
  transform: scale(1.03);
}

/* Client logo overlay — centred on image, fades out on hover */
.ptile__logo {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  z-index: 1;
  /* dark scrim so the white logo stands out (only present on tiles with a logo) */
  background: rgba(0, 0, 0, 0.35);
  transition: background 0.5s var(--ease);
}
.ptile__logo img {
  max-width: 48%;
  max-height: 38%;
  width: auto;
  height: auto;
  object-fit: contain;
  filter: brightness(0) invert(1); /* forced white, unchanged on hover */
  transform: scale(1);
  transform-origin: center;
  transition: transform 0.6s var(--ease); /* quick return when the cursor leaves */
}
/* on hover the black overlay clears (image colour-reveals); the logo stays
   put and legible — the old scale(3.4) zoom-into-image fade-out is removed. */
.ptile:hover .ptile__logo { background: rgba(0, 0, 0, 0.12); }
.ptile:hover .ptile__logo img {
  filter: brightness(0) invert(1);
  transform: scale(1);
}
@media (prefers-reduced-motion: reduce) {
  .ptile__logo img,
  .ptile:hover .ptile__logo img { transform: none; transition: none; }
}

/* Home "Latest projects" cards — same centred logo overlay as the Clients tiles */
.wcard__logo {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  z-index: 1;
  background: rgba(0, 0, 0, 0.35);
  transition: background 0.5s var(--ease);
}
.wcard__logo img {
  max-width: 48%;
  max-height: 38%;
  width: auto;
  height: auto;
  object-fit: contain;
  filter: brightness(0) invert(1);
  transform: scale(1);
  transform-origin: center;
  transition: transform 0.6s var(--ease);
}
.wcard:hover .wcard__logo { background: rgba(0, 0, 0, 0.12); }
.wcard:hover .wcard__logo img {
  filter: brightness(0) invert(1);
  transform: scale(1);
}
@media (prefers-reduced-motion: reduce) {
  .wcard__logo img,
  .wcard:hover .wcard__logo img { transform: none; transition: none; }
}

/* News — article cards */
.ncard:hover .ncard__frame img {
  filter: grayscale(0) contrast(1.02) brightness(0.9);
  transform: scale(1.03);
}

/* What We Do — hovering anywhere in the block triggers the media reveal */
.sv-block:hover .sv-block__media img {
  filter: grayscale(0) contrast(1.02) brightness(0.9);
  transform: scale(1.03);
}
.sv-block { cursor: default; }

/* What We Do — closing invitation (cursive, understated) */
.sv-invite {
  display: inline-flex;
  align-items: baseline;
  gap: 0.35em;
  font-family: var(--font-accent);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(1.8rem, 1rem + 3vw, 3.6rem);
  line-height: 1.12;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-decoration: none;
  transition: opacity 0.3s var(--ease);
}
.sv-invite svg { flex: none; transform: translateY(-0.05em); transition: transform 0.35s var(--ease); }
.sv-invite:hover { opacity: 0.6; }
.sv-invite:hover svg { transform: translate(0.35em, -0.05em); }


/* Testimonial portrait */
.testi__frame { position: relative; }
.testi__frame::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(8, 8, 8, 0.22);
  pointer-events: none;
  transition: opacity 0.65s var(--ease);
}
.testi-grid:hover .testi__frame::after { opacity: 0; }
.testi__frame img {
  width: 100%; height: 100%; object-fit: cover; object-position: center;
  filter: grayscale(1) contrast(1.1) brightness(0.78);
  transform: scale(1.75);
  transition: filter 0.65s var(--ease), transform 0.75s var(--ease);
}
.testi-grid:hover .testi__frame img {
  filter: grayscale(0) contrast(1.02) brightness(0.9);
  transform: scale(1.8);
}

/* ---- Testimonials: click to cycle through quotes ---- */
/* All quotes share one grid cell, so the block is always as tall as the LONGEST
   quote and the layout never jumps when you cycle. Swapped with opacity rather
   than display:none, which also gives a soft cross-fade. */
.testi-cycle__stage {
  display: grid;
  align-items: center;   /* short quotes sit centred in the locked-height box,
                            so they line up with the portrait beside them */
}
.testi-cycle__stage .quote {
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.35s var(--ease), visibility 0.35s var(--ease);
}
.testi-cycle__stage .quote.is-active { opacity: 1; visibility: visible; }
/* Type scales down as the quote gets longer, so each one fills a comparable
   area instead of one overflowing while another floats in empty space.
   Tier is set in PHP from the character count. */
.testi-cycle__stage .quote--xl .quote__q { font-size: clamp(1.75rem, 1.05rem + 2.8vw, 3.1rem); }
.testi-cycle__stage .quote--l  .quote__q { font-size: clamp(1.60rem, 1.00rem + 2.4vw, 2.70rem); }
.testi-cycle__stage .quote--m  .quote__q { font-size: clamp(1.45rem, 0.95rem + 2.0vw, 2.30rem); }
.testi-cycle__stage .quote--s  .quote__q { font-size: clamp(1.30rem, 0.90rem + 1.6vw, 1.95rem); line-height: 1.3; }
@media (prefers-reduced-motion: reduce) {
  .testi-cycle__stage .quote { transition: none; }
}

/* Prev / next arrows, vertically centred either side of the quote. */
.testi-cycle--multi { position: relative; padding-inline: clamp(2.8rem, 1rem + 4vw, 4.2rem); }
.testi-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: clamp(38px, 2.4vw + 1.9rem, 48px);
  height: clamp(38px, 2.4vw + 1.9rem, 48px);
  padding: 0;
  border: 1.5px solid var(--line-strong);
  border-radius: 50%;
  background: var(--bg);
  color: var(--ink-2);
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              border-color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.testi-nav--prev { left: 0; }
.testi-nav--next { right: 0; }
.testi-nav:hover {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--bg);
  transform: translateY(-50%) scale(1.08);
}
.testi-nav:active { transform: translateY(-50%) scale(0.94); }
.testi-nav:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
.testi-nav svg { display: block; }
@media (prefers-reduced-motion: reduce) {
  .testi-nav, .testi-nav:hover, .testi-nav:active { transition: none; transform: translateY(-50%); }
}
/* Phones: the arrows would crowd the text — sit them under it as a pair. */
@media (max-width: 620px) {
  .testi-cycle--multi { padding-inline: 0; padding-bottom: 4.2rem; }
  .testi-nav { top: auto; bottom: 0; transform: none; }
  .testi-nav--prev { left: 0; }
  .testi-nav--next { left: calc(clamp(38px, 2.4vw + 1.9rem, 48px) + 0.75rem); right: auto; }
  .testi-nav:hover, .testi-nav:active { transform: none; }
}

/* ---- Design honoured: clickable awards with image panels ---- */
.award__badge { display: inline-block; height: 1.3em; width: auto; margin-left: 0.55em; vertical-align: middle; }
.award__project { font-family: var(--font-mono); font-size: var(--text-2xs); letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-2); margin-top: 0.4rem; }
.award__toggle {
  margin-top: 0.8rem;
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  border-bottom: 1px solid var(--ink);
  padding-bottom: 2px;
  transition: opacity var(--dur) var(--ease);
}
.award__toggle:hover { opacity: 0.55; }
.award__toggle-close { display: none; }
.award__toggle[aria-expanded="true"] .award__toggle-open { display: none; }
.award__toggle[aria-expanded="true"] .award__toggle-close { display: inline; }
.award__panel { grid-column: 1 / -1; margin-top: 1.3rem; }
.award__panel:not([hidden]) {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: clamp(0.75rem, 0.5rem + 1vw, 1.25rem);
}
.award__img { margin: 0; overflow: hidden; background: var(--paper-3); aspect-ratio: 4/3; }
.award__img img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ---- Global "Svartvitt-effekt = AV" (body.ap-no-bw) ----
   Admin toggle (Webbplatsinnehåll → Effekter). When off, every image renders in
   full colour: no resting grayscale, no hover colour-swap, no dark portrait overlay. */
body.ap-no-bw .phero__img img,
body.ap-no-bw .wcard__frame img,
body.ap-no-bw .ptile__frame img,
body.ap-no-bw .ncard__frame img,
body.ap-no-bw .sv-hero img,
body.ap-no-bw .sv-block__media img,
body.ap-no-bw .contact2__img img,
body.ap-no-bw .testi__frame img,
body.ap-no-bw .phero:hover .phero__img img,
body.ap-no-bw .wcard:hover .wcard__frame img,
body.ap-no-bw .ptile:hover .ptile__frame img,
body.ap-no-bw .ncard:hover .ncard__frame img,
body.ap-no-bw .sv-block:hover .sv-block__media img,
body.ap-no-bw .testi-grid:hover .testi__frame img {
  filter: none !important;
}
body.ap-no-bw .testi__frame::after { opacity: 0 !important; }
/* ...but the client logos overlaid on those frames are brand marks sitting on a
   dark scrim, not photography: they must stay forced-white in BOTH modes. The
   reset above reaches them because the logo img is nested inside .*__frame. */
body.ap-no-bw .ptile__logo img,
body.ap-no-bw .ptile:hover .ptile__logo img,
body.ap-no-bw .wcard__logo img,
body.ap-no-bw .wcard:hover .wcard__logo img { filter: brightness(0) invert(1) !important; }

/* ---- Footer logo parade ---- */
.footer-logos {
  margin-top: 0;
  margin-bottom: clamp(3rem, 2rem + 4vw, 5rem);
  border-top: 1px solid color-mix(in oklab, var(--bg) 16%, transparent);
  border-bottom: 1px solid color-mix(in oklab, var(--bg) 16%, transparent);
}
.footer-logos__grid {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 0;
  /* Matches the footer's own colour. A grid always reserves full-width column
     tracks for every row, even ones with fewer than 8 real logos — with a grey
     background on the CONTAINER, that leftover space in an incomplete last row
     rendered as a solid grey block. Background here + borders on the cells
     below (instead of a gap colour) keeps any incomplete-row leftover space
     invisible, while still drawing a thin line between every actual logo. */
  background: var(--ink);
}
.footer-logos__cell {
  background: var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
  height: 88px;
  padding: 1rem 1.5rem;
  /* Each logo closes off its OWN right and bottom edge, rather than relying on
     a neighbouring cell to draw a shared line. That neighbour doesn't always
     exist (an incomplete last row, or the row sitting right above one), so a
     shared-edge approach left both trailing edges open. Self-closing borders
     fix both — automatically, at every column count (8/4/3) and any logo
     count, with no per-breakpoint math to keep updated. */
  border-right: 1px solid color-mix(in oklab, var(--bg) 10%, transparent);
  border-bottom: 1px solid color-mix(in oklab, var(--bg) 10%, transparent);
}
.footer-logos__cell img {
  max-height: 40px;
  max-width: 110px;
  width: auto;
  height: auto;
  display: block;
  filter: brightness(0) invert(1);
  opacity: 0.42;
  transition: opacity 0.35s var(--ease);
}
.footer-logos__cell:hover img { opacity: 0.88; }
a.footer-logos__cell { cursor: pointer; }

/* Footer rolling word — cycles through admin-defined words.
   No overflow clipping (the big italic glyphs and descenders must stay visible);
   the swap is a soft fade + slide instead. */
.footer__roll {
  display: inline-block;
}
.footer__roll-word {
  display: inline-block;
  transition: transform 0.38s var(--ease), opacity 0.38s var(--ease);
  will-change: transform, opacity;
}
.footer__roll.is-rolling .footer__roll-word {
  transform: translateY(-0.3em);
  opacity: 0;
}
@media (prefers-reduced-motion: reduce) {
  .footer__roll-word { transition: none; }
}

@media (max-width: 900px) {
  .footer-logos__grid { grid-template-columns: repeat(4, 1fr); }
}
@media (max-width: 540px) {
  .footer-logos__grid { grid-template-columns: repeat(3, 1fr); }
  .footer-logos__cell { height: 70px; padding: 0.75rem 1rem; }
  .footer-logos__cell img { max-height: 32px; max-width: 80px; }
}
@media (prefers-reduced-motion: reduce) {
  .footer-logos__cell img { transition: none; }
}

@media (prefers-reduced-motion: reduce) {
  .phero__img img,
  .phero__video,
  .wcard__frame img,
  .ptile__frame img,
  .ncard__frame img,
  .sv-hero img,
  .sv-block__media img,
  .testi__frame img,
  .testi__frame::after { transition: none; }
}

/* ============================================================
   Template components & utilities — extracted from inline styles
   (identical declarations; keeps templates markup-only).
   ============================================================ */

/* --- reveal stagger delays (static steps; PHP-computed ones stay inline) --- */
.rd-60  { transition-delay: 60ms; }
.rd-70  { transition-delay: 70ms; }
.rd-80  { transition-delay: 80ms; }
.rd-100 { transition-delay: 100ms; }
.rd-130 { transition-delay: 130ms; }
.rd-190 { transition-delay: 190ms; }
.rd-240 { transition-delay: 240ms; }

/* --- measure caps (ch-based max-widths) --- */
.chw-11 { max-width: 11ch; }
.chw-14 { max-width: 14ch; }
.chw-16 { max-width: 16ch; }
.chw-18 { max-width: 18ch; }
.chw-34 { max-width: 34ch; }
.chw-42 { max-width: 42ch; }
.chw-44 { max-width: 44ch; }
.chw-52 { max-width: 52ch; }
.chw-58 { max-width: 58ch; }

/* --- section rhythm --- */
.sect-pb-md      { padding-bottom: clamp(2rem, 1rem + 3vw, 4rem); }
.sect-pb-lg      { padding-bottom: clamp(3rem, 2rem + 4vw, 6rem); }
.sect-pb-xl      { padding-bottom: clamp(4rem, 3rem + 5vw, 8rem); }
.sect-pb-section { padding-bottom: var(--section-y); }
.site .page-title { margin-top: 1.4rem; } /* .site prefix beats the .site h1 margin reset */
.mt-grid         { margin-top: clamp(2.5rem, 2rem + 3vw, 4.5rem); }
.ta-center       { text-align: center; }
.d-ib            { display: inline-block; }

/* --- shared small-mono label (meta rows, next-project labels) --- */
.mono-label {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

/* --- Home --- */
.pstack .phero { height: 100svh; }
.stats-section { position: relative; overflow: hidden; }
.stats-section__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-size: cover;
  background-position: center;
  pointer-events: none;
}
.stats-section__inner { position: relative; z-index: 2; }
.home-cta-row { margin-top: clamp(3rem, 2rem + 4vw, 5rem); display: flex; justify-content: center; }
.testi-grid {
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: clamp(2rem, 1rem + 4vw, 6rem);
  align-items: center;
}
.testi__frame { overflow: hidden; background: var(--paper-3); }
.ohead-head { margin-bottom: clamp(0rem, 1vw, 1.5rem); }

/* --- Clients --- */
/* Shared filter-pill bar — used on Projects (category) and News (tag). */
.pillbar-section { padding-bottom: 1.5rem; }
.pillbar { display: flex; flex-wrap: wrap; gap: 0.7rem; align-items: center; }
.filter-count { margin-left: auto; align-self: center; }
.site .clients-intro { margin-top: 2rem; }

/* --- What we do --- */
.site .sv-title {
  margin-top: 1.6rem;
  font-size: clamp(3.2rem, 1.2rem + 8.5vw, 8.5rem);
  line-height: 0.82;
}
.sv-intro {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(1rem, 0.5rem + 2vw, 3rem);
  margin-top: clamp(2rem, 1rem + 3vw, 4rem);
}
.sv-introB { align-self: end; font-size: var(--text-lg); }
.sv-divider { border-top: 1.5px solid var(--line); }
.sv-blocks { display: flex; flex-direction: column; gap: clamp(3rem, 2rem + 5vw, 7rem); }
.sv-block .eyebrow { margin-bottom: 1.2rem; }
/* Big discipline number — at least as large as the block title (client request) */
.sv-block__numrow { display: flex; align-items: center; gap: 1.1rem; margin-bottom: 0.6rem; }
.sv-block__num {
  font-family: var(--font-display);
  font-weight: 800;
  line-height: 0.8;
  letter-spacing: -0.04em;
  font-size: clamp(2.6rem, 1rem + 5.5vw, 5rem);
  color: var(--ink);
}
.sv-block__numrow .rule { flex: 1; height: 1px; background: var(--line-strong); }
.sv-block__title { font-size: clamp(1.9rem, 1rem + 3vw, 3.4rem); }
.site .sv-block__body { margin-top: 1.4rem; }
.sv-values { padding-block: clamp(3.5rem, 2rem + 5vw, 7rem); }
.sv-values__row { display: flex; flex-wrap: wrap; gap: 0.4em 0.5em; margin-top: clamp(1.5rem, 1rem + 2vw, 3rem); }
.sv-values__word {
  font-family: var(--font-display);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: -0.03em;
  line-height: 0.95;
  font-size: clamp(2rem, 1rem + 5vw, 5rem);
  color: var(--bg);
}
.sv-values__dot {
  font-family: var(--font-accent);
  font-weight: 300;
  font-style: italic;
  color: var(--faint);
  margin: 0 0.15em;
}

/* --- Single project --- */
.pd-intro-section { padding-block: clamp(3rem, 2rem + 4vw, 6rem); }
.pd-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5em 2em;
  margin-bottom: clamp(1.5rem, 1rem + 2vw, 3rem);
}
.pd__intro {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: clamp(2rem, 1rem + 4vw, 6rem);
  margin-top: clamp(2rem, 1rem + 3vw, 4rem);
  align-items: start;
}
/* No rule above the client logo — the border read as a line struck over wide
   wordmarks (Spotify). Padding kept so the logo keeps its column rhythm. */
/* Reserved band so every client mark occupies the SAME space from project to
   project. Buckets range 68-182px tall; top-aligning them made each logo hang
   to a different depth and drift. Centred in a fixed band with a shared left
   edge, they read as one consistent element instead. */
.pd-logo-box {
  display: flex;
  align-items: center;          /* common optical centre */
  justify-content: flex-start;  /* common left edge */
  min-height: 190px;            /* tallest bucket (182px) + air */
  padding-top: 1.5rem;
}
@media (max-width: 820px) {
  .pd-logo-box { min-height: 150px; padding-top: 0.5rem; }
}
.pd-client-logo {
  display: block;
  max-width: 100%;
  width: auto;
  height: auto;
  filter: brightness(0); /* project logo always renders black on the light intro */
}
/* Equal optical weight, not equal height. Capping every mark at one height made
   a 5.7:1 wordmark (Långholmen) roughly six times the area of a near-square one
   (Paradox, Watson). Heights below are tuned so rendered AREA stays comparable. */
.pd-client-logo--xw  { max-height: 68px;  }   /* ratio >= 4.5  — Långholmen, Exeger, Rival */
.pd-client-logo--w   { max-height: 84px;  }   /* 3.0 - 4.5     — Spotify, Quickspin, Santander */
.pd-client-logo--md  { max-height: 98px;  }   /* 2.2 - 3.0     — O'Learys, Qred */
.pd-client-logo--n   { max-height: 132px; }   /* 1.6 - 2.2     — Fjällgården */
.pd-client-logo--sq  { max-height: 158px; }   /* 1.2 - 1.6     — King, Watson's Bar */
.pd-client-logo--xsq { max-height: 182px; }   /* < 1.2         — Paradox */
/* Note: the taller buckets deliberately exceed equal-area. A wordmark's glyphs
   sit small inside a wide box, so at matched area a square mark still reads
   smaller — these are tuned by eye for equal PRESENCE, not equal maths. */
@media (max-width: 820px) {
  /* one-column layout: keep the tall marks from dominating the stacked intro */
  .pd-client-logo--n   { max-height: 116px; }
  .pd-client-logo--sq  { max-height: 132px; }
  .pd-client-logo--xsq { max-height: 148px; }
}
.pd-client-name {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.1rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.pd-next { border-top: 1px solid var(--line); padding-block: clamp(2rem, 1rem + 3vw, 4rem); }
.pd-next__row { display: flex; justify-content: space-between; align-items: center; gap: 1rem; }
.pd-next__link { color: var(--ink); display: flex; align-items: center; gap: 0.7em; text-align: right; }
.pd-next__stack { display: flex; flex-direction: column; align-items: flex-end; gap: 0.2em; }
.pd-next__title {
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(1rem, 0.8rem + 1vw, 1.5rem);
  letter-spacing: -0.02em;
  line-height: 1;
}

/* --- News --- */
.site .news-empty { margin-top: 2.5rem; }

/* --- Contact --- */
.contact-hero {
  position: relative;
  aspect-ratio: 1920 / 1010;
  overflow: hidden;
  background: var(--paper-3);
  margin-bottom: clamp(3rem, 2rem + 4vw, 6rem);
}
.site .contact-tagline { margin-top: 1.8rem; }
.contact-tagline .it { font-size: 1.15em; }
.contact-lines { margin-top: clamp(2.5rem, 2rem + 3vw, 4rem); display: flex; flex-direction: column; gap: 0.6rem; }
/* Email + phone kept smaller so they don't overpower "LET'S WORK together" */
.contact-lines .contact2__line { font-size: clamp(1.15rem, 0.9rem + 1.3vw, 1.85rem); letter-spacing: -0.01em; }
.contact-info-grid {
  margin-top: clamp(2.5rem, 2rem + 3vw, 4rem);
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 2rem 1.5rem;
  max-width: 34rem;
  padding-bottom: clamp(2rem, 2rem + 4vw, 6rem);
}
.contact-info-grid--3 { grid-template-columns: repeat(3, 1fr); max-width: 48rem; }
.contact-info-grid .field__label { margin-bottom: 0.6rem; }
.contact-info-grid .body { color: var(--ink); }
.contact-links { display: flex; flex-direction: column; gap: 0.4rem; }
.contact-links a { color: var(--ink); border-bottom: 1px solid var(--line-strong); padding-bottom: 1px; width: fit-content; }

/* Project name on a client tile — pairs with the logo so "King" reads as
   "King · The Kingdom" rather than three identical cards. */
.ptile__project { color: var(--ink); font-weight: 500; text-align: right; }

/* ---- What we do — show the ENTIRE wall image (client request) ----
   The 16/7 box + object-fit:cover cropped ~34% of the height (the wall's
   central text). Let the container take the image's own ratio instead, so
   nothing is cut and no letterbox bars appear. Declared last so it wins. */
/* Slim banner centred on the wall's headline block ("HELP! THE BIG IDEA …
   MISSION ACCOMPLISHED!"), which sits in the upper third of the photo. The
   ratio is derived from the artwork: window = headline + equal margin above
   and below, anchored to the image top. Nothing important is cut. */
.sv-hero { aspect-ratio: 2048 / 480; }
.sv-hero picture { display: block; width: 100%; height: 100%; }
.sv-hero img { width: 100%; height: 100%; object-fit: cover; object-position: center top; }
/* Tablet / iPad portrait: open the banner up a little so the handwriting keeps
   a comfortable size; still anchored to the top so the headline is intact. */
@media (max-width: 1024px) {
  .sv-hero { aspect-ratio: 2048 / 620; }
}
/* Phones: a dedicated close crop of the headline is swapped in via <picture>,
   so the box matches THAT image's ratio (2.24:1) and shows it whole. */
@media (max-width: 700px) {
  .sv-hero { aspect-ratio: 1400 / 626; }
  .sv-hero img { object-position: center center; }
}
