@charset "utf-8";

/* =========================================================================
   Pet Corner By T
   Porcelain cream paper, fields of salon tile blue, hairlines instead of cards.
   Display: Bodoni Moda (self hosted, variable opsz + wght)
   Voice:   Hanken Grotesk (self hosted, variable wght)
   ========================================================================= */

/* ----- fonts ------------------------------------------------------------- */
@font-face {
  font-family: "Bodoni Moda";
  src: url("../fonts/bodoni-moda-latin.woff2") format("woff2");
  font-weight: 400 700; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Bodoni Moda";
  src: url("../fonts/bodoni-moda-latin-ext.woff2") format("woff2");
  font-weight: 400 700; font-style: normal; font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Bodoni Moda";
  src: url("../fonts/bodoni-moda-italic-latin.woff2") format("woff2");
  font-weight: 400 700; font-style: italic; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Bodoni Moda";
  src: url("../fonts/bodoni-moda-italic-latin-ext.woff2") format("woff2");
  font-weight: 400 700; font-style: italic; font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Hanken Grotesk";
  src: url("../fonts/hanken-grotesk-latin.woff2") format("woff2");
  font-weight: 300 600; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Hanken Grotesk";
  src: url("../fonts/hanken-grotesk-latin-ext.woff2") format("woff2");
  font-weight: 300 600; font-style: normal; font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ----- tokens ------------------------------------------------------------ */
:root {
  --paper:      #F6F2EA;   /* cream ground        */
  --paper-2:    #EFE8DC;   /* deeper cream        */
  --tile:       #D3E0E6;   /* salon tile blue     */
  --tile-2:     #C2D4DC;   /* tile, one step down */
  --ink:        #211F1C;   /* warm near black     */
  --ink-2:      #5A544C;   /* secondary voice     */
  --blue:       #2F5666;   /* action, deep salon blue */
  --blue-dark:  #23414D;
  --rule:       rgba(47, 86, 102, .22);
  --rule-soft:  rgba(47, 86, 102, .13);

  --display: "Bodoni Moda", "Times New Roman", serif;
  --voice: "Hanken Grotesk", system-ui, -apple-system, "Segoe UI", sans-serif;

  --gutter: clamp(1.25rem, 4vw, 3.5rem);
  --page: 1360px;
  --head-h: 4.5rem;
  --section-y: clamp(4.5rem, 11vh, 9rem);
  --ease: cubic-bezier(.16, 1, .3, 1);            /* short feedback, snaps out    */
  --ease-smooth: cubic-bezier(.4, .05, .2, 1);    /* entrances, eases in and out  */

  color-scheme: light;
  accent-color: var(--blue);
  caret-color: var(--blue);
  scrollbar-color: var(--tile-2) var(--paper);
}

/* ----- reset ------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html {
  -webkit-text-size-adjust: 100%;
  overflow-x: clip;
  scroll-padding-top: calc(var(--head-h) + 1rem);
  /* no grey-blue flash box over a tapped link on Android; the :active states
     below carry the feedback instead */
  -webkit-tap-highlight-color: transparent;
}
body {
  overflow-x: clip;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--voice);
  font-size: clamp(1rem, .95rem + .18vw, 1.0625rem);
  font-weight: 350;
  line-height: 1.65;
  letter-spacing: .002em;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
img, svg, iframe { display: block; max-width: 100%; }
img { height: auto; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
a { color: inherit; }
ul { list-style: none; padding: 0; }
::selection { background: var(--tile-2); color: var(--ink); }
:focus-visible { outline: 2px solid var(--blue); outline-offset: 4px; }

.skip {
  position: fixed; top: .75rem; left: .75rem; z-index: 90;
  padding: .7rem 1.1rem; background: var(--blue); color: var(--paper);
  font-size: .85rem; letter-spacing: .06em; text-transform: uppercase;
  transform: translateY(-160%); transition: transform .25s var(--ease);
}
.skip:focus-visible { transform: none; }
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

/* ----- type ------------------------------------------------------------- */
h1, h2, h3 {
  font-family: var(--display);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -.012em;
  text-wrap: balance;
  font-variation-settings: "opsz" 72;
}
h2 { font-size: clamp(2rem, 1.3rem + 2.4vw, 3.15rem); }
h3 { font-size: clamp(1.4rem, 1.1rem + .9vw, 1.9rem); font-variation-settings: "opsz" 36; }
p { text-wrap: pretty; }

.ico { width: 1.1em; height: 1.1em; fill: currentColor; flex: none; }
.ico--lg { width: 1.9rem; height: 1.9rem; color: var(--blue); }
/* the furminator is drawn rather than borrowed, so it is stroked to the same
   optical weight as the Phosphor light glyphs beside it */
.ico--stroke {
  fill: none; stroke: currentColor; stroke-width: 11;
  stroke-linecap: round; stroke-linejoin: round;
}

/* ----- links and buttons ------------------------------------------------ */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 3.15rem; padding: 0 1.6rem;
  font-size: .84rem; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase; text-decoration: none;
  white-space: nowrap;
  transition: background-color .3s var(--ease), color .3s var(--ease), translate .3s var(--ease);
}
.btn--primary { background: var(--blue); color: var(--paper); }
.btn--primary:hover { background: var(--blue-dark); }
.btn--primary:active { translate: 0 1px; }

/* the rule under a link is a 1px pseudo element scaled on the x axis: a
   compositor friendly wipe, and it keeps the underline out of the text box */
.link-arrow {
  position: relative;
  display: inline-flex; align-items: center; gap: .45em;
  font-size: .95rem; text-decoration: none;
  color: var(--blue);
  padding-bottom: .15em;
}
.link-arrow::after {
  content: ""; position: absolute; inset: auto 0 0 0; height: 1px;
  background: currentColor; scale: 0 1; transform-origin: left center;
  transition: scale .55s var(--ease-smooth);
}
.link-arrow:hover::after, .link-arrow:focus-visible::after { scale: 1 1; }
.link-arrow .ico { width: .95em; height: .95em; }

/* touch feedback, since a finger never hovers */
.link-arrow:active, .site-nav ul a:active, .site-foot__nav a:active { color: var(--blue-dark); }
.channels a:active { background: var(--blue); border-color: var(--blue); color: var(--paper); }
.tile:active img { scale: 1.02; }

/* ----- head and navigation ---------------------------------------------- */
.site-head {
  position: sticky; top: 0; z-index: 50;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  min-height: var(--head-h);
  padding-inline: var(--gutter);
  border-bottom: 1px solid transparent;
  transition: border-color .4s var(--ease);
}
/* the frosted ground lives on a pseudo element: backdrop-filter on the header
   itself would make it the containing block for the fixed mobile menu panel */
.site-head::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: rgba(246, 242, 234, .88);
}
@supports (backdrop-filter: blur(1px)) {
  .site-head::before {
    background: rgba(246, 242, 234, .72);
    backdrop-filter: blur(14px) saturate(115%);
  }
}
html[data-scrolled] .site-head { border-bottom-color: var(--rule-soft); }

