/* ═══════════════════════════════════════════════════════════════════════════
   GENERATED FILE — do not edit. Your changes will be overwritten.

   Built from base.css + layout.css by tools/build-css.py.
   Edit those, then re-run:  python tools/build-css.py

   These two load on every page in this order and never vary, so they are served
   as one request. The per-route sheets (home/works/contact) stay separate.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ─── base.css ─────────────────────────────────────── */
/* ═══════════════════════════════════════════════════════════════════════════
   BASE — design tokens, reset, typography, shared controls.
   Loaded on every page, first. Nothing here is specific to one section.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Webfonts, self-hosted ───────────────────────────────────────────────────
   These used to come from fonts.googleapis.com. They are served from this
   domain now, which is not a performance tweak but a data-protection one: a
   Google-hosted font transmits every visitor's IP address to Google before the
   page paints, and for an Estonian business that is a transfer it has no basis
   for. Self-hosting also removes two preconnects and a render-blocking
   third-party stylesheet from the critical path.

   Because nothing external is fetched any more, index.php can — and does —
   pin style-src and font-src to 'self'. If you ever reintroduce a hosted font,
   that CSP will block it; widen the CSP deliberately or not at all.

   Both are VARIABLE fonts, so one file covers the whole weight range rather
   than one file per weight — hence 'font-weight:400 700' rather than a single
   number. Six files, ~114 KB on disk, but a visitor only downloads the subsets
   their text actually needs:

     /et/  latin only                         ~56 KB
     /ru/  cyrillic AND latin                 ~84 KB

   The Russian pages genuinely need both: the brand name, the machine models
   (Volvo BL71, Sunward SWE 35UF) and the e-mail address are all Latin script.
   Neither language fetches latin-ext — Estonian õ ä ö ü live in the latin
   range; only š and ž would reach for it, and no copy on the site uses them.
   The files stay because that is one bad sentence away from being false.

   head.php preloads the two faces the CURRENT language paints with. Those
   hrefs must stay byte-identical to the url() values below — a preload that
   differs by so much as a ?v= stamp is a second download, not a head start.

   Licences: both are SIL Open Font License 1.1 and the licence text ships
   beside the files in assets/fonts/OFL-*.txt. Self-hosting is redistribution —
   keep those files with the fonts.

   To change a font: put the .woff2 subsets in assets/fonts/, replace the
   matching block below, and update the token in :root. Do not point a token at
   a family that has no @font-face here. */
