/* DT Huolto Oy — etusivu. Brief B (docs/design-brief-B-2026-07-31.md) + synthesis grafts G1–G6.
   Style bans in force: tools/bans.txt section C (checked against this file by the sweep).
   Depth comes from surfaces; the only angle on the page is the 73° terminal cut. */

@font-face {
  font-family: 'Big Shoulders';
  src: url(big-shoulders-var.woff2) format('woff2');
  font-weight: 100 900; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Schibsted Grotesk';
  src: url(schibsted-grotesk-var.woff2) format('woff2');
  font-weight: 400 900; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Overpass Mono';
  src: url(overpass-mono-600.woff2) format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
}

:root {
  /* 4.8. de-green (team round: two-shade green combo read as S-ryhmä; photos carried a green
     filter). Ground/surfaces/inks are neutral warm gray, display ink is charcoal — green
     survives ONLY as --green-mid accent hits on light, --green-accent on dark charcoal. */
  --ground: oklch(0.965 0.003 106);
  --surface-1: oklch(0.925 0.005 106);
  --surface-2: oklch(0.885 0.007 106);
  --surface-3: oklch(0.845 0.009 106);
  --ink: oklch(0.29 0.006 106);
  --ink-muted: oklch(0.45 0.008 106);
  --ink-display: oklch(0.25 0.010 106);
  --green-mid: oklch(0.46 0.119 149);
  --green-accent: oklch(0.65 0.136 148);
  --paper: oklch(0.975 0.003 106);
  --state-error: oklch(0.44 0.09 45);

  --f-display: 'Big Shoulders', 'Arial Narrow', sans-serif;
  --f-body: 'Schibsted Grotesk', system-ui, sans-serif;
  --f-mono: 'Overpass Mono', ui-monospace, monospace;

  --t-display: clamp(3.75rem, 9.7vw, 8.75rem);
  /* Brief B §3 gives --t-display: clamp(3.75rem, 9.7vw, 8.75rem). The hero h1 carries two
     extra terms the fold contract forces (brief B §4 authorises the tuning):
     · 15.5vh cap — the fold must FIT on short laptops (1366×635); min-height stretches but
       never shrinks, so the type itself is the compression lever (testing.md 7a).
     · 12.5vw floor — the h1 must hold TWO lines down to 320px. The constraining line is
       HUOLTO, KORJAUS (measured 6.79 × font-size, wider than JA KATSASTUS.'s 5.76), so the
       320-2×20px gutter allows at most 41.2px; the floor was 15.8vw while the widest line
       measured 5.37, and it is scaled by 5.37/6.79 to hold the same margin.
     · 7.7vw preferred — the same wider line has to clear .hero::before, the ambient right
       field, which is 42% of the viewport. That leaves 0.58vw minus the gutter for type, so
       6.79 × font fits below 7.89vw; 7.7vw keeps a 2.5% margin. At 9.7vw the line ran under
       the field and lost its last glyph at every width from 1100px up. */
  --t-h1: clamp(min(12.5vw, 3.15rem), min(7.7vw, 15.5vh), 8.75rem);
  --t-display-2: clamp(2.5rem, 5.6vw, 4.75rem);
  --t-h2: clamp(2.25rem, 4.5vw, 3.75rem);
  --t-h3: 1.5rem;
  --t-standfirst: clamp(1.125rem, 1.6vw, 1.375rem);
  --t-body: 1.0625rem;
  --t-meta: 0.8125rem;
  --t-field-label: 0.75rem;

  --s1: 8px; --s2: 16px; --s3: 24px; --s4: 40px; --s5: 64px; --s6: 96px; --s7: 128px;
  --gutter: clamp(20px, 4.45vw, 64px);
  --header-h: 76px;
  --btn-h: 48px;
  --cut: 48px;
  /* 4.8. the inner right lane: hero plate geometry, shared by every plate-lane element */
  --lane: clamp(280px, 30vw, 640px);
}

/* --- the 73° terminal cut ------------------------------------------------------------
   Measured off assets/logo/dt-logo.svg (three segments, 73.0° from horizontal):
   horizontal run = 0.306 × vertical run. --cut is the cut's vertical extent; when --cut
   equals the element height the polygon degenerates to brief A §5's full-shear rule. */
.cut-tl { clip-path: polygon(calc(0.306 * var(--cut)) 0, 100% 0, 100% 100%, 0 100%, 0 var(--cut)); }
.cut-tr { clip-path: polygon(0 0, calc(100% - 0.306 * var(--cut)) 0, 100% var(--cut), 100% 100%, 0 100%); }
.cut-br { clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - 0.306 * var(--cut)) 100%, 0 100%); }
.cut-bl { clip-path: polygon(0 0, 100% 0, 100% 100%, calc(0.306 * var(--cut)) 100%, 0 calc(100% - var(--cut))); }

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--f-body);
  font-size: var(--t-body);
  line-height: 1.6;
  hyphens: auto;
  -webkit-hyphens: auto;
  overflow-x: hidden;
}

h1, h2, h3, p, ol, figure, fieldset { margin: 0; }
ol { list-style: none; padding: 0; }
fieldset { border: 0; padding: 0; min-width: 0; }
legend { padding: 0; }
img, svg { display: block; max-width: 100%; }

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

.svg-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

::selection { background: var(--green-mid); color: var(--paper); }

/* --- skip link ----------------------------------------------------------------------- */
.skip {
  position: absolute; left: var(--s2); top: -200px; z-index: 70;
  background: var(--green-mid); color: var(--paper);
  font-family: var(--f-mono); font-size: var(--t-meta);
  text-transform: uppercase; letter-spacing: 0.08em; text-decoration: none;
  padding: 14px 20px;
}
.skip:focus { top: var(--s2); }

/* --- header -------------------------------------------------------------------------- */
.site-header {
  position: sticky; top: 0; z-index: 60;
  height: var(--header-h);
  display: flex; align-items: center; gap: var(--s4);
  padding-inline: var(--gutter);
  background: oklch(0.965 0.003 106 / 0.98);
}

.brand { display: block; }
.brand svg { height: 40px; width: auto; }
.brand--mono { display: none; }
.brand--mono svg { height: 40px; }

.nav {
  margin-left: auto;
  display: flex; align-items: center; gap: clamp(14px, 1.8vw, 32px);
}
.nav a {
  position: relative;
  font-family: var(--f-mono); font-weight: 600;
  font-size: var(--t-meta); letter-spacing: 0.08em;
  color: var(--ink); text-decoration: none;
  padding: 10px 0;
}
.nav a::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 2px; height: 3px;
  background: var(--green-mid);
  transform: scaleX(0); transform-origin: left center;
  transition: transform 120ms ease-out;
}
.nav a:hover::after { transform: scaleX(1); }
.nav a:active { color: var(--green-mid); }

.hdr-cta { --btn-h: 40px; margin-left: var(--s3); }

/* --- buttons ------------------------------------------------------------------------- */
.btn {
  --cut: var(--btn-h);
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  height: var(--btn-h); padding-inline: clamp(18px, 2vw, 28px);
  font-family: var(--f-display); font-weight: 800;
  font-size: clamp(1.0625rem, 1.35vw, 1.375rem);
  line-height: 1; letter-spacing: 0.02em; text-transform: uppercase;
  text-decoration: none; border: 0; border-radius: 0; cursor: pointer;
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - 0.306 * var(--cut)) 100%, 0 100%);
  /* felt-polish (owner 3.8.: "buttons feel satisfying"): quick eased response instead of
     an instant swap; press stays a 1px drop — transform+bg only, budget intact */
  transition: background-color 120ms ease-out, transform 80ms ease-out;
}
.btn--primary { background: var(--green-mid); color: var(--paper); }
.btn--primary:hover { background: var(--ink-display); }
/* the submit ships disabled until site.js runs (JS-off honesty). Memo 0.2: the state
   reads ARMED-waiting, not switched-off — outlined in the accent on paper, the 73° cut
   slicing the ring keeps it in the house grammar; the honest line below is its caption.
   (Border here is a state ring, not depth — deliberate deviation from surfaces-only.) */
.btn--primary:disabled {
  background: var(--paper); color: var(--green-mid);
  border: 2px solid var(--green-mid);
  cursor: default;
}
.btn--primary:disabled:hover { background: var(--paper); }
.btn--primary:disabled:hover .arrow { transform: none; }
.btn--primary:hover .arrow { transform: translateX(4px); }
.btn--primary:active { transform: translateY(1px); }
.arrow { display: inline-block; transition: transform 120ms ease-out; }

/* Alleviivattu jo lepotilassa. Kosketusnäytöllä ei ole hoveria, joten pelkkä hover-alleviivaus
   teki tästä tekstiä joka sattuu olemaan linkki — sama periaate kuin leipätekstin linkeissä.
   Vihreä viiva erottaa sen otsikoista ilman että se kilpailee viereisen napin kanssa. */
.link-secondary {
  font-family: var(--f-body); font-weight: 500;
  font-size: var(--t-standfirst); color: var(--ink);
  text-decoration: underline; text-decoration-color: var(--green-mid);
  text-decoration-thickness: 2px; text-underline-offset: 4px;
  padding: 10px 2px;
}
.link-secondary:hover { color: var(--green-mid); }

:where(a, button, input, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--green-mid); outline-offset: 2px;
}

/* --- burger (G5: three bars, sheared left ends) --------------------------------------- */
.burger {
  display: none;
  align-items: center; justify-content: flex-end; gap: 10px;
  min-width: 44px; height: 44px; margin-left: auto;
  background: none; border: 0; padding: 0 4px; cursor: pointer;
}
/* without JS the burger cannot open anything — a 44px control that does nothing is worse
   than no control. The sections stay reachable by scrolling and by the in-page anchors. */
.no-js .burger { display: none; }
.burger-bars { display: flex; flex-direction: column; justify-content: center; gap: 6px; width: 36px; height: 44px; }
/* the crossed bars alone do not say WHAT they do; the word does, in the record voice */
.burger-label {
  display: none;
  font-family: var(--f-mono); font-weight: 600;
  font-size: var(--t-meta); line-height: 1; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--green-mid);
}
.burger[aria-expanded="true"] .burger-label { display: block; }
.burger-bar {
  --cut: 4px;
  display: block; height: 4px; background: var(--ink-display);
  clip-path: polygon(calc(0.306 * var(--cut)) 0, 100% 0, 100% 100%, 0 100%, 0 var(--cut));
  transition: transform 160ms ease-out, opacity 120ms ease-out;
}
.burger-bar:nth-child(2) { width: 82%; }
.burger-bar:nth-child(3) { width: 64%; }
/* open = a close form: the outer two sheared bars cross, the middle one leaves. The bars
   keep their 73° ends, so the X is cut from the same vocabulary as everything else. */
.burger[aria-expanded="true"] .burger-bar { background: var(--green-mid); }
.burger[aria-expanded="true"] .burger-bar:nth-child(1) { transform: translateY(10px) rotate(45deg); }
.burger[aria-expanded="true"] .burger-bar:nth-child(2) { opacity: 0; transform: scaleX(0.2); }
.burger[aria-expanded="true"] .burger-bar:nth-child(3) { width: 100%; transform: translateY(-10px) rotate(-45deg); }