/* the salon's own lettering. it is a single fine line, so the stroke is set per
   size to keep the effective weight near 1.8px and the loops open */
.wordmark { display: block; text-decoration: none; }
.logo-line, .wordmark__mark, .site-foot__logo {
  fill: none; stroke: currentColor;
  stroke-miterlimit: 10; stroke-linecap: round;
}
.wordmark__mark { width: 116px; height: 58px; stroke-width: 8; }

.site-nav { display: flex; align-items: center; gap: clamp(1.5rem, 3vw, 3rem); }
.site-nav ul { display: flex; gap: clamp(1.25rem, 2.4vw, 2.4rem); }
.site-nav ul a {
  position: relative;
  display: inline-block;
  font-size: .8rem; letter-spacing: .13em; text-transform: uppercase; text-decoration: none;
  padding-bottom: .2em;
}
.site-nav ul a::after {
  content: ""; position: absolute; inset: auto 0 0 0; height: 1px;
  background: currentColor; scale: 0 1; transform-origin: left center;
  transition: scale .55s var(--ease-smooth);
}
.site-nav ul a:hover::after { scale: 1 1; }

.menu-btn { display: none; align-items: center; gap: .6rem; padding: .6rem 0; }
.menu-btn__label { font-size: .78rem; letter-spacing: .14em; text-transform: uppercase; }

/* three drawn lines rather than two swapped glyphs, so they can fold into the
   cross instead of cutting to it */
.menu-btn__bars { width: 1.7rem; height: 1.7rem; overflow: visible; }
.menu-btn__bars .bar {
  fill: none; stroke: currentColor; stroke-width: 11; stroke-linecap: round;
  transform-box: view-box; transform-origin: 128px 128px;
}
html[data-menu="open"] .bar--1 { transform: rotate(45deg) translate(0, 50px); }
html[data-menu="open"] .bar--2 { opacity: 0; scale: .2 1; }
html[data-menu="open"] .bar--3 { transform: rotate(-45deg) translate(0, -50px); }

/* ----- hero ------------------------------------------------------------- */
.hero {
  /* the tile field runs on below the portrait and meets the statement band, so
     the arch stands in one field instead of balancing on the edge of a stripe
     with a cream seam under it */
  --hero-foot: clamp(2rem, 5vh, 3.5rem);
  display: grid;
  grid-template-columns: minmax(0, 1.09fr) minmax(0, .91fr);
  align-items: end;
  gap: clamp(2rem, 5vw, 5rem);
  max-width: var(--page); margin-inline: auto;
  padding: clamp(2.5rem, 6vh, 5rem) var(--gutter) var(--hero-foot);
  min-height: calc(100dvh - var(--head-h));
}
.hero__type { padding-bottom: clamp(3rem, 9vh, 7rem); }
.hero__title {
  font-size: clamp(2.55rem, 1.1rem + 3.6vw, 4.35rem);
  font-variation-settings: "opsz" 96;
  line-height: 1.05;
  letter-spacing: -.018em;
}
.hero__title span { display: block; }
.hero__title span:nth-child(2) { --i: 1; }
.hero__title span:nth-child(3) { --i: 2; }
.hero__lede {
  max-width: 34ch; margin-top: clamp(1.5rem, 3vh, 2.25rem);
  color: var(--ink-2); font-size: 1.075rem; line-height: 1.6;
}
.hero__actions {
  display: flex; align-items: center; gap: clamp(1.25rem, 3vw, 2.5rem);
  flex-wrap: wrap; margin-top: clamp(2rem, 4.5vh, 3rem);
}

.hero__figure { position: relative; align-self: end; }
.hero__figure::before {
  content: ""; position: absolute; z-index: 0;
  /* the extra pixel closes the sub-pixel seam where this field meets the
     statement band: both are var(--tile), so the overlap is invisible */
  inset: 50% -50vw calc(-1 * var(--hero-foot) - 1px) clamp(-3rem, -4vw, -1.5rem);
  background: var(--tile);
  transform-origin: bottom center;   /* the field grows upward on load */
}
.arch {
  position: relative; z-index: 1;
  aspect-ratio: .82;
  border-radius: 999px 999px 0 0;
  /* clip, not hidden: hidden would make this box the scroll container that the
     drift timeline attaches to, and a box that never scrolls freezes the drift */
  overflow: hidden;
  overflow: clip;
  isolation: isolate;
}
/* every photographic box owns its frame; the image is absolute inside it so a
   drifting image can never stretch the layout it sits in */
.arch img, .frame img, .band img, .tile img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
.arch img { object-position: 50% 45%; }
/* the two dogs sit low in this frame, so the crop is taken off the top */
.band img { object-position: 50% 72%; }

/* ----- statement -------------------------------------------------------- */
.statement {
  background: var(--tile);
  /* no gap: this band is the same field the hero portrait stands in */
  padding: clamp(4rem, 10vh, 7rem) var(--gutter) clamp(8rem, 18vh, 12rem);
  text-align: center;
}
.statement__text {
  max-width: 33ch; margin-inline: auto;
  font-family: var(--display);
  font-size: clamp(1.45rem, .9rem + 1.9vw, 2.5rem);
  font-variation-settings: "opsz" 48;
  line-height: 1.28; letter-spacing: -.008em;
  text-wrap: balance;
}
.statement__text em { font-style: italic; }

/* ----- salon ------------------------------------------------------------ */
.frame { position: relative; overflow: hidden; overflow: clip; background: var(--paper-2); }

.salon {
  display: grid; grid-template-columns: repeat(12, 1fr);
  gap: var(--gutter) var(--gutter);
  max-width: var(--page); margin-inline: auto;
  padding: 0 var(--gutter) var(--section-y);
}
.salon__figure {
  position: relative; z-index: 2;
  grid-column: 1 / span 5;
  margin-top: clamp(-9rem, -12vh, -5rem);
}
.salon__figure .frame { aspect-ratio: .8; }
.salon__prose {
  grid-column: 7 / span 5; align-self: center;
  padding-top: clamp(1.5rem, 4vh, 3rem);
}
.salon__prose p { margin-top: 1.25rem; color: var(--ink-2); max-width: 42ch; }
/* two authored lines, like the hero: balance would otherwise split the number
   away from "više od" */
.salon__prose h2 { max-width: 22ch; }
.salon__prose h2 span { display: block; }
.salon__quote {
  font-family: var(--display); font-style: italic;
  font-size: clamp(1.15rem, 1rem + .5vw, 1.45rem);
  line-height: 1.35; color: var(--ink) !important;
  margin-top: clamp(1.75rem, 4vh, 2.5rem);
  padding-top: clamp(1.5rem, 3vh, 2rem);
  border-top: 1px solid var(--rule-soft);
  max-width: 26ch;
}

