@font-face {
  font-family: "Mona Sans Variable";
  font-style: normal;
  font-display: swap;
  font-weight: 200 900;
  src: url("../assets/fonts/mona-sans-latin-wght.woff2") format("woff2-variations");
}

/* Per-element geometry (design px). Not inherited, so a child never picks up
   its parent's size by accident. */
@property --x { syntax: "*"; inherits: false; }
@property --y { syntax: "*"; inherits: false; }
@property --w { syntax: "*"; inherits: false; }
@property --h { syntax: "*"; inherits: false; }
@property --r { syntax: "*"; inherits: false; }

:root {
  --frame-w: 1433;
  --frame-h: 5393.6;
  --orange: #ff7a28;
  --deep-red: rgba(173, 57, 27, 0.92);
  --ink: #141110;

  /* --u = one design pixel. The Figma frame is 1433 wide, so 1 design px is
     1/1433 of the screen width — capped at 1.4px so the photos never upscale
     past their resolution on very wide monitors (the page centers instead). */
  --u: min(100vw / var(--frame-w), 1.4px);
  --gutter: max(0px, (100vw - var(--frame-w) * var(--u)) / 2);
}

/* Inside the page, measure the container instead of 100vw, so a classic
   desktop scrollbar can't make the page wider than the space it has. */
.scale-wrapper {
  container-type: inline-size;
  --u: min(100cqw / var(--frame-w), 1.4px);
}

:root,
.scale-wrapper {
  /* spacing scale — every margin, padding and gap is one of these */
  --sp-1: calc(8 * var(--u));
  --sp-2: calc(16 * var(--u));
  --sp-3: calc(24 * var(--u));
  --sp-4: calc(32 * var(--u));
  --sp-6: calc(48 * var(--u));
  --sp-8: calc(64 * var(--u));
  --sp-12: calc(96 * var(--u));
  --sp-16: calc(128 * var(--u));
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

/* Layout classes like `display: flex` would otherwise override the hidden attribute. */
[hidden] {
  display: none !important;
}

html,
body {
  background: #201c1b;
  scroll-behavior: smooth;
}

body {
  overflow-x: hidden;
  font-family: "Mona Sans Variable", "Segoe UI", sans-serif;
}

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

/* Until a dedicated mobile layout exists in Figma, the whole composition keeps
   its desktop proportions and scales with the screen width. */
.scale-wrapper {
  position: relative;
  overflow: hidden;
  background: linear-gradient(to right, var(--orange) 16.827%, var(--deep-red) 37.5%);
}

.canvas {
  position: relative;
  width: calc(var(--frame-w) * var(--u));
  height: calc(var(--frame-h) * var(--u));
  margin-inline: auto;
}

.abs {
  position: absolute;
  left: calc(var(--x) * var(--u));
  top: calc(var(--y) * var(--u));
}

.abs,
.box {
  width: calc(var(--w) * var(--u));
  height: calc(var(--h) * var(--u));
  border-radius: calc(var(--r) * var(--u));
}

/* z-index lifts section content above the filament thread */
.row {
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-8);
}

.text-col {
  display: flex;
  flex-direction: column;
  max-width: calc(620 * var(--u));
}

/* ---------- background image + gradient fades ---------- */
/* Two intersected masks: a vertical fade (top/bottom) and a horizontal fade
   that stays solid toward the bleeding page edge and dissolves toward the
   content. Nothing reaches an element edge at full opacity, so no outline. */
.bg-halo--left,
.bg-halo--right {
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}