/* --- mobile menu overlay -------------------------------------------------------------- */
.menu {
  /* the header stays ABOVE the overlay so the burger remains the visible close
     affordance while it is open — a full-screen paper sheet with no way out is a trap */
  position: fixed; inset: 0; z-index: 50;
  display: flex; flex-direction: column; justify-content: flex-start;
  gap: var(--s3);
  padding: calc(var(--header-h) + var(--s3)) var(--gutter)
           calc(var(--gutter) + env(safe-area-inset-bottom, 0px));
  background: var(--ground);
  opacity: 0; visibility: hidden; transform: translateY(-10px);
  transition: opacity 160ms ease-out, transform 160ms ease-out, visibility 0s linear 160ms;
}
.menu.is-open { opacity: 1; visibility: visible; transform: none; transition-delay: 0s; }
.menu-nav { display: flex; flex-direction: column; gap: var(--s2); }
.menu-nav a {
  font-family: var(--f-display); font-weight: 800;
  font-size: clamp(2rem, 9vw, 3rem); line-height: 1;
  text-transform: uppercase; color: var(--ink-display); text-decoration: none;
  padding: 6px 0;
}
.menu-nav a:hover { color: var(--green-mid); }
/* the primary action sits on the overlay's bottom edge (thumb reach), clear of the home
   indicator via the safe-area inset in .menu's padding */
.menu-cta { --btn-h: 54px; margin-top: auto; align-self: flex-start; }

/* --- fold ----------------------------------------------------------------------------- */
.fold {
  height: calc(100vh - var(--header-h));
  height: calc(100svh - var(--header-h));
  display: flex; flex-direction: column;
}

/* space-evenly, not center: leftover height becomes three equal bands of rhythm instead of
   one void at each end. It only ever distributes POSITIVE free space, so a short laptop
   (1366×635) degrades to the gap minimums with zero overflow risk — the density floor and
   the fold contract are then satisfied by the same mechanism (canvas: whitespace is rhythm;
   testing.md 7a: the void at ultrawide is a real defect, not a matter of taste). */
.hero {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; justify-content: space-evenly;
  gap: clamp(10px, 3.6vh, 44px);
  padding-block: clamp(10px, 2vh, 28px);
}
.hero-inner { padding-inline: var(--gutter); }
.hero-inner--b {
  display: flex; flex-direction: column;
  gap: clamp(14px, 3.4vh, 44px);
}

.eyebrow {
  display: flex; align-items: center; gap: 12px;
  font-family: var(--f-mono); font-weight: 600;
  font-size: var(--t-meta); line-height: 1.4;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--green-mid);
  margin-bottom: clamp(8px, 1.4vh, 20px);
}
.tick {
  --cut: 14px;
  flex: none; display: block; width: 10px; height: 14px;
  background: var(--green-mid);
  clip-path: polygon(calc(0.306 * var(--cut)) 0, 100% 0, calc(100% - 0.306 * var(--cut)) 100%, 0 100%);
}

h1 {
  font-family: var(--f-display); font-weight: 800;
  font-size: var(--t-h1); line-height: 0.92;
  letter-spacing: 0.005em; text-transform: uppercase;
  color: var(--ink-display);
  /* the two authored lines ARE the design, and the hanging hyphen in JA -KORJAUS. is
     correct copy — never a break opportunity. A too-large floor then overflows loudly
     (the rig catches it) instead of silently rewrapping to three lines. */
  white-space: nowrap;
  hyphens: none; -webkit-hyphens: none;
}

/* full-bleed from the page's left edge to ~76% of page width (brief B §4), so it escapes
   the hero's gutter rather than the 76% of an inner box */
.flank {
  --cut: 12px;
  margin-left: calc(-1 * var(--gutter));
  margin-top: clamp(14px, 2.6vh, 34px);
  width: 76vw; height: 12px;
  background: var(--green-mid);
  clip-path: polygon(0 0, 100% 0, calc(100% - 0.306 * var(--cut)) 100%, 0 100%);
}

.standfirst {
  font-family: var(--f-body); font-weight: 500;
  font-size: var(--t-standfirst); line-height: 1.5;
  max-width: 52ch;
}

/* 2026-08-03 council SPEC A: the työmääräys-liite — a photo mounted on a dark plate in the
   fold's right field, ≥1100px only. The plate is a flat surface (depth by surface, never
   shadow), cut-bl so the ONE angle points at the flank; the flank bar passes BEHIND it
   (the second layer both liked drafts had). No caption — the KALUSTO strip below IS the
   caption layer; a KOHDE-tag on stock would fabricate ownership. Fold contract PRESERVED:
   the img is absolute (zero intrinsic height), rows size from the type column. */
/* Alle 1100px tämä on `display: none`, mutta selain lataa piilotetunkin <img>:n - ja tämä oli
   `eager` + `fetchpriority="high"`, eli puhelin haki kiireellisenä 27 kt kuvan jota se ei koskaan
   näytä, LCP-kuvan kanssa samasta kaistasta. Mitattu 375px viewportissa 8.9.2026.

   Ratkaisu on <picture>-kytkin markupissa: kapealla ruudulla <source> tarjoaa 1x1 gif-datauriä,
   jolloin oikeaa tiedostoa ei haeta lainkaan. Leveällä <img> voittaa ja pysyy eagerina, koska
   siellä kuva on foldin yläpuolella. `loading="lazy"` ei kelpaa tähän: se hidastaisi työpöytää.
   Kuvan lähde pysyy kentässä, joten Jorin vaihtama kuva menee läpi molemmilla leveyksillä. */
.hero-liite { display: none; margin: 0; }
@media (min-width: 1100px) {
  .hero {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr) var(--lane);
    grid-template-rows: auto auto;
    align-content: space-evenly;
    row-gap: clamp(10px, 3.6vh, 44px);
    column-gap: clamp(24px, 3vw, 56px);
  }
  /* wave 2.5 (owner: "hero 80% empty"): ambient right field — a flat surface plane the
     liite plate and the flank both overlap. Three flat layers = the fold's depth,
     no gradient, no shadow. Paints under all hero children (::before, z auto). */
  .hero::before {
    content: '';
    position: absolute; top: 0; right: 0; height: 100%;
    width: clamp(340px, 42%, 760px);
    background: var(--surface-1);
    --fc: clamp(72px, 8vw, 128px);
    clip-path: polygon(0 0, 100% 0, 100% 100%, calc(0.306 * var(--fc)) 100%, 0 calc(100% - var(--fc)));
  }
  .hero-inner, .hero-inner--b { grid-column: 1; }
  .hero-liite {
    --cut: 48px;
    display: block;
    grid-column: 2; grid-row: 1 / 3;
    align-self: stretch;
    margin-right: var(--gutter);
    background: var(--ink-display);
    padding: var(--s2);
    clip-path: polygon(0 0, 100% 0, 100% 100%, calc(0.306 * var(--cut)) 100%, 0 calc(100% - var(--cut)));
  }
  .hero-liite .ph { position: relative; height: 100%; }
  /* absolute-inset img: kills the WebKit circular-height trap (jalator 2026-07-30 specimen) */
  .hero-liite .ph img { position: absolute; inset: 0; }
}
/* R20 on body copy only — the display H2 rags are hand-tuned (20ch window), balance would
   rewrap them; body paragraphs get the cheap one-word-last-line insurance */
.standfirst, .prose p, .stmt-b, .palvelu-row p, .seg-block p, .band-body, .chev-b, .sec-lede { text-wrap: pretty; }

/* Leipätekstin sisäinen linkki. Alleviivattu jo lepotilassa, ei vasta hoverissa: linkki jonka
   näkee vasta osuessaan siihen ei ole linkki. Vihreä on hoverin vastaus, sama kuin .rec-link. */
.standfirst a, .prose a {
  color: inherit; text-decoration: underline; text-decoration-thickness: 2px;
  text-underline-offset: 3px; text-decoration-color: var(--green-mid);
  transition: color 120ms ease-out;
}
.standfirst a:hover, .prose a:hover { color: var(--green-mid); }

.cta-row { display: flex; align-items: center; gap: clamp(18px, 2.4vw, 36px); flex-wrap: wrap; }

/* --- kalusto + record strips (the fold's two record bands) ----------------------------- */
.kalusto, .record {
  display: flex; align-items: center;
  gap: clamp(10px, 1.4vw, 20px);
  padding: clamp(9px, 1.5vh, 16px) var(--gutter);
  font-family: var(--f-mono); font-weight: 600;
  font-size: var(--t-meta); line-height: 1.4;
  letter-spacing: 0.08em; text-transform: uppercase;
}
.kalusto { display: block; background: var(--surface-1); color: var(--ink); }
.kalusto-label { color: var(--green-mid); margin-right: clamp(10px, 1.4vw, 20px); }
/* manual, not none: authored &shy; must still be able to fire in the compounds at 320px,
   while automatic hyphenation stays off in the record grammar */
.kalusto-items { hyphens: manual; -webkit-hyphens: manual; }
.sep { color: var(--green-mid); }
/* R3 + wrap-safety (handoff trio): separators live in CSS glued to the PRECEDING item, so
   a wrapped line can never start with a stray · */
.kal { white-space: nowrap; }
.kal:not(:last-child)::after, .rb:not(:last-child)::after { content: ' ·'; color: var(--green-mid); }