/* ----- usluge: an index, not a card grid -------------------------------- */
.usluge {
  max-width: var(--page); margin-inline: auto;
  padding: var(--section-y) var(--gutter);
  background: linear-gradient(var(--paper), var(--paper));
}
.usluge__head { margin-bottom: clamp(2rem, 5vh, 3.5rem); }

/* mobile first: a single stacked column. the twelve column index, the sticky name
   rail and the alternating rhythm are added back at 900px and up, so no desktop
   placement rule can outrank the stack on a phone */
.service {
  position: relative;
  display: grid; gap: 1.5rem;
  padding: clamp(2.5rem, 6vh, 4.25rem) 0;
  align-items: start;
}
/* the separator is a pseudo element rather than a border so it can draw itself
   across as the row arrives */
.service::before {
  content: ""; position: absolute; inset: 0 0 auto 0;
  height: 1px; background: var(--rule-soft);
  transform-origin: left center;
}
.service__name .ico--lg { margin-bottom: 1rem; }
.service__figure { max-width: 26rem; }
.service__body p { color: var(--ink-2); max-width: 40ch; }
.service__body p + p { margin-top: 1rem; }
.service__list {
  display: grid; gap: .55rem; margin-top: 1.75rem;
  font-size: .95rem; color: var(--ink-2);
}
.service__list li { display: flex; align-items: baseline; gap: .7rem; }
.service__list li::before {
  content: ""; flex: none; width: .85rem; height: 1px;
  background: var(--tile-2); translate: 0 -.35em;
}
.service__figure .frame { aspect-ratio: .8; }

/* ----- quiet passage ---------------------------------------------------- */
/* The source of this one is a soft upscale, so it stops at 1100px instead of
   bleeding across a wide screen, where the lack of real detail shows. width:100%
   is load bearing: with only aspect-ratio and max-height, a short wide window
   clamps the height and the ratio then derives the width from it. */
.band {
  position: relative; overflow: clip;
  /* the same width the sections around it give their content: the page container
     minus its gutters, so this image's edges line up with the gallery grid rather
     than floating at some width of their own. Not full bleed: the source is a soft
     upscale and a wide screen shows the missing detail. */
  width: min(100% - 2 * var(--gutter), var(--page) - 2 * var(--gutter));
  margin-inline: auto;
  aspect-ratio: 2.3; max-height: 68vh;
}

/* ----- galerija --------------------------------------------------------- */
.galerija {
  max-width: var(--page); margin-inline: auto;
  padding: var(--section-y) var(--gutter);
}
.galerija__head { display: grid; gap: .75rem; margin-bottom: clamp(2rem, 5vh, 3.25rem); }
.galerija__head p { color: var(--ink-2); max-width: 40ch; }

.grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(.5rem, 1.6vw, 1.1rem);
}
.tile {
  position: relative; display: block; width: 100%;
  overflow: hidden; overflow: clip;
  background: var(--paper-2); aspect-ratio: .8;
}
.tile img { transition: scale .9s var(--ease-smooth); }
.tile:hover img, .tile:focus-visible img { scale: 1.035; }
/* The breed label a photograph carries. It is a text node rather than an
   attribute so the lightbox can read it straight out of the markup. In the grid
   it stays out of the composition; fullscreen is where it is meant to be read.
   Only the photographs whose subject is a recognisable breed have one. */
.tile__cap {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
/* the line under the grid: the way on to the whole archive on the left, the
   standing Instagram note on the right, separated by the same hairline the
   archive page uses under its title */
.galerija__more {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: .75rem 1.5rem;
  margin-top: clamp(1.75rem, 4vh, 2.75rem);
  padding-top: clamp(1.25rem, 2.5vh, 1.75rem);
  border-top: 1px solid var(--rule-soft);
  color: var(--ink-2);
}
.link-arrow--lead { font-size: 1.075rem; }

/* ----- galerija.html: the whole archive --------------------------------- */
/* The archive page reuses .grid, .tile and the lightbox untouched. New here:
   its title block, the section that carries the grid, and the closing field. */
.page-head {
  display: grid; gap: 1.1rem;
  max-width: var(--page); margin-inline: auto;
  padding: clamp(2.5rem, 7vh, 5rem) var(--gutter) clamp(1.75rem, 4vh, 2.75rem);
}
.page-head h1 {
  font-size: clamp(2.55rem, 1.1rem + 3.6vw, 4.35rem);
  font-variation-settings: "opsz" 96;
  line-height: 1.05; letter-spacing: -.018em;
}
.page-head__lede { max-width: 46ch; color: var(--ink-2); font-size: 1.075rem; line-height: 1.6; }
.page-head__meta {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: .75rem 1.5rem;
  margin-top: clamp(.75rem, 2vh, 1.5rem); padding-top: clamp(1.25rem, 2.5vh, 1.75rem);
  border-top: 1px solid var(--rule-soft);
  font-size: .78rem; letter-spacing: .13em; text-transform: uppercase; color: var(--ink-2);
}
/* the link in that row is part of the row, so it keeps its small caps */
.page-head__meta .link-arrow { font-size: inherit; letter-spacing: inherit; }

.arhiva {
  max-width: var(--page); margin-inline: auto;
  padding: 0 var(--gutter) var(--section-y);
}
/* fifty pictures, not twelve: the archive takes a third column as soon as the
   window can hold one, where the home page grid stays at two until 900px */
@media (min-width: 640px) and (max-width: 899px) {
  .arhiva .grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ----- furminiranje-pasa.html: the advice page --------------------------- */
/* One column of prose at a reading measure under one photograph. It reuses
   .page-head, .frame and the reveals; there is no new machinery here. The
   measure is wider than .salon__prose because this page is read, not scanned. */
.clanak {
  display: grid; gap: clamp(2rem, 5vh, 3.5rem);
  max-width: var(--page); margin-inline: auto;
  padding: 0 var(--gutter) var(--section-y);
}
/* The opening photograph is a portrait, not a band across the page: it keeps the
   4:5 of the gallery tiles and sits against the left edge, on the same line the
   article's text starts from, with the prose beginning underneath it. */
.clanak__figure { justify-self: start; width: min(100%, 26rem); }
.clanak__figure .frame { aspect-ratio: 0.8; }
.clanak__body { max-width: 64ch; }
.clanak__body h2 {
  font-size: clamp(1.45rem, .95rem + 1.4vw, 2.05rem);
  margin-top: clamp(2.25rem, 5vh, 3.25rem);
}
.clanak__body > h2:first-child { margin-top: 0; }
.clanak__body p { margin-top: 1.1rem; color: var(--ink-2); line-height: 1.72; }
/* Emphasis, one device only: Hanken Grotesk runs 300 to 600, so 600 against the
   350 of running text is a real jump, and the darker ink does the rest. Not an
   underline and not a second face — underline means "link" everywhere else on
   this site, and a third font would break a two-face system for no gain. The
   phrase carrying the weight is always the answer, never the topic. */
.clanak__body strong,
.faq__a strong { font-weight: 600; color: var(--ink); }

/* the services-list idiom, reused where the article actually enumerates */
.clanak__list {
  display: grid; gap: .65rem;
  margin-top: 1.1rem; color: var(--ink-2);
}
/* not flex, unlike .service__list: these items carry inline markup, and a flex
   gap would open a hole between the bold label and the text after it */
.clanak__list li { position: relative; padding-left: 1.55rem; }
.clanak__list li::before {
  content: ""; position: absolute; left: 0; top: .78em;
  width: .85rem; height: 1px; background: var(--tile-2);
}
.clanak__cta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.75rem;
  margin-top: clamp(2.25rem, 5vh, 3.25rem);
  padding-top: clamp(1.5rem, 3vh, 2rem);
  border-top: 1px solid var(--rule-soft);
}

/* the page closes on the second of the two blue fields, the way index.html does */
.poziv { background: var(--tile); padding: var(--section-y) var(--gutter); }
.poziv__inner {
  display: grid; justify-items: center; gap: 1.15rem;
  max-width: 36ch; margin-inline: auto; text-align: center;
}
.poziv p { color: var(--ink-2); }
.poziv .btn { margin-top: .75rem; }

/* ----- faq: the usluge index again, in miniature ------------------------- */
/* Hairline rows, no boxes, no icon per question. Mobile first like .service:
   a stacked column here, the sticky rail added back at 900px. */
.faq {
  max-width: var(--page); margin-inline: auto;
  padding: var(--section-y) var(--gutter);
}
.faq__head { display: grid; gap: .75rem; margin-bottom: clamp(1.75rem, 4vh, 2.5rem); }
.faq__head p { color: var(--ink-2); max-width: 34ch; }

.faq__item { border-top: 1px solid var(--rule-soft); }
.faq__item:last-child { border-bottom: 1px solid var(--rule-soft); }

.faq__item summary {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: clamp(1rem, 3vw, 2.5rem);
  padding: clamp(1.1rem, 2.4vh, 1.5rem) 0;
  cursor: pointer;
  /* both are needed: the modern one and the WebKit pseudo element */
  list-style: none;
}
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary:hover .faq__q { color: var(--blue); }
.faq__item summary:focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; }

