/* =========================================================================
   BIOMI — ბრენდის სტილი / Brand stylesheet (rebrand 2026)
   Visual language: minimal · white · photo-driven
   Palette : Biomi Original #1B1B33 · Super Blue #0249F7 · Felamushi #85519A
             Felamushi tints · Extra White · logo renders in Biomi Original
   Type    : Futura 100 + Futura 100 GEO (Latin + Georgian, incl. Mtavruli caps)
   ========================================================================= */

/* Futura 100 — variable fonts, served locally from /fonts.
   One file per script covers every weight (Light→Bold), so the whole site
   needs two downloads instead of eight static OTFs.
   The Georgian face is scoped by unicode-range, so English-only pages
   never download it. Oblique files exist in /fonts but are not wired up —
   the design uses no italics. */
@font-face{
  font-family:"Futura 100";
  src:url('../../fonts/Futura%20100/Variable/Futura100-VF-Upright.ttf') format('truetype-variations');
  font-weight:100 900;
  font-style:normal;
  font-display:swap;
}
/* Declared after the Latin face so Georgian codepoints resolve here. */
@font-face{
  font-family:"Futura 100";
  src:url('../../fonts/Futura%20100%20Georgian/Variable/Futura100-GEO-VF-Upright.ttf') format('truetype-variations');
  font-weight:100 900;
  font-style:normal;
  font-display:swap;
  unicode-range:U+10A0-10FF,U+1C90-1CBF,U+2D00-2D2F;
}

:root{
  /* brand: Biomi Original (ink) — legacy var names kept so layout rules stay untouched */
  --navy:#1b1b33;
  --navy-700:#26274a;
  /* brand: Super Blue (primary accent) — --gold* aliases kept from the old skin */
  --gold:#0249f7;
  --gold-200:#8ba4fb;   /* light super blue — accent text on dark */
  --accent-rgb:2,73,247; /* the accent as raw channels, for tinted rgba() fills */
  --gold-600:#0238be;   /* deep super blue — accent text on light */
  --gold-hover:#0238be; /* deep super blue as a *fill* — stays deep in both themes */
  --purple:#85519a;     /* brand: Felamushi (secondary accent) */
  --gray:#585b5b;
  --gray-300:#d3d3d3;
  --ink:#1b1b33;
  --ink-strong:#1b1b33; /* headings, nav, solid buttons — inverts in dark mode */
  --body:#43454e;       /* long-form article prose — softer than --ink on light */
  --purple-600:#6d3f83; /* Felamushi, hover depth — pairs with --purple */
  --ok:#1a7d46;
  --err:#b23b37;
  --muted:#6c6f72;
  --line:#e7e6ea;
  --bg:#ffffff;
  --surface:#ffffff;    /* cards, panels, inputs — anything raised off --bg */
  --bg-soft:#f1f4fc;     /* soft section backgrounds */
  --deco:#85519a;        /* brand ring decoration: the counterpoint accent */
  --cream:#e6ecfb;      /* Felamushi light — stronger accent surfaces */

  --container:1240px;
  --radius:14px;
  --radius-sm:8px;
  --shadow-sm:0 1px 2px rgba(27,27,51,.05), 0 6px 18px rgba(27,27,51,.06);
  --shadow-md:0 18px 44px rgba(27,27,51,.14);

  --ff:"Futura 100",system-ui,-apple-system,Segoe UI,Roboto,sans-serif;
  --header-h:78px;
  --ease:cubic-bezier(.22,.61,.36,1);
}

/* ---- Dark mode -------------------------------------------------------------
   Set by the inline script in each page's <head> (before first paint, so the
   theme never flashes) and toggled from the header. Palette only: no layout
   rule is duplicated here.

   --navy stays put. It is the brand ink and is still the right background for
   the footer, the dark bands and the solid header, all of which are meant to
   read dark in either theme. What moves is --ink-strong, the *text* half of
   that old double duty, which flips to near-white so headings and nav stay
   legible on a dark surface.

   Product photography is shot on white, so the tiles that hold a cut-out
   (.pgal__main, .pgal__thumbs img, .pcard__img) keep their light background in
   both themes — a dark tile would just frame a white rectangle. Same for the
   pills that sit on top of a map or a photo. */
:root[data-theme="dark"]{
  color-scheme:dark;
  --ink:#eceaf4;
  --ink-strong:#f4f3f9;
  --muted:#a1a2b6;
  --line:#2f3052;
  --bg:#0d0d1a;
  --surface:#1b1b33;
  --bg-soft:#16162c;
  --deco:#0249f7;      /* rings go blue on dark, opposite the text accent */
  --cream:#23233f;
  --gray-300:#3a3b57;
  /* Dark mode is purple throughout — accents, solid buttons and the floating
     action stack alike. The dark-mode logo artwork carries the same purple in
     its mark, so the whole theme agrees with the lockup. White on #86529b is
     5.7:1, so filled buttons stay comfortably readable. */
  --gold:#86529b;
  /* The -200 and -600 steps are the *text* accent: eyebrows, prices, icons,
     inline links, hover states. At #86529b they measured 3.4:1 against the
     page, under the 4.5 minimum, on every page carrying a section label. They
     are a few steps lighter here (8.3:1) while --gold above stays the fill, so
     solid buttons keep their deeper purple behind white text. */
  --gold-200:#c49bd8;
  --gold-600:#c49bd8;
  --gold-hover:#6b4080;  /* hover still goes deeper, just in purple */
  --accent-rgb:134,82,155;
  --purple:#c49bd8;     /* Felamushi lightened — the brand tone only hits 2.9:1 on dark */
  --purple-600:#dcbcec; /* hover goes lighter on dark, not deeper */
  /* Article prose is a soft near-black on light. Inverted straight it would be a
     soft near-black *on black* — 2:1 — so on dark it goes full white instead. */
  --body:#eceaf4;
  --ok:#5fd899;
  --err:#ff8f8a;
  --shadow-sm:0 1px 2px rgba(0,0,0,.45), 0 6px 18px rgba(0,0,0,.38);
  --shadow-md:0 18px 44px rgba(0,0,0,.55);
}
/* the dark bands and the footer already sit on --navy; against a dark page they
   need a hairline to stay separated from it */
:root[data-theme="dark"] .section--dark,
:root[data-theme="dark"] .footer{border-top:1px solid var(--line)}

/* ---- Navy in light mode: products.html and the products dropdown ----
   Both sit on the brand navy even in the light theme -- the catalogue cards'
   photo wash is navy already, and on white each one read as a dark tile cut
   out of a light page. Rather than restyle every component, the palette is
   re-declared on the container, so everything inside (crumbs, heading, rail,
   cards, menu rows) takes dark-surface colours from the tokens it already
   reads. The accent stays light mode's blue, a step lighter for text. Dark
   mode is left alone: those surfaces are dark there to begin with. */