.record {
  background: var(--surface-2); color: var(--ink-muted);
  display: grid; grid-template-columns: 2fr 1fr 1fr;
  align-items: center; column-gap: clamp(16px, 2.4vw, 40px);
}
.rec-cell { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.rec-k { color: var(--green-mid); flex: none; }
.rec-v { color: var(--ink); overflow-wrap: anywhere; }
/* memo 0.3: verified facts are affordances, not inert cells — map/YTJ links in the
   record voice; underline only on approach */
/* Pystypehmuste kasvattaa osumapinnan 34 px:stä yli 44 px:n. Inline-elementillä se ei muuta
   rivilaatikon korkeutta, joten tekstin rytmi säilyy — vain sormelle tulee tilaa. */
a.rec-link { text-decoration: none; transition: color 120ms ease-out; padding-block: 12px; }
a.rec-link:hover { text-decoration: underline; text-underline-offset: 3px; color: var(--green-mid); }
.yht-band a.rec-link { color: var(--paper); }
.yht-band a.rec-link:hover { color: var(--green-accent); }
/* A label and the blank it opens are ONE thing. Left to normal inline flow the bar orphans
   onto its own line at 320–375 and reads as a stray rule; as an inline-flex nowrap unit the
   pair breaks as a whole and the bar shrinks instead (measured: 320px leaves 61px for it). */
.slot {
  display: inline-flex; align-items: baseline; gap: 8px;
  white-space: nowrap; max-width: 100%; min-width: 0;
}
.rec-cell > .slot, .sidenote > .slot, .band-field > .slot { flex: 1 1 auto; }
.blank {
  display: inline-block; flex: 1 1 auto;
  min-width: 64px; max-width: 220px; height: 1em;
  background: var(--surface-3);
  border-bottom: 2px solid var(--ink-muted);
}
.nowrap { white-space: nowrap; }
.blank--dark { background: none; border-bottom-color: var(--green-accent); }

/* --- sections ------------------------------------------------------------------------- */
.sec { padding-inline: var(--gutter); }
.sec--palvelut { padding-block: clamp(56px, 8vw, 96px) 0; }
/* Usein kysytyt. Rivit ovat samat kuin työlistalla (.palvelu-rows) - kysymys on rivin nimi ja
   vastaus sen kuvaus, eli sama luettava kahden sarakkeen rytmi eikä uutta komponenttia.
   Oma osioluokka vain siksi, että tällä on alapehmuste toisin kuin työlistalla, jonka alla
   tulee heti tumma CTA-palkki. */
.sec--faq { padding-block: clamp(56px, 8vw, 96px) 0; }
.sec--toiminta { padding-block: clamp(56px, 8vw, 96px); }
.sec--miksi { padding-block: clamp(48px, 6vw, 80px) clamp(56px, 8vw, 96px); }
.sec--pyynto { padding-block: clamp(64px, 10vw, 128px); }
.sec--kysy { padding-block: clamp(56px, 8vw, 96px); }
.sec--yht { padding: 0; }

.sec-head { max-width: 24ch; }
.sec--toiminta .sec-head, .sec--pyynto .sec-head, .sec--kysy .sec-head { max-width: none; }

h2 {
  font-family: var(--f-display); font-weight: 700;
  font-size: var(--t-h2); line-height: 1.0;
  text-transform: uppercase; color: var(--ink-display);
  max-width: 18ch;
  hyphens: none; -webkit-hyphens: none;
}
.eyebrow--h { font-family: var(--f-mono); font-weight: 600; font-size: var(--t-meta); max-width: none; }

/* --- palvelut bands (G3: each band preselects its segment in the form) ------------------
   2026-08-03 rebuild for the comp: identical markup per band (R4), position-based styling
   (R1/R2 — :first-child carries dominance), photo panel per band (reframe: stock
   placeholders show the client what to shoot). */
.sec-lede {
  margin-top: clamp(14px, 2vw, 24px);
  font-size: var(--t-body); max-width: 46ch;
}
.bands {
  margin-inline: calc(-1 * var(--gutter));
  margin-top: clamp(32px, 4vw, 56px);
  display: flex; flex-direction: column;
}
.band {
  --cut: clamp(40px, 5vw, 72px);
  position: relative;
  display: grid; align-content: center;
  gap: clamp(6px, 0.8vw, 12px);
  min-height: clamp(150px, 18vw, 230px);
  padding: clamp(24px, 3vw, 40px) var(--gutter);
  text-decoration: none; color: var(--ink);
  clip-path: polygon(calc(0.306 * var(--cut)) 0, 100% 0, 100% 100%, 0 100%, 0 var(--cut));
  transition: background-color 120ms ease-out;
}
.band:nth-child(odd) { background: var(--surface-1); }
.band:nth-child(even) { background: var(--ground); }
/* 4.8. uniform hover (owner: middle band blended into its neighbors) — surface-2 touches
   no band's resting tone, so any hovered band separates from BOTH neighbors */
.band:hover, .band:focus-visible { background: var(--surface-2); }
.band:first-child { min-height: clamp(260px, 30vw, 400px); }
.band:focus-visible { outline-offset: -4px; }

.band-name {
  font-family: var(--f-display); font-weight: 800;
  font-size: var(--t-h2); line-height: 1;
  text-transform: uppercase; color: var(--ink-display);
}
.band:first-child .band-name { font-size: clamp(2.75rem, 6.4vw, 5.25rem); }
.band-field {
  display: flex; align-items: baseline; gap: 8px;
  font-family: var(--f-mono); font-weight: 600;
  font-size: var(--t-field-label); letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-muted); margin-top: 4px; max-width: 60ch;
}
.band-field .rec-k { flex: none; }
.band-worklist { color: var(--ink); letter-spacing: 0.06em; }
/* 4.8. action strip: closes the band stack AND separates it from the room threshold on
   ground (rooms are designed to cut against ground — the gap gets a job, not padding) */
.band-more {
  margin-inline: calc(-1 * var(--gutter));
  padding: clamp(28px, 3.6vw, 48px) var(--gutter);
  display: flex; align-items: baseline; gap: clamp(14px, 2vw, 24px); flex-wrap: wrap;
  background: var(--ground);
  text-decoration: none;
  transition: background-color 120ms ease-out;
}
.band-more:hover, .band-more:focus-visible { background: var(--surface-2); }
.band-more .rec-k {
  font-family: var(--f-mono); font-weight: 600;
  font-size: var(--t-meta); letter-spacing: 0.08em; text-transform: uppercase;
}
.band-more-t {
  font-family: var(--f-display); font-weight: 800;
  font-size: clamp(1.5rem, 2.6vw, 2.25rem); line-height: 1;
  letter-spacing: 0.02em; text-transform: uppercase;
  color: var(--green-mid);
}
.band-more:hover .band-more-t { color: var(--ink-display); }

/* --- toimintatapa --------------------------------------------------------------------- */
.pull {
  font-family: var(--f-display); font-weight: 800;
  font-size: var(--t-display-2); line-height: 0.96;
  text-transform: uppercase; color: var(--ink-display);
  margin-top: clamp(24px, 3vw, 40px);
  max-width: 16ch;
  hyphens: none; -webkit-hyphens: none;
}

/* The chevron joins are full-height 73° edges, so the shear run = 0.306 × segment height.
   CSS cannot read an element's used height, so the height is PINNED (min-height = the same
   token the clip-path uses) and the rig asserts the used height still equals it — a guessed
   total would rot silently (testing.md 7a physics). */
.chevrons {
  --chev-h: 160px;
  --chev-run: calc(0.306 * var(--chev-h));
  --chev-pad: clamp(18px, 2vw, 30px);
  margin-inline: calc(-1 * var(--gutter));
  margin-top: clamp(40px, 5vw, 64px);
  display: flex;
}
/* Flex, not grid: the negative margins that interlock the sheared edges also feed the
   free-space calculation back, so four segments still span exactly 100% of the strip. */
.chev {
  flex: 1 1 0; min-width: 0;
  min-height: var(--chev-h);
  padding: clamp(18px, 2.2vw, 28px) var(--chev-pad);
  display: grid; align-content: start; gap: 6px;
}
.chev:nth-child(odd) { background: var(--surface-1); }
.chev:nth-child(even) { background: var(--surface-2); }
/* R1 (2026-08-03): positional selectors, not --1..--4 — the strip survives a fifth step */
.chev {
  clip-path: polygon(var(--chev-run) 0, 100% 0, calc(100% - var(--chev-run)) 100%, 0 100%);
  margin-left: calc(-1 * var(--chev-run));
  padding-left: calc(var(--chev-pad) + var(--chev-run));
}
.chev:first-child {
  clip-path: polygon(0 0, 100% 0, calc(100% - var(--chev-run)) 100%, 0 100%);
  margin-left: 0;
  padding-left: var(--gutter);
}
.chev:last-child {
  clip-path: polygon(var(--chev-run) 0, 100% 0, 100% 100%, 0 100%);
  padding-right: var(--gutter);
}
/* the trailing join eats the bottom-right corner over the full run, so the content box of
   every sheared segment clears it by the whole run — a glyph on the last line can never
   reach the angle (fidelity review: segment 1 lost its final period into the join) */
.chev:not(:last-child) { padding-right: calc(var(--chev-pad) + var(--chev-run)); }
.chev-k {
  font-family: var(--f-mono); font-weight: 600;
  font-size: var(--t-meta); letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--green-mid);
}
.chev-b { font-size: var(--t-body); line-height: 1.5; }

/* --- miksi DT (G4 stagger) -------------------------------------------------------------- */
.statements { margin-top: clamp(32px, 4vw, 56px); display: grid; gap: clamp(24px, 3vw, 40px); }
/* R1: G4 stagger by position — 0 / 96 / 48, repeating for any count */
.stmt:nth-child(3n+2) { margin-left: 96px; }
.stmt:nth-child(3n) { margin-left: 48px; }
.stmt-t {
  font-family: var(--f-display); font-weight: 700;
  font-size: var(--t-h2); line-height: 1;
  text-transform: uppercase; color: var(--ink-display);
  max-width: 20ch;
  hyphens: none; -webkit-hyphens: none;
}
.stmt-b { margin-top: 10px; font-size: var(--t-body); max-width: 46ch; }

.recbox {
  --cut: 32px;
  margin-top: clamp(40px, 5vw, 64px);
  padding: clamp(20px, 2.4vw, 28px) clamp(20px, 2.4vw, 32px);
  background: var(--surface-1); color: var(--ink);
  font-family: var(--f-mono); font-weight: 600;
  font-size: var(--t-meta); line-height: 1.8;
  letter-spacing: 0.08em; text-transform: uppercase;
  clip-path: polygon(calc(0.306 * var(--cut)) 0, 100% 0, 100% 100%, 0 100%, 0 var(--cut));
}

/* --- työpyyntö form --------------------------------------------------------------------- */
.wo {
  --cut: clamp(40px, 5vw, 72px);
  margin-top: clamp(32px, 4vw, 56px);
  background: var(--surface-1);
  padding: clamp(28px, 4vw, 56px) clamp(24px, 3.4vw, 56px);
  clip-path: polygon(0 0, calc(100% - 0.306 * var(--cut)) 0, 100% var(--cut), 100% 100%, 0 100%);
}
.wo-grid { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(20px, 2.4vw, 32px); }
.f { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.f--wide { grid-column: 1 / -1; }
.f label, .seg legend {
  font-family: var(--f-mono); font-weight: 600;
  font-size: var(--t-field-label); letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-muted);
}
.f input, .f textarea {
  font-family: var(--f-body); font-size: var(--t-body); color: var(--ink);
  background: var(--surface-2);
  border: 0; border-bottom: 2px solid var(--ink);
  border-radius: 0;
  padding: 12px 14px; min-height: 48px; width: 100%;
}
.f textarea { resize: vertical; min-height: 120px; line-height: 1.5; }
.f input:focus, .f textarea:focus {
  outline: none; border-bottom: 3px solid var(--green-mid); padding-bottom: 11px;
}
.f:focus-within label { color: var(--green-mid); }
.f input:user-invalid, .f textarea:user-invalid { border-bottom-color: var(--state-error); }

.seg { display: flex; flex-direction: column; gap: 8px; }
.seg-row { display: flex; flex-wrap: wrap; gap: 2px; }
.seg input {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
.seg label {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 48px; padding: 10px 18px;
  background: var(--surface-2); color: var(--ink);
  font-family: var(--f-mono); font-weight: 600;
  font-size: var(--t-field-label); letter-spacing: 0.1em; text-transform: uppercase;
  cursor: pointer;
}
.seg input:checked + label { background: var(--green-mid); color: var(--paper); }
.seg input:focus-visible + label { outline: 2px solid var(--green-mid); outline-offset: 2px; }

.wo-foot { margin-top: clamp(28px, 3.4vw, 44px); display: flex; flex-direction: column; gap: 14px; align-items: flex-start; }
#wo-submit { --btn-h: 54px; }
.honest {
  font-family: var(--f-mono); font-weight: 600;
  font-size: var(--t-field-label); letter-spacing: 0.06em;
  color: var(--ink-muted);
}
/* --state-error is reserved for validation (brief B §2: functional only), so the demo
   marker is stamped on a surface instead of borrowing the error ink */
.demo-note {
  display: inline-block;
  font-family: var(--f-mono); font-weight: 600;
  font-size: var(--t-field-label); letter-spacing: 0.06em;
  color: var(--ink); background: var(--surface-2);
  padding: 10px 14px;
  margin-bottom: clamp(20px, 2.4vw, 28px);
}
.demo-note[hidden] { display: none; }

/* The Priimo form mounts into this box and brings no outer spacing of its own, so the section
   owns the rhythm around it exactly as it does for .sidenote below. The cap keeps the two field
   columns readable: at the full gutter width a single field runs past 650px, which reads as a
   stretched box rather than something anyone designed. */
.sec--pyynto .form { margin-top: clamp(28px, 3.5vw, 48px); max-width: 900px; }

/* Smart Ask mounts here. Centred under a heading that stays on the gutter: the box is the only
   thing on the page a visitor can type into, and centring is what separates it from the columns
   of copy above and below. The heading keeps the site's left spine so the section still lines up
   with every other one.

   900px is not a taste: the embed insets its own content by max(24px, 6%), so 900 leaves 792px
   for the suggested-question chips. Measured in the page's own font, the four chips run 734px on
   one row — they fit, with 58px to spare. Narrow this and they wrap to two rows; widen it and the
   box stops reading as centred. */
.sec--kysy .ask { margin: clamp(28px, 3.5vw, 48px) auto 0; max-width: 900px; }

/* --- tarjouspyyntölomake ---------------------------------------------------------------
   Hand-rolled form, not the Priimo embed: a scoped exception (7.9.2026) taken because the
   three things this design IS cannot be expressed through the embed's settings — the .blank
   field idiom, mono small-caps labels, and the 73° cut on the button. The embed writes its
   `--pf-*` tokens INLINE inside its shadow root, so a page stylesheet cannot reach them: an
   inherited value loses to the element's own inline declaration, every time.

   The backend stays Priimo's. site.js posts to the same form the console owns, so the lead
   row, the AI assessment and the notification address are unchanged — only the drawing moved.
   Every value below is a token from this stylesheet, so the form ages with the site rather
   than drifting from it. */
.rq-row { display: grid; gap: clamp(16px, 2vw, 20px); }
@media (min-width: 700px) { .rq-row { grid-template-columns: 1fr 1fr; } }
.rq-fld { margin: 0 0 22px; }
.rq-lbl {
  display: flex; align-items: baseline; gap: 8px;
  font-family: var(--f-mono); font-weight: 600; font-size: var(--t-field-label);
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-muted);
  margin-bottom: 8px;
}
/* The word rides the label in body case: an uppercase "VAPAAEHTOINEN" reads as a second
   field name rather than as a note about the one beside it. */