.faq__q {
  font-size: clamp(1.1rem, .98rem + .5vw, 1.45rem);
  line-height: 1.25;
  text-wrap: pretty;   /* balance sets these short questions in a ragged stack */
  transition: color .3s var(--ease);
}

/* The marker is a paw, not a plus. Opening turns it almost the whole way round
   and lets it settle tilted, the way a dog circles before it lies down: the spin
   is the fun, the tilt is what makes an open row still look open once it stops.
   Three things separate the two states, so none of them carries it alone: the
   angle, the weight of the colour, and the answer standing open underneath. */
.faq__paw {
  align-self: center;
  width: 1.15rem; height: 1.15rem;
  /* the blue token at half strength rather than the hairline colour: at .22 the
     paw read as a disabled control instead of one asking to be pressed */
  color: var(--blue); opacity: .5;
  transition: rotate .55s var(--ease), opacity .35s var(--ease), scale .55s var(--ease);
}
.faq__item[open] .faq__paw { rotate: 320deg; scale: .94; opacity: 1; }
/* a closed row answers the pointer with a little step of its own */
.faq__item:not([open]) summary:hover .faq__paw { rotate: -12deg; opacity: 1; }

.faq__a {
  padding-bottom: clamp(1.25rem, 2.8vh, 1.85rem);
  color: var(--ink-2); max-width: 58ch;
}
.faq__a p + p { margin-top: 1rem; }

/* ----- kontakt ---------------------------------------------------------- */
.kontakt {
  background: var(--tile);
  padding: var(--section-y) var(--gutter);
}
/* width:100% keeps these grid items stretched; margin auto alone would shrink
   them to fit-content and centre them, which pulls the aside out of alignment */
.kontakt > * { width: 100%; max-width: var(--page); margin-inline: auto; }
.kontakt {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: clamp(3rem, 7vh, 5rem);
}
.kontakt__lede { color: var(--ink-2); max-width: 38ch; margin-top: 1rem; }
/* the number is the messaging handle, not a call action, so it is set as type
   and selectable in one tap rather than linked to the dialer */
.kontakt__phone {
  display: inline-block; margin-top: clamp(1.75rem, 4vh, 2.5rem);
  font-family: var(--display); font-variation-settings: "opsz" 96;
  font-size: clamp(2.25rem, 1rem + 5vw, 4.15rem);
  line-height: 1; letter-spacing: -.02em;
  color: var(--blue);
  user-select: all; -webkit-user-select: all;
}

.channels {
  display: flex; flex-wrap: wrap; gap: .6rem;
  margin-top: clamp(2rem, 5vh, 3rem);
}
.channels a {
  display: inline-flex; align-items: center; gap: .55rem;
  min-height: 3rem; padding: 0 1.15rem;
  border: 1px solid var(--rule);
  font-size: .8rem; letter-spacing: .12em; text-transform: uppercase; text-decoration: none;
  transition: background-color .3s var(--ease), color .3s var(--ease), border-color .3s var(--ease);
}
.channels a:hover { background: var(--blue); border-color: var(--blue); color: var(--paper); }

.kontakt__aside h3 { display: flex; align-items: center; gap: .6rem; font-size: 1.25rem; }
.kontakt__aside h3 .ico { color: var(--blue); }
.kontakt__adresa { margin-top: .85rem; color: var(--ink-2); }
.kontakt__aside p + p { margin-top: 1rem; }
/* the second heading in this column has no section padding above it the way
   "Gde smo" does, so it has to make its own room or it sits on the address */
.kontakt__aside p + h3,
.kontakt__aside dl + h3 { margin-top: clamp(1.75rem, 3.5vh, 2.5rem); }
/* a schedule reads as two columns, not as a sentence: day on the left, hours
   on the right, both starting where the address starts. display:contents lets
   each row's dt and dd fall straight into the grid so the times line up. */
.hours {
  margin-top: .9rem;
  display: grid; grid-template-columns: auto auto;
  justify-content: start; gap: .5rem 2rem;
  color: var(--ink-2);
}
.hours > div { display: contents; }
.hours dd { font-variant-numeric: tabular-nums; white-space: nowrap; }
.kontakt__napomena { margin-top: 1.1rem; color: var(--ink-2); font-size: .92rem; }
.map {
  aspect-ratio: 1; margin: 1.5rem 0;
  border: 1px solid var(--rule); background: var(--paper);
}
.map iframe { width: 100%; height: 100%; border: 0; filter: saturate(.85) contrast(1.02); }