:root:not([data-theme="dark"]) .on-navy,
:root:not([data-theme="dark"]) .dropdown,
:root:not([data-theme="dark"]) .cookiebar,
:root:not([data-theme="dark"]) .contact__form{
  --ink:#eceaf4;
  --ink-strong:#f4f3f9;
  --body:#c9cad6;
  --muted:#a1a2b6;
  --line:#2f3052;
  --bg:var(--navy);
  --surface:#23234a;
  --bg-soft:#2a2a55;
  --cream:#2a2a55;
  --gold-200:#8ba4fb;
  --gold-600:#8ba4fb;
  --shadow-md:0 18px 44px rgba(0,0,0,.4);
}
:root:not([data-theme="dark"]) .on-navy{background:var(--navy);color:var(--ink)}
:root:not([data-theme="dark"]) .dropdown{--surface:var(--navy)}
/* the footer is the same navy, so it needs the hairline dark mode gives it */
:root:not([data-theme="dark"]) .on-navy + .footer{border-top:1px solid #2f3052}
/* the transparent-over-hero header turns solid on scroll; on a dark page it
   should land on the panel colour rather than a second, darker navy */
:root[data-theme="dark"] .header.is-solid{background:var(--surface)}
/* The floating action buttons hardcode the brand blue rather than reading the
   token, so they need saying explicitly. Everything else accent-coloured —
   bars, rules, active states, ring badges, links — already flows from --gold
   and turns purple on its own. */
:root[data-theme="dark"] .fab__ms,
:root[data-theme="dark"] .fab__ph,
:root[data-theme="dark"] .fab .fab__top{background:var(--gold)}

/* The Biomi lockup has real dark-mode artwork, swapped in by main.js, so it is
   never filtered — see .header.is-solid .brand__logo. Samsung and Mitsubishi
   have real dark artwork too; the knock-out below is only the no-JS fallback
   for them, and main.js clears it once the proper file is in place. Brands
   without a dark variant keep the knock-out for real. The marquee is left out:
   it desaturates every logo to a uniform grey by design, and dropping one
   full-colour mark into that row would break the set. */
   Vortice is the exception: its mark is a full lockup on its own green field,
   so knocking it out would leave a blank white square. It already reads on
   either background and is excluded by name, the same way main.js keeps an
   explicit list of the partners that ship a -dark.svg. */
:root[data-theme="dark"] .brand-hero__logo:not([src*="vortice"]),
:root[data-theme="dark"] .brandpick__card img:not([src*="vortice"]){filter:brightness(0) invert(1)}
/* Drawer sub-links sit a step below the top-level items, and on white --muted
   plus an opacity knock reads as exactly that. On dark the same treatment reads
   as *disabled* — every one of these is a tap target. Lift them to the body
   colour and let the indent and the smaller type carry the hierarchy instead. */
/* Drawer chapters. The products panel holds five chapters and 29 links; left
   flat it was 1548px of scroll inside an 812px drawer, so each chapter folds
   the same way the desktop mega-menu does. */
.m-sec{border-top:1px solid var(--line)}
.m-sec:first-child{border-top:0}
.m-sec__btn{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;
  padding:11px 2px;font-size:15px;font-weight:600;color:var(--gold-600);text-align:left;
  text-transform:uppercase;letter-spacing:.02em}
.m-sec__btn svg{width:15px;height:15px;flex:none;opacity:.65;transition:transform .3s}
.m-sec.open .m-sec__btn svg{transform:rotate(180deg)}
/* the drawer's version of .prod-menu__head: chapter name links, caret toggles */
.m-sec__head{display:flex;align-items:center}
.m-acc__panel .m-sec__head > a{flex:1;min-width:0;padding:11px 2px;font-size:15px;font-weight:600;
  color:var(--gold-600);text-transform:uppercase;letter-spacing:.02em}
.m-sec__head > .m-sec__btn{flex:none;width:46px;justify-content:center;padding:11px 0}
.m-sec__panel{max-height:0;overflow:hidden;transition:max-height .3s var(--ease)}
/* Subsection rows inside a drawer chapter. The label is a link to the category
   and the chevron beside it only opens that category's brand list -- two
   separate targets in one row, which is why the caret is a real <button> rather
   than the whole row being a toggle. Bold rather than blue -- the chapter above
   is the blue one, and three coloured levels flattened the hierarchy. */
.m-itm__head{display:flex;align-items:center;gap:6px}
.m-acc__panel .m-itm__head > a{flex:1;min-width:0;font-weight:600;color:var(--ink)}
.m-itm__btn{flex:none;width:36px;height:36px;display:grid;place-items:center;
  color:inherit;background:none;border:0;cursor:pointer}
.m-itm__btn svg{width:15px;height:15px;opacity:.7;transition:transform .3s}
.m-itm.open .m-itm__btn svg{transform:rotate(180deg)}
.m-itm__panel{max-height:0;overflow:hidden;transition:max-height .3s var(--ease)}
/* items with no brands to expand match, so the list reads as one set */
.m-acc__panel .m-sec__panel > a{font-weight:600;color:var(--ink)}

:root[data-theme="dark"] .m-acc__panel a{color:var(--body)}
:root[data-theme="dark"] .m-acc__panel a.m-sub{opacity:1}
:root[data-theme="dark"] .m-acc__panel .m-sec__head > a{color:var(--gold-600)}
:root[data-theme="dark"] .logos img{filter:brightness(0) invert(1);opacity:.5}
/* Dark-mode hover: the real brand colours, unfiltered wherever possible.
   Most of these marks are saturated enough to read on the dark page, so they
   get filter:none and their exact colours. Only the three drawn in near-black
   (#010101) need help, and they are handled individually below -- applying the
   invert trick to all seven muted the ones that never needed it, because CSS
   hue-rotate is a matrix approximation that desaturates as a side effect. */
:root[data-theme="dark"] .logos img:hover{filter:none;opacity:1}
/* Samsung is pure greyscale, so a straight invert is exact -- no hue to lose. */
:root[data-theme="dark"] .logos img[src*="samsung"]:hover{filter:invert(1)}
/* Mitsubishi ships a proper dark-mode asset -- white wordmark, true #EB2627
   red -- so hover swaps to it rather than approximating with a filter. Its
   viewBox matches the light file (279x80.9), so nothing shifts. This is the
   better fix wherever a real dark variant exists; a filter is the fallback. */
:root[data-theme="dark"] .logos img[src*="mitsubishi"]:hover{
  filter:none;content:url("../img/partners/mitsubishi-electric-dark.svg")}
/* Warmhaus has no dark asset in assets/, so it keeps the lightness flip: black
   wordmark to white, orange mark approximately preserved. */
:root[data-theme="dark"] .logos img[src*="warmhaus"]:hover{filter:invert(1) hue-rotate(180deg)}
/* photo tiles: keep the light backdrop, tone down the surrounding chrome */
:root[data-theme="dark"] .pgal__main,
/* :not(.active) — this rule outranks .pgal__thumbs img.active on specificity,
   so without it the selected thumbnail loses its accent ring in dark mode */
:root[data-theme="dark"] .pgal__thumbs img:not(.active){border-color:var(--line)}
/* Pure white, not an off-white tint: the photos are opaque white to the edge,
   so anything else draws a visible seam between the tile and the shot. The
   margin keeps the panel clear of the badge above it — only needed here, since
   in light mode there is no panel for the badge to collide with. */
/* no top margin any more — the badge it used to clear is gone, so the white
   photo panel runs all the way to the card's top edge */
:root[data-theme="dark"] .pcard__img{background:#fff}
/* The embedded maps keep their own light styling. Inverting a Google Maps frame
   also inverts its logo, its pin colours and its attribution, which is worse
   than a bright panel — and it can't be checked here, since the embedded
   browser composites cross-origin frames outside the parent's filter. */

*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
[hidden]{display:none!important}
body{
  font-family:var(--ff);font-weight:400;color:var(--ink);background:var(--bg);
  line-height:1.65;font-size:17px;overflow-x:hidden;
}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
button{font-family:inherit;cursor:pointer;border:0;background:none;color:inherit}
ul{list-style:none}
h1,h2,h3,h4{line-height:1.18;font-weight:700;letter-spacing:-.01em;text-transform:uppercase}
:focus-visible{outline:2px solid var(--gold-600);outline-offset:3px;border-radius:4px}

/* ---- the scrollbar ---------------------------------------------------------
   Chrome draws a grey trough down the right edge of every page, and it belongs
   to no part of this design. It is taken off: the wheel, the trackpad, the
   keyboard and a finger on a touchscreen all still scroll the page, which
   loses the bar and nothing else.
   scrollbar-width is what does it, not ::-webkit-scrollbar. The pseudo-elements
   are inert in current Chromium once the standard property is in play -- the
   same reason the two scrollers styled further down this file are written with
   the standard properties -- and the property is not inherited, so naming :root
   takes the page's own bar and leaves those two alone.
   The webkit line is for the older engines that read neither. */
:root{scrollbar-width:none}
html::-webkit-scrollbar,body::-webkit-scrollbar{width:0;height:0;display:none}

/* ---- Skip link (injected by main.js) -----------------------------------
   Parked above the viewport; slides in only when a keyboard user tabs onto it.
   Above everything, the cookie bar and call-back panel included. The section it
   jumps to takes focus without drawing a ring round the whole section. */
.skip-link{position:fixed;left:16px;top:12px;z-index:1000;padding:10px 16px;border-radius:8px;
  background:var(--gold);color:#fff;font-size:15px;font-weight:600;
  transform:translateY(calc(-100% - 20px));transition:transform .2s var(--ease)}
.skip-link:focus{transform:none;outline:2px solid #fff;outline-offset:2px}
.skip-target:focus{outline:none}

/* ---- Layout helpers ---------------------------------------------------- */
.container{width:100%;max-width:var(--container);margin-inline:auto;padding-inline:28px}
.section{padding:70px 0}
.section--soft{background:var(--bg-soft)}
.section--dark{background:var(--navy);color:#fff;position:relative;overflow:hidden}
.eyebrow{
  display:inline-block;font-size:13px;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--gold-600);margin-bottom:14px;
}
.eyebrow::after{content:"";display:block;width:42px;height:2px;background:var(--gold);margin-top:10px}
.section__head{max-width:720px;margin-bottom:36px}
.center{text-align:center;margin-inline:auto}
.center .eyebrow::after{margin-inline:auto}
/* h1 as well: a page's own title in its hero is its h1 (2026-09-17 - 44 listing,
   hub and policy pages had only an h2, and search engines read the h1) */
.section__head h1,.section__head h2{font-size:clamp(26px,3.2vw,40px)}
.section__head p{color:var(--muted);margin-top:14px;font-size:18px}
.section--dark .section__head p{color:rgba(255,255,255,.72)}
.section--dark .eyebrow{color:var(--gold-200)}

/* ---- Buttons (flat, restrained) --------------------------------------- */
.btn{
  display:inline-flex;align-items:center;gap:10px;padding:13px 26px;border-radius:6px;
  font-weight:500;font-size:16px;transition:transform .2s var(--ease),background .2s,color .2s,border-color .2s;
}
.btn svg{width:18px;height:18px}
/* the drawer's contact CTA — brand blue and set in caps, matching the uppercase
   nav links it sits under. Same in both themes: the blue carries itself. */
.btn--primary{background:var(--gold);color:#fff;text-transform:uppercase;letter-spacing:.05em;font-weight:600}
.btn--primary:hover{background:var(--gold-hover)}
.btn--gold{background:var(--gold);color:#fff}
/* --gold-600 is the accent *text* colour and lightens on dark, which would make
   a washed-out hover fill behind white text — hovers use --gold-hover instead */
.btn--gold:hover{background:var(--gold-hover)}
.btn--outline{border:1.5px solid var(--ink-strong);color:var(--ink-strong)}
.btn--outline:hover{background:var(--ink-strong);color:var(--bg)}
.btn--light{border:1.5px solid rgba(255,255,255,.4);color:#fff}
.btn--light:hover{background:#fff;color:var(--navy)}

.link-more{display:inline-flex;align-items:center;gap:8px;color:var(--ink-strong);font-weight:500;font-size:15px}
.link-more svg{width:16px;height:16px;transition:transform .25s}
.link-more:hover{color:var(--gold-600)}
.link-more:hover svg{transform:translateX(4px)}

/* =========================================================================
   HEADER — solid white · left logo · navy nav
   ========================================================================= */
.header{
  position:fixed;top:0;left:0;right:0;z-index:60;height:var(--header-h);
  display:flex;align-items:center;background:var(--surface);border-bottom:1px solid var(--line);
  transition:background .3s var(--ease),box-shadow .3s,height .3s;
}
.header__inner{display:flex;align-items:center;width:100%;gap:14px}

.brand{display:flex;align-items:center;flex:0 0 auto}
.brand__logo{height:38px;width:auto;display:block;transition:height .3s,filter .3s}

.nav{display:flex;align-items:center;gap:2px;margin-left:auto}
.nav__item{position:relative}
/* 10px sides, not 14: the Georgian nav plus the toolbar came to 1274px against a
   1240px container once the theme switch joined the row. Six links x 8px buys
   back 48px and leaves the header a little slack again. */
.nav__link{
  display:inline-flex;align-items:center;gap:5px;padding:10px 10px;border-radius:8px;
  color:var(--ink-strong);font-size:15.5px;transition:color .2s,background .2s;white-space:nowrap;
}
.nav__link:hover{background:var(--bg-soft);color:var(--gold-600)}
.nav__link .caret{width:13px;height:13px;transition:transform .25s;opacity:.7}
.nav__item:hover .nav__link .caret{transform:rotate(180deg)}

/* dropdown / mega */
.dropdown{
  position:absolute;top:calc(100% + 10px);left:50%;transform:translate(-50%,8px);
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow-md);padding:12px;min-width:230px;opacity:0;visibility:hidden;
  transition:opacity .22s var(--ease),transform .22s var(--ease);z-index:70;
}
.dropdown::before{content:"";position:absolute;top:-10px;left:0;right:0;height:10px}
.nav__item:hover .dropdown{opacity:1;visibility:visible;transform:translate(-50%,0)}
.dropdown a{display:block;padding:9px 13px;border-radius:8px;color:var(--gold-600);font-weight:500;font-size:15px;transition:.18s}
.dropdown a:hover{background:var(--bg-soft);color:var(--gold)}
/* ---- products dropdown: a flyout --------------------------------------------
   The chapters are a column, and the one under the pointer slides its
   categories out beside it -- no click needed (main.js). It moves the way the
   chapter rail on products.html does: the chosen row takes the accent and a
   rule, and the categories rise in one after another. No pictograms and no
   brands here, by request -- just chapter, then category (tools/menu-rebuild.ps1
   leaves the brands out). The phone drawer stays an accordion. */
.prod-menu{min-width:290px;padding:8px}
.prod-menu__chapter{border-bottom:1px solid var(--line)}
.prod-menu__chapter:last-child{border-bottom:0}
/* The name is a link to the chapter's page (heating.html ...); the caret beside
   it opens the flyout on a click, for a touchscreen or the keyboard. */
.prod-menu__head{display:flex;align-items:center;border-radius:8px;
  transition:background .25s var(--ease),box-shadow .25s var(--ease)}
.prod-menu__chapter.is-active > .prod-menu__head{background:var(--bg-soft);box-shadow:inset 2px 0 0 var(--gold)}
.dropdown .prod-menu__link{flex:1;min-width:0;display:flex;align-items:center;gap:11px;
  padding:9px 4px 9px 12px;font-size:13.5px;font-weight:600;letter-spacing:.04em;line-height:1.3;
  color:var(--body);text-transform:uppercase;background:none;transition:color .25s var(--ease)}
.dropdown .prod-menu__link:hover,
.dropdown .prod-menu__chapter.is-active .prod-menu__link{color:var(--gold-600);background:none}
/* a chapter with no page of its own is a single button row */
.prod-menu__btn{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;
  padding:9px 12px;font-size:13.5px;font-weight:600;letter-spacing:.04em;color:var(--body);
  text-align:left;border-radius:8px;text-transform:uppercase;transition:color .25s var(--ease)}
.prod-menu__head .prod-menu__btn{width:auto;flex:none;align-self:stretch;padding:0 12px;background:none}
.prod-menu__chapter.is-active .prod-menu__btn{color:var(--gold-600)}
.prod-menu__btn svg{width:15px;height:15px;flex:none;opacity:.6;transform:rotate(-90deg);
  transition:opacity .25s var(--ease),transform .25s var(--ease)}
.prod-menu__chapter.is-active .prod-menu__btn svg{opacity:1;transform:rotate(-90deg) translateY(2px)}
.prod-menu--flip .prod-menu__btn svg{transform:rotate(90deg)}
.prod-menu--flip .prod-menu__chapter.is-active .prod-menu__btn svg{transform:rotate(90deg) translateY(2px)}

/* The flyout opens level with the chapter that opened it and is only as tall
   as its categories -- hung off the chapter row, not the whole column, and
   nudged up so its first category sits on the same line as the chapter name.
   Horizontally it starts just past the column's own padding, over the
   dropdown's edge, so the pointer never crosses a gap on its way across: a gap
   is outside .nav__item, and leaving that closes the whole menu. display:none
   while closed, so its entrance animations run again every time. */
.prod-menu__chapter{position:relative}
.prod-menu__panel{display:none;position:absolute;z-index:2;top:-14px;left:calc(100% + 4px);
  width:max-content;min-width:230px;max-width:320px;padding:10px;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow-md)}
.prod-menu--flip .prod-menu__panel{left:auto;right:calc(100% + 4px)}
@keyframes menu-slide{from{opacity:0;transform:translateX(-12px)}to{opacity:1;transform:none}}
@keyframes menu-slide-l{from{opacity:0;transform:translateX(12px)}to{opacity:1;transform:none}}
@keyframes menu-rise{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
.prod-menu__chapter.is-active > .prod-menu__panel{display:block;animation:menu-slide .28s var(--ease) both}
.prod-menu--flip .prod-menu__chapter.is-active > .prod-menu__panel{animation-name:menu-slide-l}
.prod-menu__chapter.is-active > .prod-menu__panel > *{animation:menu-rise .36s var(--ease) both}
.prod-menu__chapter.is-active > .prod-menu__panel > :nth-child(1){animation-delay:.04s}
.prod-menu__chapter.is-active > .prod-menu__panel > :nth-child(2){animation-delay:.08s}
.prod-menu__chapter.is-active > .prod-menu__panel > :nth-child(3){animation-delay:.12s}
.prod-menu__chapter.is-active > .prod-menu__panel > :nth-child(4){animation-delay:.16s}
.prod-menu__chapter.is-active > .prod-menu__panel > :nth-child(n+5){animation-delay:.2s}
@media (prefers-reduced-motion:reduce){
  .prod-menu__chapter.is-active > .prod-menu__panel,
  .prod-menu__chapter.is-active > .prod-menu__panel > *{animation:none}
}
/* the categories: bold ink rows */
.dropdown .prod-menu__panel > a{display:block;padding:9px 12px;border-radius:8px;font-size:14.5px;
  font-weight:600;color:var(--ink);transition:background .18s,color .18s}
.dropdown .prod-menu__panel > a:hover{background:var(--bg-soft);color:var(--gold-600)}
/* tools */
.nav__tools{display:flex;align-items:center;gap:8px;margin-left:6px}
.lang{display:flex;align-items:center;border:1.5px solid var(--line);border-radius:999px;
  overflow:hidden;font-size:13px;font-weight:500}
.lang button,.lang a{padding:6px 12px;color:var(--muted);transition:.2s;cursor:pointer}
.lang button.is-active,.lang a.is-active{background:var(--gold);color:#fff}
/* Latin caps for EN pages (no-op on Georgian, which is capped via JS Mtavruli) */
.nav__link{text-transform:uppercase}
.icon-btn{width:40px;height:40px;display:grid;place-items:center;border-radius:50%;color:var(--ink-strong);transition:background .2s}
/* ---- Site search overlay (injected by main.js) ---------------------------- */
.srch{position:fixed;inset:0;z-index:95;visibility:hidden;opacity:0;transition:opacity .2s var(--ease),visibility .2s}
.srch.open{visibility:visible;opacity:1}
.srch__scrim{position:absolute;inset:0;background:rgba(13,13,26,.55);backdrop-filter:blur(2px)}
.srch__panel{position:relative;max-width:640px;margin:min(12vh,110px) auto 0;background:var(--surface);
  border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow-md);overflow:hidden;
  transform:translateY(-10px);transition:transform .25s var(--ease)}
.srch.open .srch__panel{transform:none}
.srch__bar{display:flex;align-items:center;gap:12px;padding:16px 18px}
.srch__bar svg{width:20px;height:20px;color:var(--muted);flex:none}
.srch__bar input{flex:1;min-width:0;border:0;background:none;font:inherit;font-size:17px;color:var(--ink)}
.srch__bar input:focus{outline:none}
.srch__close{border:0;background:none;cursor:pointer;color:var(--muted);font-size:12px;font-weight:600;
  border:1px solid var(--line);border-radius:6px;padding:4px 8px;flex:none}
/* the divider lives on the results, so before anything is typed the panel is
   just the search bar rather than a bar over an empty strip */
.srch__results{max-height:min(56vh,460px);overflow-y:auto;padding:8px;border-top:1px solid var(--line)}
.srch__results:empty{display:none}
.srch__item{display:flex;align-items:center;gap:14px;padding:10px 12px;border-radius:10px;
  text-decoration:none;color:var(--ink)}
.srch__item:hover,.srch__item.is-sel{background:var(--bg-soft)}
.srch__thumb{width:46px;height:46px;flex:none;border-radius:8px;background:#fff;border:1px solid var(--line);
  display:grid;place-items:center;padding:4px}
.srch__thumb img{max-width:100%;max-height:100%;object-fit:contain}
.srch__txt{min-width:0}
.srch__title{font-weight:600;font-size:15px;display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.srch__meta{font-size:12.5px;color:var(--muted);font-family:monospace}
.srch__kind{margin-left:auto;flex:none;font-size:11px;text-transform:uppercase;letter-spacing:.06em;
  color:var(--gold-600);font-weight:600}
.srch__empty{padding:26px 18px;text-align:center;color:var(--muted);font-size:15px}
@media(max-width:680px){
  .srch__panel{margin:0;max-width:none;height:100%;border-radius:0;border:0}
  .srch__results{max-height:calc(100% - 90px)}
  .srch__kind{display:none}
}
/* theme switch — injected by main.js into the toolbar and the drawer */
.theme-btn{background:none;border:0;cursor:pointer}
.theme-btn svg{width:20px;height:20px}
.drawer__theme{display:flex;align-items:center;gap:10px;width:100%;padding:12px 14px;border:1px solid var(--line);
  border-radius:10px;background:var(--surface);font:inherit;font-size:15px;font-weight:600;color:var(--ink-strong);cursor:pointer}
.drawer__theme svg{width:19px;height:19px;flex:none}
.icon-btn:hover{background:var(--bg-soft)}
.icon-btn svg{width:20px;height:20px}

.burger{display:none;width:42px;height:42px;flex-direction:column;justify-content:center;gap:5px;align-items:center;color:var(--ink-strong)}
.burger span{width:24px;height:2px;background:currentColor;border-radius:2px;transition:.3s}

/* scrolled — navy background, white content */
.header.is-solid{background:var(--navy);border-bottom-color:transparent;
  box-shadow:0 8px 30px rgba(27,27,51,.18);--header-h:66px;height:var(--header-h)}
/* no knock-out: main.js swaps in the real dark-mode lockup while the header is
   solid, so the blue mark survives the scroll instead of going flat white */
.header.is-solid .brand__logo{height:34px}
.header.is-solid .nav__link{color:#fff}
.header.is-solid .nav__link:hover{background:rgba(255,255,255,.12);color:#fff}
.header.is-solid .icon-btn{color:#fff}
.header.is-solid .icon-btn:hover{background:rgba(255,255,255,.14)}
.header.is-solid .lang{border-color:rgba(255,255,255,.4)}
.header.is-solid .lang button,.header.is-solid .lang a{color:rgba(255,255,255,.8)}
.header.is-solid .lang button.is-active,.header.is-solid .lang a.is-active{background:var(--gold);color:#fff}
.header.is-solid .burger{color:#fff}

/* =========================================================================
   HERO — white bg · title · infinite carousel of separated rounded cards
   ========================================================================= */
.hero{position:relative;background:var(--bg);overflow:hidden;
  padding-top:calc(var(--header-h) + 40px);padding-bottom:60px}
.hero__head{margin-bottom:30px}
.hero__head .tag{display:inline-block;width:48px;height:3px;background:var(--gold);margin-bottom:16px}
.hero__head h1{color:var(--ink-strong);font-size:clamp(28px,4vw,48px);font-weight:700;
  max-width:840px;letter-spacing:.01em}
/* draggable (main.js): pan-y keeps the page scrolling on a vertical swipe and
   hands a sideways one to the carousel; no text selection while dragging */
.hero__viewport{overflow:hidden;cursor:grab;touch-action:pan-y;-webkit-user-select:none;user-select:none}
.hero__viewport.is-dragging,
.hero__viewport.is-dragging *{cursor:grabbing}
.hero__viewport.is-dragging .hero__card{pointer-events:none}
.hero__track{display:flex;width:max-content;will-change:transform}
.hero__card{position:relative;flex:0 0 clamp(300px,34vw,500px);aspect-ratio:3/2.15;margin-right:26px;
  border-radius:16px;overflow:hidden;background-size:cover;background-position:center;
  box-shadow:var(--shadow-sm)}
.hero__card-label{position:absolute;left:0;right:0;bottom:0;z-index:2;padding:46px 22px 18px;
  color:#fff;font-size:clamp(20px,2.4vw,28px);font-weight:700;letter-spacing:-.01em;
  text-transform:uppercase;
  background:linear-gradient(180deg,transparent,rgba(27,27,51,.78))}

/* =========================================================================
   ABOUT — text left · photo right
   ========================================================================= */
/* The stats and the CTA are siblings of the copy rather than children of it,
   so that stacked on a phone the photo can sit between the copy and the
   numbers -- directly under the "show more" toggle. On two columns they are
   pinned back into the left column and the photo spans all three rows, which
   is the same picture as when they were nested. Row spacing stays on their own
   margins, hence row-gap:0. */
.about{display:grid;grid-template-columns:1.05fr .95fr;column-gap:60px;row-gap:0;align-items:center}
.about>.about__text,.about>.stats,.about>.about__cta{grid-column:1}
.about>.about__visual{grid-column:2;grid-row:1 / span 3;align-self:center}
.about__text h2{font-size:clamp(26px,3vw,38px);margin-bottom:8px}
.about__text .eyebrow{margin-bottom:18px}
.about__text p{color:var(--muted);margin-bottom:16px}
.about__text p:first-of-type{font-size:19px;color:var(--ink)}
.stats{display:flex;gap:40px;margin-top:30px;flex-wrap:wrap}
.stat b{display:block;font-size:40px;font-weight:700;color:var(--ink-strong);line-height:1}
.stat b i{color:var(--gold-600);font-style:normal}
.stat span{font-size:14px;color:var(--muted)}
.about__cta{margin-top:34px}
.about__visual{position:relative;border-radius:var(--radius);overflow:hidden;aspect-ratio:5/4;
  box-shadow:var(--shadow-sm)}
.about__visual .ph{position:absolute;inset:0}

/* =========================================================================
   NEWS
   ========================================================================= */
.news-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:28px}
.news{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;
  transition:transform .3s var(--ease),box-shadow .3s;display:flex;flex-direction:column}
.news:hover{transform:translateY(-5px);box-shadow:var(--shadow-md)}
.news__img{aspect-ratio:16/10;position:relative;overflow:hidden}
/* the picture links to the article as well (2026-09-18); out of the tab order
   and hidden from screen readers, since the title right below is the same link */
a.news__img{display:block}
a.news__img img{transition:transform .5s var(--ease)}
.news:hover a.news__img img{transform:scale(1.04)}
.news__img .ph{position:absolute;inset:0}
.news__date{position:absolute;left:14px;top:14px;background:#fff;color:var(--navy);
  font-size:12px;font-weight:500;padding:6px 11px;border-radius:4px}
.news__body{padding:22px 22px 24px;display:flex;flex-direction:column;gap:8px;flex:1}
.news__cat{font-size:12px;letter-spacing:.08em;text-transform:uppercase;color:var(--gold-600);font-weight:600}
.news h3{font-size:18.5px;font-weight:500}
/* the title links to the article, like the ვრცლად link below it, so hovering
   anywhere on it shows that it can be followed */
.news h3 a{color:inherit;transition:color .2s}
.news h3 a:hover{color:var(--gold-600)}
.section--dark .news h3 a:hover,.news--dark h3 a:hover{color:var(--gold-200)}
.news__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:auto;padding-top:8px}
.news__share{width:36px;height:36px;flex:none;display:grid;place-items:center;border-radius:8px;
  color:var(--muted);transition:background .2s,color .2s}
.news__share:hover{background:var(--bg-soft);color:var(--gold-600)}
.news__share.copied{color:var(--ok)}
.news__share svg{width:18px;height:18px}

/* =========================================================================
   SERVICES — process (one deliberate dark band, brand navy)
   ========================================================================= */
/* circular category ring — click a category to focus it */
.ring-wrap{position:relative}
/* The wheel is sized by the screen's height as well as its width (2026-09-18),
   so the whole section - heading, wheel, the line under it - fits on one
   screen: at 1600x900 it was 997px tall with 834px showing under the header.
   450px is everything in the section that is not the wheel, header included.
   Radius, badges, hub and hand all follow --ring, in the proportions the
   540px wheel was drawn at; phones keep their own sizes further down. */
.ring{position:relative;aspect-ratio:1;margin:0 auto;
  --ring:min(540px,92vw,max(320px,calc(100vh - 450px)));
  width:var(--ring);
  --r:calc(var(--ring) * .389); --size:calc(var(--ring) * .174); --rot:0deg;
  transition:transform .65s var(--ease)}
.ring__node{position:absolute;left:50%;top:50%;width:var(--size);height:var(--size);
  margin:calc(var(--size) / -2);
  transform:rotate(calc(var(--a) + var(--rot))) translateY(calc(-1 * var(--r))) rotate(calc(-1 * (var(--a) + var(--rot))));
  transition:transform .65s var(--ease),opacity .4s var(--ease)}
.node__badge{width:100%;height:100%;border-radius:50%;display:grid;place-items:center;cursor:pointer;
  background:rgba(var(--accent-rgb),.2);border:1px solid rgba(var(--accent-rgb),.55);color:var(--gold-200);
  transition:transform .45s var(--ease),background .35s,color .35s,box-shadow .35s}
.node__badge svg{width:44%;height:44%}
/* The artwork is white with one accent colour. That accent is --gold, which is
   why a single set of icons serves both themes -- but the selected badge fills
   with --gold too, and an accent the same colour as its own background is an
   invisible one. On the concept, technology, logistics and service icons the
   accent is most of the drawing, so it turns white while the badge is filled. */
.node__badge svg .ico-a{fill:var(--gold);transition:fill .35s}
.ring__node.is-active .node__badge svg .ico-a{fill:#fff}

/* The ALL IN ONE list on the about page wears these same badges instead of
   bullet discs, so the seven marks a reader meets there are the ones they will
   meet on the wheel. tools/ring.ps1 writes both from one list of steps.
   Unlike the ring, this sits on the page background rather than a dark section,
   so the disc is tinted from the accent and the artwork takes --gold-600, which
   is the accent that holds up against a white surface. */
.cycle{list-style:none;margin:0 0 18px;padding:0;display:flex;flex-direction:column;gap:12px}
.cycle li{display:flex;align-items:center;gap:13px}
.cycle__ico{flex:0 0 auto;width:34px;height:34px;border-radius:50%;
  display:grid;place-items:center;
  background:var(--navy);border:1px solid rgba(255,255,255,.16);
  color:var(--gold-200)}
.cycle__ico svg{width:56%;height:56%}
.cycle__ico svg .ico-a{fill:var(--gold-200)}
/* The label carries the step's full name -- „სერვისი და ტექნიკური მხარდაჭერა"
   rather than „სერვისი" -- so it wraps instead of running along the ring and
   into its neighbours. The cap sits below the arc between two nodes. */
.node__label{position:absolute;top:calc(100% + 9px);left:50%;transform:translateX(-50%);
  font-size:12px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  width:max-content;max-width:min(148px,34vw);text-align:center;line-height:1.28;
  color:rgba(255,255,255,.88);pointer-events:none;
  transition:color .35s,opacity .3s}
/* hover affordance (only when nothing is selected) */
.ring-wrap:not(.is-focused) .ring__node:hover .node__badge{transform:scale(1.12);background:rgba(var(--accent-rgb),.32)}
/* selected: enlarge at 3 o'clock, dim the rest */
.ring.has-active .ring__node{opacity:.5}
.ring.has-active .ring__node.is-active{opacity:1;z-index:5}
.ring__node.is-active .node__badge{transform:scale(1.55);background:var(--gold);color:#fff;
  box-shadow:0 16px 40px rgba(var(--accent-rgb),.45)}
.ring-wrap.is-focused .node__label{opacity:0}
/* focus: slide the wheel toward the left so the detail has room on the right */
.ring-wrap.is-focused .ring{transform:translateX(-26%)}
/* center hub */
.ring__center{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:calc(var(--ring) * .3);aspect-ratio:1;border-radius:50%;display:grid;place-items:center;
  text-align:center;border:1px dashed rgba(var(--accent-rgb),.38);transition:opacity .4s}
.ring-wrap.is-focused .ring__center{opacity:0}
.ring__center::before{content:"";position:absolute;inset:14px;border-radius:50%;border:1px solid rgba(255,255,255,.07)}
.ring__logomark{height:calc(var(--ring) * .159);width:auto;display:block}
/* tap hint — a finger tapping a category, until the user interacts */
.ring__hint{position:absolute;left:50%;top:50%;width:var(--size);height:var(--size);
  margin:calc(var(--size) / -2);z-index:6;pointer-events:none;
  transform:rotate(var(--hint-a,90deg)) translateY(calc(-1 * var(--r))) rotate(calc(-1 * var(--hint-a,90deg)));
  transition:opacity .45s var(--ease)}
.ring-wrap.is-focused .ring__hint{opacity:0}
/* Height drives the size; width:auto takes the ratio from the SVG itself, so
   replacing the artwork can never letterbox or stretch it and no width needs
   re-tuning. transform-origin sits on the fingertip, near the top of the canvas,
   so the tap animation pivots at the contact point. */
.ring__hint-hand{position:absolute;left:52%;top:46%;height:max(32px,calc(var(--ring) * .085));width:auto;
  filter:drop-shadow(0 3px 6px rgba(0,0,0,.35));transform-origin:32% 10%;
  animation:ringTap 1.9s var(--ease) infinite}
.ring__hint-ripple{position:absolute;left:50%;top:50%;width:calc(var(--size) + 6px);height:calc(var(--size) + 6px);
  margin:calc((var(--size) + 6px) / -2);border-radius:50%;border:2.5px solid var(--gold);
  opacity:0;animation:ringTapRipple 1.9s var(--ease) infinite}
@keyframes ringTap{
  0%,55%,100%{transform:translate(0,0) scale(1)}
  30%{transform:translate(-5px,-7px) scale(.92)}
  42%{transform:translate(0,0) scale(1)}
}
@keyframes ringTapRipple{
  0%,30%{transform:scale(.55);opacity:0}
  40%{opacity:.85}
  75%,100%{transform:scale(1);opacity:0}
}
@media (prefers-reduced-motion:reduce){
  .ring__hint-hand,.ring__hint-ripple{animation:none}
}
/* detail panel — fades in to the right of the focused icon */
.ring__detail{position:absolute;top:50%;right:0;width:min(42%,380px);
  transform:translateY(-50%) translateX(26px);opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .5s var(--ease) .2s,transform .5s var(--ease) .2s}
.ring-wrap.is-focused .ring__detail{opacity:1;visibility:visible;transform:translateY(-50%);pointer-events:auto}
.ring__detail-tag{display:inline-block;width:42px;height:3px;background:var(--gold);margin-bottom:16px}
.ring__detail-title{font-size:clamp(22px,2.4vw,30px);color:#fff;font-weight:600;margin-bottom:12px}
.ring__detail-desc{font-size:16px;color:rgba(255,255,255,.72);line-height:1.7}
/* A step with a page of its own gets a way through from the panel. The panel
   itself is pointer-events:none so it never blocks the ring underneath, so
   focusing has to hand interaction back or the link cannot be clicked. */
.ring__detail-link{display:inline-flex;align-items:center;gap:8px;margin-top:18px;
  font-size:14.5px;font-weight:600;color:var(--gold-200);
  border-bottom:1px solid rgba(var(--accent-rgb),.5);padding-bottom:3px;
  transition:color .25s,border-color .25s}
.ring__detail-link::after{content:"→";font-size:16px}
.ring__detail-link:hover{color:#fff;border-color:#fff}
/* The focused node sits at 3 o'clock while the panel is pinned right, so
   between these two the badge runs into the text -- measured as 52px of
   overlap at 880px and still 32px at 1000px. Below 1080 the panel stacks
   under the ring instead. */
@media (max-width:1080px){
  .ring-wrap.is-focused .ring{transform:none}
  /* Stacked, the panel takes up room in the page, and fading it out left that
     room behind: close a step and an empty gap stayed under the wheel. Closed,
     it now folds back to the height it has before anything is opened
     (--rest-h, measured by main.js), so the section returns to how it looked. */
  .ring__detail{position:static;width:auto;max-width:440px;margin:22px auto 0;text-align:center;
    transform:translateY(14px);overflow:hidden;max-height:var(--rest-h,28px);
    transition:opacity .5s var(--ease) .2s,transform .5s var(--ease) .2s,max-height .5s var(--ease)}
  .ring-wrap.is-focused .ring__detail{transform:none;max-height:560px}
}
.services__cta{margin-top:30px;display:flex;align-items:center;justify-content:space-between;
  gap:24px;flex-wrap:wrap}
/* tighter than the other sections, for the one-screen fit above */
@media (min-width:601px){
  #services{padding:44px 0}
  #services .section__head{margin-bottom:20px}
}
/* Short screens (a 1366x768 laptop leaves ~650px under the browser's bars):
   the wheel is already at its 320px floor there, and smaller would crowd its
   labels, so the heading gives up the room instead. */
@media (min-width:601px) and (max-height:800px){
  #services{padding:18px 0}
  /* the top badge's label (outward, see below) sits closer to the heading here */
  .ring-wrap{padding-top:20px}
  #services .eyebrow{margin-bottom:8px}
  /* wide enough for the intro to run on one line */
  #services .section__head{margin-bottom:12px;max-width:1000px}
  #services .section__head h2{font-size:clamp(24px,2.4vw,32px)}
  #services .section__head p{font-size:16px;margin-top:8px}
  /* the labels under the lowest badges hang ~30px below the wheel's box */
  #services .services__cta{margin-top:36px}
  /* 352 = the non-wheel height here, with the 12px .ring-wrap gains below */
  .ring{--ring:min(540px,92vw,max(300px,calc(100vh - 364px)))}
}
@media (min-width:601px) and (min-height:801px) and (max-height:880px){
  .ring{--ring:min(540px,92vw,max(320px,calc(100vh - 462px)))}
  /* room for the label that sits above the top badge (outward, see below) */
  .ring-wrap{padding-top:12px}
}
/* Below ~430px the wheel is too small for every label to hang under its badge:
   on the upper half they land on the badge below (measured at 378px: three
   did). Screens under 880px tall get a wheel that small, so there each label
   sits outward from the centre instead - right of a badge on the right, above
   the top one, and so on - pointing away from the other badges. The two
   translates: the first anchors the label's near edge on the badge centre, the
   second steps it out past the badge's rim. Browsers without CSS sin()/cos()
   keep the labels underneath. */
@media (min-width:601px) and (max-height:880px){
  @supports (transform:translate(calc(sin(30deg) * 1px))){
    .node__label{--la:calc(var(--a) + var(--rot));top:50%;left:50%;
      transform:translate(calc(-50% + sin(var(--la)) * 50%),calc(-50% - cos(var(--la)) * 50%))
                translate(calc(sin(var(--la)) * (var(--size) / 2 + 8px)),calc(cos(var(--la)) * (var(--size) / -2 - 8px)))}
  }
}
.services__cta p{font-size:20px;max-width:560px}
.services__cta p span{color:var(--gold-200)}

/* =========================================================================
   PRODUCTS — clean photo cards w/ caption overlay
   ========================================================================= */
.prod-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:18px}
/* The row stays a row at every width. This section mirrors the product menu,
   so the five chapters read as one set and their order carries meaning --
   stacking them into a column loses that. Below the width where five cards can
   share the container they become a swipeable rail instead. */
@media(max-width:1040px){
  /* proximity, not mandatory: with mandatory the snap engine fights a smooth
     programmatic scroll and drags the arrow buttons' animation back to where
     it started. proximity still settles swipes onto a card. */
  .prod-grid{display:flex;overflow-x:auto;gap:14px;
    scroll-snap-type:x proximity;overscroll-behavior-x:contain}
  .prod-grid>.prod{flex:0 0 clamp(210px,66vw,290px);scroll-snap-align:start;min-height:330px}
}
/* The native scrollbar under the rail was the only affordance and it looked
   like a stray artefact. Hidden here and replaced by the arrows below, which
   appear only while the rail actually overflows -- so at full width, where all
   five cards fit, there is nothing to show. */
.prod-grid,.news-grid,.proj-grid,.catalog__rail{scrollbar-width:none;-ms-overflow-style:none}
.prod-grid::-webkit-scrollbar,.news-grid::-webkit-scrollbar,.proj-grid::-webkit-scrollbar,
.catalog__rail::-webkit-scrollbar{display:none}
.rail{position:relative}
.rail__arrow{position:absolute;top:calc(50% - 21px);z-index:3;width:42px;height:42px;
  border-radius:50%;display:none;place-items:center;background:var(--surface);
  border:1px solid var(--line);color:var(--ink);box-shadow:var(--shadow-md);transition:.2s}
.rail.is-scrollable .rail__arrow{display:grid}
.rail__arrow:hover{background:var(--gold);border-color:var(--gold);color:#fff}
.rail__arrow:disabled{opacity:.3;pointer-events:none}
.rail__arrow svg{width:19px;height:19px}
.rail__prev{left:-10px}
.rail__next{right:-10px}
@media(max-width:600px){
  .rail__arrow{width:36px;height:36px;top:calc(50% - 18px)}
  .rail__prev{left:-4px}
  .rail__next{right:-4px}
}
.prod{position:relative;border-radius:var(--radius);overflow:hidden;min-height:380px;
  display:flex;flex-direction:column;justify-content:flex-end;padding:28px;color:#fff;
  background:var(--navy);transition:transform .35s var(--ease)}
.prod:hover{transform:translateY(-5px)}
.prod__img{position:absolute;inset:0;z-index:0;transition:transform .6s var(--ease)}
.prod:hover .prod__img{transform:scale(1.05)}
/* Scrim at the top as well as the bottom: the title moved to the top of the
   card, where the old gradient was only 15% and the raw photo showed through.
   The middle stays light so the photograph still reads. */
.prod__img::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(27,27,51,.78) 0%,rgba(27,27,51,.28) 38%,rgba(27,27,51,.92) 100%)}
.prod__img .ph{position:absolute;inset:0}
/* The body fills the card so the title can sit at the top while the tags and
   the link stay pinned to the bottom. Bottom-aligned titles sat at whatever
   height their own card's content pushed them to, so no two lined up. */
.prod__body{position:relative;z-index:1;flex:1;display:flex;flex-direction:column}
/* --gold-200 is the accent's "on dark" step in both themes (#8ba4fb light,
   #c49bd8 dark) -- the card sits on photography in either theme, so the
   on-light step would sink into it. overflow-wrap because Georgian category
   names are single long words that otherwise run past the card edge. */
.prod__body h3{font-size:19px;font-weight:700;line-height:1.25;color:var(--gold-200);
  overflow-wrap:anywhere;hyphens:auto}
.prod__body ul{margin:12px 0 16px;margin-top:auto;display:flex;flex-wrap:wrap;gap:7px}
.prod__body li{font-size:13px;background:rgba(255,255,255,.16);padding:5px 11px;border-radius:4px}
.prod__body li[data-href]{cursor:pointer;transition:background .2s,color .2s}
.prod__body li[data-href]:hover,.prod__body li[data-href]:focus-visible{background:var(--gold);color:#fff}
.prod .link-more{color:var(--gold-200)}
.prod .link-more:hover{color:#fff}

/* =========================================================================
   PROJECTS — photo cards w/ caption overlay (bento)
   ========================================================================= */
.proj-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:24px}
.proj-grid .proj:first-child{grid-row:span 2}
/* The first card spans two rows, so the grid holds one more cell than there
   are projects. An even number of projects therefore makes an odd number of
   cells and leaves the last row half empty -- give the final card the full
   width in that case. :last-child:nth-child(even) is true only when the count
   itself is even, so this corrects itself as projects are added. */
.proj-grid .proj:last-child:nth-child(even){grid-column:span 2;min-height:230px}
.proj{position:relative;border-radius:var(--radius);overflow:hidden;min-height:270px;
  display:flex;align-items:flex-end;padding:26px;color:#fff;background:var(--navy)}
.proj:first-child{min-height:auto}
.proj__img{position:absolute;inset:0;z-index:0;transition:transform .6s var(--ease)}
.proj:hover .proj__img{transform:scale(1.05)}
.proj__img::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(27,27,51,0) 35%,rgba(27,27,51,.85) 100%)}
.proj__info{position:relative;z-index:1;width:100%;display:flex;align-items:flex-end;
  justify-content:space-between;gap:16px}
.proj__meta span{font-size:13px;color:var(--gold-200);letter-spacing:.08em;text-transform:uppercase}
.proj__meta h3{font-size:23px;margin-top:6px;font-weight:500}
.proj__logo{flex:none;display:inline-flex;align-items:center;justify-content:center;
  min-width:56px;height:48px;padding:0 14px;border-radius:10px;background:rgba(255,255,255,.95);
  color:var(--navy);font-weight:700;font-size:16px;box-shadow:0 6px 18px rgba(0,0,0,.28)}
.proj__logo img{height:30px;max-width:140px;width:auto;display:block;flex:none}

/* Project card logo: pinned to the card's top-left rather than sharing a row
   with the title. As a flex:none sibling of the title it was pushed past the
   card edge whenever the name was long -- SDSU overflowed by 111px, Terminal by
   50px, the Agrarian University by 30px on a 278px card. Absolute placement
   removes it from that row entirely, so the title gets the full width and the
   chip can never be displaced. Scoped to .proj so the same chip stays inline in
   the project page's .article__topmeta, where it fits. */
/* Client logo beside the breadcrumb. Sized here rather than inline because the
   logo needs room inside the chip: several of these marks carry their own frame
   -- Terminal's artwork is literally a rectangle with the wordmark inside it --
   and a logo as tall as its chip leaves the pill's rounded edge cutting across
   that frame. The chip is sized by its padding rather than a fixed height,
   so that 7px of clearance holds however tall the logo is set below. */
.article__topmeta .proj__logo{height:auto;min-width:0;padding:7px 12px}
.article__topmeta .proj__logo img{height:var(--logo-h,20px);max-width:150px}
.proj .proj__logo{position:absolute;top:18px;left:18px;z-index:2;
  height:auto;min-width:0;padding:7px 11px;max-width:calc(100% - 36px)}
/* object-fit keeps the aspect ratio if a future logo is wide enough for
   max-width to bite -- with a fixed height it would otherwise stretch. */
.proj .proj__logo img{height:var(--logo-h,22px);max-width:100%;object-fit:contain}
/* Two shapes of client logo end up in these chips. A wide wordmark (SDSU at
   6.4:1) fills the width and reads fine at the base height. A
   stacked lockup -- mark over text, ORO 2.4:1 down to Agrarian at 1:1 --
   collapses to between 21 and 51px wide there and turns to mush, so
   it gets a much taller box and the chip grows with it. */
/* 42 + 7 + 7 is the 56px this chip used to hard-code, so it needs no rule. */
.article__topmeta .proj__logo--lockup img{--logo-h:42px}
.proj .proj__logo--lockup img{--logo-h:42px}
/* Per-logo heights, because two tiers cannot hold ratios running from
   0.95:1 (Agrarian) to 6.4:1 (SDSU). At the wordmark height Terminal and
   Kartlisi read small; at the lockup height ORO outweighs every chip beside
   it. Keying on the filename keeps the sizing in one place, and a renamed
   logo falls back to its tier rather than breaking. */
.proj .proj__logo img[src$="terminal.svg"],
.article__topmeta .proj__logo img[src$="terminal.svg"]{--logo-h:28px}
.proj .proj__logo img[src$="kartlisi.png"],
.article__topmeta .proj__logo img[src$="kartlisi.png"]{--logo-h:30px}
.proj .proj__logo img[src$="oro.svg"],
.article__topmeta .proj__logo img[src$="oro.svg"]{--logo-h:34px}

/* =========================================================================
   CONTACT strip
   ========================================================================= */
/* minmax(0,..): a bare fr column never shrinks below its content's narrowest
   width, and the form's was 646px - so between the one-column breakpoint (920)
   and about 1100px the form ran off the right edge of the screen. */
.contact{display:grid;grid-template-columns:minmax(0,.92fr) minmax(0,1.08fr);gap:56px;align-items:stretch}
.contact__intro{display:flex;flex-direction:column}
.contact__intro h2{font-size:clamp(26px,3vw,38px);margin:6px 0 14px}
.contact__intro p{color:var(--muted);font-size:18px;margin-bottom:28px}
.contact__details{display:flex;flex-direction:column;gap:14px}
.contact__details li{display:flex;gap:12px;align-items:center;font-size:16px}
.contact__details svg{width:20px;height:20px;color:var(--gold-600);flex:none}
.contact__details a:hover{color:var(--gold-600)}
.contact__map{position:relative;display:block;margin-top:22px;flex:1 1 auto;min-height:220px;border-radius:var(--radius);
  overflow:hidden;border:1px solid var(--line);box-shadow:var(--shadow-sm);
  transition:transform .25s var(--ease),box-shadow .25s}
.contact__map:hover{transform:translateY(-3px);box-shadow:var(--shadow-md)}
.contact__map iframe{position:absolute;inset:0;width:100%;height:100%;border:0;
  pointer-events:none;filter:grayscale(.15) contrast(1.02)}
.contact__map .footer__map-pin{position:absolute;left:12px;bottom:12px;z-index:2;display:inline-flex;
  align-items:center;gap:7px;background:#fff;color:var(--navy);font-size:13px;font-weight:500;
  padding:7px 13px;border-radius:999px;box-shadow:0 4px 14px rgba(27,27,51,.18)}
.contact__map .footer__map-pin svg{width:15px;height:15px;color:var(--gold-600)}

/* align-self:start so the card is only as tall as the form. Stretching it to
   match the taller column beside it left a band of empty space under the send
   button at the widths where that column wins. */
.contact__form{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow-sm);padding:28px;align-self:start}
/* Light mode: the form card is navy, like the dropdown and the cookie bar, so
   its tokens come from the .on-navy block near the top of this file. The few
   it reads beyond those take dark values: ok/error text as in dark mode, and
   the drop zone's dashed border a step lighter than dark mode's #3a3b57, which
   all but vanished on the navy. color-scheme gives the checkboxes and the
   textarea's scrollbar and resize grip their dark look. */
:root:not([data-theme="dark"]) .contact__form{background:var(--navy);color:var(--ink);border-color:var(--line);
  color-scheme:dark;--gray-300:#4f5180;--ok:#5fd899;--err:#ff8f8a}
/* minmax(0,1fr) for the same reason as .contact: an input is at least ~20
   characters wide unless told otherwise, and two of them pushed the phone
   field past the form's edge at 1000px */
.form-row{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:18px}
/* compacted 2026-09-18 (name + email now share a row, the PDF drop is one
   slim bar): the form had grown taller than the column beside it */
.field{margin-bottom:14px;display:flex;flex-direction:column;gap:6px}
.field label{font-size:14px;font-weight:500;color:var(--ink-strong)}
/* The star on a required label. Name, e-mail and phone have always been
   required and the form has always refused to send without them -- but nothing
   on the page said which three, and a field that looks optional is treated as
   one until the moment it stops you. */
.field__req{color:var(--gold-600);font-weight:700;font-size:13px;line-height:1}
.field input,.field textarea,.field select{font-family:inherit;font-size:15px;color:var(--ink);padding:12px 14px;
  border:1.5px solid var(--line);border-radius:8px;background:var(--surface);
  transition:border-color .2s,box-shadow .2s}
.field input::placeholder,.field textarea::placeholder{color:#a7abb2}
.field input:focus,.field textarea:focus,.field select:focus{outline:none;border-color:var(--gold);box-shadow:0 0 0 3px rgba(var(--accent-rgb),.18)}
.field input:user-invalid,.field textarea:user-invalid,.field select:user-invalid{border-color:#d9534f}
/* Free-text brief. resize:vertical only -- horizontal dragging would break the
   two-column form row beside it. The counter sits under the box and turns red
   past the limit; the limit itself is enforced in main.js, since HTML can cap
   characters but not words. */
.field textarea{resize:vertical;min-height:84px;line-height:1.55}
.field__count{align-self:flex-end;font-size:12.5px;color:var(--muted);margin-top:-2px}
.field__count.is-over{color:#d9534f;font-weight:600}
/* the counter line already spaces the brief from what follows it */
.field:has(> .field__count){margin-bottom:10px}
/* Native select chrome differs wildly between browsers and neither version
   matches the inputs beside it, so the arrow is drawn here instead. The chevron
   is a data URI in the placeholder grey, which reads on both the white surface
   and the dark one; padding-right keeps the text clear of it. */
.field select{appearance:none;-webkit-appearance:none;cursor:pointer;
  padding-right:38px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a7abb2' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 13px center;background-size:16px}
/* the placeholder row reads as placeholder text until a real choice is made */
.field select:has(option[value=""]:checked){color:#a7abb2}

/* one slim bar: the icon beside the two lines rather than stacked above them,
   the group centred in the bar */
.filedrop{display:grid;grid-template-columns:auto auto;justify-content:center;grid-template-areas:"icon text" "icon hint";
  column-gap:14px;row-gap:2px;align-items:center;justify-items:start;
  text-align:left;padding:13px 18px;border:1.6px dashed var(--gray-300);border-radius:10px;
  cursor:pointer;transition:border-color .2s,background .2s}
.filedrop svg{grid-area:icon}
.filedrop__text{grid-area:text}
.filedrop__hint{grid-area:hint}
.filedrop:hover,.filedrop.is-over{border-color:var(--gold);background:var(--bg-soft)}
.filedrop svg{width:28px;height:28px;color:var(--gold-600)}
.filedrop__text{font-size:15px;color:var(--ink-strong)}
.filedrop__text b{color:var(--gold-600)}
.filedrop__hint{font-size:12.5px;color:var(--muted)}

.filelist{margin-top:12px;display:flex;flex-direction:column;gap:8px}
.filechip{display:flex;align-items:center;gap:10px;background:var(--bg-soft);
  border:1px solid var(--line);border-radius:8px;padding:9px 12px;font-size:14px}
.filechip>svg{width:18px;height:18px;color:var(--gold-600);flex:none}
.filechip .name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.filechip .size{color:var(--muted);font-size:12.5px;flex:none}
.filechip button{width:24px;height:24px;display:grid;place-items:center;border-radius:6px;color:var(--muted);flex:none}
.filechip button svg{width:16px;height:16px}
.filechip button:hover{background:#fff;color:#d9534f}

/* Consents sit to the left of the send button rather than above it, which uses
   the width that was already there instead of making the card taller. */
/* No wrap above a phone: the consents at their full 46ch (444px) plus the
   button came to 619px in a 580px row, so the button always dropped under them.
   The consents give way instead -- a few more words wrap -- and the button stays
   beside them, centred on the pair. */
.form-actions{display:flex;justify-content:space-between;align-items:center;
  gap:22px;margin-top:6px;flex-wrap:nowrap}
.consents{display:flex;flex-direction:column;gap:9px;min-width:0;flex:1 1 auto}
@media (max-width:520px){.form-actions{flex-wrap:wrap}}
/* 12.5px since the third consent (2026-09-18): three document titles beside
   the send button, kept compact */
.consent{display:flex;align-items:flex-start;gap:9px;cursor:pointer;
  font-size:12.5px;line-height:1.35;color:var(--muted);max-width:46ch}
/* aligns to the first line, not the middle of a wrapped two-line label */
.consent input{width:16px;height:16px;flex:0 0 auto;margin-top:1px;accent-color:var(--gold)}
.consent a{color:var(--gold-600);text-decoration:underline;text-underline-offset:2px}
.consent a:hover{color:var(--gold)}
.form-actions .btn{flex:0 0 auto}
/* Field check bubble - the contact form's own, replacing the browser's grey
   pop-up (which speaks the browser's language, not the page's). Points up at
   a field from below; for the consent tick it sits above, pointing down, so it
   does not cover the second checkbox. */
.contact__form .field,.consent{position:relative}
.form-tip{position:absolute;left:0;top:calc(100% + 9px);z-index:6;display:flex;align-items:flex-start;gap:9px;
  width:max-content;max-width:min(340px,100%);padding:9px 13px 9px 9px;border-radius:9px;
  background:var(--surface);color:var(--ink);border:1px solid rgba(217,83,79,.5);box-shadow:var(--shadow-md);
  font-size:13.5px;line-height:1.45;font-weight:500;cursor:default;pointer-events:none;
  opacity:0;transform:translateY(-5px);transition:opacity .18s var(--ease),transform .18s var(--ease)}
.form-tip.is-in{opacity:1;transform:none}
.form-tip::before{content:"";position:absolute;left:16px;top:-6px;width:10px;height:10px;background:var(--surface);
  border-left:1px solid rgba(217,83,79,.5);border-top:1px solid rgba(217,83,79,.5);transform:rotate(45deg)}
.form-tip__icon{flex:0 0 auto;width:20px;height:20px;border-radius:50%;background:var(--err);color:#fff;
  display:grid;place-items:center;font-size:12px;font-weight:700;line-height:1}
.form-tip__text{padding-top:1px}
.form-tip--above{top:auto;bottom:calc(100% + 10px);left:-5px;max-width:min(340px,calc(100vw - 48px));transform:translateY(5px)}
.form-tip--above::before{top:auto;bottom:-6px;left:8px;transform:rotate(225deg)}
.field input.is-invalid,.field textarea.is-invalid{border-color:#d9534f;box-shadow:0 0 0 3px rgba(217,83,79,.15)}
.consent input.is-invalid{outline:2px solid #d9534f;outline-offset:2px}
.form-msg{margin:0 0 16px;font-size:14.5px;padding:12px 14px;border-radius:8px}
.form-msg.ok{background:rgba(37,166,93,.1);color:var(--ok);border:1px solid rgba(37,166,93,.25)}
.form-msg.err{background:rgba(217,83,79,.1);color:var(--err);border:1px solid rgba(217,83,79,.25)}

/* =========================================================================
   FOOTER
   ========================================================================= */
.footer{background:var(--navy);color:rgba(255,255,255,.72);padding:70px 0 26px;position:relative;overflow:hidden}
.footer .brand{color:#fff;margin-bottom:18px}
.footer__grid{display:grid;grid-template-columns:1.4fr .9fr .9fr 1.1fr 1.25fr;gap:40px}
.footer__about{font-size:15px;max-width:300px}
.footer__social{display:flex;gap:10px;margin-top:22px}
.footer__social a{width:40px;height:40px;border-radius:50%;display:grid;place-items:center;
  background:rgba(255,255,255,.08);color:#fff;transition:background .25s,transform .25s}
.footer__social a:hover{background:var(--gold);color:#fff;transform:translateY(-3px)}
.footer__social svg{width:18px;height:18px}
/* The legal links sit under the social icons rather than in a column of their
   own -- there are two short ones, and a whole column left the footer
   lopsided. The wrapper is what the phone layout moves below the map, so the
   pair travels together. */
/* Four entries since 2026-09-18 (privacy, personal data, marketing, cookie
   settings) - one column under the social icons was too long. The wrapper is
   now the footer grid's last child (tools/legal.ps1 puts it there): on desktop
   a row of its own under the brand and navigation columns, spanning both, so
   it always starts below the longer of the two. subgrid hands it the footer's
   own two columns, so each half lines up exactly; browsers without subgrid use
   the same 1.4fr .9fr ratio. Filled column by column: the two consents stay
   together, marketing and cookie settings beside them. */
.footer__policies{display:grid;grid-auto-flow:column;grid-template-rows:repeat(2,auto);
  grid-template-columns:1.4fr .9fr;grid-template-columns:subgrid;column-gap:40px;row-gap:10px;
  justify-items:start;align-items:start}
@media (min-width:921px){
  .footer__grid{grid-template-rows:auto 1fr;row-gap:26px}
  .footer__grid > :first-child{grid-column:1;grid-row:1}          /* brand       */
  .footer__grid > :nth-child(3){grid-column:2;grid-row:1}         /* navigation  */
  .footer__grid > :nth-child(4){grid-column:3;grid-row:1 / 3}     /* products    */
  .footer__grid > :nth-child(5){grid-column:4;grid-row:1 / 3}     /* contact     */
  .footer__grid > .footer__mapcol{grid-column:5;grid-row:1 / 3}
  .footer__grid > .footer__policies{grid-column:1 / 3;grid-row:2;align-self:start}
}
.footer__policy{display:inline-flex;align-items:flex-start;gap:8px;
  font-size:14px;color:rgba(255,255,255,.66);transition:color .2s}
.footer__policy:hover{color:var(--gold-200)}
.footer__policy svg{width:15px;height:15px;flex:none;margin-top:2px;color:var(--gold-200)}
/* "Cookie settings" is a button (it opens the consent bar), dressed as the links above */
.footer__policy--btn{background:none;border:0;padding:0;font:inherit;font-size:14px;text-align:left;cursor:pointer}

/* Cookie consent bar (main.js, "Analytics"): one wide, short strip centred at
   the bottom - icon, text, then the two buttons in a row - kept clear of the
   floating buttons on the right. Accept and Decline are the same size: saying
   no must be as easy as saying yes. Narrower screens stack text over buttons. */
.cookiebar{position:fixed;left:50%;bottom:20px;z-index:110;width:min(1000px,calc(100vw - 184px));
  display:flex;align-items:center;gap:18px;padding:14px 16px 14px 18px;border-radius:var(--radius);
  background:var(--surface);color:var(--ink);border:1px solid var(--line);box-shadow:var(--shadow-md);
  opacity:0;visibility:hidden;transform:translate(-50%,18px);
  transition:opacity .35s var(--ease),transform .35s var(--ease),visibility 0s linear .35s}
.cookiebar.is-open{opacity:1;visibility:visible;transform:translate(-50%,0);transition:opacity .35s var(--ease),transform .35s var(--ease)}
.cookiebar__icon{flex:0 0 auto;width:40px;height:40px;border-radius:50%;display:grid;place-items:center;
  background:rgba(var(--accent-rgb),.1);color:var(--gold-600)}
.cookiebar__icon svg{width:22px;height:22px}
.cookiebar__text{flex:1 1 auto;min-width:0}
.cookiebar h3{font-size:15px;line-height:1.3;margin:0 0 2px;color:var(--ink-strong)}
.cookiebar p{font-size:13.5px;line-height:1.45;color:var(--muted);margin:0}
.cookiebar p a{color:var(--gold-600);text-decoration:underline;text-underline-offset:2px}
.cookiebar__actions{flex:0 0 auto;display:flex;gap:8px}
/* both in capitals like the primary button: an outline button is sentence case
   elsewhere on the site, which left Reject looking smaller than Accept beside it.
   georgianCaps(bar) runs after this applies, so the Georgian gets Mtavruli too. */
.cookiebar__actions .btn{min-width:124px;justify-content:center;padding:10px 16px;font-size:13.5px;
  text-transform:uppercase;letter-spacing:.05em;font-weight:600}
:root[data-theme="dark"] .cookiebar{border-color:rgba(255,255,255,.1)}
/* In light mode the bar goes navy, like the menu dropdown: a white strip over a
   white page barely read as something to answer. The colour tokens come from
   the .on-navy block near the top of this file. */
:root:not([data-theme="dark"]) .cookiebar{background:var(--navy);border-color:var(--line)}
@media (max-width:900px){
  .cookiebar{flex-wrap:wrap;row-gap:10px}
  .cookiebar__text{flex-basis:calc(100% - 58px)}
  .cookiebar__actions{flex-basis:100%}
  .cookiebar__actions .btn{flex:1 1 0;min-width:0}
}
@media (max-width:560px){
  .cookiebar{left:12px;bottom:12px;width:calc(100vw - 96px);padding:13px 14px;transform:translateY(18px)}
  .cookiebar.is-open{transform:none}
  .cookiebar__icon{display:none}
  .cookiebar__text{flex-basis:100%}
}
.footer h4{color:#fff;font-size:14px;letter-spacing:.05em;text-transform:uppercase;margin-bottom:18px;font-weight:600}
.footer__links a{display:block;padding:7px 0;font-size:15px;transition:color .2s,padding .2s}
.footer__links a:hover{color:var(--gold-200);padding-left:5px}
.footer__contact li{display:flex;gap:12px;padding:8px 0;font-size:15px;align-items:flex-start}
.footer__contact svg{width:18px;height:18px;color:var(--gold-200);flex:none;margin-top:3px}
.footer__contact a:hover{color:var(--gold-200)}
.footer__mapcol{display:flex;flex-direction:column;order:1}
.footer__map{position:relative;display:block;flex:1 1 auto;min-height:172px;border-radius:12px;
  overflow:hidden;border:1px solid rgba(255,255,255,.14);box-shadow:0 10px 26px rgba(0,0,0,.25);
  transition:transform .25s var(--ease),box-shadow .25s}
.footer__map:hover{transform:translateY(-3px);box-shadow:0 16px 34px rgba(0,0,0,.32)}
.footer__map iframe{position:absolute;inset:0;width:100%;height:100%;border:0;
  pointer-events:none;filter:grayscale(.25) contrast(1.03)}
.footer__map::after{content:"";position:absolute;inset:0;background:rgba(27,27,51,.12);transition:background .25s}
.footer__map:hover::after{background:rgba(27,27,51,0)}
.footer__map-pin{position:absolute;left:12px;bottom:12px;z-index:2;display:inline-flex;align-items:center;
  gap:7px;background:#fff;color:var(--navy);font-size:13px;font-weight:500;padding:7px 13px;
  border-radius:999px;box-shadow:0 4px 14px rgba(0,0,0,.28)}
.footer__map-pin svg{width:15px;height:15px;color:var(--gold-600)}
.footer__bottom{border-top:1px solid rgba(255,255,255,.12);margin-top:46px;padding-top:24px;
  display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap;font-size:14px;color:rgba(255,255,255,.5)}
/* The sign-off, matching the studio's own footer. Futura carries no heart glyph,
   so the mark is drawn rather than typed -- the ❤︎ character was quietly falling
   back to a system face beside Futura letters, at whatever size and weight that
   face happened to have. Sized to the cap height (754/1000) and filled from the
   text colour, it sits on the line with the letters instead of riding above them. */
.footer__made{text-transform:uppercase;letter-spacing:.14em}
/* Georgian runs tighter. main.js converts this to Mtavruli and switches the CSS
   transform off -- uppercase would map the capitals straight back down -- and
   Mtavruli is wide enough already that Latin's tracking pulls it apart. */
html[lang="ka"] .footer__made{letter-spacing:.04em}
.footer__made .heart{height:.754em;width:auto;fill:currentColor;vertical-align:baseline}

/* =========================================================================
   FLOATING chat (messenger · whatsapp · phone)
   ========================================================================= */
.fab{position:fixed;right:20px;bottom:20px;z-index:80;display:flex;flex-direction:column;gap:11px}
.fab a,.fab button{width:52px;height:52px;border-radius:50%;display:grid;place-items:center;
  color:#fff;box-shadow:var(--shadow-md);transition:transform .25s}
.fab a:hover,.fab button:hover{transform:scale(1.08)}
.fab svg{width:27px;height:27px}
.fab__ms{background:#0249f7}
.fab__ph{background:#0249f7}
.fab__ph svg{color:#fff}
.fab .fab__top{background:#0249f7;color:#fff;opacity:0;visibility:hidden;transform:translateY(10px)}
/* social capsule: 3 symbols in one frosted-glass pill, super-blue glyphs */
.fab__social{display:flex;flex-direction:column;align-items:center;gap:2px;padding:5px;
  background:rgba(255,255,255,.4);border:1px solid rgba(255,255,255,.6);border-radius:999px;
  box-shadow:0 6px 22px rgba(27,27,51,.14);
  backdrop-filter:blur(12px) saturate(1.7);-webkit-backdrop-filter:blur(12px) saturate(1.7);
  transition:opacity .35s var(--ease),transform .35s var(--ease),visibility .35s}
.fab__social.is-hidden{opacity:0;visibility:hidden;transform:translateX(20px) scale(.92);pointer-events:none}
.fab .fab__social a{width:42px;height:42px;background:transparent;color:var(--gold);box-shadow:none}
.fab .fab__social a:hover{background:var(--bg-soft);transform:none}
.fab__social svg{width:23px;height:23px}
/* Dark mode for the social capsule. The light-mode recipe is a 40% *white*
   fill with a white hairline and a dark drop shadow -- on a dark page that
   reads as a pale slab rather than glass, and the --gold glyphs (#86529b in
   dark) sit on it with poor contrast. Glass needs to be tinted toward the
   surface it floats over, so here the fill goes dark and translucent, the
   hairline goes light, and the shadow deepens. */
:root[data-theme="dark"] .fab__social{background:rgba(20,20,40,.55);
  border-color:rgba(255,255,255,.16);box-shadow:0 8px 26px rgba(0,0,0,.5)}
:root[data-theme="dark"] .fab .fab__social a{color:var(--gold-200)}
:root[data-theme="dark"] .fab .fab__social a:hover{background:rgba(255,255,255,.1)}
.fab .fab__top svg{width:22px;height:22px}
.fab .fab__top.show{opacity:1;visibility:visible;transform:none}

/* =========================================================================
   MOBILE DRAWER
   ========================================================================= */
.drawer{position:fixed;inset:0;z-index:90;visibility:hidden}
.drawer__scrim{position:absolute;inset:0;background:rgba(27,27,51,.5);opacity:0;transition:opacity .3s}
.drawer__panel{position:absolute;top:0;right:0;height:100%;width:min(86vw,380px);background:var(--surface);
  transform:translateX(100%);transition:transform .35s var(--ease);display:flex;flex-direction:column;
  padding:22px;overflow-y:auto}
.drawer.open{visibility:visible}
.drawer.open .drawer__scrim{opacity:1}
.drawer.open .drawer__panel{transform:none}
.drawer__head{display:flex;align-items:center;justify-content:space-between;margin-bottom:18px}
.drawer__close{width:42px;height:42px;display:grid;place-items:center;border-radius:50%;color:var(--ink-strong)}
.drawer__close:hover{background:var(--bg-soft)}
.m-nav>li{border-bottom:1px solid var(--line)}
/* mobile menu matches the uppercase desktop nav (.nav__link) */
.m-nav a,.m-acc__btn{display:flex;align-items:center;justify-content:space-between;width:100%;
  padding:15px 4px;font-size:17px;color:var(--ink-strong);text-align:left;text-transform:uppercase}
/* "Products" is both a place and a disclosure. The word links to the catalogue
   and the chevron beside it opens the chapters, which is the same split the
   sub-items one level down already use (.m-itm__head). Making the whole row a
   link would cost the chapters their toggle; making it all a button is what
   left the catalogue unreachable from a phone. */
.m-acc__head{display:flex;align-items:center}
.m-acc__head > a{flex:1;min-width:0}
.m-acc__head > .m-acc__btn{flex:none;width:46px;justify-content:center;padding:15px 0}
.m-acc__btn svg{width:18px;height:18px;transition:transform .3s}
.m-acc.open .m-acc__btn svg{transform:rotate(180deg)}
.m-acc__panel{max-height:0;overflow:hidden;transition:max-height .35s var(--ease)}
.m-acc__panel a{padding:11px 16px;font-size:15px;color:var(--muted)}
.m-acc__panel a.m-sub{padding-left:34px;font-size:14px;opacity:.85}
.m-acc__group{font-size:12px;text-transform:uppercase;letter-spacing:.08em;color:var(--gold-600);
  padding:12px 16px 4px;font-weight:700}
.drawer__foot{margin-top:auto;padding-top:24px;display:flex;flex-direction:column;gap:14px}
.drawer__langs{display:flex;gap:8px}
.drawer__langs button,.drawer__langs a{flex:1;padding:10px;border:1px solid var(--line);border-radius:7px;font-size:14px;font-weight:500;text-align:center}
.drawer__langs button.is-active,.drawer__langs a.is-active{background:var(--ink-strong);color:var(--bg);border-color:var(--ink-strong)}

/* =========================================================================
   PLACEHOLDER visuals (swap with photos)
   ========================================================================= */
.ph{background:
   repeating-linear-gradient(135deg,rgba(255,255,255,.04) 0 14px,transparent 14px 28px),
   linear-gradient(135deg,#32335c,#1b1b33);
   display:grid;place-items:center;color:rgba(255,255,255,.35)}
.ph svg{width:44px;height:44px}
.ph--light{background:
   repeating-linear-gradient(135deg,rgba(27,27,51,.03) 0 14px,transparent 14px 28px),
   linear-gradient(135deg,#eceae6,#dcdad5);color:rgba(27,27,51,.3)}

/* ---- Real photos in cards ---- */
.about__visual img,.news__img img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.prod__img{background-size:cover;background-position:center}
/* These five belong to the products section alone. prod-heating.jpg and
   prod-vent.jpg are deliberately NOT reused here: the hero strip and the news
   article reference them inline, so repointing them to suit this section
   changes those too -- which it briefly did.
   -ph is an explicit placeholder; there is no heating photograph in the
   library yet. The other four are the real subject: condensers, an axial fan,
   spiral ductwork and a pipework plant room. */
.prod--heating .prod__img{background-image:url('../img/prod-heating-ph.jpg')}
.prod--cooling .prod__img{background-image:url('../img/prod-cooling.jpg')}
.prod--vent .prod__img{background-image:url('../img/prod-fan.jpg')}
.prod--duct .prod__img{background-image:url('../img/prod-duct.jpg')}
.prod--water .prod__img{background-image:url('../img/prod-water.jpg')}
/* Card-size AVIF copies (tools/projects/2-images.ps1 makes them; the full JPEGs
   stay on the project pages, where the lightbox opens them), and only once
   main.js marks the grid .is-near. A background in a stylesheet downloads with
   the page however far below the fold it sits, and these eight were 1.7 MB of
   the homepage's 3.3 MB before anyone had scrolled. */
.proj__img{background-size:cover;background-position:center;background-color:var(--bg-soft)}
.is-near .proj--1 .proj__img{background-image:url('../img/proj-terminal-card.avif')}
.is-near .proj--2 .proj__img{background-image:url('../img/proj-kartlisi-card.avif')}
.is-near .proj--3 .proj__img{background-image:url('../img/proj-oro-card.avif')}
.is-near .proj--4 .proj__img{background-image:url('../img/proj-pasha-card.avif')}
.is-near .proj--5 .proj__img{background-image:url('../img/proj-chateau-card.avif')}
.is-near .proj--6 .proj__img{background-image:url('../img/proj-culinary-card.avif')}
.is-near .proj--7 .proj__img{background-image:url('../img/proj-agrarian-card.avif')}
.is-near .proj--8 .proj__img{background-image:url('../img/proj-sdsu-card.avif')}

/* Projects gallery page: the same cards as the homepage rail, four across.
   A plain grid, not the rail's bento -- every card is equal here, so nothing
   spans two rows and the parity rule that widens a lone last card does not
   apply. The cards keep their .proj--N classes only to carry their photo. */
.proj-gallery{display:grid;grid-template-columns:repeat(4,1fr);gap:22px;margin-top:44px}
.proj-gallery .proj{min-height:300px}
/* Four columns need about 260px each to keep the title on two lines and the
   logo chip clear of it; below that, drop a column at a time. */
@media (max-width:1180px){.proj-gallery{grid-template-columns:repeat(3,1fr)}}
@media (max-width:880px){.proj-gallery{grid-template-columns:repeat(2,1fr);gap:16px}}
@media (max-width:560px){.proj-gallery{grid-template-columns:1fr}}

/* ---- Decorative brand rings (new identity: thick circle motif) ---- */
.deco{position:absolute;z-index:0;pointer-events:none}
.deco img{width:100%;height:100%;display:block}
.section--dark .container,.footer .container{position:relative;z-index:1}
.deco--ring1{bottom:-190px;left:-170px;width:420px;height:420px;opacity:.4}
.deco--ring2{top:-210px;right:-150px;width:380px;height:380px;opacity:.3}

/* logo color per context (default = white, for transparent header & footer) */
.footer .brand__logo{height:36px;filter:brightness(0) invert(1)}
.drawer__panel .brand__logo{height:34px;filter:none}

/* =========================================================================
   PRODUCT PAGE (products/*.html)
   ========================================================================= */
.page-hero{padding:calc(var(--header-h) + 56px) 0 76px}
/* A brand hub is just a logo and then the listing. The standard 76px below the
   hero was tuned for a page with a heading and copy in it; here it left a band
   of nothing between the logo and the products. */
.page-hero--brand{padding-bottom:16px}
.page-hero--brand .brand-hero__logo{margin-bottom:0}
/* The catalogue starts immediately under this heading -- there is no standing
   lede between them -- so the room a page hero leaves for the copy that
   usually follows closes up: less air above the crumb, less under it, and a
   heading a size down from the one a page of prose wants. */
.page-hero--tight{padding-top:calc(var(--header-h) + 26px)}
.page-hero--tight .crumbs{margin-bottom:16px}
.page-hero--tight .eyebrow{margin-bottom:8px}
.page-hero--tight .section__head h1,.page-hero--tight .section__head h2{font-size:clamp(24px,2.6vw,34px)}

/* ---- Page not found (404.html / 404-en.html) -------------------------------
   The server shows these in place of any missing address. The numeral carries
   the page; the message and three ways back sit beside it. The gradient runs
   accent to --deco, so it reads blue-to-purple in light and the reverse in dark. */
.nf{min-height:min(760px,88vh);display:flex;align-items:center}
.nf__inner{display:flex;align-items:center;gap:clamp(28px,5vw,72px)}
/* line-height 1 and not tighter: a background-clipped gradient only paints inside
   the line box, so at .85 the bottoms of the digits were cut off */
.nf__code{flex:none;font-size:clamp(110px,17vw,230px);font-weight:700;line-height:1;letter-spacing:-.04em;
  background:linear-gradient(135deg,var(--gold) 25%,var(--deco));-webkit-background-clip:text;background-clip:text;color:transparent}
.nf__body{max-width:560px}
.nf__body h1{font-size:clamp(28px,3.4vw,44px);margin-bottom:14px}
.nf__body p{color:var(--muted);font-size:18px;margin-bottom:28px}
.nf__actions{display:flex;flex-wrap:wrap;gap:12px}
@media (max-width:760px){
  .nf{min-height:0}
  .nf__inner{flex-direction:column;align-items:flex-start;gap:6px}
  .nf__actions .btn{flex:1 1 auto;justify-content:center}
}
.crumbs{display:flex;align-items:center;gap:9px;font-size:13.5px;color:var(--muted);
  margin-bottom:30px;flex-wrap:wrap}
.crumbs a:hover{color:var(--gold-600)}
.crumbs .sep{opacity:.45}
.crumbs b{color:var(--ink);font-weight:500}
.phero{display:grid;grid-template-columns:1.02fr .98fr;gap:56px;align-items:center}
.phero h1{font-size:clamp(30px,3.6vw,46px);margin:6px 0 16px}
.phero__lead{color:var(--muted);font-size:18px;margin-bottom:26px}
.phero__cta{display:flex;gap:14px;flex-wrap:wrap}
.phero__img{border-radius:var(--radius);overflow:hidden;aspect-ratio:4/3;box-shadow:var(--shadow-md)}
.phero__img img{width:100%;height:100%;object-fit:cover}
.pfeat-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:26px}
.pfeat{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:26px;
  transition:transform .3s var(--ease),box-shadow .3s}
.pfeat:hover{transform:translateY(-4px);box-shadow:var(--shadow-md)}
.pfeat__ic{width:46px;height:46px;border-radius:12px;display:grid;place-items:center;
  background:rgba(var(--accent-rgb),.12);color:var(--gold-600);margin-bottom:16px}
.pfeat__ic svg{width:24px;height:24px}
.pfeat h3{font-size:17.5px;font-weight:600;margin-bottom:8px}
.pfeat p{font-size:14.5px;color:var(--muted)}
.usecases{display:flex;flex-wrap:wrap;gap:10px}
.usecases li{background:var(--surface);border:1px solid var(--line);padding:9px 18px;border-radius:999px;font-size:14.5px}
/* partner-logo infinite marquee */
.logos{position:relative;overflow:hidden;margin:6px 0 26px;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent)}
.logos__track{display:flex;align-items:center;gap:60px;width:max-content;
  animation:logos-scroll 32s linear infinite}
.logos:hover .logos__track{animation-play-state:paused}
/* Each mark links to the manufacturer's own site. The anchor takes the sizing
   the image had: it is the flex child now, and without this the picture inside
   it stretches to whatever the track gives it. */
.logos a{flex:0 0 auto;display:flex;align-items:center;padding:0;border-radius:0}
.logos img{flex:0 0 auto;height:30px;width:auto;object-fit:contain;
  opacity:.62;filter:grayscale(1);transition:opacity .25s,filter .25s}
.logos img:hover{opacity:1;filter:none}
@keyframes logos-scroll{to{transform:translateX(-50%)}}
@media (prefers-reduced-motion:reduce){.logos__track{animation:none}}
/* brand page hero logo */
.brand-hero__logo{height:42px;width:auto;max-width:240px;display:block;margin:6px 0 16px}
/* A square lockup set to the wordmarks' height reads as a stamp rather than a
   logo, because the others spend their 42px across ~240px of width. Match the
   optical weight instead of the number. */
.brand-hero__logo[src*="vortice"],
.brandpick__card img[src*="vortice"]{height:76px}

/* ---- Samsung brand page: DVM/CAC/FJM subsection tabs (horizontal) ---- */
.subtabs{display:block}
.subtabs__list{display:flex;flex-direction:row;flex-wrap:wrap;gap:12px;margin-bottom:26px}
.subtabs__btn{flex:1 1 180px;position:relative;text-align:left;padding:15px 18px;border:1px solid var(--line);
  border-radius:12px;background:var(--surface);font-weight:600;font-size:15.5px;color:var(--ink);
  transition:.2s;display:flex;align-items:center;justify-content:space-between;gap:10px}
.subtabs__btn small{display:block;font-size:12px;font-weight:400;color:var(--muted);margin-top:3px}
.subtabs__btn:hover{border-color:var(--gold-200)}
.subtabs__btn.active{background:var(--gold);border-color:var(--gold);color:#fff}
.subtabs__btn.active small{color:rgba(255,255,255,.85)}
.subtabs__btn svg{width:16px;height:16px;flex:none;opacity:.7;transition:transform .25s}
.subtabs__btn.active svg{transform:rotate(90deg)}
.subtabs__panel{display:none;animation:foldin .35s var(--ease)}
.subtabs__panel.active{display:block}
@keyframes foldin{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
@media (max-width:620px){
  .subtabs__list{flex-wrap:nowrap;overflow-x:auto;padding-bottom:4px}
  .subtabs__btn{flex:0 0 auto}
  .subtabs__btn small{display:none}
}

/* ---- article image gallery + lightbox ---- */
/* Gallery strip: themed drag bar, and edges that fade rather than cut.
   The native scrollbar was default chrome grey and read as browser furniture
   sitting under the card. The homepage rails hide it outright and use arrows,
   but a thumbnail strip is short enough that a visible drag affordance earns
   its keep -- so it is styled to match instead of removed. */
.gallery{display:flex;gap:12px;margin:14px 0 8px;overflow-x:auto;padding-bottom:8px;
  scrollbar-width:thin;scrollbar-color:var(--gold-600) transparent}
/* The drag bar is styled with the standard properties only. ::-webkit-scrollbar
   and friends are inert in current Chromium once scrollbar-width is in play --
   even display:none on them leaves the bar's reserved height untouched -- so the
   arrow buttons the platform draws at each end cannot be styled away. The only
   way to remove them is scrollbar-width:none, which takes the whole bar with it.
   Colour note: this was --gold-200, which is #8ba4fb in light mode and read as
   washed out on white; --gold-600 is solid in both themes. */
/* Edge fade for any horizontally scrolling strip -- the thumbnail galleries and
   the product/news/project rails. main.js adds .edgefade and keeps has-left /
   has-right in step with the scroll position, so only the side that still has
   content beyond it fades and a strip that does not overflow never fades. */
.edgefade{--fade:linear-gradient(#000,#000);-webkit-mask-image:var(--fade);mask-image:var(--fade)}
.edgefade.has-left.has-right{--fade:linear-gradient(90deg,transparent 0,#000 36px,#000 calc(100% - 36px),transparent 100%)}
.edgefade.has-right:not(.has-left){--fade:linear-gradient(90deg,#000 calc(100% - 36px),transparent 100%)}
.edgefade.has-left:not(.has-right){--fade:linear-gradient(90deg,transparent 0,#000 36px)}
/* The thumbnail strip is the only one with a visible drag bar, so it unions a
   second layer that keeps the bottom 10px opaque and the bar solid end to end.
   The rails must NOT have this -- they hide their scrollbar, and the strip would
   leave the bottom of the outermost cards stubbornly unfaded. */
.gallery.edgefade{
  -webkit-mask-image:var(--fade),linear-gradient(180deg,transparent calc(100% - 16px),#000 calc(100% - 16px));
  mask-image:var(--fade),linear-gradient(180deg,transparent calc(100% - 16px),#000 calc(100% - 16px));
  -webkit-mask-composite:source-over;mask-composite:add}.gallery img{flex:0 0 auto;height:88px;width:132px;object-fit:cover;border-radius:10px;
  border:1px solid var(--line);cursor:zoom-in;transition:transform .2s,box-shadow .2s}
.gallery img:hover{transform:translateY(-2px);box-shadow:var(--shadow-sm);border-color:var(--gold-200)}
.lightbox{position:fixed;inset:0;z-index:200;background:rgba(15,15,30,.92);
  display:flex;align-items:center;justify-content:center;padding:24px;
  opacity:0;visibility:hidden;transition:opacity .25s}
.lightbox.open{opacity:1;visibility:visible}
.lightbox img{max-width:92vw;max-height:88vh;border-radius:10px;box-shadow:0 24px 70px rgba(0,0,0,.5)}
/* picture (or video) with its name under it; the picture gives up a little
   height when there is a name, so the two always fit the screen together */
.lightbox__stage{display:flex;flex-direction:column;align-items:center;gap:16px;max-width:92vw}
.lightbox.has-cap img{max-height:calc(88vh - 56px)}
.lightbox__cap{margin:0;max-width:min(92vw,900px);color:#fff;text-align:center;
  font-size:clamp(15px,1.7vw,20px);font-weight:600;line-height:1.35;letter-spacing:.01em}
.lightbox__cap:empty{display:none}
.lightbox__close{position:absolute;top:20px;right:24px;width:46px;height:46px;border-radius:50%;
  background:rgba(255,255,255,.15);color:#fff;display:grid;place-items:center;cursor:pointer;
  border:none;transition:background .2s}
.lightbox__close:hover{background:rgba(255,255,255,.28)}
.lightbox__close svg{width:22px;height:22px}
.lightbox__nav{position:absolute;top:50%;transform:translateY(-50%);width:52px;height:52px;
  border-radius:50%;background:rgba(255,255,255,.14);color:#fff;border:none;display:grid;
  place-items:center;cursor:pointer;transition:background .2s;z-index:2}
.lightbox__nav:hover{background:rgba(255,255,255,.3)}
.lightbox__prev{left:20px}
.lightbox__next{right:20px}
.lightbox__nav svg{width:26px;height:26px}
@media (max-width:620px){
  .lightbox__nav{width:42px;height:42px}
  .lightbox__prev{left:8px}
  .lightbox__next{right:8px}
}

/* ---- product cards (inside a subsection) ---- */
.pcard-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:20px}
.pcard{display:flex;flex-direction:column;background:var(--surface);border:1px solid var(--line);
  border-radius:var(--radius);overflow:hidden;transition:.25s;text-decoration:none;color:inherit}
.pcard:hover{box-shadow:var(--shadow-md);transform:translateY(-3px);border-color:var(--gold-200)}
/* No tint behind the shot. The product photography is already cut out on solid
   white, so on a white card the tile was a grey box drawn around an image that
   needed no frame. Dark mode still needs one — see the dark block. */
.pcard__img{position:relative;aspect-ratio:1/1;background:transparent;display:grid;place-items:center;padding:14px}
/* Brand mark in the corner of the photo panel. The listings now mix brands, so
   the card has to say whose product it is without being opened. */
.pcard__brand{position:absolute;top:12px;left:12px;z-index:1;display:block;pointer-events:none;line-height:0}
/* Scoped through .pcard__img on purpose. The ".pcard__img img" rule further
   down also matches this logo and carries max-height:100%; at equal specificity
   the later rule won and silently clamped the mark's height. */
.pcard__img .pcard__brand img{display:block;width:auto;max-width:none;max-height:none}
/* Sized per brand, because one height suits none of them: Samsung's wordmark is
   6.5:1, Mitsubishi's 3.45:1 and Vortice's a 1:1 lockup carrying both the mark
   and the wordmark. These heights give all three roughly the same width on the
   card, which is what reads as equal weight. No negative margins -- the card
   clips its own overflow, so anything pulled past the corner is cut off. */
/* Fallback first: a brand with no rule of its own would otherwise get no
   height at all and render 0x0 -- which is exactly what happened when the
   boiler brands arrived. */
.pcard__brand img{height:16px}
.pcard__brand img[src*="samsung"]{height:14px}
.pcard__brand img[src*="omega"]{height:18px}   /* 308x79 viewBox - wide, so it sits at the Beretta height */
.pcard__brand img[src*="mitsubishi"]{height:21px}
.pcard__brand img[src*="beretta"]{height:18px}
.pcard__brand img[src*="riello"]{height:22px}
.pcard__brand img[src*="warmhaus"]{height:20px}
.pcard__brand img[src*="vortice"]{height:38px;border-radius:4px}
/* the compat tab's cards are about a third the size, so the marks scale too */
.ptabs__panel[data-panel="compat"] .pcard__brand{top:8px;left:8px}
.ptabs__panel[data-panel="compat"] .pcard__brand img[src*="samsung"]{height:9px}
.ptabs__panel[data-panel="compat"] .pcard__brand img[src*="mitsubishi"]{height:15px}
.ptabs__panel[data-panel="compat"] .pcard__brand img[src*="vortice"]{height:26px}
.pcard__img img{max-width:100%;max-height:100%;object-fit:contain}
/* The name band is brand navy in both themes — in light mode it gives the white
   photo panel above it an edge to sit against, and it keeps the card reading
   the same either way. White on --navy is ~16:1. */
.pcard__body{padding:16px 18px 18px;display:flex;flex-direction:column;gap:6px;flex:1;
  background:var(--navy);color:#fff}
.pcard__body h4{font-size:16px}
.pcard__price{margin-top:auto;font-size:18px;font-weight:600;color:var(--gold-600)}
.pcard__price small{font-size:12px;font-weight:400;color:var(--muted)}
.subsoon{background:var(--bg-soft);border:1px dashed var(--cream);border-radius:var(--radius);
  padding:34px;text-align:center;color:var(--muted)}


/* ---- Product catalogue (products.html) ------------------------------------
   The dropdown laid out to be read instead of hovered. One panel per chapter of
   menu-tree.json, written by tools/products-page.ps1 from the same tree the
   menu and the drawer are drawn from, so a category cannot exist in one and not
   the others.

   Five chapters as five columns asked the reader to take in every category the
   company sells at once. It is a row of chapters now, with one of them open
   below it and each of its categories drawn as a card: the product, the name,
   an arrow.

   Progressive enhancement, and the reason the row starts hidden: main.js adds
   .catalog--tabs, and only under that class does the row appear and the
   inactive panels go away. With no JavaScript the row -- five buttons that
   would do nothing -- is never drawn and all five chapters stack, which is what
   this page was before and what a crawler reads either way. */
.catalog__rail{display:none}
.catalog__view{display:flex;flex-direction:column;gap:54px}

/* min-width:0: a grid item is min-width:auto by default and sizes to its own
   content, which on this page means a long chapter name setting the width
   rather than fitting inside it. */
.catalog__chapter{min-width:0}
/* Uppercase, which for Georgian means Mtavruli: main.js reads the computed
   text-transform, converts the Mkhedruli in place and then switches the CSS
   transform off on the element, because uppercase would otherwise map Mtavruli
   straight back down. Setting it here is the whole opt-in.
   The tracking turns positive with it -- caps set tight run together. */
.catalog__chapter > h3{margin:0 0 22px;font-size:clamp(18px,1.9vw,24px);
  line-height:1.2;letter-spacing:.02em;overflow-wrap:break-word;
  text-transform:uppercase;color:var(--ink-strong)}
/* the chapter name opens the whole chapter on one page */
.catalog__all{display:inline-flex;align-items:center;gap:.4em;color:inherit;transition:color .2s}
.catalog__all svg{width:.8em;height:.8em;flex:none;transition:transform .2s}
.catalog__all:hover{color:var(--gold-600)}
.catalog__all:hover svg{transform:translateX(3px)}

/* Four columns whatever the chapter holds, so a card is the same size in the
   chapter with one category as in the one with four: tracks that shared the row
   out between them would draw cooling's single category the width of the page. */
.catalog__grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:18px}
.catalog__card{display:flex;flex-direction:column;min-width:0;
  border:1px solid var(--line);border-radius:14px;overflow:hidden;
  background:var(--surface);
  transition:border-color .25s var(--ease),transform .25s var(--ease),
             box-shadow .25s var(--ease)}
.catalog__card:hover{border-color:var(--gold);transform:translateY(-4px);
  box-shadow:0 18px 40px rgba(0,0,0,.3)}
/* The wash is the ground the whole band already stands on, so the card is a
   pane of glass laid on it rather than a second picture: the product is the
   only thing drawn inside it. */
.catalog__pic{position:relative;display:block;aspect-ratio:4/3;
  background:var(--navy) center/cover no-repeat}
/* Two caps and no set size, so the picture scales to whichever it meets first
   and keeps its own proportions. These cut-outs run from a 398x700 boiler to a
   700x411 wall unit: setting a height would stretch the wide ones and setting a
   width would leave the boiler taller than its card.
   Centred by the inset-0 + margin:auto pair, which does that for a replaced
   element without the parent having to become a grid. */
.catalog__pic img{position:absolute;inset:0;margin:auto;max-width:76%;max-height:80%;
  filter:drop-shadow(0 14px 20px rgba(0,0,0,.45));transition:transform .35s var(--ease)}
.catalog__card:hover .catalog__pic img{transform:scale(1.06)}
/* A category with a photograph instead of a cut-out -- the pumping station, shot
   in its plant room -- fills the card rather than floating in the middle of it. */
.catalog__pic--photo img{max-width:none;max-height:none;width:100%;height:100%;
  object-fit:cover;filter:none}
.catalog__name{display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:13px 15px;font-size:14.5px;font-weight:600;line-height:1.3;
  color:var(--ink-strong);transition:color .2s}
.catalog__name svg{width:16px;height:16px;flex:0 0 auto;color:var(--gold);
  transition:transform .2s var(--ease)}
.catalog__card:hover .catalog__name svg{transform:translateX(4px)}
/* A range we carry with no listing published yet. The card still goes
   somewhere -- to the holding page, which says so and offers the form -- and
   its name is grey until there is something to list. */
.catalog__card--soon .catalog__name,
.catalog__card--soon .catalog__name svg{color:var(--muted)}
.catalog__card--soon:hover .catalog__name{color:var(--ink-strong)}
.catalog__card--soon:hover .catalog__name svg{color:var(--gold-600)}

/* ---- the chapters ---------------------------------------------------------
   Buttons, not links: they open the panel below them, they do not navigate.
   font:inherit because a button does not inherit type by default, and these are
   a row of names rather than labels on controls -- which is also why the text
   is aligned left against the browser's centred default. */
.catalog--tabs{display:block}
.catalog--tabs .catalog__rail{display:flex;align-items:stretch;gap:2px;
  margin-bottom:28px;border-bottom:1px solid var(--line);
  overflow-x:auto;overscroll-behavior-x:contain}
.catalog--tabs .catalog__chapter{display:none}
.catalog--tabs .catalog__chapter.is-on{display:block}
/* Room for the tallest chapter, so opening a shorter one does not pull the
   footer up the page under the pointer that is still on the row. */
.catalog--tabs .catalog__view{min-height:420px}
/* margin-bottom:-1px so the open tab's rule sits on the row's own hairline
   rather than a pixel below it. */
.cat-tab{position:relative;display:flex;align-items:center;gap:10px;
  margin-bottom:-1px;padding:12px 16px 14px;
  font:inherit;text-align:left;color:var(--body);background:none;cursor:pointer;
  border:0;border-bottom:2px solid transparent;white-space:nowrap;
  transition:color .25s var(--ease),border-color .25s var(--ease)}
.cat-tab:hover{color:var(--ink-strong)}
.cat-tab.is-on{color:var(--gold-600);border-bottom-color:var(--gold)}
.cat-tab:focus-visible{outline:2px solid var(--gold);outline-offset:-3px;border-radius:8px}
.cat-tab__ico{flex:0 0 auto;width:28px;height:28px;transition:transform .4s var(--ease)}
.cat-tab.is-on .cat-tab__ico{transform:scale(1.1)}
/* min-width:0, or the flex child sizes to the longest unbroken word and pushes
   the row wider than the space it has. */
.cat-tab__txt{min-width:0;display:flex;flex-direction:column;gap:4px}
.cat-tab__txt b{font-size:13px;font-weight:600;letter-spacing:.04em;line-height:1.3;
  text-transform:uppercase;color:inherit}
.cat-tab__txt small{display:none}

/* ---- switching ------------------------------------------------------------
   The panel is display:none until its tab is chosen, so the animations restart
   on their own each time one is: an element coming back from display:none runs
   its animation again with no help from script. */
@keyframes cat-rise{from{opacity:0;transform:translateY(18px)}to{opacity:1;transform:none}}
.catalog--tabs .catalog__chapter.is-on > h3{animation:cat-rise .34s var(--ease) both}
.catalog--tabs .catalog__chapter.is-on .catalog__card{animation:cat-rise .44s var(--ease) both}
.catalog--tabs .catalog__chapter.is-on .catalog__card:nth-child(1){animation-delay:.06s}
.catalog--tabs .catalog__chapter.is-on .catalog__card:nth-child(2){animation-delay:.12s}
.catalog--tabs .catalog__chapter.is-on .catalog__card:nth-child(3){animation-delay:.18s}
.catalog--tabs .catalog__chapter.is-on .catalog__card:nth-child(4){animation-delay:.24s}
@media (prefers-reduced-motion:reduce){
  .catalog--tabs .catalog__chapter.is-on > h3,
  .catalog--tabs .catalog__chapter.is-on .catalog__card{animation:none}
  .cat-tab,.cat-tab__ico,.catalog__card,.catalog__pic img{transition:none}
}

@media (max-width:1120px){
  .catalog__grid{gap:14px}
  .cat-tab{padding:11px 12px 13px;gap:8px}
}
/* Tablet and phone: the row of chapters becomes a block of pills, wrapped so
   all five are in view at once. It scrolled sideways at first, which put the
   last two off the edge of the screen -- and a chapter nobody can see is a
   chapter nobody opens.
   Two columns, and five chapters leave one over: it takes the width of both
   rather than standing half a row on its own. :last-child on its own would
   span a sixth pill as readily as a fifth -- :nth-child(odd) is the part that
   says "the one with no partner". */
@media (max-width:900px){
  .catalog--tabs .catalog__rail{display:grid;gap:7px;margin-bottom:22px;
    grid-template-columns:repeat(2,minmax(0,1fr));
    border-bottom:0;overflow:visible;background:none}
  .cat-tab:nth-child(odd):last-child{grid-column:1/-1}
  /* A pill rather than a tab: an underline belongs to a row, and reads as
     nothing at all once the row has wrapped into a block.
     min-height so a one-line label and a two-line one still stand the same
     height, rather than the row growing around the longest name in it. */
  .cat-tab{width:auto;min-height:46px;gap:9px;margin-bottom:0;padding:6px 14px;
    border:1px solid var(--line);border-radius:100px;background:var(--surface);
    white-space:normal}
  .cat-tab.is-on{border-color:var(--gold)}
  .cat-tab__ico{width:20px;height:20px}
  /* 10.5, not 11: half a pill on a 375px screen leaves 99px for a label and
     the longest name that stays whole there wants 88 of it. At 11 it wants 92,
     which is room enough until the face renders a hair wider somewhere and one
     name goes onto two lines while the four beside it stay on one. */
  .cat-tab__txt b{font-size:10.5px;line-height:1.25}
  /* Two cards across. Four on a phone is a row of thumbnails; two is a picture
     you can see what is in. */
  .catalog__grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
  .catalog__name{padding:11px 12px;font-size:13px}
  .catalog__chapter > h3{margin-bottom:16px;font-size:clamp(18px,4.4vw,24px)}
  .catalog--tabs .catalog__view{min-height:0}
}
@media (max-width:560px){
  .cat-tab__tail{display:none}
}

/* ---- product detail page ---- */
.pprice{display:inline-flex;flex-direction:column;gap:3px;background:var(--bg-soft);
  border:1px solid var(--cream);border-radius:14px;padding:14px 22px;margin:4px 0 20px}
.pprice b{font-size:27px;color:var(--gold-600);line-height:1}
.pprice span{font-size:12.5px;color:var(--muted)}
.pgallery{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:14px}
.pgallery img{width:100%;height:190px;object-fit:cover;border-radius:var(--radius);
  border:1px solid var(--line);background:#fff}
/* The panel is tinted rather than set to --surface, because on light --surface
   and --bg are both #ffffff: the same rule that reads as a card on dark
   rendered an invisible box on light, leaving the rows floating on the page.
   --bg-soft is the step above the page in each theme; dark keeps --surface
   below, which is a touch lighter still and is what that theme already used. */
.spec-table{width:100%;border-collapse:collapse;font-size:15px;background:var(--bg-soft);
  border:1px solid var(--line);border-radius:var(--radius);overflow:hidden}
:root[data-theme="dark"] .spec-table{background:var(--surface)}
.spec-table th,.spec-table td{text-align:left;padding:13px 16px;border-bottom:1px solid var(--line)}
.spec-table th{width:44%;font-weight:500;color:var(--muted)}
/* --muted was picked against white and lands at 4.43:1 on the tinted panel,
   just under the 4.5 minimum. One step darker restores it (4.71:1) while
   staying clearly lighter than the values beside it. Dark is unaffected -- its
   labels already sit at 6.7:1. */
:root:not([data-theme="dark"]) .spec-table th{color:#686b6e}
.spec-table td{font-weight:500;color:var(--ink)}
.spec-table tr:last-child th,.spec-table tr:last-child td{border-bottom:0}
.pfeat-row{display:grid;grid-template-columns:1.05fr .95fr;gap:26px;align-items:center;margin:26px 0}
.pfeat-row:nth-child(even) .pfeat-row__img{order:2}
.pfeat-row__img img{width:100%;border-radius:var(--radius);border:1px solid var(--line);display:block}
@media (max-width:760px){.pfeat-row{grid-template-columns:1fr;gap:16px}.pfeat-row:nth-child(even) .pfeat-row__img{order:0}}
@media (max-width:920px){
  .phero{grid-template-columns:1fr;gap:36px}
  .pfeat-grid{grid-template-columns:1fr 1fr}
}
@media (max-width:680px){
  /* About on phones. The section ran 1341px -- 1.7 screens on a 375px viewport
     -- with the numbers row stacking into three rows at 40px type, a 5:4 photo,
     and 449px of copy. Condensed without dropping a word: the numbers go
     3-across, the photo takes a wider crop, and the copy collapses behind a
     toggle (added in main.js, and only when it actually overflows). */
  .stats{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-top:24px}
  .stat b{font-size:25px}
  .stat span{font-size:12.5px;line-height:1.3}
  .about__visual{aspect-ratio:16/10}
  .about__text p:first-of-type{font-size:17px}
  .about__cta{margin-top:24px}
  .about__copy{overflow:hidden}
  .about__copy:not(.is-open){max-height:11.5em;
    -webkit-mask-image:linear-gradient(#000 68%,transparent);
    mask-image:linear-gradient(#000 68%,transparent)}
  .about__more{margin-top:4px;font-size:15px;font-weight:600;color:var(--gold-600);
    background:none;border:0;padding:0;cursor:pointer}
  .pfeat-grid{grid-template-columns:1fr}
}

/* =========================================================================
   NEWS ARTICLE PAGE (news/*.html)
   ========================================================================= */
.article{max-width:800px;margin-inline:auto}
/* Centring the 800px measure is right when the article is the whole page.
   On the projects gallery it sits above a grid that fills the container, so
   the heading ended up indented well to the right of the first card. Flush
   left lines the two up; the measure is unchanged. */
.article--flush{margin-inline:0}
.article__topmeta{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin-bottom:6px}
.article__date{display:inline-flex;align-items:center;gap:7px;font-size:13.5px;color:var(--muted)}
.article__date svg{width:15px;height:15px;color:var(--gold-600)}
.article h1{font-size:clamp(28px,3.4vw,42px);margin:10px 0 24px}
.article__lead{font-size:19px;color:var(--ink);margin-bottom:6px}
.article__img{border-radius:var(--radius);overflow:hidden;margin:30px 0;box-shadow:var(--shadow-sm)}
.article__img img{width:100%;display:block}
/* The caption sits inside the figure, which is a rounded card with
   overflow:hidden. With no bottom padding the last line ran into that
   rounded edge and lost its descenders, and 4px left it almost touching
   the sides. It never showed while every caption was one short line. */
.article__img figcaption{font-size:13px;color:var(--muted);line-height:1.5;
  padding:12px 16px 14px}
.article__body p{margin-bottom:18px;color:var(--body)}
.article__body h2{font-size:23px;margin:36px 0 14px}
.article__body ul{margin:0 0 18px 22px;list-style:disc;color:var(--body)}
.article__body ul li{margin-bottom:8px}
.article__body a{color:var(--gold-600);text-decoration:underline;text-underline-offset:3px}
.article__body a:hover{color:var(--gold)}
.article__body blockquote{border-left:3px solid var(--gold);padding:4px 0 4px 22px;margin:28px 0;
  font-size:19px;line-height:1.6;color:var(--gold-600)}
.article__body blockquote cite{display:block;font-style:normal;font-size:14px;color:var(--muted);margin-top:10px}
.article__stats{display:flex;gap:36px;flex-wrap:wrap;background:var(--bg-soft);
  border-radius:var(--radius);padding:26px 30px;margin:30px 0}
.article__foot{display:flex;align-items:center;justify-content:space-between;gap:14px;
  border-top:1px solid var(--line);margin-top:38px;padding-top:24px}
.article__foot span{font-size:14.5px;color:var(--muted)}
/* news articles carry only the share button here, so keep it on the right
   where it sat when there was a line of text beside it */
.article__foot .news__share{margin-left:auto}
/* Two CTAs side by side squeeze each label onto three lines at phone width --
   the service page is the first article foot to carry two buttons rather than
   a line of text and one. Stack them and let each take the full width. */
@media (max-width:680px){
  .article__foot{flex-direction:column;align-items:stretch;gap:12px}
  .article__foot .btn{justify-content:center}
}

/* Article pages on a phone still rendered their body at desktop sizes -- a
   19px lead, 23px headings with 36px above them, 18px between paragraphs. On a
   list-heavy page like the service one that ran far taller than it needed to.
   Nothing is hidden or cut: the type and the spacing simply tighten. */
@media (max-width:600px){
  .page-hero{padding-top:calc(var(--header-h) + 34px)}
  .article h1{margin:8px 0 16px}
  .article__lead{font-size:16.5px;line-height:1.55}
  .article__img{margin:22px 0}
  .article__body p{margin-bottom:14px;line-height:1.62}
  .article__body h2{font-size:19px;margin:26px 0 10px}
  .article__body ul{margin:0 0 14px 18px}
  .article__body ul li{margin-bottom:6px;line-height:1.55}
  .article__body blockquote{font-size:16.5px;margin:22px 0;padding-left:16px}
  .article__foot{margin-top:28px;padding-top:20px}
}

/* ---- Reveal on scroll ---- */
.reveal{opacity:0;transform:translateY(24px);transition:opacity .7s var(--ease),transform .7s var(--ease)}
.reveal.in{opacity:1;transform:none}

/* =========================================================================
   RESPONSIVE
   ========================================================================= */
@media (max-width:1140px){
  .nav,.lang,.icon-btn{display:none}
  .burger{display:flex}
  .header__inner{justify-content:space-between}
  .brand{order:-1}
  .nav__tools{margin-left:auto}
  .prod-menu{min-width:0}
}
@media (max-width:920px){
  /* one column: copy, photo, numbers, button -- the photo rides up under the
     "show more" toggle instead of sitting at the foot of the section */
  .about{grid-template-columns:1fr;column-gap:0}
  .about>.about__visual{grid-column:1;grid-row:auto;margin-top:36px}
  .news-grid{grid-template-columns:1fr 1fr}
  /* .prod-grid deliberately absent: it is a horizontal rail below 1040px and
     must not collapse to a column here. */
  .footer__grid{grid-template-columns:1fr 1fr}
  /* a full-width row of its own in this two-column footer, above the map */
  .footer__grid > .footer__policies{grid-column:1 / -1}
  .contact{grid-template-columns:1fr;gap:36px}
}
@media (max-width:680px){
  .section{padding:64px 0}
  /* One row on phones, same as the products row. Three stacked articles turn
     the section into a long scroll for very little content, and the rail
     arrows are already there to move through them. */
  .news-grid{display:flex;overflow-x:auto;gap:14px;
    scroll-snap-type:x proximity;overscroll-behavior-x:contain}
  .news-grid>.news{flex:0 0 clamp(230px,74vw,300px);scroll-snap-align:start}
  /* One row on phones, like the products and news rows. min-height is reset
     because the feature card is normally auto-height while spanning two grid
     rows -- in a flex rail that would leave it shorter than its neighbours. */
  .proj-grid{display:flex;overflow-x:auto;gap:14px;
    scroll-snap-type:x proximity;overscroll-behavior-x:contain}
  .proj-grid>.proj{flex:0 0 clamp(230px,74vw,300px);scroll-snap-align:start;min-height:270px}
  /* footer on phones: two short link lists sit side by side, everything else
     spans the full width. DOM order is brand, map, navigation, products,
     contact -- so only children 3 and 4 share a row. */
  .footer__grid{grid-template-columns:1fr 1fr}
  .footer__grid > *{grid-column:1 / -1}
  .footer__grid > :nth-child(3){grid-column:1}   /* navigation */
  .footer__grid > :nth-child(4){grid-column:2}   /* products   */
  /* The legal links belong to the brand column, so they cannot be ordered
     against the map while they are nested inside it. display:contents lifts
     that column's children up to be grid items themselves, which lets the
     pair sit last, under the map. Selectors still follow the DOM, hence the
     child selector rather than .footer__grid > *. */
  .footer__grid > :first-child{display:contents}
  .footer__grid > :first-child > *{grid-column:1 / -1}
  .footer__mapcol{order:1}
  /* One column on phones: a half-width column (~150px) is narrower than
     "კონფიდენციალურობის" alone, and the shared (subgrid) columns then pushed
     the whole footer grid past the screen edge, map included. minmax(0,1fr)
     keeps the footer's own two columns from being widened by any word. */
  .footer__grid{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
  .footer__policies{order:2;margin-top:0;grid-auto-flow:row;grid-template-rows:none;
    grid-template-columns:minmax(0,1fr)}
  /* the grid gap spaces these now that they are grid items */
  .footer__social{margin-top:0}
  .form-row{grid-template-columns:1fr;gap:0}
  .contact__form{padding:24px}
  .fab{right:14px;bottom:14px;gap:9px}
  .fab a,.fab button{width:44px;height:44px}
  .fab .fab__social a{width:38px;height:38px}
  .fab svg{width:23px;height:23px}
  .fab__social svg{width:20px;height:20px}
  .fab .fab__top svg{width:19px;height:19px}
}
/* ---- Mobile presentation polish: shorter footer · smaller UI · centred ring ---- */
@media (max-width:600px){
  body{font-size:15px}
  .section{padding:46px 0}
  .section__head{margin-bottom:28px}
  .section__head p{font-size:15.5px}

  /* hero: slightly smaller cards + label */
  .hero__card{flex:0 0 78vw;margin-right:14px}
  .hero__card-label{padding:32px 16px 13px;font-size:19px}

  /* Services ring: icons only.
     Seven labelled nodes cannot share a circle this size. Each label now
     carries the step's full name -- "Service and technical support" rather
     than "Service" -- so at 51 degrees apart they would collide outright. The
     names are not lost: tapping a node puts its full title and description in
     the panel below, which is exactly what the pointing-hand hint is there to
     teach. Dropping the labels also frees the room to make the badges bigger,
     so they are easier to hit. */
  .ring{--ring:min(300px,82vw);width:var(--ring);--r:clamp(96px,30vw,122px);--size:62px;margin:8px auto 20px}
  .node__badge svg{width:46%;height:46%}
  .node__label{display:none}
  .ring__center{width:33vw}
  .ring__logomark{height:15vw}
  .ring__detail-title{font-size:19px}
  .ring__detail-desc{font-size:14px}
  .services__cta{margin-top:30px}
  .services__cta p{font-size:16.5px}

  /* footer: much shorter */
  .footer{padding:40px 0 18px}
  .footer__grid{gap:24px}
  .footer__map{min-height:0;height:150px}
  .footer h4{margin-bottom:6px}
  .footer__about{font-size:13.5px}
  .footer__bottom{margin-top:24px;padding-top:16px;font-size:12.5px}
}
@media (prefers-reduced-motion:reduce){
  *{animation:none!important;transition:none!important;scroll-behavior:auto!important}
  .reveal{opacity:1;transform:none}
  .hero__track{transition:none}
}

/* ============================================================
   PRODUCT SECTION REDESIGN  (brand picker · listing · detail)
   ============================================================ */
.brandpick{display:grid;grid-template-columns:repeat(2,1fr);gap:24px;max-width:820px;margin:8px auto 0}
.brandpick__card{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:22px;
  min-height:220px;padding:30px;background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  text-decoration:none;color:var(--ink);transition:.25s}
.brandpick__card:hover{box-shadow:var(--shadow-md);transform:translateY(-4px);border-color:var(--gold-200)}
.brandpick__card img{height:42px;width:auto;max-width:80%;object-fit:contain}
.brandpick__go{font-size:14px;font-weight:600;color:var(--gold);display:inline-flex;align-items:center;gap:6px}
.brandpick__go svg{width:16px;height:16px}
@media(max-width:600px){.brandpick{grid-template-columns:1fr}}

.cattabs{display:flex;flex-wrap:wrap;gap:9px;margin-bottom:24px}
.cattabs button{padding:9px 18px;border:1px solid var(--line);border-radius:999px;background:var(--surface);
  font-weight:600;font-size:14px;color:var(--ink);cursor:pointer;transition:.2s}
.cattabs button:hover{border-color:var(--gold-200)}
.cattabs button.active{background:var(--ink-strong);color:var(--bg);border-color:var(--ink-strong)}
/* In the sidebar the tabs are just another filter, so they read as a list
   rather than a pill row: full width, left aligned, stacked. */
.pfilter .cattabs{flex-direction:column;flex-wrap:nowrap;gap:6px;margin:0}
.pfilter .cattabs button{width:100%;text-align:left;padding:8px 12px;border-radius:9px;font-weight:500}

.plist{display:grid;grid-template-columns:250px 1fr;gap:32px;align-items:start}
.pfilter__search{position:relative;margin-bottom:20px}
.pfilter__search input{width:100%;padding:11px 14px 11px 40px;border:1px solid var(--line);border-radius:10px;font:inherit;font-size:14px}
.pfilter__search svg{position:absolute;left:13px;top:50%;transform:translateY(-50%);width:17px;height:17px;color:var(--muted)}
.pfilter__head{display:flex;justify-content:space-between;align-items:center;font-weight:600;font-size:15px;margin-bottom:4px}
/* injected by main.js for phones; the sidebar is always open on wider screens */
.pfilter__toggle{display:none}
.pfilter__head a{font-size:13px;color:var(--gold);font-weight:500;cursor:pointer}
.pfilter__group{border-top:1px solid var(--line);padding:14px 0}
/* The sections lead the panel and the filters follow it. Same checkboxes either
   way, so the break has to come from the spacing: a wider gap under the sections
   than between the filter groups themselves. */
.pfilter__group--cats{padding-bottom:24px}
.pfilter__group h4{display:flex;justify-content:space-between;align-items:center;font-size:15px;cursor:pointer;margin:0}
.pfilter__group h4 svg{width:16px;height:16px;transition:transform .25s}
.pfilter__group.closed h4 svg{transform:rotate(-90deg)}
.pfilter__group.closed .pfilter__opts{display:none}
.pfilter__opts{padding-top:10px}
.pfilter__opts label{display:flex;align-items:center;gap:10px;padding:5px 0;font-size:14px;color:var(--muted);cursor:pointer}
.pfilter__opts input{width:16px;height:16px;accent-color:var(--gold)}

/* A filter option that carries a one-line explanation. Trade abbreviations
   (DVM, FJM, Mr Slim) mean nothing to a visitor, so the gloss sits under the
   label instead of behind a tooltip. The checkbox aligns to the first line
   rather than to the middle of a two-line block, hence the separate class --
   plain options keep their vertical centring. */
.pfilter__opts label.has-hint{align-items:flex-start}
.pfilter__opts label.has-hint input{margin-top:2px;flex:0 0 auto}
.pfilter__opts .opt{display:flex;flex-direction:column;gap:2px;min-width:0}
.pfilter__opts .opt small{font-size:12px;line-height:1.35;opacity:.68}
/* A category's own filters on a chapter page (heating.html ...): closed until
   its box is ticked, then dropping down under it, indented on an accent rule
   so they read as belonging to that category. main.js opens and scopes them. */
.pfilter__sub{margin:2px 0 8px 7px;padding:2px 0 4px 17px;border-left:2px solid var(--gold);
  animation:pfilter-drop .28s var(--ease) both}
.pfilter__sub[hidden]{display:none}
@keyframes pfilter-drop{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}
.pfilter__subgroup + .pfilter__subgroup{margin-top:6px}
.pfilter__subgroup h5{margin:6px 0 1px;font-size:12px;font-weight:600;letter-spacing:.04em;
  text-transform:uppercase;color:var(--ink)}
.pfilter__opts .pfilter__sub label{padding:4px 0;font-size:13.5px}

/* The "!" beside a series name (vrf-vrv). Hover (where there is one) shows the
   explanation as a tip to the right, over the grid; a click or tap pins it
   open (.is-open, main.js). */
.pfilter__info{position:relative;flex:none;display:inline-grid;place-items:center;width:17px;height:17px;
  padding:0;border:1.5px solid currentColor;border-radius:50%;background:none;cursor:pointer;
  font:700 11px/1 var(--ff);color:var(--gold-600);transition:background .18s,color .18s,border-color .18s}
.pfilter__info:hover,.pfilter__info:focus-visible{background:var(--gold);border-color:var(--gold);color:#fff}
.pfilter__info::after{content:attr(data-tip);position:absolute;z-index:30;left:calc(100% + 12px);top:50%;
  width:300px;padding:12px 14px;border:1px solid var(--line);border-radius:10px;
  background:var(--surface);box-shadow:var(--shadow-md);
  font-size:13px;font-weight:400;line-height:1.55;letter-spacing:0;text-align:left;text-transform:none;
  white-space:normal;color:var(--body);
  opacity:0;visibility:hidden;pointer-events:none;transform:translate(-4px,-50%);
  transition:opacity .18s,transform .18s,visibility .18s}
@media (hover:hover){
  .pfilter__info:hover::after,.pfilter__info:focus-visible::after{opacity:1;visibility:visible;transform:translate(0,-50%)}
}
.pfilter__info.is-open{background:var(--gold);border-color:var(--gold);color:#fff}
.pfilter__info.is-open::after{opacity:1;visibility:visible;transform:translate(0,-50%)}
/* One column (filter above the grid): no room to the right, so the tip opens
   under the "!" instead, starting a little left of it to stay on screen. */
@media (max-width:900px){
  .pfilter__info::after{left:-70px;top:calc(100% + 10px);width:min(300px,80vw);transform:translateY(-4px)}
  .pfilter__info.is-open::after,.pfilter__info:hover::after,.pfilter__info:focus-visible::after{transform:none}
}

/* one-line explainer under a category page title */
/* size and colour come from .section__head p, which this always sits inside */
.page-lede{margin:10px 0 0;max-width:66ch}

/* The brand slogan keeps only the "ეკო" / "eco" stem bold and sets the rest of
   the line at regular weight, so the stem carries the emphasis on its own.
   Headings are 700 (see the h1,h2,h3,h4 rule), hence 400 here. */
.slogan-reg{font-weight:400}

/* =========================================================================
   PRIVACY POLICY document
   -------------------------------------------------------------------------
   Real text, not page images. It was images before, to deter copying, but a
   policy has to be readable by a screen reader, searchable, translatable and
   quotable back at us -- and the deterrent was thin anyway, since nothing on a
   web page can stop a screenshot. So selection and printing are open now.

   Measure is 820px rather than the 900px the images used: the same column of
   Georgian body copy reads long past that.
   ========================================================================= */
.policy{max-width:820px;margin:0 auto;color:var(--muted);font-size:15.5px;line-height:1.75}
/* Selection switched off on the policy body, by request.
   What it does: stops a reader dragging across the text, stops Ctrl+A picking
   it up, and stops iOS offering Copy on a long press.
   What it does not do: protect the text. These are static pages on a public
   URL, so the whole policy is one View Source, one Reader Mode or one curl
   away, and no amount of CSS changes that.
   Deliberately left working: printing, and screen readers, which read the DOM
   and never touch the selection -- this is a document a data subject has a
   right to read, so it must not become unreachable to anyone relying on those. */
.policy{user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}
/* The heading block is held to the same measure, so the breadcrumb, the title
   and the first clause all start on one line rather than the heading running
   the full container while the document sits centred inside it. */
.policy-head{max-width:820px;margin-inline:auto}
/* Same reasoning as .page-hero--brand: 76px below the hero plus the section's
   own 70px left 146px of nothing between the lede and the first clause. */
.page-hero--policy{padding-bottom:30px}
.page-hero--policy + .section{padding-top:0}
/* The English page still carries the policy as page images. */
.policy img{width:100%;height:auto;display:block;margin-bottom:18px;
  border-radius:14px;border:1px solid var(--line);background:#fff}
.policy h2{margin:38px 0 12px;font-size:19px;line-height:1.3;color:var(--ink-strong)}
.policy h2:first-child{margin-top:0}
.policy h3{margin:26px 0 10px;font-size:16.5px;line-height:1.35;color:var(--ink)}
.policy p{margin:0 0 14px}
.policy ul{margin:0 0 16px;padding:0;list-style:none}
/* the marker is drawn rather than a bullet, so a clause that runs to several
   lines keeps its text on one left edge instead of hanging under the dot */
.policy li{position:relative;padding-left:20px;margin-bottom:9px}
.policy li::before{content:"";position:absolute;left:3px;top:.62em;
  width:6px;height:6px;border-radius:50%;background:var(--gold-600)}
/* The agree / do not agree pairs carry an empty square rather than a dot: they
   are the choices made on the contact form, not statements of fact, and the
   square says so without pretending to be a live control. */
.policy li.policy__opt::before{width:11px;height:11px;border-radius:3px;top:.42em;left:1px;
  background:none;border:1.5px solid var(--gold-600)}
.policy a{color:var(--gold-600);font-weight:500;text-decoration:underline;text-underline-offset:2px}
.policy a:hover{color:var(--gold)}
.policy__note{margin:34px auto 0;max-width:820px;text-align:center;
  color:var(--muted);font-size:14.5px;padding-top:22px;border-top:1px solid var(--line)}
.policy__note a{color:var(--gold-600);font-weight:500}
.policy__print{display:none}

/* =========================================================================
   DUCTING gallery
   -------------------------------------------------------------------------
   Made-to-order parts, so this is a gallery rather than the filterable card
   listing the brand categories use: there is nothing to filter on and nothing
   to click through to. The renders are on white, so each sits on its own white
   plate to keep it off the page background in both themes.
   ========================================================================= */
/* The parts sit in .pgrid beside the filter now, like every other product
   listing, so the gallery's own grid and its group headings are gone: the
   filter groups them, and a heading would be left standing over nothing each
   time its group was filtered out. */
.duct{margin:0;background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  overflow:hidden;display:flex;flex-direction:column}
.duct__shot{display:block;background:#fff;padding:10px}
.duct__shot img{width:100%;height:auto;aspect-ratio:3/2;object-fit:contain;display:block}
/* Brand navy in both themes, exactly like .pcard__body above: the render sits on
   a white panel, and in light mode the name band is what gives that panel an
   edge to stop against. Letting it follow the surface token would leave a white
   caption under a white photo and the card would lose its bottom. */
.duct figcaption{padding:14px 16px 16px;display:flex;flex-direction:column;gap:7px;
  background:var(--navy);color:#fff}
.duct figcaption b{font-size:14.5px;font-weight:500;color:#fff;line-height:1.35}
.duct figcaption ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:4px}
.duct figcaption li{font-size:12.5px;line-height:1.4;color:rgba(255,255,255,.72)}
.duct__note{margin:34px 0 0;display:flex;align-items:center;gap:18px;flex-wrap:wrap;
  font-size:14.5px;color:var(--muted)}
/* Only the last button is pushed right. On the ducting page that is the single
   button after the note, which is the intent; on the holding page, where the row
   is two buttons and no text, "auto" on both split the gap between them and left
   the first one floating in the middle instead of under the heading. */
.duct__note .btn:last-child{margin-left:auto}
@media (max-width:680px){
  .duct figcaption{padding:11px 12px 13px}
  /* :last-child here too -- a media query adds no specificity, so plain
     .duct__note .btn would lose to the rule above and stay pushed right */
  .duct__note .btn{width:100%;justify-content:center}
  .duct__note .btn:last-child{margin-left:0}
}
/* Water supply: the two pumping stations side by side. Photographed in their
   plant rooms rather than rendered on white, so each fills its frame instead of
   sitting on a white panel the way a .duct part does. */
.pstations{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:22px}
.pstation{margin:0;border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;
  display:flex;flex-direction:column;background:var(--navy)}
.pstation__shot{display:block;aspect-ratio:16/9;overflow:hidden}
.pstation__shot img{width:100%;height:100%;object-fit:cover;display:block;cursor:zoom-in;
  transition:transform .35s var(--ease)}
.pstation__shot:hover img{transform:scale(1.03)}
.pstation figcaption{display:flex;align-items:center;gap:14px;padding:16px 18px;color:#fff}
/* on a white tile: DAB's mark is a dark green that would vanish on the navy */
.pstation__logo{height:40px;width:auto;flex:0 0 auto;background:#fff;padding:8px 11px;border-radius:8px}
.pstation__txt{display:flex;flex-direction:column;gap:2px;min-width:0}
.pstation__txt b{font-size:16px;font-weight:600;color:#fff}
.pstation__txt small{font-size:13px;color:rgba(255,255,255,.72)}
.pstation__site{margin-left:auto;font-size:13px;color:var(--gold-200);white-space:nowrap}
.pstation__site:hover{text-decoration:underline}
@media (max-width:760px){.pstations{grid-template-columns:1fr}}
.pgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(228px,1fr));gap:20px}
.pgrid__empty{grid-column:1/-1;padding:40px;text-align:center;color:var(--muted)}
/* padding, not margin: the button below uses margin-top:auto to bottom-align, so
   this is what keeps a 12px floor (6px here + the 6px flex gap) above it on
   cards whose title wraps and leaves no slack. */
/* the model code is the last line now, so it carries the body's bottom padding */

.pdetail{display:grid;grid-template-columns:1.05fr .95fr;gap:38px;align-items:start;margin-bottom:0}
/* The dead band under the gallery, closed on a desktop the way the phone rule
   further down already closes it: 76px of page-hero padding plus 20px of
   .pdetail margin, on top of the 24px the tabs section carries inline, left
   120px between the photo and the tabs. Only a product page's hero closes up;
   the listing heroes keep their breathing room. */
.page-hero:has(.pdetail){padding-bottom:18px}
.pgal__main{position:relative;background:#fff;border:1px solid var(--line);border-radius:var(--radius);
  aspect-ratio:4/3;display:grid;place-items:center;padding:26px;overflow:hidden}
.pgal__main img{max-width:100%;max-height:100%;object-fit:contain}
.pgal__arrow{position:absolute;top:50%;transform:translateY(-50%);width:44px;height:44px;border-radius:50%;
  background:var(--surface);border:1px solid var(--line);display:grid;place-items:center;cursor:pointer;box-shadow:var(--shadow-sm);transition:.2s}
.pgal__arrow:hover{background:var(--bg-soft)}
.pgal__arrow svg{width:20px;height:20px}
.pgal__prev{left:14px}.pgal__next{right:14px}
/* One row, always. The thumbs divide the gallery's width between them rather
   than each claiming a fixed 66px and wrapping onto a second line — the count
   varies per product (3 to 7) and even changes underfoot when a colour swatch
   swaps the set, so the size has to follow the count. max-width stops a
   three-shot gallery from inflating its thumbs into a second hero image. */
/* min-width:0 on both: a grid/flex child defaults to min-width:auto, i.e. it
   refuses to shrink below its content — with nowrap that made the strip force
   the whole page wider than the viewport instead of the thumbs getting smaller. */
.pgal{min-width:0}
.pgal__thumbs{display:flex;gap:8px;margin-top:14px;flex-wrap:nowrap;min-width:0}
.pgal__thumbs img{flex:1 1 0;min-width:0;max-width:92px;aspect-ratio:1/1;object-fit:contain;
  padding:5px;background:#fff;border:1px solid var(--line);border-radius:10px;cursor:pointer;transition:.2s}
.pgal__thumbs img.active{border-color:var(--gold)}
.pbuy{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:28px;position:relative}
/* "Made in" flag, pinned to the panel's top-right corner. Rendered only where
   the workbook states an origin, so a product with none simply has no flag --
   the alternative would be inferring manufacture from the brand, which is often
   wrong for HVAC. The title/alt carries the wording; the flag alone is not a
   label a screen reader could read. */
/* The flag sits on the identity row -- beside the brand mark and its output,
   or beside the descriptive tag on the Vortice pages. It was in the panel's
   top-right corner, but an absolute position cannot track that row: the title
   wraps to two lines on some models, so the flag drifted away from what it
   belongs to and collided with the heading. In flow it simply follows. */
.pbuy__ident{display:flex;align-items:center;justify-content:space-between;gap:18px}
/* On the cooling pages the identity line keeps its series/refrigerant tag --
   it is the useful label there, not a figure -- so it takes the accent instead
   of being replaced, with the abbreviation spelled out beneath it. */
.pbuy__ident .pbuy__tag{font-size:15px;font-weight:600;color:var(--gold-600);margin-bottom:3px}
.pbuy__gloss{font-size:12.5px;line-height:1.4;color:var(--muted);max-width:34ch}
.pbuy__origin{flex:none;line-height:0;align-self:flex-start}
.pbuy__origin img{height:40px;width:auto;display:block;border-radius:3px;
  box-shadow:0 1px 4px rgba(27,27,51,.28)}
:root[data-theme="dark"] .pbuy__origin img{box-shadow:0 1px 4px rgba(0,0,0,.5)}
.pbuy__model{font-size:13px;color:var(--muted);font-family:monospace}
.pbuy h1{font-size:clamp(22px,3vw,28px);margin:6px 0 16px}
.pbuy__tag{font-size:13px;color:var(--muted);margin-bottom:8px}
/* Brand shown as its logo, with the output on its own line beneath it.
   The logo is painted as a flat colour, not shown in its own palette: a filter
   cannot map an arbitrary logo colour onto one specific blue, so the shape is
   used as a mask and filled from a token. The <img> stays for layout -- it
   carries the real aspect ratio, so the box sizes itself and any logo works
   without a per-brand width -- and is hidden, with the mask painted over it.
   --m is set inline by the page generator, which knows the brand. */
.pbuy__brand{position:relative;display:inline-block;width:max-content;margin:0 0 11px}
.pbuy__brand img{height:22px;width:auto;max-width:150px;display:block;visibility:hidden}
.pbuy__brand::after{content:'';position:absolute;inset:0;background:#1b1b33;
  -webkit-mask:var(--m) no-repeat left center/contain;mask:var(--m) no-repeat left center/contain}
/* navy on the light panel, white on the dark one */
:root[data-theme="dark"] .pbuy__brand::after{background:#fff}
/* the output is the headline figure on this panel, so it takes the accent and
   a size to match; --gold-600 resolves per theme and reads on both surfaces */
.pbuy__kw{font-size:22px;font-weight:700;line-height:1;color:var(--gold-600);margin-bottom:4px}
.pbuy__label{font-size:11px;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);margin:26px 0 10px}
.chipset{display:flex;flex-wrap:wrap;gap:9px}
.chip{padding:9px 15px;border:1px solid var(--line);border-radius:9px;font-size:14px;font-weight:500;background:var(--surface);cursor:pointer;transition:.15s}
.chip:hover{border-color:var(--gold-200)}
.chip.active{border-color:var(--gold);color:var(--gold-600);box-shadow:inset 0 0 0 1px var(--gold)}
/* colour picker: a squircle of the finish itself, no label -- the swatch is the
   name. The colour comes from --sw on the chip, so a new finish is markup only.
   The inner block carries a dark hairline of its own so a white finish still
   reads as a swatch against the white panel; the outer button keeps the shared
   .chip border so the gold selected ring sits *around* the colour, not on it. */
.chip--sw{width:38px;height:38px;padding:3px;border-radius:12px;line-height:0}
.chip--sw::before{content:"";display:block;width:100%;height:100%;border-radius:9px;
  background:var(--sw,#fff);border:1px solid rgba(0,0,0,.45)}
/* the description that sits under the pickers, above the quote button */
.pbuy__desc{margin:18px 0 0;font-size:14px;line-height:1.65;color:var(--muted)}
.pbuy .btn{width:100%;justify-content:center;margin-top:24px}

/* Desktop: the summary card matches the gallery's height instead of ending
   wherever its text happens to stop. Both columns stretch to the taller of the
   two -- the image box grows past its 4:3 base to take up any slack, and the
   quote button is pushed to the bottom of the summary. Left alone below 900px,
   where the two are stacked and equal heights would mean nothing. */
@media(min-width:901px){
  .pdetail{align-items:stretch}
  .pgal{display:flex;flex-direction:column}
  .pgal__main{flex:1 1 auto}
  .pbuy{display:flex;flex-direction:column}
  .pbuy__desc{margin-bottom:24px}
  .pbuy > .btn{margin-top:auto}
}

.ptabs__nav{display:flex;flex-wrap:wrap;gap:4px;border-bottom:1px solid var(--line);margin-bottom:28px}
.ptabs__nav button{padding:14px 18px;background:none;border:0;border-bottom:2px solid transparent;
  font-weight:600;font-size:15px;color:var(--muted);cursor:pointer;margin-bottom:-1px;transition:.2s}
.ptabs__nav button:hover{color:var(--ink)}
.ptabs__nav button.active{color:var(--ink);border-bottom-color:var(--gold)}
.ptabs__panel{display:none;animation:foldin .3s var(--ease)}
.ptabs__panel.active{display:block}
.ptabs__panel h3{font-size:18px;margin-bottom:12px}

.dl-list{display:flex;flex-direction:column;gap:10px;max-width:520px}
.dl-list a{display:flex;align-items:center;gap:12px;padding:14px 16px;border:1px solid var(--line);
  border-radius:10px;text-decoration:none;color:var(--ink);font-weight:500;transition:.2s}
.dl-list a:hover{border-color:var(--gold-200);background:var(--bg-soft)}
.dl-list svg{width:22px;height:22px;color:var(--gold-600);flex:none}
.dl-list small{display:block;color:var(--muted);font-weight:400;font-size:12.5px}
.energy{display:inline-flex;align-items:center;gap:10px;font-weight:700;color:#fff;background:#3aab5a;padding:10px 18px;border-radius:8px;font-size:18px}

/* ---- Compatibility tab: outdoor unit + accessories ------------------------ */
.compat__h{font-size:13px;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);
  font-weight:600;margin:0 0 12px}
.compat__h + .acc-grid,.compat__h + .pcard-grid{margin-bottom:26px}
/* In the compatibility tab the product cards sit directly above the accessory
   grid, so they take its sizing rather than the hub's larger card: a single
   compatible outdoor unit was rendering three times the width of the
   accessories listed right beneath it. auto-fill (not auto-fit) keeps the
   empty tracks, so one card stays card-sized instead of stretching the row. */
.ptabs__panel[data-panel="compat"] .pcard-grid{
  grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px}
.ptabs__panel[data-panel="compat"] .pcard__img{aspect-ratio:4/3;padding:10px}
.ptabs__panel[data-panel="compat"] .pcard__body{padding:9px 11px 11px;gap:2px}
.ptabs__panel[data-panel="compat"] .pcard__body h4{font-size:12.5px;line-height:1.3}
@media(max-width:600px){
  .ptabs__panel[data-panel="compat"] .pcard-grid{grid-template-columns:1fr 1fr;gap:10px}
  .ptabs__panel[data-panel="compat"] .pcard__body{padding:8px 9px 9px}
  .ptabs__panel[data-panel="compat"] .pcard__body h4{font-size:11.5px}
}
/* the accessory images stay folded away until asked for — a wall of eleven
   remotes and panels buried the rest of the tab, and they are reference
   material rather than something every visitor needs */
.acc-toggle{display:inline-flex;align-items:center;gap:9px;padding:10px 16px;cursor:pointer;
  border:1px solid var(--line);border-radius:9px;background:var(--surface);color:var(--ink);
  font:inherit;font-size:14px;font-weight:600;margin-bottom:26px;transition:.18s}
.acc-toggle:hover{border-color:var(--gold-200)}
.acc-toggle svg{width:16px;height:16px;transition:transform .25s var(--ease)}
.acc-toggle[aria-expanded="true"] svg{transform:rotate(180deg)}
.acc-toggle[aria-expanded="true"]{margin-bottom:14px}
.acc-grid[hidden]{display:none}
.acc-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px}
.acc{display:flex;flex-direction:column;background:var(--surface);border:1px solid var(--line);
  border-radius:var(--radius);overflow:hidden}
.acc__img{aspect-ratio:4/3;background:#fff;display:grid;place-items:center;padding:10px}
.acc__img img{max-width:100%;max-height:100%;object-fit:contain}
.acc__body{padding:9px 11px 11px;display:flex;flex-direction:column;gap:2px;
  background:var(--navy);color:#fff;flex:1}
.acc__body b{font-size:12.5px;font-family:monospace;letter-spacing:.02em}
.acc__body span{font-size:12px;color:rgba(255,255,255,.72);line-height:1.3}
@media(max-width:600px){
  .acc-grid{grid-template-columns:1fr 1fr;gap:10px}
  .acc__body{padding:8px 9px 9px}
  .acc__body b{font-size:11.5px}
  .acc__body span{font-size:11px}
}

.compare{overflow-x:auto;border:1px solid var(--line);border-radius:var(--radius)}
.compare table{width:100%;border-collapse:collapse;font-size:14.5px;min-width:640px}
.compare th,.compare td{padding:14px 16px;text-align:left;border-bottom:1px solid var(--line);vertical-align:top}
.compare thead th{background:var(--bg-soft)}
.compare thead img{height:70px;width:auto;object-fit:contain;display:block;margin-bottom:8px}
.compare tbody th{font-weight:500;color:var(--muted);width:24%}
.compare tr:last-child td,.compare tr:last-child th{border-bottom:0}
/* The left-hand column is the product everything else is being compared
   against, so the whole column carries the accent -- not just its model cell,
   which used to leave one tinted row in an otherwise plain column. The link in
   the last row needs naming explicitly because .link-more sets its own colour.
   Weight still marks the model itself. */
.compare tbody td:first-of-type,
.compare tbody td:first-of-type .link-more{color:var(--gold-600)}
.compare .is-this{font-weight:700}

@media(max-width:900px){
  .plist{grid-template-columns:1fr}
  .pfilter{border:1px solid var(--line);border-radius:var(--radius);padding:16px}
  .pdetail{grid-template-columns:1fr;gap:24px}
}

/* ---- Product list on phones ----------------------------------------------
   Two problems this solves:
   1. The filter sidebar stacks ABOVE the grid, so the first thing on screen is
      a wall of checkboxes rather than products. Below 760px the checkbox groups
      collapse behind a toggle (injected by main.js) and only the search stays
      visible, so the grid starts near the top of the screen.
   2. One card per row made a full-screen card and an endless scroll. Two
      columns with tighter internals fit ~2 rows per screen.               */
@media(max-width:760px){
  .pfilter{padding:12px 14px}
  .pfilter__search{margin-bottom:0}
  .pfilter.is-collapsible .pfilter__body{display:none}
  .pfilter.is-collapsible.is-open .pfilter__body{display:block}
  .pfilter__toggle{display:flex;align-items:center;justify-content:space-between;gap:8px;
    width:100%;margin-top:10px;padding:9px 12px;border:1px solid var(--line);border-radius:10px;
    background:var(--bg-soft);font:inherit;font-size:14px;font-weight:600;color:var(--ink);cursor:pointer}
  .pfilter__toggle svg{width:16px;height:16px;transition:transform .25s}
  .pfilter.is-open .pfilter__toggle svg{transform:rotate(180deg)}
  .pfilter__toggle .pfilter__count{min-width:20px;height:20px;padding:0 6px;border-radius:10px;
    background:var(--gold);color:#fff;font-size:12px;display:none;place-items:center}
  .pfilter__toggle .pfilter__count.on{display:grid}
  .pfilter__group{padding:12px 0}
  /* the toggle already says "filter", so the head keeps only the clear link */
  .pfilter__head{justify-content:flex-end;margin:6px 0 0}
  .pfilter__head span{display:none}

  .pgrid{grid-template-columns:1fr 1fr;gap:12px}
  .pcard__img{padding:10px}
  .pcard__body{padding:10px 11px 12px;gap:4px}
  .pcard__body h4{font-size:13.5px;line-height:1.25}
  .pgal__thumbs{gap:6px}
  .pgal__thumbs img{padding:3px;border-radius:8px}

  /* ---- Product detail on phones ----
     The page was running very long: a roomy summary card, a spec table with
     desktop padding, and tab labels wrapping onto a third row. Everything here
     is spacing and type scale — no content is hidden, it just stops using
     desktop-sized gaps on a 375px screen. */
  .pbuy{padding:18px 16px}
  .pbuy h1{font-size:21px;margin:2px 0 12px}
  .pbuy__tag{font-size:12.5px;margin-bottom:4px}
  .pbuy__origin img{height:30px;width:auto}
  .pbuy__brand{margin-bottom:9px}
  .pbuy__brand img{height:19px}
  .pbuy__kw{font-size:19px;margin-bottom:3px}
  .pbuy__label{font-size:10px;margin:20px 0 8px}
  .chipset{gap:7px}
  .chip{padding:8px 12px;font-size:13.5px}
  /* restated after .chip: the tighter phone padding would otherwise squash the
     colour swatches out of square */
  .chip--sw{padding:3px}
  .pbuy__desc{margin-top:14px;font-size:13.5px;line-height:1.55}
  .pbuy .btn{margin-top:16px;padding:12px 18px}

  /* the label column was 44% wide, so long values wrapped to three lines
     beside a two-word label — narrower label, tighter rows */
  .spec-table{font-size:13.5px}
  .spec-table th,.spec-table td{padding:9px 11px}
  .spec-table th{width:38%}

  .ptabs__nav{gap:2px;margin-bottom:18px}
  .ptabs__nav button{padding:10px 11px;font-size:13.5px}

  /* related products side by side instead of stacked — two cards of a series
     took nearly a full screen each when they were full-width */
  .pcard-grid{grid-template-columns:1fr 1fr;gap:12px}

  /* Close the dead band under the summary card. It measured 120px: 76px of
     page-hero bottom padding, 20px of .pdetail margin and the 24px the tabs
     section carries inline. Trimming the first two leaves a normal break. */
  .page-hero{padding-bottom:18px}
  .pdetail{margin-bottom:0}
  .section{padding:34px 0}
  .section__head{margin-bottom:18px}

  /* Comparison table fits the screen instead of scrolling sideways. It is four
     columns — one label plus three products — so dropping the 640px floor and
     the desktop padding is enough; nothing has to be hidden or stacked. */
  /* overflow stays clipped, not visible: the border-radius on .compare is what
     rounds the corners, and only a clipping overflow makes the thead's own
     background respect it. The table fits at this size, so nothing scrolls. */
  .compare{overflow:hidden}
  .compare table{min-width:0;font-size:11.5px;table-layout:fixed}
  .compare th,.compare td{padding:7px 6px;word-break:break-word}
  .compare thead th:first-child{width:26%}
  .compare thead img{height:38px;margin-bottom:4px}
}
@media(max-width:360px){
  .pgrid{gap:9px}
  .pcard__body{padding:9px 9px 10px}
}

/* ---- Responsive YouTube embed (about page · news article) ---- */
.video-embed{position:relative;width:100%;aspect-ratio:16/9;margin:26px 0;border-radius:var(--radius);
  overflow:hidden;box-shadow:var(--shadow-sm);background:#000}
.video-embed iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
.video-h{font-size:23px;margin:36px 0 14px}

/* ---- Video facade (poster + play) · lightbox video · gallery video thumb ---- */
.video-facade{display:block;position:absolute;inset:0;width:100%;height:100%;padding:0;border:0;cursor:pointer;background:#000}
.video-facade img{width:100%;height:100%;object-fit:cover;display:block}
.video-facade__play,.play-badge{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:72px;height:50px;border-radius:14px;background:rgba(var(--accent-rgb),.92);display:grid;place-items:center;
  box-shadow:0 10px 26px rgba(0,0,0,.4);transition:transform .2s,background .2s;pointer-events:none}
.video-facade:hover .video-facade__play{transform:translate(-50%,-50%) scale(1.08);background:var(--gold-hover)}
.video-facade__play svg,.play-badge svg{width:26px;height:26px;color:#fff;margin-left:3px}
.lightbox__frame{width:min(1000px,92vw);aspect-ratio:16/9;max-height:86vh;border:0;border-radius:10px;
  box-shadow:0 24px 70px rgba(0,0,0,.5);background:#000}
.gallery__vid{position:relative;flex:0 0 auto;height:88px;width:132px;border:1px solid var(--line);
  border-radius:10px;overflow:hidden;padding:0;cursor:zoom-in;background:#000;
  transition:transform .2s,box-shadow .2s,border-color .2s}
.gallery__vid img{width:100%;height:100%;object-fit:cover;display:block}
.gallery__vid .play-badge{width:44px;height:31px;border-radius:9px}
.gallery__vid .play-badge svg{width:17px;height:17px}
.gallery__vid:hover{transform:translateY(-2px);box-shadow:var(--shadow-sm);border-color:var(--gold-200)}

/* project video: 16:9 embed matching the article figure treatment */
.article__video{position:relative;aspect-ratio:16/9;margin:26px 0;border-radius:14px;overflow:hidden;background:#000}
.article__video iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}

/* Project headings carry a descriptor after the name. It reads as a subtitle
   rather than part of the title, so it drops to lead size on its own line and
   the em dash that used to separate them is no longer needed. */
.article h1 .article__sub{display:block;margin-top:10px;font-size:clamp(16px,1.6vw,20px);
  font-weight:500;line-height:1.4;color:var(--muted)}

/* =========================================================================
   BRAND RING DECORATION
   Purple in light, blue in dark -- deliberately the inverse of the text accent,
   so the decoration reads as a counterpoint instead of competing with links.

   Drawn with a border rather than brand-ring-*.svg: those two files carry a
   hard-coded stroke (#0249f7 / #85519a) and cannot follow a theme. A border
   circle needs no asset and takes the token directly. The footer's existing
   <img> rings stay in the markup -- 164 pages carry them -- and are swapped by
   file per theme instead.

   Every decorated section gets overflow:hidden so a ring hanging off the edge
   cannot widen the page, and its .container is raised above the ring: a
   positioned element with z-index:0 otherwise paints over in-flow content.
   ========================================================================= */
/* The footer rings take their colour from --deco, the same token the section
   decorations use: Felamushi on light, blue on dark. Masking one neutral ring
   rather than swapping between a purple and a blue file means one source of
   truth, and no fallback that can show the wrong colour -- content:url() on an
   <img> silently leaves the element's own src in place wherever it does not
   apply, and that src is the blue ring. */
.deco--ring1 img,.deco--ring2 img{
  -webkit-mask:url('../img/brand-ring.svg') center/contain no-repeat;
          mask:url('../img/brand-ring.svg') center/contain no-repeat;
  background:var(--deco)}
/* The footer is navy in both themes, so its rings have to be judged against
   navy rather than against the page. The mid-tone Felamushi that reads
   correctly on a light section desaturates over navy at 40% until it looks
   blue, so on light the footer takes the lighter tint instead. Dark keeps
   --deco: the blue is vivid enough to hold up. */
:root:not([data-theme="dark"]) .footer .deco--ring1 img,
:root:not([data-theme="dark"]) .footer .deco--ring2 img{background:#c49bd8}

#about,#services,#projects,.page-hero{position:relative;overflow:hidden}
#about > .container,#services > .container,#projects > .container,
.page-hero > .container{position:relative;z-index:1}

#about::before,#services::after,#projects::before,.page-hero::after{
  content:'';position:absolute;z-index:0;pointer-events:none;
  border-radius:50%;border-style:solid;border-color:var(--deco);opacity:.24}
/* sizes follow the SVG's proportions -- its stroke is 12% of the diameter.
   Offsets grow with the radius so each ring keeps roughly the same slice
   showing; scaling the circle without moving it just crowds the copy. */
#about::before{width:470px;height:470px;border-width:56px;left:-200px;bottom:-210px}
#services::after{width:400px;height:400px;border-width:48px;right:-165px;top:-140px}
#projects::before{width:540px;height:540px;border-width:65px;right:-235px;bottom:-250px}
.page-hero::after{width:430px;height:430px;border-width:52px;right:-190px;top:-180px}
@media (max-width:680px){
  /* smaller and further out on phones, where a full-size ring crowds the copy */
  #about::before,#services::after,#projects::before,.page-hero::after{opacity:.18}
  #about::before{width:310px;height:310px;border-width:37px;left:-145px}
  #services::after{width:275px;height:275px;border-width:33px;right:-125px}
  #projects::before{width:340px;height:340px;border-width:41px;right:-155px}
  .page-hero::after{width:290px;height:290px;border-width:35px;right:-130px}
}
/* Boiler cards carry the model name and its output only, so the figure gets a
   line of its own under the name. White, not the accent: .pcard__body is
   var(--navy) in both themes, so an accent colour lands on dark navy. */
.pcard__kw{font-size:14px;font-weight:600;color:#fff}

/* Vortice is a stacked badge, not a wide lockup, so 22px leaves its wordmark
   illegible; it gets its own height and the flag follows suit. */
.pbuy__brand--tall img{height:36px}

/* ---- Call-back panel -------------------------------------------------------
   Opened from the phone button in the floating stack. A tel: link does nothing
   on a desktop browser, so the button opens this instead and keeps the direct
   dial link inside it for anyone who would rather just call. The markup is
   assembled in main.js, so every page gets it without being edited -- same
   reason the social capsule above it is built there. */
.cbk{position:fixed;inset:0;z-index:120;display:none}
.cbk.is-open{display:block}
.cbk__scrim{position:absolute;inset:0;background:rgba(27,27,51,.45);
  opacity:0;transition:opacity .22s var(--ease)}
.cbk.is-open .cbk__scrim{opacity:1}
.cbk__panel{position:absolute;right:20px;bottom:88px;width:344px;
  max-width:calc(100vw - 40px);max-height:calc(100vh - 110px);overflow-y:auto;
  background:var(--surface);border-radius:var(--radius);box-shadow:var(--shadow-md);
  padding:22px 22px 18px;
  opacity:0;transform:translateY(10px) scale(.985);
  transition:opacity .22s var(--ease),transform .22s var(--ease)}
.cbk.is-open .cbk__panel{opacity:1;transform:none}
.cbk__close{position:absolute;top:9px;right:9px;width:30px;height:30px;border-radius:50%;
  display:grid;place-items:center;color:var(--muted);transition:background .2s,color .2s}
.cbk__close:hover{background:var(--bg-soft);color:var(--ink-strong)}
.cbk__close svg{width:15px;height:15px}
.cbk__panel h3{font-size:18px;line-height:1.3;margin:0 26px 6px 0}
.cbk__sub{font-size:13.5px;color:var(--muted);line-height:1.5;margin:0 0 16px}
.cbk .field{margin-bottom:13px}
.cbk .field label{font-size:13px}
/* min-width:0 on both: a grid item sizes to its content by default, and the
   longest date option ("12 September, Friday") would otherwise widen the column
   past the panel and put a scrollbar under it. */
.cbk__row{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.cbk__row .field{min-width:0}
.cbk__row select{min-width:0;width:100%;font-size:14px;padding-right:32px}
/* The country code is fixed: the form is for Georgian numbers, so the prefix is
   chrome rather than an editable field, and the input holds only the 9 digits. */
.cbk__tel{display:flex;align-items:stretch;overflow:hidden;
  border:1.5px solid var(--line);border-radius:8px;background:var(--surface);
  transition:border-color .2s,box-shadow .2s}
.cbk__tel:focus-within{border-color:var(--gold);box-shadow:0 0 0 3px rgba(var(--accent-rgb),.18)}
.cbk__tel.is-bad{border-color:#d9534f}
.cbk__cc{display:flex;align-items:center;gap:7px;padding:0 11px;white-space:nowrap;
  background:var(--bg-soft);border-right:1.5px solid var(--line);
  font-size:14px;color:var(--ink)}
.cbk__flag{width:21px;height:14px;border-radius:2px;flex:0 0 auto;
  box-shadow:0 0 0 1px rgba(27,27,51,.14)}
.cbk__tel input{flex:1;min-width:0;border:0;background:transparent;
  padding:12px 13px;font-family:inherit;font-size:15px;color:var(--ink);
  letter-spacing:.02em}
.cbk__tel input:focus{outline:none}
.cbk__tel input::placeholder{color:#a7abb2;letter-spacing:normal}
.cbk__submit{width:100%;justify-content:center;margin-top:3px}
/* Citynet's SMS code step, shown in place of the number and time fields */
.cbk__otp input{width:100%;font-size:20px;letter-spacing:.35em;text-align:center}
.cbk__otp input::placeholder{letter-spacing:.2em}
.cbk__now{display:block;text-align:center;margin-top:11px;font-size:13.5px;
  color:var(--gold-600);text-decoration:underline;text-underline-offset:3px}
.cbk__now:hover{color:var(--gold)}
.cbk .form-msg{margin:0 0 12px;font-size:13.5px;padding:10px 12px}
/* On a phone the popover would crowd the button it came from, so it becomes a
   sheet on the bottom edge -- where the thumb already is. */
@media (max-width:560px){
  .cbk__panel{right:0;left:0;bottom:0;width:auto;max-width:none;
    max-height:calc(100vh - 70px);
    border-radius:var(--radius) var(--radius) 0 0;
    padding:20px 18px calc(18px + env(safe-area-inset-bottom));
    transform:translateY(18px)}
  .cbk.is-open .cbk__panel{transform:none}
}

/* ---- Themed dropdown -------------------------------------------------------
   A native select's popup is browser chrome: its border, its corners and the
   scrollbar down the side of a 31-entry time list are drawn by the platform and
   no CSS reaches them. On a panel this small that stock grey list was the one
   part that did not look like the site, so the two pickers are built instead.

   The list is position:fixed and placed by JS rather than absolute: the panel it
   sits in scrolls when it runs out of height, and an absolutely positioned child
   would be clipped by that. Fixed escapes the clip -- as long as no ancestor
   carries a transform, which is why .cbk__panel resolves to transform:none once
   it is open rather than keeping a transform at its resting state. */
.pick{position:relative}
/* a span, not a <label>: the control it names is a button, not a form field */
.pick__lbl{font-size:13px;font-weight:500;color:var(--ink-strong)}
.pick__btn{
  display:flex;align-items:center;gap:8px;width:100%;appearance:none;
  font-family:inherit;font-size:14px;color:var(--ink);text-align:left;
  padding:12px 12px 12px 14px;border:1.5px solid var(--line);border-radius:8px;
  background:var(--surface);cursor:pointer;
  transition:border-color .2s,box-shadow .2s}
.pick__btn:hover{border-color:var(--gray-300)}
.pick__btn:focus-visible,.pick.is-open .pick__btn{
  outline:none;border-color:var(--gold);box-shadow:0 0 0 3px rgba(var(--accent-rgb),.18)}
.pick__val{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pick__arrow{width:16px;height:16px;flex:0 0 auto;color:#a7abb2;
  transition:transform .2s var(--ease),color .2s}
.pick.is-open .pick__arrow{transform:rotate(180deg);color:var(--gold)}
.pick__list{
  position:fixed;z-index:130;padding:5px;
  background:var(--surface);border:1.5px solid var(--line);border-radius:10px;
  box-shadow:var(--shadow-md);
  max-height:236px;overflow-y:auto;overscroll-behavior:contain;
  /* The same thin brand bar as the gallery strip -- standard properties only,
     since ::-webkit-scrollbar is inert once scrollbar-width is in play. */
  scrollbar-width:thin;scrollbar-color:var(--gold-600) transparent;
  opacity:0;transform:translateY(-4px);
  transition:opacity .16s var(--ease),transform .16s var(--ease)}
.pick__list.is-in{opacity:1;transform:none}
.pick__opt{
  padding:9px 11px;border-radius:6px;font-size:14px;color:var(--ink);
  cursor:pointer;white-space:nowrap;transition:background .12s,color .12s}
.pick__opt.is-active{background:var(--bg-soft)}
.pick__opt[aria-selected="true"]{
  background:rgba(var(--accent-rgb),.1);color:var(--gold-600);font-weight:600}
@media (hover:hover){ .pick__opt:hover{background:var(--bg-soft)} }
@media (max-width:560px){
  /* thumb-sized rows, and a list that cannot swallow the sheet it opens over */
  .pick__opt{padding:12px}
  .pick__list{max-height:44vh}
}