.rq-opt {
  font-family: var(--f-body); font-weight: 400; font-size: 0.75rem;
  letter-spacing: 0; text-transform: none; opacity: 0.8;
}
/* The site's own .blank idiom, promoted to a working field: surface-3 ground under a 2px
   rule, no box and no radius. */
.rq-inp {
  display: block; width: 100%; height: var(--btn-h);
  background: var(--surface-3); border: 0; border-bottom: 2px solid var(--ink-muted);
  border-radius: 0; padding: 0 14px;
  font-family: var(--f-body); font-size: 16px; color: var(--ink);
  transition: border-color 120ms ease-out, background-color 120ms ease-out;
}
.rq-inp::placeholder { color: var(--ink-muted); opacity: 0.62; }
.rq-area { height: 124px; padding-top: 13px; resize: vertical; line-height: 1.45; }
.rq-inp:focus-visible {
  outline: 2px solid var(--green-mid); outline-offset: 2px;
  border-bottom-color: var(--green-mid); background: var(--surface-2);
}
.rq-inp[aria-invalid="true"] { border-bottom-color: var(--state-error); }
.rq-hint, .rq-note { margin: 7px 0 0; font-size: var(--t-meta); color: var(--ink-muted); line-height: 1.4; }
.rq-err { margin: 7px 0 0; font-size: var(--t-meta); color: var(--state-error); }
.rq-send { margin-top: 4px; }
/* Off-screen rather than display:none — a hidden input is not submitted by some browsers,
   and the trap only works if a bot can find and fill it. */
.rq-hp { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.rq-done { max-width: 60ch; }
.rq-done h3 { font-family: var(--f-display); font-weight: 800; font-size: var(--t-display-2); line-height: 1.05; text-transform: uppercase; }
.rq-done p { margin-top: 12px; }
.sidenote {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  margin-top: clamp(24px, 3vw, 36px);
  font-family: var(--f-mono); font-weight: 600;
  font-size: var(--t-field-label); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink-muted);
}
.sidenote .blank { background: var(--surface-2); max-width: 180px; }

/* --- blogi ------------------------------------------------------------------------------
   Lista lainaa palvelulistan rytmin: nimi näyttötyypillä, kuvaus leipätekstinä, seepraraidat.
   Ero on että rivi on linkki, joten se saa myös hover-pinnan ja nuolen. Artikkelisivu on yksi
   kapea palsta — mitään muuta siellä ei ole, eikä pidäkään olla. */
.sec--blogi { padding-block: clamp(40px, 6vw, 72px) clamp(56px, 8vw, 96px); }
.blogi-rows { display: grid; }
.blogi-row {
  position: relative; display: grid; gap: 8px;
  padding: clamp(20px, 2.6vw, 30px) clamp(16px, 2vw, 24px);
  color: var(--ink); text-decoration: none;
  transition: background-color 120ms ease-out;
}
.blogi-row:nth-child(even) { background: var(--surface-1); }
.blogi-row:hover, .blogi-row:focus-visible { background: var(--surface-2); }
.blogi-row h2 {
  font-family: var(--f-display); font-weight: 800;
  font-size: var(--t-h3); line-height: 1.15; text-transform: uppercase;
  color: var(--ink-display); max-width: 32ch;
}
.blogi-ingressi { font-size: var(--t-body); max-width: 58ch; }
.blogi-meta {
  font-family: var(--f-mono); font-weight: 600; font-size: var(--t-field-label);
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-muted);
  display: flex; align-items: center; gap: 10px;
}
.blogi-row:hover .blogi-meta .arrow { transform: translateX(4px); }
.blogi-meta .arrow { color: var(--green-mid); transition: transform 120ms ease-out; }
.blogi-kuva { height: clamp(160px, 26vw, 220px); }
@media (min-width: 900px) {
  .blogi-row { grid-template-columns: minmax(220px, 300px) 1fr; column-gap: clamp(24px, 3vw, 48px); align-items: start; }
  .blogi-kuva { grid-row: span 3; height: 100%; min-height: 180px; }
  .blogi-row h2 { grid-column: 2; }
  .blogi-ingressi, .blogi-meta { grid-column: 2; }
}

/* Artikkeli. Yksi palsta, mitta 60ch, ja otsikot samaa näyttötypografiaa kuin muualla —
   sisältö on tekstiä eikä sen ympärille tarvita mitään. */
.sec--artikkeli { padding-block: clamp(32px, 5vw, 56px) clamp(48px, 6vw, 80px); }
.artikkeli-meta {
  display: flex; align-items: baseline; gap: 10px 18px; flex-wrap: wrap;
  margin-top: clamp(20px, 2.6vw, 28px);
  font-family: var(--f-mono); font-weight: 600;
  font-size: var(--t-field-label); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink-muted);
}
.sec--artikkeli .eyebrow { min-height: 44px; margin-bottom: 4px; }
.sec--artikkeli .eyebrow a {
  display: inline-flex; align-items: center;
  min-height: 44px; padding-inline-end: 8px;
  color: var(--green-mid);
}
.sec--artikkeli .eyebrow a:hover,
.sec--artikkeli .eyebrow a:focus-visible { color: var(--ink-display); }
.sec--artikkeli .page-h1 {
  font-size: clamp(28px, 4vw, 50px);
  max-width: 26ch;
}
/* Article layout B: a contents rail holds the left edge and the text moves off it. Approved
   from the 10.9. mockup comparison. Single column below 1100px — a sticky rail needs height the
   page does not have on a phone, and the list would just push the article down. */
.sec--artikkeli .eyebrow,
.sec--artikkeli .page-h1,
.sec--artikkeli .standfirst,
.sec--artikkeli .artikkeli-meta { max-width: 900px; }
.artikkeli-palsta { display: grid; }
.artikkeli-rail { display: none; }
.artikkeli-teksti h2 { scroll-margin-top: 88px; }
@media (min-width: 1100px) {
  .artikkeli-palsta {
    grid-template-columns: 230px minmax(0, 1fr);
    column-gap: clamp(40px, 4vw, 56px);
    align-items: start;
  }
  .artikkeli-rail {
    display: block;
    position: sticky; top: 24px;
    border-top: 2px solid var(--ink-display);
    padding-top: 12px;
    margin-top: clamp(28px, 3.5vw, 44px);
    max-height: calc(100vh - 48px); overflow-y: auto;
  }
  .artikkeli-rail[hidden] { display: none; }
  .rail-otsikko {
    font-family: var(--f-mono); font-weight: 600;
    font-size: 11px; letter-spacing: 0.09em; text-transform: uppercase;
    color: var(--green-mid); margin: 0 0 10px;
  }
  .artikkeli-toc { list-style: none; padding: 0; margin: 0; display: grid; gap: 1px; counter-reset: t; }
  .artikkeli-toc li { counter-increment: t; font-size: 13px; line-height: 1.35; }
  .artikkeli-toc a {
    color: var(--ink-muted); text-decoration: none;
    display: flex; gap: 8px; align-items: baseline;
    /* WCAG 2.5.8: a one-line entry is 18px of text, and a pointer target may not be under 24. */
    padding-block: 4px; min-height: 24px;
  }
  .artikkeli-toc a::before {
    content: counter(t, decimal-leading-zero);
    color: var(--green-mid); font-family: var(--f-mono); font-size: 10px;
  }
  .artikkeli-toc a:hover, .artikkeli-toc a:focus-visible { color: var(--ink-display); }
  .sec--artikkeli .artikkeli-teksti { max-width: 68ch; }
}
.artikkeli-kuva {
  margin-top: clamp(24px, 3vw, 36px);
  max-width: 900px;
  aspect-ratio: 3 / 2;
  height: auto;
}
.artikkeli-kuva img { width: 100%; height: 100%; object-fit: cover; }
.artikkeli-teksti { margin-top: clamp(28px, 3.5vw, 44px); max-width: 62ch; gap: 1.1em; }
.artikkeli-teksti h2 {
  font-family: var(--f-display); font-weight: 700;
  font-size: var(--t-h3); line-height: 1.05; text-transform: uppercase;
  color: var(--ink-display); max-width: 22ch; margin-top: 0.6em;
}
.artikkeli-teksti h3 {
  font-family: var(--f-body); font-weight: 600;
  font-size: var(--t-standfirst); line-height: 1.35; color: var(--ink-display);
  max-width: 40ch; margin-top: 0.4em;
}
.artikkeli-teksti ul { display: grid; gap: 0.7em; padding-left: 1.15em; list-style: disc; }
.artikkeli-teksti ol { display: grid; gap: 0.7em; padding-left: 1.5em; list-style: decimal; }
.artikkeli-teksti li { font-size: var(--t-body); line-height: 1.55; }
.artikkeli-teksti li::marker { color: var(--green-mid); font-weight: 700; }
.artikkeli-teksti a { color: var(--green-mid); text-decoration-thickness: 1px; text-underline-offset: 2px; }
.artikkeli-teksti a:hover, .artikkeli-teksti a:focus-visible { color: var(--ink-display); }
.artikkeli-teksti strong { font-weight: 700; }

/* --- yhteystiedot + footer -------------------------------------------------------------- */
.yht-band {
  background: var(--ink-display); color: var(--paper);
  padding: clamp(40px, 5vw, 72px) var(--gutter);
  display: grid; grid-template-columns: 1fr 1.2fr; gap: clamp(24px, 3vw, 48px);
  align-items: start;
  font-family: var(--f-mono); font-weight: 600;
  font-size: var(--t-meta); line-height: 1.45;
  letter-spacing: 0.08em; text-transform: uppercase;
}
.yht-cell { display: flex; align-items: baseline; gap: 10px; }
.yht-band .rec-k { color: var(--green-accent); }
.yht-band .rec-v { color: var(--paper); }
.yht-col { display: grid; gap: clamp(20px, 2.6vw, 36px); align-content: start; }
/* D-6: three slots of different label length ragged their bars at both edges and read as
   debris. Subgrid pins every bar to one value column — same start, same end — so the
   cluster reads as a form awaiting entries, which is exactly what it is. */