/* ----- footer ----------------------------------------------------------- */
.site-foot {
  display: grid; gap: 1.25rem; justify-items: start;
  max-width: var(--page); margin-inline: auto;
  padding: clamp(3rem, 8vh, 5rem) var(--gutter) clamp(2.5rem, 6vh, 4rem);
}
.site-foot__logo {
  width: min(272px, 62vw); height: auto; aspect-ratio: 1028.7 / 517.44;
  stroke-width: 4;
}
.site-foot__line {
  font-family: var(--display); font-style: italic;
  font-size: clamp(1.1rem, 1rem + .5vw, 1.4rem); color: var(--ink-2);
}
.site-foot__nav { display: flex; flex-wrap: wrap; gap: 1.1rem 1.75rem; padding-top: 1.25rem; border-top: 1px solid var(--rule-soft); width: 100%; }
.site-foot__nav a {
  font-size: .78rem; letter-spacing: .13em; text-transform: uppercase; text-decoration: none;
  color: var(--ink-2);
  transition: color .3s var(--ease);
}
.site-foot__nav a:hover { color: var(--ink); }
.site-foot__fine { font-size: .82rem; color: var(--ink-2); letter-spacing: .02em; }

/* ----- lightbox --------------------------------------------------------- */
.lb {
  width: 100%; max-width: 100%; height: 100%; max-height: 100%;
  border: 0; padding: clamp(1rem, 4vh, 3rem); margin: 0;
  background: transparent; color: var(--ink);
  display: none;
  place-items: center;
}
.lb[open] { display: grid; }
.lb::backdrop { background: rgba(246, 242, 234, .94); }
@supports (backdrop-filter: blur(1px)) {
  .lb::backdrop { background: rgba(246, 242, 234, .84); backdrop-filter: blur(18px) saturate(120%); }
}
.lb__figure { max-height: 100%; display: grid; place-items: center; }
.lb__figure img { max-height: min(82dvh, 100%); width: auto; max-width: 100%; object-fit: contain; }
.lb__close { position: absolute; top: clamp(.75rem, 2vh, 1.5rem); right: clamp(.75rem, 2vw, 1.75rem); padding: .6rem; }
.lb__close .ico { width: 1.6rem; height: 1.6rem; }
.lb__nav { position: absolute; top: 50%; translate: 0 -50%; padding: .75rem; color: var(--ink-2); transition: color .25s var(--ease); }
.lb__nav:hover { color: var(--ink); }
.lb__nav .ico { width: 1.9rem; height: 1.9rem; }
.lb__nav--prev { left: clamp(.25rem, 1.5vw, 1.5rem); }
.lb__nav--next { right: clamp(.25rem, 1.5vw, 1.5rem); }
.lb__cap {
  position: absolute; bottom: clamp(2.6rem, 5.5vh, 4.25rem); left: 50%; translate: -50% 0;
  max-width: min(48ch, 86vw); text-align: center;
  font-size: .95rem; line-height: 1.5; color: var(--ink-2);
}
/* the English name rides on the same line a shade lighter, so the Serbian still
   reads as the label and this as its translation rather than a second one */
.lb__cap span { color: color-mix(in oklab, var(--ink-2) 58%, var(--paper)); }
/* every photograph now carries a breed; the rule stays so a future one without
   a readable breed can simply omit .tile__cap and leave no empty box */