@font-face{
  font-family:'Onest';font-style:normal;font-weight:400 700;font-display:swap;
  src:url('../fonts/onest-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'Onest';font-style:normal;font-weight:400 700;font-display:swap;
  src:url('../fonts/onest-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Onest';font-style:normal;font-weight:400 700;font-display:swap;
  src:url('../fonts/onest-cyrillic.woff2') format('woff2');
  unicode-range:U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face{
  font-family:'Manrope';font-style:normal;font-weight:400 700;font-display:swap;
  src:url('../fonts/manrope-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'Manrope';font-style:normal;font-weight:400 700;font-display:swap;
  src:url('../fonts/manrope-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Manrope';font-style:normal;font-weight:400 700;font-display:swap;
  src:url('../fonts/manrope-cyrillic.woff2') format('woff2');
  unicode-range:U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* JetBrains Mono used to be declared here, in three subsets. It was removed:
   52 KB of webfont — a third of the site's total font weight, and more than
   every stylesheet combined — to set roughly a dozen small captions in
   letter-spaced caps (section kickers, equipment specs, case tags, the date
   line on the privacy notice). At 11-13px with heavy tracking, the difference
   between JetBrains Mono and the system monospace face is not something a
   visitor can see; the download was something they could feel.

   --mono now points at the platform stack. Every OS in use ships a monospace
   face with both Latin and Cyrillic coverage, so the Russian captions are
   safe — which is the check that matters here, and the one the old Sora
   display font failed. See the note on --display below. */

:root{
  /* Palette. Prefer these over new hardcoded colours. */
  --ink:#1a1c1a;
  --amber:#f2a900;
  --amber-dark:#8a5d00;
  --muted:#6f6f6f;
  --focus:#a66f00;
  --body:#3a3a3a;
  --paper:#faf8f3;          /* page background */
  --sand:#f2ede2;           /* contact section background */
  --line:#e3e0d8;

  /* --display was Sora, which ships latin + latin-ext and NO Cyrillic. Every
     Russian heading therefore fell back to system-ui while Estonian got the
     real face, so the site's own default language was rendering in a typeface
     nobody chose. Onest is the closest geometric match that covers Cyrillic.
     Any replacement must cover it too — check before swapping. */
  --display:Onest,system-ui,sans-serif;
  --manrope:Manrope,system-ui,sans-serif;
  --mono:ui-monospace,SFMono-Regular,'SF Mono',Menlo,Consolas,'Liberation Mono',monospace;

  /* Fluid section padding. Use these rather than inventing new values —
     the whole page keeps its rhythm because every section shares them. */
  --pad-x:clamp(20px,5vw,80px);
  --pad-y:clamp(60px,8vw,100px);

  --header-h:72px;
}

*{box-sizing:border-box}

/* Load-bearing: .form is display:grid, which would otherwise beat the
   hidden attribute and show elements that are meant to be hidden. */
[hidden]{display:none !important}

html{scroll-behavior:smooth}
@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.01ms !important;transition-duration:.01ms !important}
}

body{
  margin:0;
  background:var(--paper);
  font-family:var(--manrope);
  color:var(--ink);
  -webkit-font-smoothing:antialiased;
}

a{color:var(--ink);text-decoration:none}
a:hover{color:var(--amber-dark)}

img,svg{max-width:100%}
input,textarea,button,select{font-family:inherit}
::placeholder{color:var(--muted);opacity:1}

h1,h2,h3{margin:0;font-family:var(--display)}
h2{font-weight:600;font-size:clamp(25px,3.2vw,32px)}

/* Visible focus for keyboard users. The design has no other focus styling,
   so without this the site is unusable without a mouse. */
:focus-visible{
  outline:3px solid #fff;outline-offset:2px;
  box-shadow:0 0 0 5px var(--focus);
}

/* ── Shared controls ─────────────────────────────────────────────────────── */
.cta{
  display:inline-block;width:fit-content;
  background:var(--amber);color:var(--ink);
  font-weight:700;font-size:16px;
  padding:16px 34px;border-radius:999px;
  transition:background .18s ease;
}
.cta:hover{background:#dc9900;color:var(--ink)}

/* Screen-reader-only, but focusable — used by the skip link. */
.visually-hidden{
  position:absolute;width:1px;height:1px;
  margin:-1px;padding:0;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0;
}

/* The contact form's honeypot. Off-screen rather than display:none — some bots
   skip hidden fields but will happily fill one that is merely positioned away.

   This lives in base.css, which every page loads, rather than in contact.css
   with the rest of the form. The form renders on any route carrying the 'form'
   flag, and a route can be given that flag without 'contact' in its styles —
   at which point the honeypot would be a visible input labelled "Website",
   right above the submit button. A visitor who filled it in would be answered
   with the success page and their enquiry silently discarded, because filling
   it is defined to mean "bot". Hiding it must not depend on an optional
   stylesheet. */
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

/* ─── layout.css ─────────────────────────────────────── */
/* ═══════════════════════════════════════════════════════════════════════════
   LAYOUT — site header, navigation, language switcher, page banner, footer.
   Everything shared by all four pages. Loaded on every page.

   The header is new: the original prototype was a single page and needed only
   a floating language switcher. Two variants:

     .site-header--overlay   home only — transparent, sits on top of the hero
     .site-header            interior pages — solid, in normal flow

   Both are the same markup; only the modifier differs.
   ═══════════════════════════════════════════════════════════════════════════ */

.skip-link{
  position:absolute;top:8px;left:8px;z-index:100;
  background:var(--amber);color:var(--ink);
  padding:10px 18px;border-radius:8px;font-weight:700;
  transform:translateY(-200%);transition:transform .15s ease;
}
.skip-link:focus{transform:translateY(0)}

/* ── Header ──────────────────────────────────────────────────────────────── */
.site-header{
  position:relative;z-index:20;
  background:var(--ink);
  min-height:var(--header-h);
  display:flex;align-items:center;gap:24px;
  padding:0 var(--pad-x);
}
/* Overlay variant: the links sit directly on the hero photograph, whose top
   band is bright sky and birch foliage — white-on-white. A fully transparent
   header made the navigation unreadable there. The scrim gives the links
   something to sit against and fades out before it reaches the hero panel, so
   the photo still reads as a photo. The text-shadow is the second layer, for
   the few pixels where a light branch survives the gradient. */
.site-header--overlay{
  position:absolute;top:0;left:0;right:0;
  background:linear-gradient(180deg,
              rgba(20,22,20,0.68) 0%,
              rgba(20,22,20,0.40) 55%,
              rgba(20,22,20,0) 100%);
}
.site-header--overlay .brand,
.site-header--overlay .nav a{text-shadow:0 1px 4px rgba(0,0,0,0.55)}
.site-header--overlay .nav a{color:rgba(255,255,255,0.92)}

.brand{
  font-family:var(--display);font-weight:600;font-size:17px;
  color:#fff;line-height:1.2;margin-right:auto;
  padding:16px 0;
  display:inline-flex;align-items:center;gap:10px;
}
.brand:hover{color:var(--amber)}
/* No fill here on purpose — the mark is a two-colour tile with its fills
   written into the markup, and one CSS fill would flatten it to a solid square.
   So the tile is the constant and only the name reacts on hover.
   flex:none stops it being squeezed when the header runs out of room on a
   narrow phone; the tile is the one thing that must not distort. */
.brand-mark{flex:none;display:block}

/* ── Navigation ──────────────────────────────────────────────────────────── */
.nav{display:flex;align-items:center;gap:clamp(14px,2.2vw,30px)}
.nav a{
  color:rgba(255,255,255,0.78);
  font-size:15px;font-weight:500;
  padding:10px 0;position:relative;
  transition:color .15s ease;
}
.nav a:hover{color:#fff}
.nav a[aria-current="page"]{color:#fff}
.nav a[aria-current="page"]::after{
  content:"";position:absolute;left:0;right:0;bottom:2px;
  height:2px;background:var(--amber);
}

.nav-toggle{
  display:none;
  flex:none;
  width:42px;height:42px;padding:0;
  background:transparent;border:1px solid rgba(255,255,255,0.28);
  border-radius:9px;cursor:pointer;
  align-items:center;justify-content:center;
}
.nav-toggle span{
  display:block;width:18px;height:2px;background:#fff;position:relative;
}
.nav-toggle span::before,.nav-toggle span::after{
  content:"";position:absolute;left:0;width:18px;height:2px;background:#fff;
}
.nav-toggle span::before{top:-6px}
.nav-toggle span::after{top:6px}

/* ── Language switcher ───────────────────────────────────────────────────── */
/* Real links now, not buttons: each language is its own URL, so switching is
   a navigation and the choice survives a copied link or a bookmark. */
.lang{display:flex;gap:8px;flex:none}
.lang a{
  display:flex;align-items:center;gap:6px;
  padding:7px 12px;border-radius:8px;
  border:1px solid rgba(255,255,255,0.18);
  background:rgba(255,255,255,0.92);
  color:#5f5f5f;
  font-size:13px;font-weight:700;
  transition:border-color .15s ease,color .15s ease;
}
.lang a:hover{color:var(--ink)}
.lang a.is-on{border-color:var(--amber);color:var(--ink)}

/* ── Interior page banner ────────────────────────────────────────────────
   Interior pages have no hero photograph, so this dark band carries the
   heading and keeps the header from floating against bare paper. */
.page-head{
  background:var(--ink);color:#fff;
  padding:clamp(40px,6vw,72px) var(--pad-x) clamp(48px,7vw,84px);
}
.page-head h1{
  font-weight:700;font-size:clamp(30px,4.4vw,44px);
  line-height:1.1;text-wrap:balance;color:#fff;
}
.page-head p{
  font-size:clamp(16px,1.6vw,18px);line-height:1.6;
  color:rgba(255,255,255,0.75);
  margin:18px 0 0;max-width:560px;text-wrap:pretty;
}
.page-kicker{
  font-family:var(--mono);font-size:12px;letter-spacing:0.14em;
  text-transform:uppercase;color:var(--amber);margin-bottom:16px;
}

/* Generic prose block — the 404 body and the privacy notice.
   It lives in layout.css rather than a page stylesheet because the routes that
   use it carry no 'styles' of their own: base.css and layout.css are all they
   load. A privacy page that arrives unstyled reads as broken, and this is the
   page a visitor is most likely to be suspicious on. */
.prose{padding:var(--pad-y) var(--pad-x);max-width:760px}
.prose p{font-size:17px;line-height:1.7;color:var(--body);margin:0 0 20px}
.prose h2{
  font-size:clamp(20px,2.4vw,25px);margin:40px 0 14px;
  text-wrap:balance;
}
.prose h2:first-of-type{margin-top:0}
.prose ul{margin:0 0 20px;padding:0 0 0 22px}
.prose li{
  font-size:17px;line-height:1.7;color:var(--body);
  margin-bottom:8px;padding-left:4px;
}
.prose li::marker{color:var(--amber-dark)}
/* Date line above the body — quieter than the text it introduces. */
.prose-meta{
  font-family:var(--mono);font-size:12px;letter-spacing:0.04em;
  color:var(--muted);margin:0 0 36px !important;
}

/* ── Footer ──────────────────────────────────────────────────────────────── */
.footer{
  background:var(--ink);color:#cfcfca;
  padding:clamp(40px,5vw,56px) var(--pad-x);
  display:flex;flex-wrap:wrap;justify-content:space-between;
  gap:24px;font-size:14px;line-height:1.8;
}
.footer a{color:#cfcfca}
.footer a:hover{color:var(--amber)}
.footer-company{font-family:var(--display);font-weight:600;color:#fff;font-size:18px}
.footer-right{text-align:right}
.footer-rights{margin-top:10px;color:#9a9a94}
.footer-nav{display:flex;flex-wrap:wrap;gap:18px;margin-top:14px}

/* ── Responsive ──────────────────────────────────────────────────────────── */
@media(max-width:860px){
  .js .nav-toggle{display:flex}
  .nav{
    position:absolute;top:100%;left:0;right:0;
    flex-direction:column;align-items:stretch;gap:0;
    background:var(--ink);
    padding:8px var(--pad-x) 20px;
    border-top:1px solid rgba(255,255,255,0.1);
  }
  .js .nav{display:none}
  .js .nav.is-open{display:flex}
  .nav a{padding:14px 0;border-bottom:1px solid rgba(255,255,255,0.08)}
  .nav a[aria-current="page"]::after{display:none}
  .nav a[aria-current="page"]{color:var(--amber)}

  /* With JavaScript unavailable the toggle stays hidden and the full
     navigation remains visible in normal flow. */
  .no-js .site-header{flex-wrap:wrap}
  .no-js .site-header--overlay{position:relative;background:var(--ink)}
  .no-js .lang{order:1}
  .no-js .nav{
    order:2;
    position:static;flex:1 0 100%;
    padding:8px 0 20px;box-shadow:none;
  }
}
@media(max-width:560px){
  .site-header{gap:12px}
  .brand{font-size:15px}
  .lang a{padding:6px 9px;font-size:12px}
  .lang svg{width:18px;height:12px}
}
@media(max-width:374px){
  /* Preserve full-size controls at the narrowest supported viewport. The
     accessible name stays on the brand link when its visible text is hidden. */
  .brand{gap:0}
  .brand span{display:none}
}
@media(max-width:640px){
  .footer{flex-direction:column}
  .footer-right{text-align:left}
}