.yht-open { display: grid; grid-template-columns: max-content 1fr; row-gap: 12px; column-gap: 10px; align-content: start; }
.yht-open-k { color: var(--green-accent); grid-column: 1 / -1; }
.yht-open .yht-cell { display: grid; grid-template-columns: subgrid; grid-column: 1 / -1; }
.yht-mech {
  font-family: var(--f-body); font-weight: 400; font-size: var(--t-body);
  letter-spacing: 0; text-transform: none; line-height: 1.65;
  color: var(--paper); max-width: 46ch;
}

/* 2026-08-03 council SPEC B: the wordmark gains companions (desc + site nav) and the page
   CLOSES on a record strip (.foot-terminal reuses the fold record strip's recipe — open on
   a record, close on a record). */
.footmark {
  padding: clamp(48px, 6vw, 96px) var(--gutter) clamp(40px, 5vw, 72px);
  display: grid; gap: clamp(32px, 4vw, 56px);
  align-items: end;
}
@media (min-width: 1024px) { .footmark { grid-template-columns: minmax(0, 720px) 1fr; } }
.footmark-brand { display: grid; gap: var(--s3); justify-items: start; }
.foot-desc { font-size: var(--t-body); color: var(--ink-muted); }
.foot-nav {
  display: grid; gap: 0; justify-items: start; align-content: end;
  font-family: var(--f-mono); font-weight: 600; font-size: var(--t-meta);
  letter-spacing: 0.08em; text-transform: uppercase;
}
@media (min-width: 1024px) { .foot-nav { justify-self: end; } }
/* 44 px kosketuskorkeus. Linkit olivat 21 px korkeita, mikä alittaa WCAG 2.5.8:n 24 px:n
   vähimmäisrajan — ja alatunnisteessa on tilaa, joten mitään ei tarvinnut tiivistää sen eteen. */
.foot-nav a {
  color: var(--ink); text-decoration: none; transition: color 120ms ease-out;
  display: flex; align-items: center; min-height: 44px;
}
.foot-nav a:hover, .foot-nav a[aria-current="page"] { color: var(--green-mid); }
.foot-terminal {
  display: flex; justify-content: space-between; align-items: baseline; gap: var(--s3); flex-wrap: wrap;
  padding: clamp(9px, 1.5vh, 16px) var(--gutter);
  background: var(--surface-2); color: var(--ink-muted);
  font-family: var(--f-mono); font-weight: 600; font-size: var(--t-field-label);
  letter-spacing: 0.08em; text-transform: uppercase;
}
/* an inline <svg> with only a viewBox falls back to the CSS default object size (300px),
   so the shrink-to-fit span capped the set-piece at 300px and `width: min(100%,720px)` on
   the svg resolved against that 300. The SPAN carries the desktop width; mobile keeps the
   as-cut 300px default. */
.brand--big svg { height: auto; width: min(100%, 720px); }
/* SPEC C (council): yritys evidence grids + values 3-across; recbox goes full-bleed
   everywhere (wide/narrow rhythm — emptiness structured, not filled) */
.recbox { margin-inline: calc(-1 * var(--gutter)); padding-inline: var(--gutter); }
@media (min-width: 1100px) {
  #arki, #ihmiset {
    display: grid;
    grid-template-columns: minmax(0, 60ch) minmax(300px, 1fr);
    column-gap: clamp(40px, 5vw, 96px);
  }
  #arki .sec-head, #arki .prose { grid-column: 1; }
  #arki .media-panel { grid-column: 2; grid-row: 1 / 3; align-self: start; max-width: none; margin-top: 0; }
  #ihmiset .eyebrow--h, #ihmiset .prose, #ihmiset .fact-rows { grid-column: 1; }
  #ihmiset .photo-slot { grid-column: 2; grid-row: 1 / 4; align-self: start; max-width: none; margin-top: 0; }
  /* memo 0.1: the 3-across rule was #arvot-scoped by accident — palvelut's identical
     markup fell to single column and left 60% of the viewport empty (the KENEN AUTOT
     "emptiness" was a missing selector, not a design) */
  .seg-blocks { grid-template-columns: repeat(3, 1fr); gap: clamp(32px, 4vw, 64px); }
}

/* --- breakpoints -------------------------------------------------------------------------- */
@media (min-width: 1024px) {
  .brand--big { width: min(100%, 720px); }

  /* The two quoted display H2s ragged into three narrow lines because the 18ch type cap
     (and the palvelut head's 24ch BODY-ch cap) both bite well before the measure does.
     20ch is measured, both engines, 1024→3440: the window that keeps the authored rag
     (”TEETTEKÖ TÄLLÄSTÄ / TYÖTÄ?” · ”MILLO ONNISTUU JA / MILLON ON VALMISTA?”) is
     [18.4ch, 21.9ch] — outside it the line either swallows MILLON or breaks a third time. */
  .sec--palvelut .sec-head { max-width: none; }
  .sec--palvelut h2, .sec--toiminta h2 { max-width: 20ch; }
}

@media (max-width: 1023px) {
  :root { --header-h: 60px; }
  .nav, .hdr-cta { display: none; }
  .burger { display: flex; }
  .brand--full { display: none; }
  .brand--mono { display: block; }

  .record { grid-template-columns: 1fr 1fr; row-gap: 6px; }
  .rec-osoite { grid-column: 1 / -1; }

  /* Stacked: the join cannot stay a full-height near-vertical edge, so each segment keeps
     the SAME measured cut on its leading (top-left) corner — one constant, no new angle. */
  .chevrons { --chev-h: 72px; flex-direction: column; }
  .chev, .chev:first-child, .chev:last-child, .chev:not(:last-child) {
    flex: 0 0 auto; margin-left: 0; min-height: 0;
    padding-block: clamp(18px, 4vw, 26px);
    padding-inline: var(--gutter);
    clip-path: polygon(var(--chev-run) 0, 100% 0, 100% 100%, 0 100%, 0 var(--chev-h));
  }

  .wo-grid { grid-template-columns: 1fr; }
  .yht-band { grid-template-columns: 1fr; }
  .stmt:nth-child(3n+2) { margin-left: 24px; }
  .stmt:nth-child(3n) { margin-left: 12px; }
}

@media (max-width: 560px) {
  #hero-cta, .menu-cta { --btn-h: 54px; width: 100%; }
  .cta-row { align-items: flex-start; flex-direction: column; gap: 14px; }
  .seg-row { display: grid; grid-template-columns: 1fr 1fr; }
  .blank { min-width: 48px; }
  .kalusto, .record { font-size: 0.75rem; letter-spacing: 0.05em; }
  /* Yksi sarake, ei kahta. Kahdella 160 px:n sarakkeella "PUHELIN: 050 414 2883" katkesi
     kesken numeron ja Y-tunnus jäi eri korkeudelle kuin puhelin — mitattu 375 px:llä 9.9.2026,
     ja se luki rikkinäisenä. Osoite vei jo koko rivin, joten sarakkeita oli kaksi vain kahdelle
     lyhyelle riville. Yhtenä pinona jokainen tieto saa oman rivinsä eikä numero katkea. */
  .record { grid-template-columns: 1fr; column-gap: 14px; row-gap: 8px; }
  /* flow the record cells as text on phones: WebKit's mono advance is a hair wider than
     Chromium's, so the address wraps at 360px in one engine and not the other — as flex
     rows that produced a hanging indent under the label instead of a plain text wrap. */
  .record .rec-cell, .record .rec-k, .record .rec-v { display: inline; }
  .record .rec-cell { display: block; }
  .record .blank { width: 96px; min-width: 0; height: 0.85em; vertical-align: -1px; }
}

/* ==== 2026-08-03 wave 2: the ambient stack (memo A1+A2+A3) ==============================
   A1 TONAL ROOMS — sections get floors from the existing ramp; the 73° cut scaled up as
   the section threshold (next room's ground shows through the notch = depth from flat
   surfaces). Deployment varies corner and rhythm — never every section (zebra-at-scale).
   Content inside a room steps one surface up; the form panel steps LIGHTER (paper) —
   elevation-by-lighter is the house depth law at composed scale. */
.room { background-color: var(--surface-1); }
/* 4.8. (owner): a room following a surface-1 zebra list steps DEEPER so the threshold
   never carries the previous section's tint across the cut */
.room--deep { background-color: var(--surface-2); }
.room--deep .recbox { background: var(--surface-3); }
.room--cut-tl {
  --room-cut: clamp(56px, 9vw, 140px);
  clip-path: polygon(calc(0.306 * var(--room-cut)) 0, 100% 0, 100% 100%, 0 100%, 0 var(--room-cut));
  padding-top: calc(var(--room-cut) + clamp(24px, 3vw, 48px));
}
.room--cut-tr {
  --room-cut: clamp(56px, 9vw, 140px);
  clip-path: polygon(0 0, calc(100% - 0.306 * var(--room-cut)) 0, 100% var(--room-cut), 100% 100%, 0 100%);
  padding-top: calc(var(--room-cut) + clamp(24px, 3vw, 48px));
}
/* room content steps: chevrons up one, form/CTA plates go lighter than the floor */
.room .chev:nth-child(odd) { background: var(--surface-2); }
.room .chev:nth-child(even) { background: var(--surface-3); }
/* WCAG 1.4.3: --green-mid on --surface-3 measures 4.25:1 at 13px. Two steps darker lands on exactly
   the 4.79:1 the odd segments already have on --surface-2, so the strip keeps one contrast. */
.room .chev:nth-child(even) .chev-k { color: oklch(0.43 0.119 149); }
.room .wo { background: var(--paper); }
.room .recbox { background: var(--surface-2); }
.room .photo-slot { background: var(--surface-2); }

/* A3's työmääräys ruling lived here: faint ledger lines behind the two request sections, on the
   argument that ruling under a form is content rather than decoration. It was drawn when those
   sections held a heading and an empty box. Now they hold an actual form, and the 44px rules run
   straight through the field boxes and their labels - the reading the argument assumed is exactly
   the reading it prevents. Removed 7.9.2026 (owner). The tile is in git if the ledger returns. */

/* A2 — paper grain, the measured whisper: mono SVG noise, multiply (ink-on-paper — only
   darkens), 0.05 at the perceptible-not-dirt point. One fixed layer, applied to the whole
   page so every surface shares the same material. */
body::after {
  content: '';
  position: fixed; inset: 0; z-index: 200;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  mix-blend-mode: multiply;
  opacity: 0.05;
}

/* ==== 2026-08-03 comp build: photos, subpages, motion additions =========================
   Photo policy (reframe): stock placeholders, self-hosted, DT-graded in CSS (grade never
   baked into files so the client's real photos drop in and match). NO text over photos —
   captions sit on the ground below. Grade = neutral desaturation only — the 4.8. team
   round killed the hue-148 cast ("even pics have green filter"). */

.ph { display: block; position: relative; overflow: hidden; background: var(--surface-2); }