.lb__cap:empty { display: none; }
.lb__count {
  position: absolute; bottom: clamp(.75rem, 2.5vh, 2rem); left: 50%; translate: -50% 0;
  font-size: .78rem; letter-spacing: .16em; color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
/* From 900px up the caption and the counter are ROWS under the picture rather
   than labels floating over it. Pinning them to the floor meant a short wide
   window grew the photograph down behind the text — and any caption that wrapped
   to a second line made it worse. As tracks they take exactly the height they
   need, the picture gets what is left, and no caption length can overlap it.
   Under 900px the controls stay pinned, because there they form one bar at the
   bottom of the screen that must hold still as pictures of different heights
   come and go, and the dialog already keeps a gutter the size of that bar. */
@media (min-width: 900px) {
  .lb[open] { grid-template-rows: minmax(0, 1fr) auto auto; }
  /* The figure has to FILL its row, not hug the picture: centred it sizes to its
     own content, which leaves the image's max-height: 100% with nothing definite
     to measure, so the 82dvh cap wins and a tall picture spills into the
     caption's row anyway. Stretching is not enough on its own — a percentage
     height against a stretched GRID item still does not resolve in Chrome, while
     against a flex container it does, so the figure switches to flex here. */
  .lb__figure {
    align-self: stretch; min-height: 0;
    display: flex; align-items: center; justify-content: center;
  }
  .lb__cap, .lb__count { position: static; translate: none; }
  /* 48ch is a reading measure and this is a label: at that width the longest
     pair broke inside the English half ("...· French Bulldog / and Pomeranian").
     Wider, every caption sits on one line, which also hands the height back to
     the photograph. */
  .lb__cap { margin-top: clamp(1rem, 2.4vh, 1.6rem); max-width: min(62ch, 86vw); }
  .lb__count { margin-top: .9rem; }
}

/* Under 900px the picture fills the width, so side arrows would sit on top of it.
   The controls move into a row beneath the image: prev, counter, next. Grid
   placement does this without touching the markup order. */
@media (max-width: 899px) {
  /* The controls are pinned to the bottom of the screen rather than to the
     picture, so they hold still while images of different heights come and go.
     The dialog keeps a bottom gutter the size of that bar so a tall picture
     never reaches it. */
  .lb[open] { padding-bottom: 6.5rem; }
  .lb__figure img { max-height: min(68dvh, 100%); }
  .lb__nav { top: auto; bottom: 3.4rem; translate: none; padding: .5rem 1rem; }
  .lb__nav--prev { left: auto; right: 50%; margin-right: 2.5rem; }
  .lb__nav--next { right: auto; left: 50%; margin-left: 2.5rem; }
  .lb__count { bottom: 4.35rem; }
  /* clears the whole control bar: the arrows are the tallest thing in it, and
     they finish 6.3rem up from the dialog floor */
  .lb__cap { bottom: 7.25rem; font-size: .88rem; max-width: 82vw; }
}

/* =========================================================================
   responsive
   ========================================================================= */
@media (max-width: 899px) {
  :root { --head-h: 4rem; }

  /* mobile menu: the nav becomes a quiet full page panel */
  .menu-btn { display: inline-flex; }
  .site-nav {
    position: fixed; inset: 0; z-index: 45;
    flex-direction: column; align-items: flex-start; justify-content: center;
    gap: 2.5rem; padding: var(--gutter);
    background: var(--paper);
    /* It only fades. The panel is inset:0, so it is exactly the size of the
       screen: sliding it even 1.5rem left its bottom edge hanging above the
       viewport floor and the page showing through as a moving strip, which read
       as a rectangle arriving rather than a panel appearing. The stagger on the
       links below supplies the motion instead. */
    visibility: hidden; opacity: 0;
    /* Two durations, because a transition is owned by the state it runs TOWARDS.
       This rule is the closed state, so it times the CLOSE: slower, because the
       open spreads itself over a staggered cascade and a symmetrical close by
       the clock reads as abrupt next to it. */
    transition: opacity .75s var(--ease-smooth), visibility .75s;
  }
  html[data-menu="open"] .site-nav {
    visibility: visible; opacity: 1;
    transition: opacity .32s var(--ease-smooth), visibility .32s;
  }
  html[data-menu="open"] { overflow: hidden; }
  .menu-btn, .wordmark { position: relative; z-index: 46; }
  .wordmark__mark { width: 100px; height: 50px; stroke-width: 9; }
  /* the panel reads from the right edge, under the menu button */
  .site-nav { align-items: flex-end; text-align: right; }
  .site-nav ul { flex-direction: column; align-items: flex-end; gap: 1.35rem; }
  .site-nav ul a { font-size: 1.1rem; letter-spacing: .1em; }

  .hero {
    grid-template-columns: minmax(0, 1fr);
    min-height: 0;
    padding-top: clamp(1.5rem, 4vh, 3rem);
    gap: clamp(2rem, 6vh, 3rem);
  }
  .hero { --hero-foot: clamp(2.5rem, 7vh, 4.5rem); }
  .hero__type { padding-bottom: 0; }
  /* tuned so the first line still fits on one row at 360px */
  .hero__title { font-size: clamp(2.15rem, .7rem + 7.2vw, 3.4rem); }
  .hero__figure { max-width: 30rem; width: 100%; margin-inline: auto; }
  .hero__figure::before { inset: 55% -50vw calc(-1 * var(--hero-foot) - 1px) -50vw; }

  .statement { padding-top: clamp(3rem, 8vh, 5rem); }

  .salon { grid-template-columns: minmax(0, 1fr); }
  .salon__figure { grid-column: 1; margin-top: clamp(-7rem, -10vh, -4rem); max-width: 30rem; }
  .salon__prose { grid-column: 1; }

  .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 900px) {
  /* the services become an index: a sticky name rail, prose, photograph, with the
     even rows shifting the prose left and widening the photograph for rhythm */
  .service { grid-template-columns: repeat(12, 1fr); gap: var(--gutter); }
  .service__name { grid-column: 1 / span 3; position: sticky; top: calc(var(--head-h) + 2rem); }
  .service__body { grid-column: 5 / span 4; }
  .service__figure { grid-column: 9 / span 4; max-width: none; }
  .service:nth-of-type(even) .service__body { grid-column: 4 / span 4; }
  .service:nth-of-type(even) .service__figure { grid-column: 8 / span 5; }

  /* the same rail the services use, so the two indexes read as one system */
  .faq { display: grid; grid-template-columns: repeat(12, 1fr); column-gap: var(--gutter); }
  .faq__head {
    grid-column: 1 / span 3; margin-bottom: 0;
    position: sticky; top: calc(var(--head-h) + 2rem); align-self: start;
  }
  .faq__list { grid-column: 5 / span 8; }

  .kontakt {
    grid-template-columns: repeat(12, 1fr);
    column-gap: var(--gutter);
    max-width: none;
  }
  .kontakt > * { width: auto; max-width: none; margin-inline: 0; }
  .kontakt__main { grid-column: 2 / span 6; }
  .kontakt__aside { grid-column: 9 / span 4; }
  .grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .site-foot { grid-template-columns: 1fr auto; align-items: end; }
  .site-foot__mark { grid-column: 1; }
  .site-foot__line { grid-column: 2; grid-row: 1; justify-self: end; }
  .site-foot__nav { grid-column: 1 / -1; }
  .site-foot__fine { grid-column: 1 / -1; }
}

@media (min-width: 1400px) {
  .kontakt { padding-inline: max(var(--gutter), calc((100vw - var(--page)) / 2)); }
}

/* =========================================================================
   motion

   Three kinds, on purpose:
   1. the load moment: the hero portrait rising out of the tile field
   2. entrances: triggered when an element reaches the middle band of the
      viewport, so the animation plays where the visitor is actually looking,
      at its own pace, once per visit
   3. scroll linked: only the parallax drift, where the scroll itself is the
      point (photographs, gallery columns)

   Everything is gated on .js so nothing hides without scripting, and the whole
   block is inside prefers-reduced-motion: no-preference.
   ========================================================================= */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }

  /* ---- 1. the load moment ---------------------------------------------- */
  .js .hero__title span { opacity: 0; translate: 0 .6em; }
  .js .hero__lede, .js .hero__actions { opacity: 0; translate: 0 1rem; }
  .js .arch { clip-path: inset(100% 0 0 0); }
  .js .arch img { scale: 1.08; }

  html.is-ready .hero__title span {
    animation: rise 1.2s var(--ease-smooth) both;
    animation-delay: calc(var(--i, 0) * 130ms + 140ms);
  }
  html.is-ready .hero__lede { animation: rise 1.1s var(--ease-smooth) both .66s; }
  html.is-ready .hero__actions { animation: rise 1.1s var(--ease-smooth) both .82s; }
  .js .hero__figure::before { scale: 1 0; }
  html.is-ready .hero__figure::before { animation: field-rise 1.4s var(--ease-smooth) both .06s; }
  html.is-ready .arch { animation: curtain 1.5s var(--ease-smooth) both .2s; }
  html.is-ready .arch img { animation: settle 2.2s var(--ease-smooth) both .2s; }

  @keyframes rise { from { opacity: 0; translate: 0 .6em; } to { opacity: 1; translate: 0; } }
  @keyframes curtain { from { clip-path: inset(100% 0 0 0); } to { clip-path: inset(0 0 0 0); } }
  @keyframes settle { from { scale: 1.08; } to { scale: 1; } }
  @keyframes field-rise { from { scale: 1 0; } to { scale: 1 1; } }
  @keyframes field-drop { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0 0 -1% 0); } }

  /* ---- 2. entrances, triggered in the middle of the viewport ------------ */
  .js [data-reveal] { opacity: 0; }
  .js [data-reveal="rise"] { translate: 0 3rem; }
  /* not a data-reveal kind: the sentence cascades off the band's trigger, so it
     carries its own resting state the way the service row's children do */
  .js .statement__text { opacity: 0; translate: 0 2rem; clip-path: inset(0 0 100% 0); }
  /* these animate something other than their own opacity, so they stay painted.
     Miss one out and the blanket rule above leaves it invisible for good. */
  .js [data-reveal="row"] { opacity: 1; }
  .js [data-reveal="field"] { opacity: 1; }
  .js [data-reveal="plate"] { opacity: 1; }
  .js [data-reveal="wipe"] { opacity: 1; clip-path: inset(0 100% 0 0); }
  .js [data-reveal="photo"] { scale: 1.05; filter: blur(10px); }
  .js [data-reveal="tile"] { translate: 0 2rem; scale: .94; }
  /* the signature writes itself. every path in the symbol carries pathLength="1",
     and dash properties inherit, so this reaches the <use> shadow content that a
     descendant selector never could */
  .js [data-reveal="draw"] { opacity: 1; stroke-dasharray: 1; stroke-dashoffset: 1; }

  .js [data-reveal="rise"].in { animation: rise-up 1.3s var(--ease-smooth) both; }
  /* the blue field wipes down and the sentence rises inside it */
  .js [data-reveal="field"] { clip-path: inset(0 0 100% 0); }
  .js [data-reveal="field"].in { animation: field-drop 1.5s var(--ease-smooth) both; }
  /* The sentence starts with the band rather than on a trigger of its own. It used
     to carry data-reveal="statement" and arm separately, but it sits a third of the
     way down a section taller than the viewport, so its own arm point came several
     hundred pixels of scrolling after the band's: the field wiped open and then sat
     there empty, and a reader moving at any pace was past it before the words came.
     Timings are unchanged; only the moment it starts moved. */
  .js .statement.in .statement__text { animation: statement-in 1.6s var(--ease-smooth) both .25s; }
  .js [data-reveal="wipe"].in { animation: wipe 1.4s var(--ease-smooth) both; }
  .js [data-reveal="photo"].in { animation: photo-in 1.6s var(--ease-smooth) both; }
  .js [data-reveal="tile"].in { animation: tile-in 1.2s var(--ease-smooth) both; }
  .js [data-reveal="plate"] { clip-path: inset(0 100% 0 0); }
  .js [data-reveal="plate"] img { filter: blur(9px); transition: filter 1.5s var(--ease-smooth); }
  .js [data-reveal="plate"].in { animation: plate-open 1.6s var(--ease-smooth) both; }
  .js [data-reveal="plate"].in img { filter: blur(0); }
  /* a hand accelerates and settles, so this one curve is not the page's ease out */
  .js [data-reveal="draw"].in { animation: draw 2.4s cubic-bezier(.45, .05, .25, 1) both .2s; }

  /* What an arrival from another page jumped straight past. It carries .in as
     well, and running that animation in no time at all leaves every kind on its
     finished values through the both fill — which is why this needs no reversed
     copy of the resting states above, and why a kind added later is covered too.
     The plate's photograph deblurs on a transition rather than an animation, so
     it is the one thing named here. */
  .js [data-reveal].shown,
  .js [data-reveal].shown * {
    animation-duration: 0s !important;
    animation-delay: 0s !important;
  }
  .js [data-reveal="plate"].shown img { transition: none; }

  @keyframes rise-up { from { opacity: 0; translate: 0 3rem; } to { opacity: 1; translate: 0; } }
  @keyframes statement-in {
    from { opacity: 0; translate: 0 2rem; clip-path: inset(0 0 100% 0); }
    to { opacity: 1; translate: 0; clip-path: inset(0 0 -2% 0); }
  }
  @keyframes wipe { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 -2% 0 0); } }
  @keyframes photo-in {
    from { opacity: 0; scale: 1.05; filter: blur(10px); }
    to { opacity: 1; scale: 1; filter: blur(0); }
  }
  @keyframes plate-open {
    from { clip-path: inset(0 100% 0 0); }
    to { clip-path: inset(0 -1% 0 0); }
  }
  @keyframes tile-in {
    from { opacity: 0; translate: 0 2rem; scale: .94; }
    to { opacity: 1; translate: 0; scale: 1; }
  }
  @keyframes draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }

  /* the service row is choreographed: the rule draws across, then the name, the
     prose, and the photograph */
  /* the prose column is the one part that does not start hidden as a whole:
     its paragraphs hide themselves and arrive one at a time, the way the
     hygiene list already did, so a two or three paragraph service reads the
     same way rather than landing in one slab */
  .js .service > *:not(.service__body) { opacity: 0; }
  .js .service__body > p { opacity: 0; }
  .js [data-reveal="row"]::before { scale: 0 1; }
  .js [data-reveal="row"].in::before { animation: rule-draw 1.5s var(--ease-smooth) both; }
  @keyframes rule-draw { from { scale: 0 1; } to { scale: 1 1; } }
  .js .service.in .service__name { animation: slide-right 1.2s var(--ease-smooth) both; }
  /* 120ms apart, so the second element of every service — a paragraph here, the
     first list row under Higijenski tretman — always lands on the same 300ms
     beat and the whole section shares one rhythm */
  .js .service.in .service__body > p {
    animation: rise-small 1s var(--ease-smooth) both;
    animation-delay: calc(var(--i, 0) * 120ms + 180ms);
  }
  /* The photograph is NOT driven off the row's trigger. Stacked on a phone a
     service row is taller than the screen, so when the row arms, its picture is
     still a few hundred pixels below the fold and its whole arrival plays where
     nobody can see it: by the time you scroll down the image is simply there,
     and only the text ever appears to move. It carries data-reveal="photo" in
     the markup instead, so it arrives when the reader actually reaches it. Above
     900px the three sit side by side and arm together anyway, so the row reads
     exactly as before. */
  @keyframes slide-right { from { opacity: 0; translate: -1.5rem 0; } to { opacity: 1; translate: 0; } }

  /* children cascade off their parent's trigger. h1 is here for the archive
     page title; index.html's only h1 is the hero, which animates on load */
  /* .faq__q is excluded: all of them sit in one rise block, so this cascade
     would wipe every question on the same .14s while their own rows are still
     fading up one after another. The row's stagger below owns the question. */
  .js [data-reveal="rise"] h1,
  .js [data-reveal="rise"] h2,
  .js [data-reveal="rise"] h3:not(.faq__q) { clip-path: inset(0 100% 0 0); }
  .js [data-reveal="rise"].in h1,
  .js [data-reveal="rise"].in h2,
  .js [data-reveal="rise"].in h3:not(.faq__q) { animation: wipe 1.4s var(--ease-smooth) both .14s; }

  .js .service__list li,
  .js .channels li,
  .js .site-foot__nav a,
  .js .faq__item,
  .js .kontakt__phone,
  .js .salon__quote { opacity: 0; }
  .js .service.in .service__list li,
  .js [data-reveal="rise"].in .channels li,
  .js [data-reveal="rise"].in .site-foot__nav a,
  .js [data-reveal="rise"].in .faq__item,
  .js [data-reveal="rise"].in .kontakt__phone,
  .js [data-reveal="rise"].in .salon__quote {
    animation: rise-small 1s var(--ease-smooth) both;
    animation-delay: calc(var(--i, 0) * 95ms + 300ms);
  }
  @keyframes rise-small { from { opacity: 0; translate: 0 1.25rem; } to { opacity: 1; translate: 0; } }

  /* stagger indices, so a cascade needs no javascript */
  .service__list li:nth-child(2), .channels li:nth-child(2),
  .site-foot__nav a:nth-child(2), .grid > li:nth-child(4n+2) { --i: 1; }
  .service__list li:nth-child(3), .channels li:nth-child(3),
  .site-foot__nav a:nth-child(3), .grid > li:nth-child(4n+3) { --i: 2; }
  .service__list li:nth-child(4), .channels li:nth-child(4),
  .site-foot__nav a:nth-child(4), .grid > li:nth-child(4n) { --i: 3; }
  .service__list li:nth-child(5), .site-foot__nav a:nth-child(5) { --i: 4; }
  /* paragraphs always precede the list inside .service__body, so nth-child
     counts them correctly even where a <ul> follows */
  .service__body > p:nth-child(2) { --i: 1; }
  .service__body > p:nth-child(3) { --i: 2; }
  .service__body > p:nth-child(4) { --i: 3; }
  .js [data-reveal="tile"].in { animation-delay: calc(var(--i, 0) * 110ms); }

  /* the FAQ rows run past where the shared indices above stop, so they
     carry their own; extend this list if a question is ever added */
  .faq__item:nth-child(2) { --i: 1; }
  .faq__item:nth-child(3) { --i: 2; }
  .faq__item:nth-child(4) { --i: 3; }
  .faq__item:nth-child(5) { --i: 4; }
  .faq__item:nth-child(6) { --i: 5; }
  .faq__item:nth-child(7) { --i: 6; }
  .faq__item:nth-child(8) { --i: 7; }
  .faq__item:nth-child(9) { --i: 8; }
  .faq__item:nth-child(10) { --i: 9; }

  /* a panel opening is interaction, not an entrance. The answer rises whatever
     the browser can manage with the height; where interpolate-size is supported
     the height eases with it, and everywhere else it simply snaps open under a
     rising answer, which is what <details> does unaided anyway. */
  .faq__item[open] .faq__a { animation: rise-small .55s var(--ease-smooth) both; }
  @supports (interpolate-size: allow-keywords) {
    .faq__item { interpolate-size: allow-keywords; }
    .faq__item::details-content {
      block-size: 0; overflow: hidden;
      transition: block-size .45s var(--ease-smooth),
                  content-visibility .45s allow-discrete;
    }
    .faq__item[open]::details-content { block-size: auto; }
  }

  /* ---- 3. scroll linked: the drift, where the scroll is the point ------- */
  @supports (animation-timeline: view()) {
    /* an explicit height, not auto: auto on a replaced element resolves from the
       intrinsic ratio, which would leave the frame uncovered at drift extremes */
    .arch img { top: -4.5%; bottom: auto; height: 109%; }
    .band img { top: -4%; bottom: auto; height: 108%; }
    .salon__figure .frame img,
    .service__figure .frame img { top: -3.5%; bottom: auto; height: 107%; }

    .arch img {
      animation: drift-hero linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
    }
    /* the shorthand below resets animation-timeline, so both longhands follow it */
    html.is-ready .arch img {
      animation: settle 2.2s var(--ease-smooth) both .2s, drift-hero linear both;
      animation-timeline: auto, view();
      animation-range: normal, cover 0% cover 100%;
    }
    @keyframes drift-hero { from { translate: 0 -3.2%; } to { translate: 0 3.2%; } }

    .band img { animation: drift-band linear both; animation-timeline: view(); }
    @keyframes drift-band { from { translate: 0 -3%; } to { translate: 0 3%; } }

    .salon__figure .frame img,
    .service__figure .frame img { animation: drift-soft linear both; animation-timeline: view(); }
    @keyframes drift-soft { from { translate: 0 -2.6%; } to { translate: 0 2.6%; } }

    @media (min-width: 900px) {
      /* the drift rides the tile itself; the entry animation owns the list item */
      .grid > li > .tile {
        animation: col-a linear both;
        animation-timeline: view();
        animation-range: entry 0% exit 100%;
      }
      .grid > li:nth-child(4n+2) > .tile { animation-name: col-b; }
      .grid > li:nth-child(4n+3) > .tile { animation-name: col-c; }
      .grid > li:nth-child(4n) > .tile { animation-name: col-d; }
      @keyframes col-a { from { translate: 0 20px; } to { translate: 0 -20px; } }
      @keyframes col-b { from { translate: 0 -13px; } to { translate: 0 13px; } }
      @keyframes col-c { from { translate: 0 16px; } to { translate: 0 -16px; } }
      @keyframes col-d { from { translate: 0 -18px; } to { translate: 0 18px; } }
    }
  }

  /* ---- the mobile menu opens from the top, one link after another ------- */
  @media (max-width: 899px) {
    /* the three lines fold into the cross: outer bars slide to the middle and
       rotate, the middle one collapses into itself */
    .menu-btn__bars .bar {
      transition: transform .5s var(--ease-smooth), opacity .3s var(--ease-smooth),
                  scale .4s var(--ease-smooth);
    }
    .menu-btn__bars .bar--2 { transition-duration: .25s; }

    .site-nav ul li {
      opacity: 0; translate: 0 -1.25rem;
      /* closing: the links clear quickly and the panel dissolves after them, so
         the menu is put away rather than switched off */
      transition: opacity .45s var(--ease-smooth), translate .5s var(--ease-smooth);
    }
    html[data-menu="open"] .site-nav ul li {
      opacity: 1; translate: 0;
      transition: opacity .6s var(--ease-smooth), translate .7s var(--ease-smooth);
    }
    html[data-menu="open"] .site-nav ul li:nth-child(1) { transition-delay: .12s; }
    html[data-menu="open"] .site-nav ul li:nth-child(2) { transition-delay: .24s; }
    html[data-menu="open"] .site-nav ul li:nth-child(3) { transition-delay: .36s; }
    html[data-menu="open"] .site-nav ul li:nth-child(4) { transition-delay: .48s; }
  }

  /* ---- hover answers back everywhere a pointer can go ------------------- */
  .link-arrow .ico { transition: translate .35s var(--ease); }
  .link-arrow:hover .ico, .link-arrow:focus-visible .ico { translate: .18em -.18em; }
  .btn--primary:hover { translate: 0 -1px; }
  .service__name .ico--lg { transition: rotate .5s var(--ease), scale .5s var(--ease); }
  .service:hover .ico--lg { rotate: -6deg; scale: 1.06; }
}

@media (prefers-reduced-motion: reduce) {
  .lb { transition: none; }
  /* the paw still marks the open row, it just stops turning to get there: a near
     full rotation is the one thing on this page worth withdrawing. The tilt stays
     and simply snaps, so the open state is never colour alone; an instant change
     is not the kind of motion this preference is asking us to drop. */
  .faq__paw { transition: opacity .35s var(--ease); }
  .faq__item[open] .faq__paw { rotate: -20deg; scale: 1; }
}

/* =========================================================================
   print
   ========================================================================= */
@media print {
  .site-head, .band, .map, .lb, .skip, .galerija, .arhiva { display: none !important; }
  body { background: #fff; color: #000; font-size: 11pt; }
  .statement, .kontakt { background: #fff; }
}