.bg-halo--left {
  -webkit-mask-image:
    linear-gradient(to bottom, transparent 0%, #000 22%, #000 78%, transparent 100%),
    linear-gradient(to right, #000 0%, #000 60%, transparent 100%);
  mask-image:
    linear-gradient(to bottom, transparent 0%, #000 22%, #000 78%, transparent 100%),
    linear-gradient(to right, #000 0%, #000 60%, transparent 100%);
}

.bg-halo--right {
  -webkit-mask-image:
    linear-gradient(to bottom, transparent 0%, #000 22%, #000 78%, transparent 100%),
    linear-gradient(to right, transparent 0%, #000 40%, #000 100%);
  mask-image:
    linear-gradient(to bottom, transparent 0%, #000 22%, #000 78%, transparent 100%),
    linear-gradient(to right, transparent 0%, #000 40%, #000 100%);
}

.fade-y {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 22%, #000 78%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 22%, #000 78%, transparent 100%);
}

.hero-veil {
  background: rgba(255, 255, 255, 0.05);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 14%, #000 82%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 14%, #000 82%, transparent 100%);
}

img.cover,
video.cover {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  max-width: none;
  pointer-events: none;
}

/* ---------- gradient text helper ---------- */
.grad-text {
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
}

/* ---------- fixed nav ---------- */
/* The nav is the same floating bar before and after scrolling — at the top just its
   white outline, so it's already clearly there; on scroll it fills in.
   Inset (16) + inner padding (48) = 64, so the logo stays on the page's 64 content
   edge at every screen width. The rim is an inset shadow, so it adds no width.
   Bar: 24 from the top, 72 tall → its bottom sits 64 above the hero's cap top (160). */
.site-nav {
  position: fixed;
  top: max(12px, var(--sp-3));
  left: calc(var(--gutter) + var(--sp-2));
  right: calc(var(--gutter) + var(--sp-2));
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: max(8px, var(--sp-2)) var(--sp-6);
  border-radius: max(12px, var(--sp-3));
  background: transparent;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.3);
  transition:
    background-color 0.4s ease,
    box-shadow 0.4s ease;
}

/* Scrolled: the nav drops down off the viewport edge as a floating bar.
   Inset (16) + inner padding (48) = 64, so the logo stays on the page's
   64 content edge at every screen width. */
.site-nav.is-scrolled {
  background: rgba(255, 255, 255, 0.85);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.6),
    0 var(--sp-1) var(--sp-4) rgba(32, 28, 27, 0.18);
}

.logo {
  font-size: max(22px, calc(40 * var(--u)));
  line-height: 1;
  color: #000;
  font-weight: 500;
  transition: color 0.3s ease;
}

.nav-link {
  font-size: max(14px, calc(20 * var(--u)));
  line-height: 1;
  color: #fff;
  font-weight: 500;
  transition: color 0.3s ease;
}

.site-nav.is-scrolled .nav-link {
  color: #1a1a1a;
}

/* ---------- hero ---------- */
.hero-heading-box {
  display: flex;
  flex-direction: column;
  font-size: calc(110 * var(--u));
  font-weight: 400;
}

.hero-line1 {
  /* line-height must stay >= ~1.3x font-size: background-clip:text on a
     gradient-filled heading clips ascenders/dots to the line box, so a
     tight line-height (Figma's raw 100px on a 110px font) cuts off letter
     tops. Raise this value first if any gradient heading looks clipped. */
  line-height: 1.3;
  background-image: linear-gradient(to left, #a93417 0%, #431509 11.538%);
}

/* The rotating word is the second line of the same paragraph: an identical 1.3
   line box, pulled up so baseline-to-baseline is 1.05em (tight display leading). */
.hero-cycle {
  position: relative;
  height: 1.3em;
  margin-top: -0.25em;
}

.hero-word {
  position: absolute;
  inset: 0;
  margin: 0;
  line-height: 1.3;
  color: #fff;
  white-space: nowrap;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
}

@keyframes cycle-specialdel {
  0% { animation-timing-function: ease-out; opacity: 0; }
  12.642% { animation-timing-function: ease-out; opacity: 1; }
  21.492% { opacity: 0; }
  100% { opacity: 0; }
}

@keyframes cycle-reservdel {
  0% { opacity: 0; }
  21.492% { animation-timing-function: ease-out; opacity: 0; }
  36.662% { animation-timing-function: ease-out; opacity: 1; }
  45.512% { opacity: 0; }
  100% { opacity: 0; }
}

@keyframes cycle-present {
  0% { opacity: 0; }
  45.512% { animation-timing-function: ease-out; opacity: 0; }
  61.942% { opacity: 1; }
  64.47% { animation-timing-function: ease-out; opacity: 1; }
  72.898% { opacity: 0; }
  100% { opacity: 0; }
}

@keyframes cycle-prototyp {
  0% { opacity: 0; }
  72.898% { animation-timing-function: ease-out; opacity: 0; }
  91.026% { animation-timing-function: ease-out; opacity: 1; }
  99.875% { opacity: 0; }
  100% { opacity: 0; }
}

.word-specialdel { animation-name: cycle-specialdel; animation-duration: 11.3s; }
.word-reservdel { animation-name: cycle-reservdel; animation-duration: 11.3s; }
.word-present { animation-name: cycle-present; animation-duration: 11.3s; }
.word-prototyp { animation-name: cycle-prototyp; animation-duration: 11.3s; }

/* Optical alignment: each word's first letter lines up with where the "V" *reads* as
   starting, not with its sharp tip. The eye takes a letter's edge as its mean left
   edge over one stroke weight (8.9 at this size): for the slanted "V" that is 1.54
   inside its tip, for the round "s" 0.73 inside, for the "p"/"r" stems exactly the
   stem. So the V's tip hangs out slightly, as in professional typesetting.
   Measured from the rendered glyphs, in em. */
.word-present,
.word-prototyp,
.word-reservdel { translate: -0.0368em 0; }
.word-specialdel { translate: -0.008em 0; }

.hero-subtext,
.kunder-subtext,
.branschen-subtext {
  font-family: "Instrument Serif", serif;
  font-style: normal;
  color: #fff;
}

.hero-subtext {
  font-size: calc(36 * var(--u));
  line-height: calc(50 * var(--u));
}

.kunder-subtext,
.branschen-subtext {
  font-size: calc(32 * var(--u));
  line-height: 1.4;
  margin-top: var(--sp-4);
}

/* All section-level headings (H2 tier) share one size: 96, line-height 1.3.
   Only the hero H1 ("Vi gör din ...") is intentionally larger, at 110. */
.kunder-heading,
.branschen-heading,
.kapacitet-heading,
.offert-heading {
  font-size: calc(96 * var(--u));
  line-height: 1.3;
  font-weight: 400;
}

.counter {
  font-variant-numeric: tabular-nums;
}

/* Display tracking for the two Mona Sans headings: a touch tighter at 96, which also keeps
   "13+ år bakom" on one line inside the 620 column — so the heading doesn't jump from two
   lines to three while the counter climbs from 0 to 13. */
.kunder-heading,
.branschen-heading {
  letter-spacing: -0.015em;
}

/* ---------- section 2: kunder ---------- */
.kunder-heading {
  background-image: linear-gradient(to bottom, #940000 0%, #201c1b 73.077%);
}

/* ---------- section 3: branschen ---------- */
/* Diagonal, not vertical: the page behind this heading turns deep red toward the right,
   where "bakom" sits, so the ink has to be darkest there (contrast 2.8 instead of 1.0),
   while the words over the orange start from a warmer red. */
.branschen-heading {
  background-image: linear-gradient(135deg, #8a2a12 0%, #3a1208 40%, #141110 75%);
}

/* Photo frames. Every photo (and the hero video) is framed from one shared "sheet": a
   marble image under a coral → deep-red gradient, both sized to the page width and
   offset by the element's x (--frame-x, design px), so each frame shows its own slice
   of the same sheet — one colour story, never quite the same colour. The photo covers
   the padding box, so the sheet only shows in the border ring; a light-to-dark wash on
   top gives every frame the same shading. */
.card-photo {
  --sheet: calc(1433 * var(--u));
  --offset: calc(var(--frame-x, 0) * -1 * var(--u));
  border-style: solid;
  border-width: calc(7 * var(--u));
  border-color: transparent;
  overflow: hidden;
  background:
    linear-gradient(to bottom, rgba(255, 228, 210, 0.2), transparent 45%, rgba(20, 10, 6, 0.3)) border-box,
    linear-gradient(90deg, rgba(236, 110, 84, 0.6), rgba(214, 62, 26, 0.6) 50%, rgba(150, 32, 16, 0.6)) var(--offset) 0 / var(--sheet) 100% no-repeat border-box,
    url("../assets/images/marble-frame.webp") var(--offset) 50% / var(--sheet) auto no-repeat border-box;
  box-shadow: 0 var(--sp-3) var(--sp-8) calc(-16 * var(--u)) rgba(32, 28, 27, 0.55);
}

/* kunder background: overlay keeps the page colours but lets the ripple's lights
   and darks come through clearly (soft-light was too faint) */
.ripple-bg {
  mix-blend-mode: overlay;
  opacity: 0.85;
}

/* offert background (see index.html) */
.offert-bg {
  overflow: hidden;
  pointer-events: none;
  opacity: 0.7;
}

.offert-bg img {
  transform: scaleY(-1);
}

/* branschen background layers (see index.html): colour melts in, outlines show through */
.shapes-bg {
  mix-blend-mode: soft-light;
  opacity: 0.7;
}

.shapes-outline {
  mix-blend-mode: multiply;
  opacity: 0.45;
}

/* ---------- section 4: kapacitet ---------- */
.kapacitet-bg {
  overflow: hidden;
  mix-blend-mode: soft-light;
  /* the marble is high-contrast; at half strength its flow reads without
     swallowing the heading or the card labels */
  opacity: 0.5;
}

/* the marbled image: a landscape slice cut to the band's own ratio, so its
   horizontal flow stays horizontal; it drifts slowly under the soft-light blend */
.kapacitet-bg__img {
  animation: kapacitet-drift 28s ease-in-out infinite alternate;
  will-change: transform;
}

@keyframes kapacitet-drift {
  from { transform: scale(1.06) translate3d(0, 0, 0); }
  to { transform: scale(1.16) translate3d(-2%, 1.5%, 0); }
}

.kapacitet-orbs {
  overflow: hidden;
  pointer-events: none;
}

.kapacitet-orb {
  position: absolute;
  width: calc(720 * var(--u));
  height: calc(720 * var(--u));
  border-radius: 50%;
  will-change: transform;
}

.kapacitet-orb--a {
  left: 4%;
  top: 18%;
  background: radial-gradient(circle, rgba(255, 122, 40, 0.45) 0%, rgba(255, 122, 40, 0) 70%);
  animation: orb-float-a 18s ease-in-out infinite alternate;
}

.kapacitet-orb--b {
  right: 2%;
  top: 38%;
  background: radial-gradient(circle, rgba(221, 64, 24, 0.4) 0%, rgba(221, 64, 24, 0) 70%);
  animation: orb-float-b 22s ease-in-out infinite alternate;
}

@keyframes orb-float-a {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(calc(160 * var(--u)), calc(64 * var(--u)), 0); }
}

@keyframes orb-float-b {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(calc(-192 * var(--u)), calc(-64 * var(--u)), 0); }
}

/* z-index keeps the content explicitly above the background and glow layers */
.kapacitet {
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* Solid ink black — the same ink as the filament thread. */
.kapacitet-heading,
.offert-heading {
  font-family: "Anton", sans-serif;
  margin-bottom: var(--sp-8);
  color: var(--ink);
}

/* Kapacitet gets a gradient like the other section titles: deep red into ink.
   (color: transparent again, since the rule above comes after .grad-text) */
.kapacitet-heading {
  background-image: linear-gradient(to bottom, #6e1808 25%, #141110 85%);
  color: transparent;
}

.kapacitet-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-8);
  width: 100%;
}

.kapacitet-card {
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* Label (Anton) + spec line (Instrument Serif): the same headline/body pairing
   every other section uses, so the specs read as part of the page's voice. */
.card-caption {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-bottom: var(--sp-3);
  text-align: center;
  white-space: nowrap;
  /* text-shadow rather than filter: drop-shadow, which gave every caption its own filtered layer */
  text-shadow: 0 var(--sp-1) var(--sp-2) rgba(32, 28, 27, 0.25);
}

.card-label {
  font-family: "Anton", sans-serif;
  font-size: calc(56 * var(--u));
  line-height: 1.2;
  font-weight: 400;
  color: #fff;
}

.card-spec {
  margin-top: var(--sp-1);
  font-family: "Instrument Serif", serif;
  font-size: calc(28 * var(--u));
  line-height: 1.4;
  color: rgba(255, 255, 255, 0.88);
}

/* frame from the shared sheet (see .card-photo), a little heavier on these cards */
.kapacitet-card .card-photo {
  position: relative;
  width: 100%;
  height: calc(368 * var(--u));
  border-width: calc(10 * var(--u));
  border-radius: calc(90 * var(--u));
}

.kapacitet-card:nth-child(1) .card-photo { --frame-x: 64; }
.kapacitet-card:nth-child(2) .card-photo { --frame-x: 520.3; }
.kapacitet-card:nth-child(3) .card-photo { --frame-x: 976.7; }

.kapacitet-card .card-photo img {
  transition: transform 0.6s ease;
}

.kapacitet-card:hover .card-photo img {
  transform: scale(1.04);
}

/* Step-in reveal, left → right. Same easing as the hero words, but it fades in
   once and stays. The hidden state only applies once reveal.js has run. */
.kapacitet.reveal-ready .kapacitet-card {
  opacity: 0;
}

.kapacitet.reveal-ready.is-visible .kapacitet-card {
  opacity: 1;
  transition: opacity 0.55s ease-out;
}

.kapacitet.reveal-ready.is-visible .kapacitet-card:nth-child(2) {
  transition-delay: 0.15s;
}

.kapacitet.reveal-ready.is-visible .kapacitet-card:nth-child(3) {
  transition-delay: 0.3s;
}

/* js/offscreen.js pauses the looping animations while their section is off screen */
.is-offscreen,
.is-offscreen * {
  animation-play-state: paused !important;
}

@media (prefers-reduced-motion: reduce) {
  .kapacitet-bg__img,
  .kapacitet-orb {
    animation: none;
  }
}

/* ---------- filament thread ---------- */
.filament {
  color: var(--ink);
  pointer-events: none;
  /* everything the script draws stays inside this box, so repaints of the thread
     never make the browser re-check the rest of the page */
  contain: layout paint;
}

.filament svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* The spool sketches itself once when it first comes into view; the Benchy
   sketches itself out of the end of the thread. Stroke by stroke, via
   each stroke's own --draw / --delay. */
.spool__progress,
.benchy__progress {
  transition: stroke-dashoffset var(--draw) cubic-bezier(0.45, 0.05, 0.3, 1) var(--delay);
}

.filament.is-spool-drawn .spool__progress,
.filament.is-benchy-drawn .benchy__progress {
  stroke-dashoffset: 0;
}

@media (prefers-reduced-motion: reduce) {
  .spool__progress,
  .benchy__progress {
    transition: none;
  }
}

/* ---------- offert: quote chat ---------- */
.offert {
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  transition: opacity 0.6s ease-out, translate 0.6s ease-out;
}

/* ---------- offert heading: sails in beside the Benchy ---------- */
/* Hidden only while filament.js runs and the boat isn't drawn yet. Words arrive from
   the right one by one once it is; the section follows. Delays apply on the way in
   only (the "drawn" state carries them), so scrolling back up hides them at once. */
.offert-heading {
  z-index: 1;
  white-space: nowrap;
  scroll-margin-top: var(--sp-16);
}

.offert-heading__word {
  display: inline-block;
  transition: opacity 0.6s cubic-bezier(0.2, 0.8, 0.2, 1), translate 0.6s cubic-bezier(0.2, 0.8, 0.2, 1);
}

.filament.is-ready:not(.is-benchy-drawn) ~ .offert-heading .offert-heading__word {
  opacity: 0;
  translate: calc(96 * var(--u)) 0;
}

.filament.is-benchy-drawn ~ .offert-heading .offert-heading__word {
  transition-delay: calc(0.3s + var(--i) * 0.1s);
}

.filament.is-ready:not(.is-benchy-drawn) ~ .offert {
  opacity: 0;
  translate: 0 var(--sp-6);
}

.filament.is-benchy-drawn ~ .offert {
  transition-delay: 0.6s;
}

/* Same glass as the scrolled nav, same corner radius as the photo cards. Both
   panels (file upload, design-help chat) share it and the same fixed size, so
   switching between them never moves the page. */
.offert-card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  width: calc(816 * var(--u));
  height: calc(720 * var(--u));
  padding: var(--sp-6);
  border-radius: calc(55 * var(--u));
  background: rgba(255, 255, 255, 0.85);
  box-shadow: 0 var(--sp-3) var(--sp-8) calc(-16 * var(--u)) rgba(32, 28, 27, 0.45);
  color: var(--ink);
  animation: panel-in 0.35s ease-out;
}

@keyframes panel-in {
  from { opacity: 0; translate: 0 var(--sp-2); }
  to { opacity: 1; translate: 0 0; }
}

.card-head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding-bottom: var(--sp-3);
  border-bottom: calc(1.5 * var(--u)) solid rgba(20, 17, 16, 0.1);
}

.card-head__avatar {
  display: grid;
  place-items: center;
  width: calc(56 * var(--u));
  height: calc(56 * var(--u));
  border-radius: 50%;
  background: var(--ink);
  color: #fff;
  font-family: "Anton", sans-serif;
  font-size: calc(22 * var(--u));
}

.card-head__name {
  font-size: calc(22 * var(--u));
  font-weight: 600;
  line-height: 1.2;
}

.card-head__status {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  font-size: calc(16 * var(--u));
  color: rgba(20, 17, 16, 0.6);
}

.card-head__status::before {
  content: "";
  width: var(--sp-1);
  height: var(--sp-1);
  border-radius: 50%;
  background: var(--orange);
}

/* Fixed-height card with a scrolling log, so a long conversation never pushes
   the page layout around. */
.chat__log {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding-block: var(--sp-1);
  overflow-y: auto;
}

.chat__bubble {
  max-width: 80%;
  padding: var(--sp-2) var(--sp-3);
  border-radius: calc(24 * var(--u));
  font-size: calc(22 * var(--u));
  line-height: 1.45;
  overflow-wrap: anywhere;
  animation: bubble-in 0.35s ease-out both;
}

.chat__bubble--bot {
  align-self: flex-start;
  background: rgba(20, 17, 16, 0.06);
  border-top-left-radius: var(--sp-1);
}

.chat__bubble--bot.is-question {
  font-family: "Instrument Serif", serif;
  font-size: calc(32 * var(--u));
  line-height: 1.25;
}

.chat__bubble--user {
  align-self: flex-end;
  background: var(--ink);
  color: #fff;
  border-top-right-radius: var(--sp-1);
  white-space: pre-wrap;
}

@keyframes bubble-in {
  from { opacity: 0; translate: 0 var(--sp-1); }
  to { opacity: 1; translate: 0 0; }
}

.chat__typing {
  display: flex;
  gap: calc(6 * var(--u));
}

.chat__typing span {
  width: calc(10 * var(--u));
  height: calc(10 * var(--u));
  border-radius: 50%;
  background: rgba(20, 17, 16, 0.45);
  animation: typing-dot 1s ease-in-out infinite;
}

.chat__typing span:nth-child(2) { animation-delay: 0.15s; }
.chat__typing span:nth-child(3) { animation-delay: 0.3s; }

@keyframes typing-dot {
  0%, 60%, 100% { translate: 0 0; opacity: 0.45; }
  30% { translate: 0 calc(-6 * var(--u)); opacity: 1; }
}

.chat__composer {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.chat__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1);
}

.chat__chip {
  padding: var(--sp-1) var(--sp-3);
  border: calc(1.5 * var(--u)) solid rgba(20, 17, 16, 0.2);
  border-radius: 999px;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: calc(18 * var(--u));
  cursor: pointer;
  transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}

.chat__chip:hover,
.chat__chip:focus-visible {
  border-color: var(--ink);
  background: var(--ink);
  color: #fff;
}

.chat__field,
.upload__field {
  display: flex;
  align-items: flex-end;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-3);
  border: calc(1.5 * var(--u)) solid rgba(20, 17, 16, 0.15);
  border-radius: calc(32 * var(--u));
  background: #fff;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.chat__field:focus-within,
.upload__field:focus-within {
  border-color: var(--orange);
  box-shadow: 0 0 0 calc(4 * var(--u)) rgba(255, 122, 40, 0.25);
}

.chat__input,
.upload__input {
  flex: 1;
  min-width: 0;
  max-height: calc(160 * var(--u));
  padding-block: var(--sp-1);
  border: 0;
  outline: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: calc(22 * var(--u));
  line-height: 1.45;
  resize: none;
}

.chat__input::placeholder,
.upload__input::placeholder {
  color: rgba(20, 17, 16, 0.4);
}

/* The quote button: ink black like the thread, warming to the hero red on hover. */
.chat__send,
.upload__send {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  gap: var(--sp-1);
  padding: var(--sp-2) var(--sp-3);
  border: 0;
  border-radius: 999px;
  background: var(--ink);
  color: #fff;
  font: inherit;
  font-size: calc(20 * var(--u));
  font-weight: 600;
  cursor: pointer;
  transition: background-color 0.2s ease, transform 0.2s ease, opacity 0.2s ease;
}

.chat__send:hover:not(:disabled),
.upload__send:hover:not(:disabled) {
  background: #a93417;
}

.chat__send:active:not(:disabled),
.upload__send:active:not(:disabled) {
  transform: scale(0.97);
}

.chat__send:disabled,
.upload__send:disabled {
  opacity: 0.35;
  cursor: default;
}

.chat__send svg,
.upload__send svg {
  width: calc(20 * var(--u));
  height: calc(20 * var(--u));
}

.chat__restart,
.upload__again {
  align-self: center;
  padding: var(--sp-1) var(--sp-3);
  border: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: calc(18 * var(--u));
  text-decoration: underline;
  text-underline-offset: calc(4 * var(--u));
  cursor: pointer;
}

.card-head__avatar svg {
  width: calc(28 * var(--u));
  height: calc(28 * var(--u));
}

/* ---------- offert: service choice ---------- */
.choice {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-2);
  width: calc(816 * var(--u));
  min-inline-size: 0;
  margin-bottom: var(--sp-4);
  border: 0;
}

/* Glass like the panels; the chosen one flips to ink black, like a sent message. */
.choice__option {
  --layer: rgba(255, 255, 255, 0.9);
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  padding: var(--sp-4);
  border: calc(2 * var(--u)) solid rgba(255, 255, 255, 0.6);
  border-radius: calc(40 * var(--u));
  background: rgba(255, 255, 255, 0.85);
  box-shadow: 0 var(--sp-2) var(--sp-6) calc(-16 * var(--u)) rgba(32, 28, 27, 0.35);
  color: var(--ink);
  cursor: pointer;
  transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease, translate 0.25s ease;
}

.choice__option:hover {
  translate: 0 calc(-4 * var(--u));
}

.choice__option:has(input:checked) {
  --layer: var(--ink);
  border-color: var(--ink);
  background: var(--ink);
  color: #fff;
}

.choice__option:has(input:focus-visible) {
  outline: calc(3 * var(--u)) solid var(--orange);
  outline-offset: calc(4 * var(--u));
}

.choice__radio {
  position: absolute;
  top: var(--sp-4);
  right: var(--sp-4);
  display: grid;
  place-items: center;
  width: calc(28 * var(--u));
  height: calc(28 * var(--u));
  border: calc(2 * var(--u)) solid currentColor;
  border-radius: 50%;
  opacity: 0.35;
  transition: opacity 0.2s ease;
}

.choice__radio::after {
  content: "";
  width: calc(12 * var(--u));
  height: calc(12 * var(--u));
  border-radius: 50%;
  background: var(--orange);
  scale: 0;
  transition: scale 0.2s ease;
}

.choice__option:has(input:checked) .choice__radio {
  opacity: 1;
}

.choice__option:has(input:checked) .choice__radio::after {
  scale: 1;
}

.choice__icon {
  width: auto;
  height: calc(80 * var(--u));
  margin-bottom: var(--sp-2);
  align-self: flex-start;
}

.choice__title {
  font-family: "Anton", sans-serif;
  font-size: calc(40 * var(--u));
  line-height: 1.15;
}

.choice__text {
  font-family: "Instrument Serif", serif;
  font-size: calc(24 * var(--u));
  line-height: 1.3;
  opacity: 0.85;
}

.choice__meta {
  margin-top: auto;
  padding-top: var(--sp-2);
  font-size: calc(16 * var(--u));
  font-weight: 600;
  letter-spacing: 0.04em;
  opacity: 0.7;
}

.choice__meta:has(.choice__price) {
  opacity: 1;
}

.choice__price {
  display: inline-block;
  padding: var(--sp-1) var(--sp-2);
  border-radius: 999px;
  background: var(--orange);
  color: var(--ink);
  font-size: calc(18 * var(--u));
  letter-spacing: 0;
}

/* "fr. 29 kr" price sticker on the Print on demand card: a level orange disc with a
   hand-drawn ring in the card's text colour (white when selected, ink when not). */
.choice__badge {
  position: absolute;
  right: var(--sp-3);
  bottom: var(--sp-3);
  display: grid;
  place-items: center;
  width: calc(124 * var(--u));
  height: calc(124 * var(--u));
  pointer-events: none;
}

.choice__badge::before {
  content: "";
  position: absolute;
  inset: calc(14 * var(--u));
  border-radius: 50%;
  background: var(--orange);
}

.choice__badge svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.choice__badge-ring {
  fill: none;
  stroke: currentColor;
  stroke-width: 2.5;
  stroke-linecap: round;
}

.choice__badge-text {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  font-family: "Anton", sans-serif;
  font-size: calc(30 * var(--u));
  line-height: 1;
  color: var(--ink);
}

.choice__badge-text small {
  margin-bottom: calc(2 * var(--u));
  font-family: "Instrument Serif", serif;
  font-size: calc(20 * var(--u));
}

/* "Vi svarar inom en dag – även på helger!" — the promise right under the forms: close
   to them (48), a full section gap above the footer. The dot pulses like an online light. */
.offert-note {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-top: var(--sp-6);
  font-family: "Instrument Serif", serif;
  font-size: calc(32 * var(--u));
  line-height: 1.3;
  color: #fff;
}

/* the aside is said a little quieter */
.offert-note__aside {
  opacity: 0.7;
}

.offert-note__dot {
  flex-shrink: 0;
  width: calc(12 * var(--u));
  height: calc(12 * var(--u));
  border-radius: 50%;
  background: var(--orange);
  animation: note-pulse 2s ease-out infinite;
}

@keyframes note-pulse {
  0% { box-shadow: 0 0 0 0 rgba(255, 122, 40, 0.6); }
  70% { box-shadow: 0 0 0 calc(12 * var(--u)) rgba(255, 122, 40, 0); }
  100% { box-shadow: 0 0 0 0 rgba(255, 122, 40, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .offert-note__dot {
    animation: none;
  }
}

/* ---------- offert: file upload ---------- */
.upload__work {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.dropzone {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-1);
  padding: var(--sp-4);
  border: calc(2 * var(--u)) dashed rgba(20, 17, 16, 0.25);
  border-radius: calc(32 * var(--u));
  background: rgba(255, 255, 255, 0.5);
  text-align: center;
  cursor: pointer;
  transition: border-color 0.2s ease, background-color 0.2s ease;
}

.dropzone:hover,
.dropzone.is-dragging,
.dropzone:has(input:focus-visible) {
  border-color: var(--orange);
  background: rgba(255, 122, 40, 0.08);
}

.dropzone__icon {
  width: calc(64 * var(--u));
  height: calc(64 * var(--u));
  margin-bottom: var(--sp-1);
}

.dropzone__title {
  font-family: "Instrument Serif", serif;
  font-size: calc(36 * var(--u));
  line-height: 1.2;
}

.dropzone__hint {
  font-size: calc(20 * var(--u));
}

.dropzone__link {
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: calc(4 * var(--u));
}

.dropzone__formats {
  margin-top: var(--sp-1);
  font-size: calc(16 * var(--u));
  font-weight: 600;
  letter-spacing: 0.04em;
  color: rgba(20, 17, 16, 0.55);
}

.upload__files {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  max-height: calc(128 * var(--u));
  overflow-y: auto;
  list-style: none;
}

.upload__files:empty {
  display: none;
}

.upload__file {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-1) var(--sp-1) var(--sp-3);
  border-radius: calc(24 * var(--u));
  background: #fff;
  font-size: calc(18 * var(--u));
}

.upload__file-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.upload__file-size {
  color: rgba(20, 17, 16, 0.55);
}

.upload__remove {
  display: grid;
  place-items: center;
  width: calc(32 * var(--u));
  height: calc(32 * var(--u));
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: calc(24 * var(--u));
  line-height: 1;
  cursor: pointer;
}

.upload__remove:hover,
.upload__remove:focus-visible {
  background: rgba(20, 17, 16, 0.08);
}

.upload__status {
  min-height: calc(26 * var(--u));
  font-size: calc(18 * var(--u));
  color: rgba(20, 17, 16, 0.7);
}

.upload__status.is-error {
  color: #a93417;
}

.upload__done {
  --layer: rgba(255, 255, 255, 0.85);
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-1);
  text-align: center;
  animation: panel-in 0.35s ease-out;
}

.upload__done-icon {
  width: auto;
  height: calc(120 * var(--u));
  margin-bottom: var(--sp-2);
}

.upload__done-title {
  font-family: "Anton", sans-serif;
  font-size: calc(56 * var(--u));
  line-height: 1.2;
}

.upload__done-text {
  font-family: "Instrument Serif", serif;
  font-size: calc(32 * var(--u));
}

/* ---------- footer ---------- */
/* An ink slab: the same black as the thread, rounded on top like the photo cards. */
.site-footer {
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: var(--sp-12);
  /* 192 on top (128 + 64) leaves the waves their own band above the content */
  padding: calc(192 * var(--u)) var(--sp-8) var(--sp-6);
  border-radius: calc(90 * var(--u)) calc(90 * var(--u)) 0 0;
  overflow: hidden;
  background: var(--ink);
  color: #fff;
}

/* The wave band: lighten keeps the photo's black from darkening the ink, so only the
   red and cream waves show; they fade out downward before the logo and columns. */
.site-footer__art {
  position: absolute;
  inset: 0 0 auto;
  /* gone by 210 — the content starts at 192, so only a faint trace reaches the logo */
  height: calc(280 * var(--u));
  pointer-events: none;
  mix-blend-mode: lighten;
  opacity: 0.8;
  -webkit-mask-image: linear-gradient(to bottom, #000 25%, transparent 75%);
  mask-image: linear-gradient(to bottom, #000 25%, transparent 75%);
}

.site-footer__art img {
  object-position: 50% 0%;
}

.site-footer__top,
.site-footer__bottom {
  position: relative;
}

.site-footer__top {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--sp-8);
}

.site-footer__logo {
  font-size: calc(96 * var(--u));
  line-height: 1;
  font-weight: 500;
}

.site-footer__dot {
  color: var(--orange);
}

.site-footer__tagline {
  max-width: calc(480 * var(--u));
  margin-top: var(--sp-3);
  font-family: "Instrument Serif", serif;
  font-size: calc(32 * var(--u));
  line-height: 1.3;
  color: rgba(255, 255, 255, 0.7);
}

.site-footer__col {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-2);
  font-size: calc(22 * var(--u));
  line-height: 1.3;
}

.site-footer__heading {
  margin-bottom: var(--sp-1);
  font-size: calc(16 * var(--u));
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.5);
}

.site-footer a {
  transition: color 0.2s ease;
}

.site-footer a:hover,
.site-footer a:focus-visible {
  color: var(--orange);
}

.site-footer__bottom {
  display: flex;
  justify-content: space-between;
  padding-top: var(--sp-4);
  border-top: calc(1.5 * var(--u)) solid rgba(255, 255, 255, 0.15);
  font-size: calc(18 * var(--u));
  color: rgba(255, 255, 255, 0.55);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  .offert-card,
  .chat__bubble,
  .chat__typing span {
    animation: none;
  }

  .choice__option,
  .offert,
  .offert-heading__word {
    transition: none;
  }
}