/* Kuvien esiaste (LQIP). `.ph`:n oma --surface-2 on vaalea ja valokuvat ovat tummia
   dokumenttikuvia, joten lazy-kuvan ilmestyminen oli hyppy vaaleasta tummaan - se on se
   välähdys jonka silmä huomaa. Alla jokaiselle kuvalle 24px leveä versio itsestään, joka
   venytetään paikalle: arvo ja muoto ovat valmiiksi oikein, ja tarkka kuva vaihtuu päälle
   ilman hyppyä.

   Sävy on poltettu esiasteeseen (grayscale 0.88 x saturate 0.9, sama kuin `.ph img`), jotta
   se vastaa lopullista kuvaa eikä välähdä värillisenä.

   Sidottu tiedostonimeen `:has()`-valitsimella tarkoituksella: kuvat ovat asiakkaan kenttiä,
   ja kun Jori vaihtaa kuvan, valitsin lakkaa osumasta ja `.ph` palaa nykyiseen pintaansa.
   Vanhentumisen seuraus on siis nykytila, ei rikkinäinen sivu. Yhteensä 6,9 kt.
   Selain joka ei tunne `:has()`-valitsinta saa niin ikään nykytilan. */
.ph { background-size: cover; background-position: 50% 50%; background-repeat: no-repeat; }
.ph:has(img[src$="detail-kansi-tyokalu-800.webp"]) { background-image: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDABMNDhEODBMRDxEVFBMXHTAfHRoaHToqLCMwRT1JR0Q9Q0FMVm1dTFFoUkFDX4JgaHF1e3x7SlyGkIV3j214e3b/2wBDARQVFR0ZHTgfHzh2T0NPdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnb/wAARCAAQABgDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAwABBv/EAB4QAAEEAwEBAQAAAAAAAAAAAAEAAgMEERIhE0Ex/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/AOfsU5bIL4WmQNHQP1F5tkobF2JIzqWn6EVa7Ypyl0TsE/Cs2fLIXPwXOOThAORuAeBSUR+kwZGOnhBUg//Z); }
.ph:has(img[src$="detail-paku-nostin-800.webp"]) { background-image: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDABMNDhEODBMRDxEVFBMXHTAfHRoaHToqLCMwRT1JR0Q9Q0FMVm1dTFFoUkFDX4JgaHF1e3x7SlyGkIV3j214e3b/2wBDARQVFR0ZHTgfHzh2T0NPdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnb/wAARCAAQABgDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAMEBQb/xAAiEAACAQMEAgMAAAAAAAAAAAABAgMABBEFEiExEzJBYXH/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8ATquIrhYodnkc4yx9R90+ztJooX81ys3GQIzz+Vh62LuG7K3HsxyCvyKkgEqOA5ZFJ76oOnR4VVG3OjHsNwaKkTUEltMSANImMNjvFFB//9k=); }
.ph:has(img[src$="detail-vaihteisto-800.webp"]) { background-image: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDABMNDhEODBMRDxEVFBMXHTAfHRoaHToqLCMwRT1JR0Q9Q0FMVm1dTFFoUkFDX4JgaHF1e3x7SlyGkIV3j214e3b/2wBDARQVFR0ZHTgfHzh2T0NPdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnb/wAARCAAQABgDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAMEBf/EACMQAAIBBAEDBQAAAAAAAAAAAAECAwAEBRESFSExIkFRgaH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/AIxePFiwjSkyht81PkCndSleeMyowiHcgdifg03LYfnJGttGBGBrX3V7W0caM7hm4qPSfbVQZOS5EJdmIiIfh3RT5zc5ErCRxj8jtRVH/9k=); }
.ph:has(img[src$="detail-vaunu-kuilu-800.webp"]) { background-image: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDABMNDhEODBMRDxEVFBMXHTAfHRoaHToqLCMwRT1JR0Q9Q0FMVm1dTFFoUkFDX4JgaHF1e3x7SlyGkIV3j214e3b/2wBDARQVFR0ZHTgfHzh2T0NPdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnb/wAARCAAQABgDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQFAgP/xAAgEAACAgIBBQEAAAAAAAAAAAABAgQRAANRBRIhIjFB/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/AOetJiajJkAELRCXXzMSZshgnfpHsLWny5NhmR8ekqiOcg9WjmKmjZqJNvRH5gNaYhnIh2k6mXg2MMcWMkVdb+e1gPa/F8YYH//Z); }
.ph:has(img[src$="hero-halli-oma-1400.webp"]) { background-image: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDABMNDhEODBMRDxEVFBMXHTAfHRoaHToqLCMwRT1JR0Q9Q0FMVm1dTFFoUkFDX4JgaHF1e3x7SlyGkIV3j214e3b/2wBDARQVFR0ZHTgfHzh2T0NPdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnb/wAARCAANABgDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAMCBAX/xAAiEAACAgEDBAMAAAAAAAAAAAABAgADEQQSMQUUIUFRYaH/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8AqPl773TdzgKo/IgtcGNTIwweIprXXUCqtiobyT9x1tbd01ZsYnYCW9mBv9MpFVAByWbnMJHR6orfRVtBFgyT8Qgf/9k=); }
.ph:has(img[src$="hero-outcome-tie-1400.webp"]) { background-image: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDABMNDhEODBMRDxEVFBMXHTAfHRoaHToqLCMwRT1JR0Q9Q0FMVm1dTFFoUkFDX4JgaHF1e3x7SlyGkIV3j214e3b/2wBDARQVFR0ZHTgfHzh2T0NPdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnb/wAARCAAQABgDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAABgAF/8QAIhABAAIBAgYDAAAAAAAAAAAAAQIDAAQRBRITITFBFCNR/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/AD0Q0lgwmsVPWM9Dr6fh1/Yb7ePeCLen0yJePfwDmzXo4VUxkuzyEuYe7vga2s4vCqRyo5Yb1NUVQsd39ywP/9k=); }
.ph:has(img[src$="hero-palvelut-tilt-1400.webp"]) { background-image: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDABMNDhEODBMRDxEVFBMXHTAfHRoaHToqLCMwRT1JR0Q9Q0FMVm1dTFFoUkFDX4JgaHF1e3x7SlyGkIV3j214e3b/2wBDARQVFR0ZHTgfHzh2T0NPdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnb/wAARCAAQABgDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAQBAgb/xAAfEAACAgICAwEAAAAAAAAAAAABAgMRAAQSMSEiQbH/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8AzuntlNdfQMS9eRlNyZZuZaNUZTQCjFoHeEi17ugRjUGqu1ZU230XWAlx5IXHV1hkzwya7lHFH9wwP//Z); }
.ph:has(img[src$="hero-yhteys-halli-1400.webp"]) { background-image: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDABMNDhEODBMRDxEVFBMXHTAfHRoaHToqLCMwRT1JR0Q9Q0FMVm1dTFFoUkFDX4JgaHF1e3x7SlyGkIV3j214e3b/2wBDARQVFR0ZHTgfHzh2T0NPdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnb/wAARCAAQABgDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAMFBAb/xAAiEAACAQMEAgMAAAAAAAAAAAABAgADERIEBRMhFEExUWH/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A5ngP1Gpo2ewVbkyoa235Nx1FxB6v7j6Or0qriMWF/cDDQ2lQDmSz26C/AhK3l02JsVA/IQP/2Q==); }
.ph:has(img[src$="hero-yritys-halli-1400.webp"]) { background-image: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDABMNDhEODBMRDxEVFBMXHTAfHRoaHToqLCMwRT1JR0Q9Q0FMVm1dTFFoUkFDX4JgaHF1e3x7SlyGkIV3j214e3b/2wBDARQVFR0ZHTgfHzh2T0NPdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnb/wAARCAAxABgDASIAAhEBAxEB/8QAGgAAAgMBAQAAAAAAAAAAAAAAAAIBAwQFBv/EACEQAAICAQUBAAMAAAAAAAAAAAABAgMRBBIhMUEiFUJR/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/APHY+kNKGPBo7XPr06+o02l/GV2Vybt/ZAcFsB54XjACU3HDL43ScMZ49MycrGoZz4jVLTW6erc5LbLhpMDLOWcgWzrnU9zXfvgATpoxj9tcmm63fTKLZjhPhDbwK4XThxnMf4wGeO8ABVDscAAhgAAf/9k=); }
.ph:has(img[src$="liite-rekka-800.webp"]) { background-image: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDABMNDhEODBMRDxEVFBMXHTAfHRoaHToqLCMwRT1JR0Q9Q0FMVm1dTFFoUkFDX4JgaHF1e3x7SlyGkIV3j214e3b/2wBDARQVFR0ZHTgfHzh2T0NPdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnb/wAARCAAgABgDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAMBBAUG/8QAIRABAAIDAAIBBQAAAAAAAAAAAQIDAAQREjFBBRQhUbH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/AKdUK5vkyn3nOHrG3Uv282sl0FO/OZG1ttB4VnV57zT+n7ENrVLGwlZE5KMl/GQc7Om6t8p1ziftMMt7E57O0iHyBH04ZRE+zssISCScFeYnV2HWquj3kk4ZEllex6dxMYttyAqvowHaey1bUbHqno53DNHR04az52BKz+YYH//Z); }
.ph:has(img[src$="panel-band-matkailuautot-800.webp"]) { background-image: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDABMNDhEODBMRDxEVFBMXHTAfHRoaHToqLCMwRT1JR0Q9Q0FMVm1dTFFoUkFDX4JgaHF1e3x7SlyGkIV3j214e3b/2wBDARQVFR0ZHTgfHzh2T0NPdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnb/wAARCAAkABgDASIAAhEBAxEB/8QAGgABAAIDAQAAAAAAAAAAAAAAAAMEAQIFBv/EACEQAAICAgEFAQEAAAAAAAAAAAECAAMREgUEEyFBgXGR/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwDoLTJlqhiqDLHAkK8h03tiD+SotdoRFFtd9YdDkRIry9nVbZBub7OfcjF9++QPeoMuNx9RPnb+zKcdQPTH7AkqvepAu7sMeMHESwiLWuoGAIgayRYiBkjzERA//9k=); }
.ph:has(img[src$="panel-band-pakettiautot-800.webp"]) { background-image: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDABMNDhEODBMRDxEVFBMXHTAfHRoaHToqLCMwRT1JR0Q9Q0FMVm1dTFFoUkFDX4JgaHF1e3x7SlyGkIV3j214e3b/2wBDARQVFR0ZHTgfHzh2T0NPdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnb/wAARCAAbABgDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAQFA//EACIQAAICAgICAgMAAAAAAAAAAAECAxEABBIhBRMiMVFSkf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwDWRFVGZloKO7yVtbuxFKuzFfruhfV5q/l+UbD1DiO+zZOLz72xspREQUrQH1gMa+4zSK0go/d1V4YgskgoSECulAN1hgNQ+M2YdjlHEzJVfNhd5snhpmioqqv+S/X8rLQJN94WScCXqeFeOXlLPGy/rRwytxGGB//Z); }
.ph:has(img[src$="panel-rekat-keula-800.webp"]) { background-image: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDABMNDhEODBMRDxEVFBMXHTAfHRoaHToqLCMwRT1JR0Q9Q0FMVm1dTFFoUkFDX4JgaHF1e3x7SlyGkIV3j214e3b/2wBDARQVFR0ZHTgfHzh2T0NPdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnb/wAARCAASABgDASIAAhEBAxEB/8QAGgABAAIDAQAAAAAAAAAAAAAAAAMEAQIFBv/EACMQAQABBAEDBQEAAAAAAAAAAAECAAMEEQUSITETIkFCYYH/xAAVAQEBAAAAAAAAAAAAAAAAAAABAP/EABURAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIRAxEAPwCLmuauRzWxjXOnQd3WmqM+U5GTtybe/wAmVQy+mGQCSWMQkPndQrafiR/KU9Dw/K3L+S42RcZykPuHsUri4koFyRFkMooPh3SpM5yuddV29VV3zSlIbW19WHf7FKUopf/Z); }
.ph:has(img[src$="panel-toiminta-diag-800.webp"]) { background-image: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDABMNDhEODBMRDxEVFBMXHTAfHRoaHToqLCMwRT1JR0Q9Q0FMVm1dTFFoUkFDX4JgaHF1e3x7SlyGkIV3j214e3b/2wBDARQVFR0ZHTgfHzh2T0NPdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnb/wAARCAAQABgDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAgAEBf/EACIQAAICAgEDBQAAAAAAAAAAAAECAxEAEgQTFTEhIkFRgf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwDjAL2yl9GaSiPzMvHuGQuYw8YNEXhSZxH0ovcNtvGNIp9t2Gob4JwDy2V6Kihfj6yxdGQMbXLA/9k=); }
.ph img {
  display: block; width: 100%; height: 100%; object-fit: cover;
  filter: grayscale(0.88) saturate(0.9);
}

/* full-bleed photo bands (index below-fold · outcome · yhteystiedot) */
.photo-band { margin: 0; }
.photo-band .ph {
  --cut: clamp(40px, 5vw, 72px);
  height: clamp(300px, 42vw, 560px);
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - 0.306 * var(--cut)) 100%, 0 100%);
}
.ph-caption {
  display: flex; align-items: center; gap: 12px;
  padding: clamp(12px, 1.6vh, 18px) var(--gutter);
  font-family: var(--f-mono); font-weight: 600;
  font-size: var(--t-meta); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--green-mid);
}

/* band photo panel (right slab ≥900px, top strip below) */
.band-photo { display: block; }
.band-photo .ph, .band-photo img { height: 100%; }
@media (min-width: 900px) {
  .band-photo {
    position: absolute; inset-block: 0; right: 0;
    width: min(38%, 560px);
  }
  .band-photo .ph {
    --cut: 48px; height: 100%;
    clip-path: polygon(0 0, 100% 0, 100% 100%, calc(0.306 * var(--cut)) 100%, 0 calc(100% - var(--cut)));
  }
  .band > :not(.band-photo) { max-width: calc(100% - min(38%, 560px) - var(--s3)); }
}
@media (max-width: 899px) {
  .band-photo {
    order: -1;
    margin: calc(-1 * clamp(24px, 3vw, 40px)) calc(-1 * var(--gutter)) 8px;
  }
  .band-photo .ph { height: clamp(150px, 34vw, 240px); }
}

/* toimintatapa: the CONVERSATION (4.8.) — customers' question top-left, the shop's answer
   in the right column dropped a beat LOWER: the vertical mismatch is what makes two quoted
   display lines read as question and reply. Mobile stacks like chat (answer indented). */
.toiminta-head { display: grid; gap: clamp(20px, 3vw, 40px); }
.pull--answer { margin-left: clamp(24px, 8vw, 48px); }
@media (min-width: 1024px) {
  .toiminta-head { grid-template-columns: minmax(0, 1fr) var(--lane); column-gap: clamp(40px, 5vw, 96px); }
  .pull--answer {
    grid-column: 2;
    margin-left: 0;
    margin-top: clamp(96px, 14vw, 200px);
    align-self: start;
  }
}

/* miksi: claims left, evidence right (the freed photo reads as quality inspection) */
@media (min-width: 1100px) {
  .miksi-grid { display: grid; grid-template-columns: minmax(0, 1fr) var(--lane); column-gap: clamp(40px, 5vw, 96px); align-items: center; }
  .miksi-media { margin-top: 0; max-width: none; }
}

/* two-up detail strip (palvelut) + standalone media panel (yritys) */
.detail-duo {
  margin-top: clamp(32px, 4vw, 56px);
  display: grid; gap: clamp(16px, 2vw, 24px);
}
.detail-duo .ph {
  --cut: 48px;
  aspect-ratio: 3 / 2;
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - 0.306 * var(--cut)) 100%, 0 100%);
}
@media (min-width: 700px) { .detail-duo { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); } }
/* 4.8. (owner): without the rail, ONE photo is the beat between list and CTA — a stack of
   three before the dark band read as filler on small screens */
@media (max-width: 1199px) {
  .detail-duo { grid-template-columns: 1fr; }
  .detail-duo .ph:not(:first-child) { display: none; }
}
.media-panel { margin-top: clamp(24px, 3vw, 40px); max-width: 560px; }
.media-panel .ph {
  --cut: 48px;
  aspect-ratio: 3 / 2;
  clip-path: polygon(calc(0.306 * var(--cut)) 0, 100% 0, 100% 100%, 0 100%, 0 var(--cut));
}

/* honest empty photo slot (yritys TIIMIKUVA — no stock faces as staff, ever) */
.photo-slot {
  --cut: 48px;
  min-height: clamp(220px, 30vw, 360px);
  display: grid; place-content: center;
  background: var(--surface-2);
  clip-path: polygon(calc(0.306 * var(--cut)) 0, 100% 0, 100% 100%, 0 100%, 0 var(--cut));
}
.photo-slot p {
  font-family: var(--f-mono); font-weight: 600;
  font-size: var(--t-meta); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink-muted);
}

/* --- subpage skeleton ------------------------------------------------------------------ */
:root { --t-page-h1: clamp(2.75rem, 6vw, 5.75rem); }
.page-hero { padding: clamp(40px, 6vw, 80px) var(--gutter) clamp(32px, 4vw, 56px); }
/* wave 2.5: subpage heroes get the same ambient right field as the fold */
@media (min-width: 1100px) {
  .page-hero { position: relative; }
  .page-hero::before {
    content: '';
    position: absolute; top: 0; right: 0; height: 100%;
    width: clamp(280px, 34%, 640px);
    background: var(--surface-1);
    --fc: clamp(64px, 7vw, 112px);
    clip-path: polygon(0 0, 100% 0, 100% 100%, calc(0.306 * var(--fc)) 100%, 0 calc(100% - var(--fc)));
  }
  .page-hero > * { position: relative; }
}
.page-h1 {
  font-family: var(--f-display); font-weight: 800;
  font-size: var(--t-page-h1); line-height: 0.95;
  letter-spacing: 0.005em; text-transform: uppercase;
  color: var(--ink-display);
  hyphens: none; -webkit-hyphens: none;
  /* the base h1 rule pins nowrap for the front page's authored two-liner (R17 note there);
     subpage H1s are normal wrapping copy */
  white-space: normal;
}
.page-hero .standfirst { margin-top: clamp(16px, 2.4vw, 28px); }

/* 73° curtain wipe — the one entrance beat per subpage (CSS-only). Inverted gating: the
   default state is fully visible; hiding + animating exists ONLY inside no-preference,
   so JS-off, reduced-motion and unknown UAs all get plain visible content. */
@media (prefers-reduced-motion: no-preference) {
  .page-h1 { clip-path: polygon(-2% 0, -2% 0, -8% 110%, -8% 110%); animation: h1-wipe 560ms cubic-bezier(0.16, 1, 0.3, 1) 80ms forwards; }
  @keyframes h1-wipe {
    to { clip-path: polygon(-2% 0, 102% 0, 96% 110%, -8% 110%); }
  }
}

/* palvelulista — scannable rows (NOT a numbered index: identity ledger), underline draw */
.palvelu-rows { margin-top: clamp(32px, 4vw, 56px); display: grid; }
.palvelu-row {
  position: relative;
  display: grid; gap: 6px;
  padding: clamp(18px, 2.4vw, 28px) clamp(16px, 2vw, 24px);
  transition: background-color 120ms ease-out;
}
.palvelu-row:nth-child(even) { background: var(--surface-1); }
.palvelu-row:hover { background: var(--surface-2); }
.palvelu-row h3 {
  position: relative; align-self: start; justify-self: start;
  font-family: var(--f-display); font-weight: 800;
  font-size: var(--t-h3); line-height: 1.1; text-transform: uppercase;
  color: var(--ink-display);
}
.palvelu-row h3::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -4px; height: 3px;
  background: var(--green-mid);
  transform: scaleX(0); transform-origin: left center;
  transition: transform 160ms ease-out;
}
.palvelu-row:hover h3::after { transform: scaleX(1); }
.palvelu-row p { font-size: var(--t-body); max-width: 60ch; }
@media (min-width: 900px) {
  .palvelu-row { grid-template-columns: minmax(220px, 320px) 1fr; gap: clamp(16px, 3vw, 48px); align-items: baseline; }
}

/* kalusto segments + arvot (yritys) — same statement+body grammar as #miksi */
.seg-blocks { margin-top: clamp(32px, 4vw, 56px); display: grid; gap: clamp(28px, 4vw, 48px); }
.seg-block h3 {
  font-family: var(--f-display); font-weight: 700;
  font-size: var(--t-h2); line-height: 1; text-transform: uppercase;
  color: var(--ink-display);
}
.seg-block p { margin-top: 10px; font-size: var(--t-body); max-width: 52ch; }

/* prose (yritys tarina) */
.prose { margin-top: clamp(24px, 3vw, 40px); max-width: 60ch; display: grid; gap: 1em; }
.prose p { font-size: var(--t-standfirst); line-height: 1.6; }

/* mono record rows (yhteystiedot facts + yritys person row) */
.fact-rows {
  margin-top: clamp(24px, 3vw, 40px);
  display: grid; gap: 12px;
  font-family: var(--f-mono); font-weight: 600;
  font-size: var(--t-meta); letter-spacing: 0.08em; text-transform: uppercase;
}
.fact-rows p { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.fact-rows .rec-v { letter-spacing: 0.06em; }

/* dark CTA band (4.8., owner swap + hover-carry fix): the mid-page conversion moment on
   an inverse ground — no zebra/hover surface can ever collide with it (genre: a dark CTA
   band mid-page was 4/6 on the premium live-web audit) */
.sec--cta {
  --cut: clamp(56px, 8vw, 120px);
  margin-top: clamp(48px, 6vw, 88px);
  padding-block: calc(var(--cut) * 0.5 + clamp(32px, 4.4vw, 56px)) clamp(48px, 6vw, 80px);
  background: var(--ink-display); color: var(--paper);
  display: grid; gap: clamp(18px, 2.6vw, 28px); justify-items: start;
  clip-path: polygon(calc(0.306 * var(--cut)) 0, 100% 0, 100% 100%, 0 100%, 0 var(--cut));
}
.sec--cta p { font-size: var(--t-standfirst); max-width: 46ch; color: var(--paper); text-wrap: pretty; }
.sec--cta .btn--primary:hover { background: var(--paper); color: var(--ink-display); }

/* ==== wave 4: microstates + section treatments (memo C2/C3a/C4/B3/D3) =================== */
/* C2 — the page's biggest links answer in three channels (65's liked hover grammar) */
.band-photo .ph img { transition: transform 300ms cubic-bezier(0.33, 1, 0.68, 1); }
.band:hover .band-photo .ph img, .band:focus-visible .band-photo .ph img { transform: scale(1.03); }
.band-name { transition: transform 200ms cubic-bezier(0.33, 1, 0.68, 1); }
.band:hover .band-name, .band:focus-visible .band-name { transform: translateX(8px); }

/* C3a REVERTED 4.8. (memo + owner): rows are inert information — hover stays as a
   reading aid; conversion lives in the CTA band ("Useampi työ samaan pyyntöön — kuvaus
   riittää."). Accordion decision gated on the record drafts (docs/memo-service-list). */

/* C4 — uniform microstate coverage: every interactive element answers in ≤160ms */
.link-secondary, .band-outro a, .seg label, .f input, .f textarea, .menu-nav a, .nav a {
  transition: color 120ms ease-out, background-color 120ms ease-out, border-color 120ms ease-out;
}
.foot-nav a .arrow { transition: transform 120ms ease-out; }
.foot-nav a:hover .arrow { transform: translateX(4px); }

/* B3 — photo bands drift a few percent slower than the page (scroll-driven, zero JS;
   Firefox and reduce get the static band) */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .photo-band .ph { overflow: hidden; }
    .photo-band .ph img {
      height: 116%;
      animation: band-drift linear both;
      animation-timeline: view();
    }
    @keyframes band-drift {
      from { transform: translateY(0); }
      to { transform: translateY(-13%); }
    }
  }
}

/* D3 — TYOLISTA side rail (owner's false-floor concern: the list stays UNBROKEN; photos
   carry mass beside it, anchored top and bottom of the rail; mobile keeps them after
   the list where an ending is correct) */
@media (min-width: 1200px) {
  .tyolista-wrap { display: grid; grid-template-columns: minmax(0, 1fr) minmax(300px, 380px); column-gap: clamp(32px, 4vw, 64px); }
  .tyolista-wrap .detail-duo { grid-template-columns: 1fr; align-content: space-between; margin-top: clamp(32px, 4vw, 56px); }
}

/* ==== wave 3: entrance grammar (memo B1+B2+B4) ==========================================
   Hidden states live ONLY under html.motion (JS-set, never under reduced-motion) AND
   inside no-preference — belt and braces: any failure mode lands on the painted page.
   One family: 500ms ease-out breath, 14px rise, group children cascade via --d. */
@media (prefers-reduced-motion: no-preference) {
  html.motion .rv {
    opacity: 0;
    transform: translateY(14px);
    transition:
      opacity 500ms cubic-bezier(0.33, 1, 0.68, 1) var(--d, 0ms),
      transform 500ms cubic-bezier(0.33, 1, 0.68, 1) var(--d, 0ms);
  }
  html.motion [data-inview].rv,
  html.motion [data-inview] > .rv {
    opacity: 1;
    transform: none;
  }
  /* B4: the eyebrow tick draws in after its section head lands */
  html.motion .sec-head.rv .tick, html.motion .eyebrow--h.rv .tick {
    transform: scaleY(0); transform-origin: bottom left;
    transition: transform 280ms cubic-bezier(0.33, 1, 0.68, 1) 260ms;
  }
  html.motion .sec-head[data-inview] .tick, html.motion .eyebrow--h[data-inview] .tick {
    transform: scaleY(1);
  }
}

/* header hairline: appears on first scroll (a divider as scroll feedback, not depth) */
.site-header { border-bottom: 1px solid transparent; transition: border-color 200ms ease-out; }
html.scrolled .site-header { border-bottom-color: var(--surface-3); }

/* Logo tightens on the first scroll, alongside the hairline above: 40px -> 30px, one easing,
   no swap between the wordmark and the mark. The chosen option of five (7.9.2026).

   The LOGO shrinks and the header does not. `.site-header` is sticky, which means it still
   occupies its height in flow — animating that height would pull every pixel below it up by
   the same amount, and a page that moves under you while you scroll it is the one complaint
   this whole header is trying not to earn. The perceived tightening comes from the mark; the
   band stays exactly where it was.

   Both marks carry it: the wordmark on desktop, the square mark below 837px.

   Rajattu otsikkopalkkiin. `.brand` on myös alatunnisteen isolla merkillä (`.brand--big`,
   `height: auto`), ja rajaamaton `html.scrolled .brand svg` voitti sen tarkkuudella - eli
   kutisti alatunnisteen logon 30 pikseliin heti kun sivua oli vieritetty, mikä on aina siihen
   mennessä kun alatunniste on näkyvissä. Löytyi julkaistulta sivulta 8.9.2026. */
/* Osumapinta ei kutistu logon mukana. Kun merkki menee 40 px:stä 30 px:iin, linkin korkeus
   seurasi perässä ja jäi alle kosketuskoon — oman animaation sivuvaikutus, mitattu 375 px:llä.
   Merkki saa kutistua, laatikko ei. Rajattu palkkiin, koska .brand on myös alatunnisteessa. */
.site-header .brand { display: flex; align-items: center; min-height: 44px; }
/* `display: flex` yllä on tarkempi kuin `.brand--mono { display: none }`, joten ilman näitä
   kahta riviä molemmat merkit näkyisivät vierekkäin. Vaihto toistetaan tässä samalla
   tarkkuudella ja samalla rajalla (1023px) kuin alkuperäinen sääntö. */
.site-header .brand--mono { display: none; }
@media (max-width: 1023px) {
  .site-header .brand--full { display: none; }
  .site-header .brand--mono { display: flex; }
}
.site-header .brand svg { transition: height 420ms cubic-bezier(0.22, 0.61, 0.36, 1); }
html.scrolled .site-header .brand svg { height: 30px; }
@media (prefers-reduced-motion: reduce) {
  .site-header .brand svg { transition: none; }
}

/* Sivunvaihto ristiin. Neljä sivua on yksi esine, ei neljä latausta: selain ottaa vanhasta
   ja uudesta sivusta tilannekuvan ja häivyttää ne ristiin 200 ms:ssä. Ei JS:ää, ei reittiä,
   ei kirjastoa - Safari ja Firefox saavat nykyisen kovan leikkauksen kunnes ne tukevat tämän.

   Otsikkopalkilla on oma nimi, ja se on koko idea: ilman sitä palkki kuuluisi sivun
   tilannekuvaan ja välähtäisi mukana. Nimettynä se on oma kerroksensa joka pysyy paikallaan
   vaihdon yli, ja vain sen sisältö - aktiivisen linkin alleviivaus - vaihtuu pehmeästi.
   Silloin liike lukee tarkoitukselliselta eikä lataukselta. */
@view-transition { navigation: auto; }
::view-transition-old(root), ::view-transition-new(root) {
  animation-duration: 200ms;
  animation-timing-function: cubic-bezier(0.22, 0.61, 0.36, 1);
}
.site-header { view-transition-name: site-header; }
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) {
    animation: none !important;
  }
}

/* sliding nav indicator (JS enhancement; static per-link underbar is the fallback) */
.nav { position: relative; }
.nav-indicator {
  position: absolute; left: 0; bottom: 2px; height: 3px; width: 1px;
  background: var(--green-mid);
  transform-origin: left center;
  transition: transform 160ms ease-out, opacity 120ms ease-out;
  opacity: 0; pointer-events: none;
}
.js .nav.has-indicator a::after { content: none; }
.nav a[aria-current="page"] { color: var(--green-mid); }
html:not(.js) .nav a[aria-current="page"]::after,
.nav:not(.has-indicator) a[aria-current="page"]::after { transform: scaleX(1); }

@media (prefers-reduced-motion: reduce) {
  .nav a::after { transition: none; transform: scaleX(1); opacity: 0; }
  .nav a:hover::after { opacity: 1; }
  .arrow, .btn, .menu, .band, .burger-bar { transition: none; }
  .btn--primary:hover .arrow { transform: none; }
  .btn--primary:active { transform: none; }
  .menu { transform: none; }
  .palvelu-row h3::after { transition: none; transform: scaleX(1); opacity: 0; }
  .palvelu-row:hover h3::after { opacity: 1; }
  .nav-indicator { transition: none; display: none; }
  .js .nav.has-indicator a::after { content: ''; }
  .nav a[aria-current="page"]::after { opacity: 1; }
  /* wave 4 states go static under reduce */
  .band-photo .ph img, .band-name, .foot-nav a .arrow,
  .link-secondary, .band-outro a, .seg label, .f input, .f textarea, .menu-nav a { transition: none; }
  .band:hover .band-photo .ph img, .band:hover .band-name { transform: none; }
  .foot-nav a:hover .arrow { transform: none; }
}

/* --- tietosuoja: seloste, lomakehuomautus, alareunan ilmoitus ------------------------------- */
.foot-tietosuoja { display: flex; flex-wrap: wrap; column-gap: 20px; }
.foot-tietosuoja a, .foot-evasteet { color: inherit; text-decoration: underline; text-underline-offset: 3px;
  display: inline-flex; align-items: center; min-height: 44px; }
/* a button, because it opens something rather than going somewhere - dressed as its link sibling */
.foot-evasteet { background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; letter-spacing: inherit; text-transform: inherit; }
.foot-evasteet[hidden] { display: none; }
.lomake-tietosuoja { margin-top: 14px; font-size: 14px; line-height: 1.5; color: var(--ink-muted); max-width: 60ch; }
.lomake-tietosuoja a { color: var(--green-mid); text-underline-offset: 2px;
  display: inline-flex; align-items: center; min-height: 44px; }

/* Consent for Google Analytics, and nothing else: the site works fully without it and Priimo's own
   visitor counts are cookieless. Not a wall - it never blocks the page or traps focus, and sits under
   the header (60) and the mobile menu (50) so neither is ever covered by it. Refusing and accepting
   are the same button, same size, same colour: a choice nudged one way is not a free one. */
.tietosuoja-ilmoitus {
  position: fixed; z-index: 40;
  left: clamp(12px, 2.5vw, 28px); bottom: clamp(12px, 2.5vw, 28px);
  width: min(420px, calc(100vw - 24px));
  background: var(--paper); color: var(--ink-display);
  border-top: 3px solid var(--green-mid);
  box-shadow: 0 12px 32px rgba(20, 22, 18, 0.18), 0 1px 3px rgba(20, 22, 18, 0.10);
  padding: 16px 18px 12px;
  opacity: 0; transform: translateY(14px);
  transition: opacity 240ms cubic-bezier(0.33, 1, 0.68, 1), transform 240ms cubic-bezier(0.33, 1, 0.68, 1);
}
.tietosuoja-ilmoitus[hidden] { display: none; }
.tietosuoja-ilmoitus.is-in { opacity: 1; transform: none; }
.tietosuoja-ilmoitus-k {
  display: flex; align-items: center; gap: 10px; margin: 0 0 8px;
  font-family: var(--f-mono); font-weight: 600; font-size: 11px;
  letter-spacing: 0.09em; text-transform: uppercase; color: var(--green-mid);
}
.tietosuoja-ilmoitus-teksti { margin: 0; font-size: 14px; line-height: 1.5; hyphens: manual; -webkit-hyphens: manual; }
.tietosuoja-ilmoitus:focus { outline: none; }
.tietosuoja-ilmoitus:focus-visible { outline: 2px solid var(--green-mid); outline-offset: 3px; }
.tietosuoja-ilmoitus-linkki {
  font-family: var(--f-mono); font-weight: 600; font-size: 12px; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--green-mid); text-underline-offset: 3px;
  display: inline-flex; align-items: center; min-height: 44px;
}
.tietosuoja-ilmoitus-toiminnot { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 4px; }
/* two equal halves, so neither answer is the smaller one - which is why both labels are capped short */
.tietosuoja-ilmoitus-nappi { --btn-h: 44px; min-width: 0; font-size: 1.125rem; padding-inline: 12px; }
@media (min-width: 900px) {
  /* Right, not left: on the front page the left edge is where the hero's primary action sits,
     and a notice touching "Jätä tarjouspyyntö" is a notice competing with the one thing the page
     is for. The right edge only ever has decorative imagery under it. */
  .tietosuoja-ilmoitus { left: auto; right: clamp(12px, 2.5vw, 28px); }
}
@media (max-width: 560px) {
  .tietosuoja-ilmoitus { left: 0; right: 0; bottom: 0; width: auto; padding: 14px 16px 10px; }
}
@media (prefers-reduced-motion: reduce) {
  .tietosuoja-ilmoitus { transition: none; transform: none; }
}
