/* Easy Cheesy catering landing, v2 ("Standard" world, approved comp .impeccable/mocks/comps/comp-s1.png). The whole
   page stands on the first screen's night (owner, live mode 2026-09-26): light text, mustard accents, the photos glow.
   First viewport at 390x844 follows the measured layout of the comp; sizes of the small text come from the comp
   source (build-phase notes). One typeface, Urbanist, a free geometric grotesk in the spirit of Objektiv on
   nowa.restaurant (owner, 2026-09-27, chosen from four free analogues shown side by side): thin for the big lines,
   regular for reading. Before it: Gloock headings, Brygada 1918 sublines and Fira Sans text. */

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

:root {
  --ink: #1E1714;
  --paper: #FFFFFF;
  --mustard: #F5CF76;
  --red: #C82818;
  --night: 14 11 10;              /* the scrim over the hero photo, as rgb channels */
  /* The night's text is warm ivory in three steps, not white (owner, 2026-09-27, direction A "quiet" of three shown):
     beside the warm night and the food photos pure white read grey. Contrast on the night: 16:1, 14:1 and 8.9:1. */
  --ivory: #F3ECE1;
  --on-night: var(--ivory);
  --on-night-soft: #E3D9CB;
  --on-night-quiet: #B9AD9D;
  --rule: rgb(243 236 225 / .14);    /* hairlines between list rows, on the night */
  --field-fill: rgb(255 255 255 / .065);   /* the soft tile of a form field, on the night */
  --error: #FF8A7A;                  /* the logo red lifted for the night: 8.5:1 */
  --mustard-hover: #F8DA93;
  --mustard-active: #EDC25E;
  --font-display: "Urbanist", "Avenir Next", system-ui, sans-serif;   /* thin, for the big lines */
  --font-sub: "Urbanist", "Avenir Next", system-ui, sans-serif;       /* regular, for the leads */
  --font-text: "Urbanist", "Avenir Next", system-ui, sans-serif;
  --header-h: 60px;
  --header-shade: 64px;             /* the night falling off under the header */
  --header-room: calc(var(--header-h) + 16px);   /* kept clear above whatever the page scrolls into view */
  --gutter: 22px;
  --radius: 6px;
  --max: 1240px;
  --space-section: 76px;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; color-scheme: dark;
  scrollbar-color: rgb(255 255 255 / .3) rgb(var(--night));
  scroll-padding-top: var(--header-room); }  /* a section reached by a link lands clear of the header */
/* The page is its own layer, so the final page (layer -1, the footer) lies above the page's ground and under
   everything else, and still takes clicks where the page has ended. */
body { isolation: isolate; margin: 0; background: rgb(var(--night)); color: var(--on-night-soft); font-family: var(--font-text); font-size: 17px;
  line-height: 1.6; -webkit-font-smoothing: antialiased; caret-color: var(--mustard); }
img { display: block; max-width: 100%; }
a { color: inherit; }
h1, h2, h3, p, ul, ol, figure { margin: 0; }
ul, ol { padding: 0; }
button, input, select, textarea { font: inherit; color: inherit; }
[hidden] { display: none !important; }
.nowrap { white-space: nowrap; }
.visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0; }
p, li, figcaption { text-wrap: pretty; }

::selection { background: var(--mustard); color: var(--ink); }
:focus-visible { outline: 3px solid var(--mustard); outline-offset: 3px; border-radius: 2px; }
.skip-link { position: absolute; z-index: 20; top: 8px; left: 8px; padding: 12px 16px; background: var(--mustard); color: var(--ink);
  border-radius: var(--radius); font-weight: 600; text-decoration: none; transform: translateY(-160%); }
.skip-link:focus { transform: none; outline-color: var(--on-night); }
.icon { flex: none; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.icon--arrow { width: 1.15em; height: auto; vertical-align: -.08em; }

/* Header (owner, live mode 2026-09-26): a night bar that stays at the top of the screen while the page scrolls, so the
   menu of the page's sections is always at hand: the logo plate left, "Menu" right. It sits under the skip link (20). */
.site-header { position: sticky; top: 0; z-index: 15; height: var(--header-h); display: flex; align-items: center;
  justify-content: space-between; padding: 0 19px 0 17px; color: var(--on-night-soft); background: rgb(var(--night)); }
/* Under the bar the night falls off over 64px along the page's dusk curve (owner, live mode 2026-09-26), so a photo
   passing under the bar never meets a hard edge. A section reached from the menu still clears it: its own top
   padding carries its heading below the shade. */
.site-header::after { content: ""; position: absolute; top: 100%; left: 0; right: 0; height: var(--header-shade);
  pointer-events: none; background: linear-gradient(to bottom, rgb(var(--night)) 0, rgb(var(--night) / .7) 20%,
    rgb(var(--night) / .42) 42%, rgb(var(--night) / .18) 66%, rgb(var(--night) / .05) 86%, rgb(var(--night) / 0)); }
/* The page keeps a room clear at its top for the header (html, scroll-padding-top), and the header's own links and
   MENU sit in that room, so a browser took them, once focused, for hidden under the header and scrolled the page up
   to them: by up to 394 px on a phone (decision 97). For scrolling into view each counts as moved one room down and
   44px shorter (every control in the header is at least 44px tall, a tap target): a line just below the room, where
   nothing needs scrolling, which still fits a screen 160px tall. The open menu's links are left out: the menu scrolls
   them itself. */
.site-header :is(a, button):not(.site-menu *) { scroll-margin-top: calc(-1 * var(--header-room));
  scroll-margin-bottom: calc(var(--header-room) - 44px); }
/* On a short screen (a phone turned sideways, a page zoomed to 400%) the header and its shade step up out of the way
   while the page scrolls down and come back as soon as it scrolls up, so they no longer take half the screen with the
   floating bar; the menu stays one flick away (owner, 2026-09-29, variant "hides while scrolling" of four shown,
   decision 91; v2.js sets .is-away and keeps the header while the keyboard's focus is in it). It leaves by its own
   height and its shade (the 404 page's header takes two rows on a narrow screen), quicker than it comes back, like the
   floating bar. */
@media (max-height: 440px) {
  .site-header { transition: translate .5s cubic-bezier(.16, 1, .3, 1); }
  .site-header.is-away { translate: 0 calc(-100% - var(--header-shade)); transition: translate .3s cubic-bezier(.55, 0, 1, .45); }
  /* With the header away, a focused element no longer keeps the header's room above it, so it stays clear of the
     floating bar below (audit 2026-09-30, decision 95). */
  html:has(.site-header.is-away) { scroll-padding-top: 16px; }
}
@media (max-height: 440px) and (prefers-reduced-motion: reduce) {
  .site-header, .site-header.is-away { transition: none; }
}
@media (hover: hover) {   /* underlines on hover only where there is a hover: on touch screens a tap leaves them stuck */
  .site-header a:hover, .site-header__menu:hover { text-decoration: underline; text-decoration-color: var(--mustard);
    text-decoration-thickness: 1.5px; text-underline-offset: 4px; }
  .site-menu__contact a:hover { text-decoration: underline; text-decoration-color: var(--ink);
    text-decoration-thickness: 1.5px; text-underline-offset: 5px; }
  .faq__item summary:hover span { text-decoration: underline; text-decoration-color: var(--mustard);
    text-decoration-thickness: 1.5px; text-underline-offset: 4px; }
}
.site-header__logo { display: flex; align-items: center; min-height: 44px; }  /* 44px tap target around the 29px plate */
.site-header__logo img { width: 90px; height: auto; }
.site-header__nav { display: flex; gap: 15px; font-size: 13.5px; font-weight: 500; line-height: 1; }  /* 404 page */
.site-header__nav a { display: flex; align-items: center; min-height: 44px; text-decoration: none; }
.site-header__break { display: none; }
/* The 404 page on a phone: the phone, the address and the shop do not fit beside the logo, so the logo and the shop
   keep the bar and the phone and the address take a second row (owner, live 2026-09-28: the address beside every
   phone). */
@media (max-width: 539.98px) {
  .site-header:has(> .site-header__nav) { height: auto; min-height: var(--header-h); flex-wrap: wrap; justify-content: flex-start;
    column-gap: 15px; padding-block: 8px; }
  .site-header__nav { display: contents; }
  .site-header__nav a[href^="https:"] { order: 1; margin-left: auto; }
  .site-header__break { display: block; order: 2; flex-basis: 100%; height: 0; }
  .site-header__nav a[href^="tel:"] { order: 3; }
  .site-header__nav a[href^="mailto:"] { order: 4; }
}
.site-header__menu { display: inline-flex; align-items: center; gap: 9px; min-height: 44px; padding: 0 2px; border: 0;
  background: none; color: var(--on-night); font: 500 12px/1 var(--font-text); letter-spacing: .16em; text-transform: uppercase; cursor: pointer; }
.icon--menu { width: 18px; height: auto; }
.icon__close, .site-header:has(.site-menu:popover-open) .icon__bars { display: none; }
.site-header:has(.site-menu:popover-open) .icon__close { display: inline; }

/* The hand-off: while the first screen's wordmark shows the bar has no logo. With the first screen's hold (decision 106,
   "Hero" below) the plate fades in while the wordmark sinks; without it (reduced motion) it fades in as the first sheet,
   whose top edge is 100svh down the page, slides over the wordmark in the middle of the screen (the range below covers
   that on phones and desktops alike). Where the browser lacks scroll-driven animation, and on pages without the first
   screen (404), the plate simply stays. */
@supports (animation-timeline: scroll()) {
  body:has(.hero) .site-header__logo { animation: header-logo-in linear both; animation-timeline: scroll(root);
    animation-range: calc(54svh - 100px) calc(56svh - 10px); }
}
@keyframes header-logo-in { from { opacity: 0; visibility: hidden; } to { opacity: 1; visibility: visible; } }

/* The menu: a native popover (a click outside or Esc closes it, and so does picking a section, v2.js) that opens under the
   bar as a mustard page (owner, 2026-09-27, direction "mustard poster" of three shown): the sections' titles in big ink
   lines set to the left like a poster's type, the request as an ink button, the phone and the shop at the foot. Mustard
   is the page here, so the menu draws its focus rings, underlines and selection in ink. Items lead to the sections
   themselves: a heading still on its way in (the sections' arrival) would land under the bar. */
.site-menu { position: fixed; inset: var(--header-h) 0 0 0; width: auto; height: auto; max-height: calc(100dvh - var(--header-h));
  margin: 0; border: 0; padding: 6svh var(--gutter) 5svh; display: none; flex-direction: column; justify-content: space-between;
  gap: 32px; overflow: auto; overscroll-behavior: contain; text-align: left; color: var(--ink); background: var(--mustard); }
.site-menu:popover-open { display: flex; }
.site-menu__list { list-style: none; display: grid; gap: .4svh; }
.site-menu a { color: inherit; text-decoration: none; }
.site-menu :focus-visible { outline-color: var(--ink); }
.site-menu ::selection { background: var(--ink); color: var(--mustard); }
.site-menu__list a { display: inline-block; padding: 4px 0; font-family: var(--font-display); font-weight: 250;
  font-size: clamp(34px, 6.4svh, 56px); line-height: 1.02; letter-spacing: -.01em; }
/* The request is the menu's way out of the page (owner, 2026-09-26: the request lives in the menu); on the mustard page
   the button turns ink. */
/* A section's name answers the pointer (owner, live 2026-09-28): it moves a little to the right while an ink line draws
   under it from the left; the keyboard's focus gets the same. With reduced motion the line simply shows. */
.site-menu__list li:not(.site-menu__cta) a { position: relative; transition: translate .3s cubic-bezier(.2, .7, .2, 1); }
.site-menu__list li:not(.site-menu__cta) a::after { content: ""; position: absolute; left: 0; right: 0; bottom: -.1em;
  height: 2px; border-radius: 1px; background: currentColor; transform: scaleX(0); transform-origin: left;
  transition: transform .3s cubic-bezier(.2, .7, .2, 1); }
@media (hover: hover) {
  .site-menu__list li:not(.site-menu__cta) a:hover { translate: 10px 0; text-decoration: none; }
  .site-menu__list li:not(.site-menu__cta) a:hover::after { transform: scaleX(1); }
}
.site-menu__list li:not(.site-menu__cta) a:focus-visible { translate: 10px 0; }
.site-menu__list li:not(.site-menu__cta) a:focus-visible::after { transform: scaleX(1); }
@media (prefers-reduced-motion: reduce) {
  .site-menu__list li:not(.site-menu__cta) a, .site-menu__list li:not(.site-menu__cta) a::after { transition: none; }
  .site-menu__list li:not(.site-menu__cta) a:is(:hover, :focus-visible) { translate: none; }
}
.site-menu__list .site-menu__cta { margin-top: 2.4svh; }
.site-menu__list .btn { display: inline-flex; padding: 0 32px; font-family: var(--font-text); font-size: 18px; font-weight: 600; line-height: 1.2;
  letter-spacing: 0; background: var(--ink); color: var(--mustard); }
.site-menu__list .btn:hover { background: #000; color: var(--mustard); text-decoration: none; }
.site-menu__list .site-menu__cta + .site-menu__cta { margin-top: 1.2svh; }
.site-menu__list .btn--boxy { background: transparent; color: var(--ink); border-color: var(--ink); }
.site-menu__list .btn--boxy:hover { background: var(--ink); color: var(--mustard); }
.site-menu__contact { display: flex; flex-wrap: wrap; gap: 0 28px; font-size: 16px; font-weight: 500; }
.site-menu__contact a { display: inline-flex; align-items: center; min-height: 44px; }
/* Instagram stands among the contacts as a small ink tag with the owner's camera, drawn on as the menu opens (owner,
   2026-10-02, variant C of three shown: «С»; decision 115): easy to find, still below the two buttons. */
.site-menu__contact .site-menu__ig { gap: 8px; padding: 0 18px 0 12px; border-radius: 999px; background: var(--ink);
  color: var(--mustard); transition: background-color .3s cubic-bezier(.2, .7, .2, 1); }
.site-menu__contact .site-menu__ig:hover { background: #000; text-decoration: none; }
.site-menu__cam { flex: none; width: 22px; height: auto; overflow: visible; stroke-width: 6.6; }
/* A still life in the menu's free space (owner, 2026-09-28, variant 2 "still life" of three shown): the owner's tiered
   stand with canapés in ink lines, drawn as the menu opens. On a phone and a tablet the stand stands alone at the right,
   between the request and the phone number, as tall as that space allows (up to 200px; below 72px it is left out);
   from 1024px it stands between a flower in a vase and a glass in the menu's right column. The lines of the three keep
   one weight: each drawing's stroke width is set against its own width. */
.site-menu__still { flex: 1 1 0; min-height: 0; margin-block: -16px; display: flex; justify-content: flex-end;
  align-items: center; container-type: size; pointer-events: none; }
.site-menu__art { display: block; height: 100%; max-height: 200px; width: auto; overflow: visible; stroke-width: var(--sw, 1.65); }
.site-menu__art--flower, .site-menu__art--glass { display: none; }
@container (max-height: 72px) { .site-menu__art { display: none; } }
/* The menu's foot shares the free space under the buttons between the still life and the contacts. With three contacts
   (Instagram since decision 115) a phone's row of them breaks in two and the stand loses its room, so where the foot
   is tall enough for the three in a column they stand at its left and the stand beside them at the right (owner,
   2026-10-02, «Столбиком рядом с этажеркой», one of two shown); a lower foot keeps the row, where the stand gives way to
   the links as before. The foot's own height decides, not the screen's: the section names grow with the screen and
   may wrap. From 1024px the menu's own two columns take over. */
.site-menu__foot { flex: 1 1 0; min-height: 44px; container: menu-foot / size; }
.site-menu__foot-in { height: 100%; display: flex; flex-direction: column; justify-content: flex-end;
  justify-content: safe flex-end; gap: 32px; }   /* a foot lower than its links lets them run down: the menu scrolls */
@container menu-foot (min-height: 116px) {
  /* the column reaches 16px up into the gap over it, as the stand does in the row: 116 + 16 holds the three links */
  .site-menu__foot-in { height: calc(100% + 16px); margin-top: -16px; display: grid;
    grid-template-columns: max-content minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); column-gap: 20px; }
  .site-menu__contact { grid-column: 1; grid-row: 1; align-self: end; flex-direction: column; align-items: flex-start; }
  .site-menu__still { grid-column: 2; grid-row: 1; margin: 0; align-items: flex-end; }
  .site-menu__art { max-width: 100%; }   /* a narrow, tall window: the stand shrinks into its column, never over the links */
}
/* A short phone (a screen under 600px, an iPhone SE in Safari) keeps the whole menu on one screen with the Instagram tag
   in its second row: a little less air between and around the menu's parts (decision 115). */
@media (max-width: 699px) and (max-height: 600px) {
  .site-menu { gap: 16px; padding-block: 4svh 3svh; }
}
@media (prefers-reduced-motion: no-preference) {
  .site-menu { transition: opacity .24s ease, translate .3s cubic-bezier(.2, .7, .2, 1), display .3s allow-discrete,
    overlay .3s allow-discrete; }
  .site-menu:not(:popover-open) { opacity: 0; translate: 0 -10px; }
  @starting-style { .site-menu:popover-open { opacity: 0; translate: 0 -10px; } }
  /* Each line of the still life draws itself from its start, the flower first and the glass last; the gap of the dash
     is twice the line, so no dot of a round cap shows before a line starts. */
  .site-menu:popover-open .site-menu__art path { stroke-dasharray: 1 2; stroke-dashoffset: 1.02;
    animation: menu-draw 1.3s cubic-bezier(.45, .05, .25, 1) .2s forwards; }
  .site-menu:popover-open .site-menu__art--stand path { animation-delay: .3s; }
  .site-menu:popover-open .site-menu__art--glass path { animation-delay: .45s; }
  .site-menu:popover-open .site-menu__cam path { stroke-dasharray: 1 2; stroke-dashoffset: 1.02;
    animation: menu-draw 1.3s cubic-bezier(.45, .05, .25, 1) .5s forwards; }
}
@keyframes menu-draw { to { stroke-dashoffset: 0; } }

/* Hero (owner, live 2026-10-01 after marquet.nyc: the first of four variants shown, with a round shape instead of the
   pill; decision 106. Before it the bar filled the whole screen, live 2026-09-26/27 after domarb.com.au). The owner's
   marble bar (IMG_4783 of 24.10.2025) stands in a circle over the same photo blurred into the night, the brand's
   wordmark across it and one line of facts along the circle's foot. The screen opens with a mustard curtain leaving to
   the left, the circle opening from its centre and the wordmark rising into place. On scroll the screen first stands
   still while the circle opens to the whole photo and the wordmark sinks, and only then does the first sheet slide up
   over it (owner: «Сначала при скролле раскрытие картинки потом уже сдвиг вниз»); the photo then sinks into the night
   as before. Every block after it is an opaque sheet above it. Decision 107 (owner, 2026-10-02): the first sheet comes
   as soon as the photo has filled the screen («как только страница раскрылась полностью, сразу проявлять следующую
   страницу при скролле»), and the circle starts a little smaller («чуть уже, но не сильно»: a tenth). */
@property --hero-open { syntax: "<number>"; inherits: true; initial-value: 1; }
@property --hero-grow { syntax: "<number>"; inherits: true; initial-value: 0; }
/* Registered so that they compute to plain pixels: the line of facts below divides them with tan(atan2()). */
@property --hero-reach { syntax: "<length>"; inherits: true; initial-value: 0px; }
@property --hero-ring-0 { syntax: "<length>"; inherits: true; initial-value: 0px; }
/* The circle's centre stands --hero-y down the screen's box, --hero-k of the box below it. --hero-hold is how much
   scrolling the screen stands still for: the circle grows over all of it, and the first sheet comes right after.
   --hero-reach is how far the circle grows: the way from its centre to the farthest corner, exactly (hypot(), below),
   so that the photo fills the screen just as the hold ends (decision 107; before it the reach was taken long and the
   full photo stood still for a quarter of a screen). Where hypot() is unknown the longer leg plus 0.42 of the shorter
   stands in: never short of the diagonal and at most 8.5% over it. */
.hero { position: sticky; top: var(--header-h); z-index: 0; isolation: isolate; overflow: hidden; overflow: clip;
  min-height: calc(100svh - var(--header-h)); --hero-r: min(38vw, 27svh); --hero-y: 44%; --hero-k: .56;
  --hero-hold: 70svh;
  --hero-reach: calc(max(50vw, var(--hero-k) * (100svh - var(--header-h)))
    + .42 * min(50vw, var(--hero-k) * (100svh - var(--header-h))) - var(--hero-r)); }
@supports (width: hypot(1px, 1px)) {
  .hero { --hero-reach: calc(hypot(50vw, var(--hero-k) * (100svh - var(--header-h))) - var(--hero-r)); }
}
/* clip (no scroll box; hidden only where clip is unknown, Safari before 16) keeps the curtain and the blur inside the
   screen; the night behind it is the page's own. */
.hero__backdrop { position: absolute; inset: -48px; z-index: -3; }
/* The screen's box falls into the night at its top and foot, so that no edge of it shows hard once the circle has
   opened: when the header steps away on a low screen, or a phone's browser bar folds away and the box ends above the
   foot of the screen (review, 2026-10-02). Each scrim stops 8px short of the circle at rest, so the circle itself is
   never shaded there; under the line of facts it only deepens the frame. */
.hero::before, .hero::after { content: ""; position: absolute; left: 0; right: 0; z-index: -1; pointer-events: none; }
.hero::before { top: 0; height: max(0px, min(14%, var(--hero-y) - var(--hero-r) - 8px));
  background: linear-gradient(rgb(var(--night)), rgb(var(--night) / .55) 35%, rgb(var(--night) / .18) 70%, rgb(var(--night) / 0)); }
.hero::after { bottom: 0; height: max(0px, min(18%, 100% - var(--hero-y) - var(--hero-r) - 8px));
  background: linear-gradient(to top, rgb(var(--night)), rgb(var(--night) / .55) 35%, rgb(var(--night) / .18) 70%, rgb(var(--night) / 0)); }
/* Where the header steps away (screens under 440px high), the top scrim keeps at least 24px even where the circle nearly
   touches the box's top (a page zoomed to 300-400%, a small phone on its side; re-review, 2026-10-02): there it may
   shade the circle's very top at rest, which reads softer than a hard edge under the night. */
@media (max-height: 440px) { .hero::before { height: max(24px, min(14%, var(--hero-y) - var(--hero-r) - 8px)); } }
/* The frame around the circle is the same photo blurred and drained of colour, a black-and-white print in the dark
   (owner, 2026-10-01: «как будто черно-белая картинка», as on marquet.nyc), in the grey of the dimmed grounds; under the
   letters of the facts at least 9.4:1 on six screens, phones to 1920x1080 (measured 2026-10-02, decision 107). */
.hero__backdrop img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 40%;
  filter: blur(26px) grayscale(1) contrast(1.05) brightness(.36); }
/* The cover photo of the owner's RENT brochure: the same bar seen from its corner, from the lamps' ruffled edges to the
   counter (owner, 2026-09-27); the coffee machines, the branded bottles and the stool of that evening stay out of the
   frame (PRODUCT.md: no coffee, not even in imagery; no third-party logos). Phones get a crop of their own shape
   (hero-corner-phone); screens wider than 11:20 get the brochure's 4:5 frame (hero-corner-cover). The circle opens from
   nothing to its radius (--hero-open) and on scroll past the screen's corners (--hero-grow); the fallbacks in var()
   keep the circle where @property is unknown (Safari before 16.4, Firefox before 128) and the two stay unset. */
.hero__photo { position: absolute; inset: 0; z-index: -2;
  clip-path: circle(calc(var(--hero-r) * var(--hero-open, 1) + var(--hero-reach) * var(--hero-grow, 0)) at 50% var(--hero-y)); }
.hero__photo img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 52%; }
main > :not(.hero) { position: relative; z-index: 1; background: rgb(var(--night)); }
/* The brand's wordmark from the owner's brochure across the circle, wider than it; it is the first screen's only name. */
.hero__wordmark { position: absolute; top: var(--hero-y); left: 50%; width: min(88vw, 760px, 64svh);
  transform: translate(-50%, -50%); overflow: hidden; pointer-events: none; }
.hero__wordmark img { display: block; width: 100%; height: auto; }
/* One line of facts along the circle's foot, 28px out from it: the arc runs 0.4 of the box's width from its centre, and
   that centre stands 0.025 of the width below the box's top. The drawing scales with its box, so its type is set back by
   the box's scale to read 13px, growing with the circle to 16px, on any screen: tan(atan2()) turns a ratio of two
   lengths into a number. Over the unregistered vw/svh sums WebKit 26.5 misread it (0-29px measured), hence the
   registered lengths, and the rule waits for relative colour syntax, which came with @property in Safari 16.4 and
   Firefox 128 (CSS cannot test @property itself); before them the drawing keeps 11 units. On scroll the line rides out
   with the circle's edge while it fades, so the opening photo never runs under letters still showing (measured
   2026-10-01: a line left in place was overrun after 3svh, at 0.87 opacity, 1:1 in places). It is scaled about the
   circle's centre, not resized: a box resized on every frame cost long frames in 4 of 6 runs on a slowed phone. */
.hero__caption { --hero-ring-0: calc(var(--hero-r) * 2.5 + 70px);
  position: absolute; left: 50%; width: var(--hero-ring-0); top: calc(var(--hero-y) - var(--hero-ring-0) * .025);
  translate: -50% 0; transform-origin: 50% calc(var(--hero-ring-0) * .025); pointer-events: none; }
.hero__caption svg { display: block; width: 100%; height: auto; overflow: visible; }
.hero__caption text { font-family: var(--font-text); font-size: 11px; font-weight: 500; letter-spacing: .05em;
  fill: var(--on-night-soft); }
@supports (font-size: calc(1px / tan(atan2(1px, 1px)))) and (color: rgb(from red r g b)) {
  /* The line's scale where it is gone, three tenths into the hold: the circle has grown by 0.3 of its reach by then
     (the ranges below), and the arc, 0.4 of the box, keeps 28px off the circle when the box grows by 2.5 times that. */
  .hero__caption { --hero-ring-out: calc(1 + .3 * 2.5 * tan(atan2(var(--hero-reach), var(--hero-ring-0)))); }
  .hero__caption text { font-size: calc(clamp(13px, var(--hero-ring-0) * .0175, 16px) / tan(atan2(var(--hero-ring-0), 400px))); }
}
/* Under 340px of screen height (a small phone on its side, a page zoomed to 300-400%) the circle is too small to carry
   the line: it filled the half-circle and ran off the screen's foot (review, 2026-10-02). Its facts stand in «O nas». */
@media (max-height: 340px) { .hero__caption { display: none; } }
.hero__curtain { display: none; position: absolute; inset: 0; z-index: 4; background: var(--mustard); }
@media (prefers-reduced-motion: no-preference) {
  .hero__curtain { display: block; animation: hero-curtain .95s cubic-bezier(.76, 0, .24, 1) .12s both; }
  .hero__photo { animation: hero-open 1.5s cubic-bezier(.16, 1, .3, 1) .3s both; }
  .hero__wordmark img { animation: hero-rise 1.1s cubic-bezier(.16, 1, .3, 1) .9s both; }
  .hero__caption svg { animation: hero-fade-in .8s ease 1.5s both; }
  /* Until the photo is in, the circle and its line hold still (hero-wait, set and cleared by the script in the page's
     head); the scroll's growth, the second animation once there is one, runs on. */
  .hero-wait .hero__photo { animation-play-state: paused, running; }
  .hero-wait .hero__caption svg { animation-play-state: paused; }
  /* The screen stays put for --hero-hold of scrolling (the margin under it) while the circle opens; the first sheet
     comes right after it, and the header's logo plate takes over as the wordmark sinks. */
  @supports (animation-timeline: scroll()) {
    .hero { margin-bottom: var(--hero-hold); animation: hero-sink linear both; animation-timeline: scroll(root);
      animation-range: var(--hero-hold) calc(var(--hero-hold) + 90svh); }
    .hero__photo { animation: hero-open 1.5s cubic-bezier(.16, 1, .3, 1) .3s both, hero-grow linear both;
      animation-timeline: auto, scroll(root); animation-range: normal, 0 var(--hero-hold); }
    .hero__wordmark img { animation: hero-rise 1.1s cubic-bezier(.16, 1, .3, 1) .9s both, hero-word-sink linear both;
      animation-timeline: auto, scroll(root); animation-range: normal, 0 40svh; }
    .hero__caption { animation: hero-ride-out linear both; animation-timeline: scroll(root);
      animation-range: 0 calc(var(--hero-hold) * .3); }
    body:has(.hero) .site-header__logo { animation-range: 25svh 45svh; }
  }
}
@keyframes hero-sink { to { opacity: .22; } }
@keyframes hero-open { from { --hero-open: 0; } to { --hero-open: 1; } }
@keyframes hero-grow { to { --hero-grow: 1; } }
@keyframes hero-rise { from { translate: 0 108%; } }
@keyframes hero-word-sink { to { transform: translateY(108%); } }
@keyframes hero-fade-in { from { opacity: 0; } }
@keyframes hero-ride-out { to { opacity: 0; scale: var(--hero-ring-out, 1); } }
@keyframes hero-curtain { to { translate: -101% 0; } }


/* The action stays at hand: a button floating above the foot of the screen on every layout, the page's own button
   (owner, live a50bf740 2026-09-28, variant "floating" of four shown; corners of 16px, the owner's knob), a pill in
   the middle, 360px wide and on a phone at most 74% of the screen: Safari 26 on iOS tints its own toolbar with a fixed
   element at the foot of the screen that is at least 80% as wide, and the gutter-wide bar painted it mustard (owner's
   choice of four fixes, 2026-10-01, decision 99). Since 2026-10-01 it is night glass instead of a mustard fill, so it
   no longer outshines the page (owner, live 89da3fd6: variant 4 of four shown, then a thin mustard line and the doodle
   in mustard without its disc; decision 101): the night at 70% over a 16px blur keeps the ivory words readable over
   whatever scrolls under it, and the mustard is left to the line and the doodle. Before 2026-09-28 a full-width bar
   (2026-09-27). It is not on the first screen: it rises, slowing down smoothly, once the first sheet has slid all the
   way over the photo, and sinks away, quicker, when the photo shows again (v2.js sets .is-shown; without JavaScript it
   stays hidden, since its window needs the script and the menu keeps the phone and e-mail, decision 76). The quote
   window and the menu open above it; the final page keeps its last line clear of it, and over that mustard page the
   bar turns ink. */
.cta-bar { position: fixed; left: 50%; width: min(360px, 74vw); translate: -50% 0; bottom: calc(12px + env(safe-area-inset-bottom)); z-index: 14;
  display: flex; align-items: center; justify-content: center; min-height: 56px; padding: 0 20px; border-radius: 16px;
  box-shadow: inset 0 0 0 1px rgb(245 207 118 / .7), 0 10px 26px rgb(0 0 0 / .38);
  background: rgb(var(--night) / .7);
  -webkit-backdrop-filter: blur(16px) saturate(1.2); backdrop-filter: blur(16px) saturate(1.2);
  color: var(--on-night); font-size: 18px; font-weight: 600; line-height: 1.2; text-decoration: none;
  transition: background-color .3s cubic-bezier(.2, .7, .2, 1); }
.cta-bar:hover { background: rgb(var(--night) / .86); }
.cta-bar:active { background: rgb(var(--night) / .94); }
/* The owner's doodle of a note with ticks and a pencil stands left of the words, still (owner, 2026-09-28, the third
   of three drawings shown, "without animation"): about as tall as the letters with their accents, its line thin
   enough to keep the ticks apart; in mustard since decision 101. */
.cta-bar__art { flex: none; width: 26px; height: 28px; margin-right: 10px; stroke-width: 5.4; color: var(--mustard); }
.cta-bar { transform: translateY(calc(100% + 12px + env(safe-area-inset-bottom))); opacity: 0; visibility: hidden;
  transition: transform .34s cubic-bezier(.55, 0, 1, .45), opacity .3s ease-in, visibility 0s linear .34s,
    background-color .2s cubic-bezier(.2, .7, .2, 1); }
.cta-bar.is-shown { transform: none; opacity: 1; visibility: visible;
  transition: transform .8s cubic-bezier(.16, 1, .3, 1), opacity .6s cubic-bezier(.16, 1, .3, 1), visibility 0s,
    background-color .2s cubic-bezier(.2, .7, .2, 1),
    color .2s cubic-bezier(.2, .7, .2, 1); }
/* While the bar stands, a focused element scrolled into view stops above it. The bar is always at hand (owner,
   2026-09-28), so it never steps aside; the menu, the services, the occasions and the skip link are the page's other
   ways in. */
html:has(.cta-bar.is-shown) { scroll-padding-bottom: calc(72px + env(safe-area-inset-bottom)); }
@media (prefers-reduced-motion: reduce) {
  .cta-bar, .cta-bar.is-shown { transform: none; }
  .cta-bar { transition: opacity .25s ease, visibility 0s linear .25s; }
  .cta-bar.is-shown { transition: opacity .25s ease, visibility 0s; }
}
.cta-bar__mark { position: absolute; top: 0; left: 0; width: 1px; height: 1px; pointer-events: none; }
/* Over the mustard final page the bar turns ink, so it still reads as the button there (owner, 2026-09-28; v2.js
   switches it as the end of the last section passes the middle of the bar). There a ring outside it would vanish into
   the mustard, so focus is drawn inside it. */
.cta-bar__mark--end { top: auto; bottom: 0; }
.cta-bar.is-over-end { background: var(--ink); color: var(--mustard); }
.cta-bar.is-over-end:hover, .cta-bar.is-over-end:active { background: #000; }
.cta-bar.is-over-end:focus-visible { outline-color: var(--mustard); outline-offset: -7px; }

/* ---------- Sections below the first screen: the first screen's night, its type and radii ---------- */

.wrap { width: 100%; max-width: var(--max); margin-inline: auto; padding-inline: var(--gutter); }
.section { padding-top: var(--space-section); }   /* the gap sits above each heading, never below the block before */

.section-head { margin-bottom: 32px; }
/* One word of each section's heading in mustard (owner, live 2026-09-28, option 2 of three shown), the way the slogan
   and the order count already are. */
.section-title__accent { color: var(--mustard); }
.section-title { font-family: var(--font-display); font-weight: 200; font-size: min(37px, 9.6vw); line-height: 1.08;
  letter-spacing: -.01em; text-wrap: balance; color: var(--on-night); }
.section-lead { margin-top: 12px; max-width: 34em; font-family: var(--font-sub); font-size: 20px; line-height: 1.6; color: var(--on-night-soft);
  text-wrap: pretty; }

/* Buttons: the hero's mustard action everywhere; a quiet white outline for the shop. The boxes window's «Zamów gotowe
   boxy» to the shop is mustard too (owner, live 2026-09-28; its words, decision 76): it stands where that window's request
   button used to be. */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 10px; min-height: 56px; padding: 0 28px;
  border: 1.5px solid transparent; border-radius: var(--radius); font-size: 18px; font-weight: 600; line-height: 1.2;
  text-decoration: none; cursor: pointer; transition: background-color .3s cubic-bezier(.2, .7, .2, 1),
  color .3s cubic-bezier(.2, .7, .2, 1); }
.btn--primary { background: var(--mustard); color: var(--ink); }
.btn--primary:hover { background: var(--mustard-hover); }
.btn--primary:active { background: var(--mustard-active); }
.btn--block { width: 100%; }
.btn[aria-disabled="true"] { cursor: progress; }
/* The shop's ready boxes (owner, live 2026-09-28): the same button as the request with the owner's doodle of a box, but
   drawn in outline instead of filled, so the request stays the first way out. The doodle is drawn once in a hidden sprite
   at the top of the page and shown here through <use>. */
.doodle-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.btn--boxy { background: transparent; border-color: currentColor; }
.btn__art { flex: none; width: 36px; height: auto; overflow: visible; stroke-width: 3.8; }

/* "O nas" (owner, 2026-09-27, variant 3 of three shown, after domarb.com.au/venue/monte): the first sheet over the first
   screen, one with the words that used to open it (owner, 2026-09-27: "a short slogan, then O nas"). It opens with the
   page's headline, one sentence in the brand's mustard; a hairline, then the heading and a short description. The sheet
   casts a soft shadow up onto the photo it covers. */
.about { box-shadow: 0 -22px 44px rgb(0 0 0 / .55); }
.about__slogan { max-width: 14em; font-family: var(--font-display); font-weight: 200; font-size: min(44px, 11vw); line-height: 1.06;
  letter-spacing: -.01em; color: var(--mustard); text-wrap: balance; }
.about .section-head { margin-top: 72px; }
.about__text { margin-top: 20px; max-width: 34em; font-family: var(--font-sub); font-size: 20px; line-height: 1.6;
  color: var(--on-night-soft); text-wrap: pretty; }

/* Black and white photographs lie under every chapter as a ground (owner, 2026-09-27, after nowa.restaurant: "black and
   white photos as a background where there is much text"; on 2026-09-28 the whole page, straight-on frames, variant B of
   two shown): one photograph per group of neighbouring chapters, scaled to the whole group (owner, 2026-09-28): the 18.11.2025 shoot
   under "O nas" from the headline to the order count, the branches by a white wall under the services and the occasions,
   the 18.11.2025 shoot again under the steps and the questions; the final page after them is mustard, without a photograph (owner, 2026-09-28). Dimmed to about a third and falling into the night at
   both ends, so the words keep their contrast; the food keeps its colour everywhere else. */
.about { --about-pad: 44px; padding-top: var(--about-pad); padding-bottom: 24px; }   /* the order facts' own air before the services (decision 116) */
.about__intro { position: relative; isolation: isolate; }
.about, .chapters { isolation: isolate; }
.ground { position: absolute; inset: 0; z-index: -1; overflow: hidden; pointer-events: none; }
/* The photo and its shade keep the height of the chapter with every row and question closed (v2.js sets --ground-h), so
   opening one lengthens the chapter without zooming the photo (owner, live 2026-09-28); below it the night goes on. */
.ground img { width: 100%; height: var(--ground-h, 100%); object-fit: cover; filter: grayscale(1) contrast(1.05) brightness(.36); }
.ground::after { content: ""; position: absolute; inset: 0 0 auto 0; height: var(--ground-h, 100%); background: linear-gradient(rgb(var(--night)) 0,
  rgb(var(--night) / .4) 18%, rgb(var(--night) / .5) 70%, rgb(var(--night)) 100%); }
/* A group taller than three screens (the services and the occasions since decision 108) keeps its photo one screen tall
   and holds it in place while the group scrolls over it (v2.js sets ground--held): stretched over the whole group it
   zoomed 3.4 to 14 times into flat grey (review, 2026-10-02). Its shade falls into the night at the group's two ends. */
.ground--held { overflow: clip; }   /* hidden would make it the scroll box the photo sticks to, so it would never hold */
.ground--held picture { position: sticky; top: 0; display: block; height: 100lvh; }
.ground--held img { height: 100%; }
.ground--held::after { height: 100%; background: linear-gradient(rgb(var(--night)) 0, rgb(var(--night) / .45) 6%,
  rgb(var(--night) / .5) 94%, rgb(var(--night)) 100%); }
/* Over a photograph the quiet tone would drop under 4.5:1 near a candle, so the steps' and the answers' words take the
   reading tone there. */
.process .step__body p, .faq .faq__answer p { color: var(--on-night-soft); }

/* The chapters zigzag (owner, 2026-09-27, variant 1 "zigzag" of two shown, so the words do not all stand on one side):
   the slogan and the "O nas" words both start on the left (owner, live 397237b7 2026-09-28; they answered from the right
   before); "Co oferujemy" turns right, the occasions
   return left, the steps turn right again, and the questions put their heading on the right. On a phone only the
   headings and the short leads turn; the reading text always starts on the left. */
.about .section-head, .about__text { width: min(86%, 36rem); }
.formats .section-head, .process .section-head, .faq .section-head { text-align: right; }
/* The services' lead runs several lines, so it reads from the left while its block stays on the right (decision 78). */
.formats .section-lead { margin-left: auto; text-align: left; }

/* The description ends on a fact from the order books (owner, 2026-09-27, after gusto.com): "Ponad 1500 realizacji", the
   owner's words, with the count in mustard, and around it photos of real orders pop up one by one, drift up a little and
   go, like prints passed across a table. Six places take turns (top left, bottom right, top middle, bottom left, top
   right, bottom middle), so the three or four pictures on screen at a time never cover one another or the words. The
   round plays only while it is in view (v2.js); with reduced motion the first six simply lie in their places. On a phone
   the pictures keep to a band above and below the words, from 700px they stand around them.
   Three facts take turns in that place (owner, live 3319e84d 2026-09-28, variant "the drum" of three shown): "Ponad 1500
   zrealizowanych zamówień" (the owner's rewording of "Ponad 1500 realizacji", the same day), "Ponad 150 firm nam zaufało" (152 companies by NIP in the invoicing program's client base, owner's choice) and
   "Zrobiliśmy ponad 40 000 przekąsek" (47 598 pieces in the owner's summary for June 2023 to May 2025 alone), one every
   4.4 seconds, so each gets four of the photos. They roll like a drum: every fact fills the whole window, the old one
   leaves by exactly its height while the next comes up right under it, and the old one is gone before the next shows
   (owner: the previous phrase showed while it turned). The words are
   smaller than the single fact was: a tenth, then another tenth (owner: "чуточку уменьши"; live 6fd7ccb9, the knob at
   its 10%), and from 700px the block is a little taller, so the
   fact on three lines clears the photos. The drum stops with the photos off screen; under the pointer both keep going
   (owner, live 2026-09-28: the animation runs all the time); with reduced motion the facts only cross-fade. */
.about__stat { container-type: inline-size; margin-top: 60px; }   /* air under the words (owner, live 2026-09-28; 60px since decision 116) */
.stat { position: relative; display: grid; place-items: center; height: min(140cqi, 600px); }
.stat__facts { position: relative; z-index: 1; display: grid; margin: 0; padding: 10px 0; list-style: none; overflow: clip;
  mask-image: linear-gradient(transparent, #000 10px, #000 calc(100% - 10px), transparent); }
/* min-width: the longest word ("zrealizowanych") widens the column instead of running out of it to the right */
.stat__fact { grid-area: 1 / 1; display: grid; place-items: center; min-width: min-content; max-width: 9.5em; font-family: var(--font-display);
  font-weight: 200; font-size: min(13.05cqi, 52.2px); line-height: 1.02; letter-spacing: -.005em; text-align: center;
  text-wrap: balance; color: var(--on-night); animation: stat-fact-roll 13.2s linear infinite both; }
.stat__fact:nth-child(2) { animation-delay: -8.8s; }
.stat__fact:nth-child(3) { animation-delay: -4.4s; }
/* Below 700px the longest word still fits as set, but enlarged text spacing (WCAG 1.4.12) can make it wider than the
   block and push the page sideways; there a word may break instead, never a number (decision 88). From 700px the facts
   are 6em wide and keep their words whole, so «ponad 40 000» stays in one piece. */
@media (max-width: 699.98px) { .stat__fact { overflow-wrap: anywhere; } .stat__num { white-space: nowrap; } }
.stat__num { color: var(--mustard); }
.stat__photos { list-style: none; position: absolute; inset: 0; margin: 0; padding: 0; }
.stat__photo { --w: min(26cqi, 132px); position: absolute; left: var(--x); top: var(--y); width: var(--w); aspect-ratio: 4 / 5;
  overflow: hidden; border-radius: 4px; background: rgb(255 255 255 / .06); box-shadow: 0 10px 24px rgb(0 0 0 / .45);
  opacity: 0; animation: stat-pop 13.2s infinite both; }
.stat__photo:nth-child(3n) { --w: min(36cqi, 183px); aspect-ratio: 3 / 2; }
.stat__photo img { width: 100%; height: 100%; object-fit: cover; }
.stat__photo:nth-child(9) img { object-position: 50% 72%; }
.stat.is-paused :is(.stat__photo, .stat__fact) { animation-play-state: paused; }
/* A print shows only once its picture has come (v2.js sets is-in, decision 93): a slow connection never pops an empty
   frame. */
.stat__photo:not(.is-in) { visibility: hidden; }
.stat__photo:nth-child(6n + 1) { --x: 0%; --y: 4%; --r: -2deg; }
.stat__photo:nth-child(6n + 2) { --x: calc(98% - var(--w)); --y: 72%; --r: 2deg; }
.stat__photo:nth-child(6n + 3) { --x: calc(50% - var(--w) / 2); --y: 13%; --r: 1.5deg; }
.stat__photo:nth-child(6n + 4) { --x: 2%; --y: 70%; --r: 1.5deg; }
.stat__photo:nth-child(6n + 5) { --x: calc(100% - var(--w)); --y: 0%; --r: 2.5deg; }
.stat__photo:nth-child(6n + 6) { --x: calc(50% - var(--w) / 2); --y: 76%; --r: -1.5deg; }
.stat__photo:nth-child(2) { animation-delay: 1.1s; }
.stat__photo:nth-child(3) { animation-delay: 2.2s; }
.stat__photo:nth-child(4) { animation-delay: 3.3s; }
.stat__photo:nth-child(5) { animation-delay: 4.4s; }
.stat__photo:nth-child(6) { animation-delay: 5.5s; }
.stat__photo:nth-child(7) { animation-delay: 6.6s; --y: 7%; --r: 1.5deg; }
.stat__photo:nth-child(8) { animation-delay: 7.7s; --y: 69%; --r: -1.5deg; }
.stat__photo:nth-child(9) { animation-delay: 8.8s; --y: 10%; --r: -1deg; }
.stat__photo:nth-child(10) { animation-delay: 9.9s; --y: 73%; --r: -2deg; }
.stat__photo:nth-child(11) { animation-delay: 11s; --y: 2%; --r: -2deg; }
.stat__photo:nth-child(12) { animation-delay: 12.1s; --y: 74%; --r: 2deg; }
@keyframes stat-pop {
  0% { opacity: 0; transform: translateY(16px) scale(.84) rotate(var(--r)); animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  4% { opacity: 1; transform: translateY(9px) scale(1) rotate(var(--r)); animation-timing-function: linear; }
  24% { opacity: 1; transform: translateY(-9px) scale(1) rotate(var(--r)); animation-timing-function: cubic-bezier(.55, 0, 1, .45); }
  29%, 100% { opacity: 0; transform: translateY(-18px) scale(.97) rotate(var(--r)); }
}
@keyframes stat-fact-roll {   /* the old fact dissolves in the first half of the turn, the next appears in the second */
  0%, 26.667% { transform: none; opacity: 1; animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  30% { opacity: 0; }
  33.333% { transform: translateY(calc(-100% - 12px)); opacity: 0; animation-timing-function: steps(1, end); }
  93.333% { transform: translateY(calc(100% + 12px)); opacity: 0; animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
  96.667% { opacity: 0; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  100% { transform: none; opacity: 1; }
}
@keyframes stat-fact-fade {   /* with reduced motion: the old fact fades out first, then the next fades in */
  0%, 26.667% { opacity: 1; animation-timing-function: ease-in; }
  30% { opacity: 0; animation-timing-function: steps(1, end); }
  96.667% { opacity: 0; animation-timing-function: ease-out; }
  100% { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .stat__photo { animation: none; opacity: 1; transform: rotate(var(--r)); }
  .stat__photo:nth-child(n + 7) { display: none; }
  .stat__fact { animation-name: stat-fact-fade; }
}

/* Services as five open blocks, after marquet.nyc's menu (owner, 2026-10-02, decision 108: «возьмем идею анимаций и
   представления этих 2 секций и заменим наши»; one big photo each, the owner's pick of three shown). Each service is a
   chapter of its own: its name in the page's largest thin type, its words and its button under it, and one tall photo,
   the first of the three the owner chose for it, beside the words from 1024px and above them on a phone. No numbers:
   the list has no order to tell (decision 78). It replaced the index that opened in place (live 66caa7da, 2026-09-28). */
.formats__list { display: grid; gap: clamp(88px, 22vw, 176px); margin: 48px 0 0; padding: 0; list-style: none; }
.formats__item { display: grid; gap: 28px; }
.formats__photo { width: min(82%, 420px); aspect-ratio: 4 / 5; overflow: clip; border-radius: 12px;
  background: rgb(255 255 255 / .06); }
.formats__photo img { display: block; width: 100%; height: 100%; object-fit: cover; }
.formats__words { view-timeline: --words block; }
.formats__name { font-family: var(--font-display); font-weight: 200; font-size: calc(.9 * clamp(44px, 12vw, 104px));
  line-height: 1; letter-spacing: -.01em; color: var(--mustard); text-wrap: balance; }
/* Each word sits in its own line box, so it can rise out of it (the box is shared with the chapters' headings, in the
   arrivals block below). */
.formats__text { margin-top: 22px; }
.formats__text p { max-width: 34em; font-size: 17px; line-height: 1.6; color: var(--on-night-soft); }
.formats__text p + p { margin-top: 10px; }
.formats__cta { margin: 26px 0 0; }
/* The names in the page's mustard, their buttons quiet and the type a touch smaller (owner, 2026-10-02, decision 111:
   the second of three live variants, with the owner's knobs: names 0.9, descriptions 16.5px and 0.9 of the name).
   The button keeps its words and place and loses its fill: a hairline of Heading Ivory at 60% (decision 112: 4.4 to
   5.7:1 against the ground), mustard under the pointer. From 700px each description is nine tenths as wide as its
   name's longest line, which v2.js measures (--name-w; a wrapped name's box is as wide as its column); without the
   script it keeps 34em. */
.formats__cta .btn { min-height: 46px; padding: 0 22px; border: 1px solid rgb(243 236 225 / .6);
  background: transparent; color: var(--on-night); font-size: 16px; font-weight: 500; }
.formats__cta .btn { transition-property: background-color, color, border-color; }   /* line and words turn together */
.formats__cta .btn:hover { border-color: var(--mustard); color: var(--mustard); }
@media (min-width: 700px) {
  .formats__text { max-width: calc(var(--name-w, 37.78em) * .9); }
  .formats__text p { max-width: none; }
}
@media (min-width: 700px) { .formats__photo { width: min(60%, 460px); } }
@media (min-width: 1024px) {
  .formats__list { margin-top: 72px; }
  .formats__item { grid-template-columns: minmax(0, 7fr) minmax(0, 4fr); column-gap: clamp(48px, 6vw, 96px);
    align-items: center; }
  .formats__photo { grid-column: 2; grid-row: 1; width: 100%; }
  .formats__words { grid-column: 1; grid-row: 1; }
}
/* The name holds, as on marquet.nyc (owner, 2026-10-02, decision 109: the second of three live variants, taken with
   its knobs as the owner set them), and the services follow one another close up (decision 110: «Встык», the second
   of three spacing variants, with both of the owner's knobs at the top of their range). From 700px wide on a screen at
   least 600px tall each service is a stretch of 2.3 screens, the 0.4 of a screen after it included (a screen is the
   height under the header): its words, only as tall as they are, stand under the header for a little over a screen
   while its photo, half the row on a tablet and 24/55 of it from 1024px, comes up from the foot of the screen, past
   them and out at the top; the next name comes about half a screen under the last button. The name is capped at
   12svh. All of it waits for the list's .is-held, which v2.js sets only on a small viewport at least 600px tall and
   while every service's held words end above its foot and clear of the floating bar (on 700x600 and 1024x600 the
   second service's would not); smaller or lower screens, a page without the script and paper keep the flow above. */
@media screen and (min-width: 700px) {
  .formats__list.is-held { gap: 0; }
  .is-held .formats__item { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: clamp(32px, 5vw, 96px);
    row-gap: 0; align-items: start; min-height: calc(2.3 * (100svh - var(--header-h)));
    padding-bottom: calc(.4 * (100svh - var(--header-h))); }
  .is-held .formats__words { grid-column: 1; grid-row: 1; position: sticky; top: var(--header-h); display: flex;
    flex-direction: column; padding-top: 9svh; }
  .is-held .formats__photo { grid-column: 2; grid-row: 1; width: 100%; align-self: center; }
  .is-held .formats__name { font-size: calc(.9 * min(clamp(40px, 7.2vw, 76px), 12svh)); }
}
@media screen and (min-width: 1024px) {
  .is-held .formats__item { grid-template-columns: minmax(0, 31fr) minmax(0, 24fr);
    column-gap: clamp(48px, 6vw, 96px); }
  .is-held .formats__name { font-size: calc(.9 * min(clamp(44px, 12vw, 104px), 12svh)); }
}
/* The motion, after marquet.nyc: the words of a name rise out of their lines one after another as the words come up the
   screen, and the text comes out of the page's haze after them (the button stands sharp: the page's action never comes
   out of a haze, and axe read its first frames as 1.07:1); the photo is uncovered from below, then
   climbs past the words a little faster than the page while it settles from a slight zoom. Scroll-driven CSS where the
   browser has it; elsewhere v2-motion.js gives each block the page's quiet entrance, and with reduced motion, in print
   or under keyboard focus everything simply stands. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .formats__name .w > span { animation: svc-word linear both; animation-timeline: --words;
      animation-range: entry calc(var(--i, 0) * 8%) entry calc(55% + var(--i, 0) * 8%); }
    .formats__name .w:nth-child(2) > span { --i: 1; }
    .formats__name .w:nth-child(3) > span { --i: 2; }
    .formats__name .w:nth-child(4) > span { --i: 3; }
    .formats__name .w:nth-child(n + 5) > span { --i: 4; }
    .formats__text { animation: arrive-haze linear both; animation-timeline: view();
      animation-range: entry 0% entry 100%; animation-range: entry 0% entry min(100%, 240px); }
    .formats__photo { animation: svc-uncover linear both, svc-climb linear both; animation-timeline: view(), view();
      animation-range: entry 0% entry 75%, cover 0% cover 100%; }
    .formats__photo img { animation: svc-settle linear both; animation-timeline: view(); animation-range: entry 0% cover 55%; }
    .formats__item:focus-within :is(.formats__name .w > span, .formats__text, .formats__photo, .formats__photo img) {
      animation: none; }
  }
  /* While the name holds (above), the photo trails the page a little instead of climbing past the words (decision
     109). */
  @media screen and (prefers-reduced-motion: no-preference) and (min-width: 700px) {
    .is-held .formats__photo { animation: svc-uncover linear both, svc-drift linear both;
      animation-timeline: view(), view();
      animation-range: entry 0% entry 75%, cover 0% cover 100%; }
  }
}
@keyframes svc-drift { from { translate: 0 -5%; } to { translate: 0 5%; } }
@keyframes svc-word { from { translate: 0 105%; } }
@keyframes svc-uncover { from { clip-path: inset(100% 0 0 0 round 12px); } to { clip-path: inset(0 round 12px); } }
@keyframes svc-climb { from { translate: 0 12%; } to { translate: 0 -12%; } }
@keyframes svc-settle { from { scale: 1.2; } to { scale: 1; } }
@media (min-width: 1024px) { @keyframes svc-climb { from { translate: 0 22%; } to { translate: 0 -22%; } } }
.icon--close { width: 14px; height: 14px; }

/* The quote window comes in and goes out softly. */
@media (prefers-reduced-motion: no-preference) {
  .quote-dialog, .quote-dialog::backdrop { transition: opacity .28s ease,
    translate .32s cubic-bezier(.2, .7, .2, 1), display .32s allow-discrete, overlay .32s allow-discrete; }
  .quote-dialog:not([open]) { opacity: 0; translate: 0 16px; }
  .quote-dialog:not([open])::backdrop { opacity: 0; }
  @starting-style { .quote-dialog[open] { opacity: 0; translate: 0 16px; }
    .quote-dialog[open]::backdrop { opacity: 0; } }
}


/* Occasions as a strip that runs sideways while the screen holds, after marquet.nyc's events (owner, 2026-10-02,
   decision 108). The six real tables stand in one row of tall photos; while the page scrolls, the row is pinned under
   the header and slides to the left, and the name of the occasion in view stands large under it, beside six marks for
   how far along the row is (both from v2.js, which also keeps a focused photo in view and names a photo under the
   pointer). Each photo still opens the quote window with its occasion marked. It replaced the wall of frames (live
   5962c7c6 and 375fac00, 2026-09-28). The row slides on scroll-driven CSS where the browser has it and from the scroll
   position in v2.js elsewhere. With reduced motion, on a screen under 520px high, where all six photos fit side by side
   anyway, or with no script, it is a strip to swipe with the names on the photos. Two photos stay mirrored (owner, live
   effb3f9f, 2026-09-28). */
.occasions__stage { --occ-fs: clamp(30px, 8vw, 64px); margin-top: 40px; }   /* the occasion name's size */
/* A photo keeps within the screen under the header where it can, so a phone on its side shows it whole, but is never
   narrower than 160px, so its name still fits on a page zoomed to 300-400% (re-review, 2026-10-02); there the width
   wins and the photo runs a little past the screen's foot. A row narrower than the screen stands in its middle. */
.occasions__list { --w: max(160px, min(72vw, calc((100svh - var(--header-h) - 40px) * .8))); --g: 14px; display: flex; gap: var(--g);
  justify-content: flex-start; justify-content: safe center; margin: 0; padding: 0 var(--gutter);
  list-style: none; overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--gutter); scrollbar-width: none; }
.occasions__list::-webkit-scrollbar { display: none; }
.occasions__item { flex: none; width: var(--w); scroll-snap-align: start; }
.occasion { position: relative; isolation: isolate; display: flex; align-items: flex-end; aspect-ratio: 4 / 5; overflow: clip;
  border-radius: 12px; background: rgb(255 255 255 / .06); color: var(--on-night); text-decoration: none; }
.occasion__photo { position: absolute; inset: 0; z-index: -2; }
.occasion__photo img { width: 100%; height: 100%; object-fit: cover; transition: scale .6s cubic-bezier(.19, 1, .22, 1); }
.occasion::after { content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(transparent 30%, rgb(14 11 10 / .5) 58%, rgb(14 11 10 / .88)); }
.occasion__name { padding: 14px 16px; font-family: var(--font-display); font-weight: 300; font-size: 19px; line-height: 1.15;
  text-wrap: balance; transition: color .3s cubic-bezier(.2, .7, .2, 1); }
.occasion:is(:hover, :focus-visible) .occasion__name { color: var(--mustard); }
/* Only a photo with no readable text in frame is mirrored; transform rather than scale, so the zoom on hover keeps it. */
.occasion__photo--mirrored img { transform: scaleX(-1); }
@media (hover: hover) { .occasion:hover .occasion__photo img { scale: 1.05; } }
.occasions__bar { display: none; }
@media (min-width: 1024px) {
  .occasions__list { --w: min(30vw, 432px, calc((100svh - var(--header-h) - 40px) * .8)); --g: 24px; }
  .occasion__name { padding: 22px 24px; font-size: 26px; }
}

/* Pinned (html.occ-pin, set by v2.js when motion is welcome, the screen is at least 520px high and the row is wider than
   the screen): the stage is as tall as the screen plus the row's travel,
   the row stands in a sticky frame under the header and moves by that travel while the frame holds. A photo is sized so
   that it and the name under it fit the screen. */
/* Widths come from the section's own width (a container), so a classic scrollbar does not shorten the row's last gap;
   a photo is at most 400px wide (432px from 1024px), as far as its 800px file stays sharp (review, 2026-10-02). */
.occasions { container-type: inline-size; }
.occ-pin .occasions__stage { --w: min(72cqw, 400px, calc((100svh - var(--header-h) - 250px) * .8)); --g: 14px;
  --travel: max(0px, calc(6 * var(--w) + 5 * var(--g) + 2 * var(--gutter) - 100cqw));
  height: calc(100svh - var(--header-h) + var(--travel)); margin-top: 24px;
  view-timeline: --occ block; view-timeline-inset: var(--header-h) 0; }
/* As the run ends, the next chapter slides up over the frame's free foot to 12px under the occasion's name (owner,
   2026-10-02, decision 115, variant B of three shown: «B - супер»), so «Jak to działa» stands about as far from the
   strip as «Pytania» from the steps (the «symmetric» rule below), where the frame's empty lower part used to leave a
   pause of 200-245px. The foot is worked out from the frame's own parts: the row of photos (--w at 4:5), the 22px gap,
   the name's bar (--occ-bar: the marks over two lines of the name on a phone, the name beside them from 700px, one line
   on a low screen on its side) and the 68px kept for the floating button, all centred in the screen under the header.
   The stage's negative bottom margin stays inside the occasions section (its inline-size container makes it a
   formatting context of its own), so the section, and with it the chapter, ends that much earlier and the steps'
   chapter starts over the frame's free foot; no gap opens between the chapters. It never rises by more than the row's
   travel, and only on screen: printed, the strip stands loose and the steps follow it. */
.occ-pin .occasions__stage { --occ-bar: calc(16px + 2.1 * var(--occ-fs));
  --occ-free: calc((100svh - var(--header-h) + 68px + env(safe-area-inset-bottom, 0px) - 1.25 * var(--w) - 22px
    - var(--occ-bar)) / 2); }
@media screen {
  .occ-pin .occasions__stage { margin-bottom: calc(-1 * clamp(0px, var(--occ-free) - 12px, var(--travel))); }
}
/* The frame's foot is kept free for the page's floating button, so the row and its name centre above it. */
.occ-pin .occasions__pin { position: sticky; top: var(--header-h); height: calc(100svh - var(--header-h)); overflow: clip;
  display: flex; flex-direction: column; justify-content: center; gap: 22px;
  padding-bottom: calc(68px + env(safe-area-inset-bottom)); }
.occ-pin .occasions__list { --w: inherit; --g: inherit; flex: none; width: max-content; overflow: visible;
  scroll-snap-type: none; translate: calc(var(--occ-p, 0) * -1 * var(--travel)) 0; }
.occ-pin .occasion::after { content: none; }
.occ-pin .occasion__name { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip-path: inset(50%);
  white-space: nowrap; }
/* On a phone the marks stand over the name, so a long name keeps the whole width; from 700px they stand beside it. */
.occ-pin .occasions__bar { display: grid; gap: 14px; padding: 0 var(--gutter); }
.occasions__dots { justify-self: end; order: -1; }
.occasions__now { min-height: 2.1em; max-width: 13em; margin: 0; font-family: var(--font-display); font-weight: 200;
  font-size: var(--occ-fs); line-height: 1.05; color: var(--on-night); text-wrap: balance; }
.occasions__now.is-changing { animation: occ-name .45s cubic-bezier(.2, .7, .2, 1); }
.occasions__dots { display: flex; flex: none; gap: 6px; }
.occasions__dots span { width: 20px; height: 2px; background: var(--rule); transition: background-color .3s ease; }
.occasions__dots span.is-on { background: var(--on-night); }
@keyframes occ-name { from { opacity: 0; translate: 0 .35em; } }
@supports (animation-timeline: view()) {
  .occ-pin .occasions__list { animation: occ-slide linear both; animation-timeline: --occ;
    animation-range: contain 0% contain 100%; }
  /* Inside its frame each photo drifts a little against the row, as the photos in marquet.nyc's row do. */
  .occ-pin .occasion__photo { scale: 1.08; animation: occ-drift linear both; animation-timeline: --occ;
    animation-range: contain 0% contain 100%; }
}
@keyframes occ-slide { from { translate: 0 0; } to { translate: calc(-1 * var(--travel)) 0; } }
@keyframes occ-drift { from { translate: 3.5% 0; } to { translate: -3.5% 0; } }
@media (min-width: 700px) {
  .occ-pin .occasions__stage { --occ-bar: calc(2.1 * var(--occ-fs)); }
  .occ-pin .occasions__bar { grid-template-columns: minmax(0, 1fr) auto; align-items: start; gap: 24px; }
  .occasions__dots { order: 2; padding-top: .9em; }
}
@media (min-width: 1024px) {
  .occ-pin .occasions__stage { --w: min(30cqw, 432px, calc((100svh - var(--header-h) - 290px) * .8)); --g: 24px; }
}
/* A low screen on its side keeps the photo larger and the name on one line. */
@media (min-aspect-ratio: 1/1) and (max-height: 560px) {
  .occasions__stage { --occ-fs: 26px; }
  .occ-pin .occasions__stage { --w: calc((100svh - var(--header-h) - 150px) * .8); --occ-bar: calc(16px + 1.1 * var(--occ-fs)); }
  .occasions__now { min-height: 1.1em; max-width: none; }
}
@media (min-aspect-ratio: 1/1) and (max-height: 560px) and (min-width: 700px) {
  .occ-pin .occasions__stage { --occ-bar: calc(1.1 * var(--occ-fs)); }
}
/* Each photo develops from black and white into colour (owner, live 375fac00, 2026-09-28): on the strip as it comes
   up the screen, on the pinned row as the stage rises into view. A change of colour rather than movement, so it stays
   with reduced motion; where the browser has no scroll-driven animations the photos simply keep their colour. */
@supports (animation-timeline: view()) {
  .occasion__photo img { animation: occasion-develop linear both; animation-timeline: view(); animation-range: cover 0% cover 30vh; }
  .occ-pin .occasion__photo img { animation-timeline: --occ; animation-range: entry 0% entry 100%; }
}
@keyframes occasion-develop { from { filter: grayscale(1); } to { filter: grayscale(0); } }
@media (prefers-reduced-motion: reduce) {
  .occasion__photo img { transition: none; }
  .occasion:hover .occasion__photo img { scale: none; }
}
/* The questions end the page's words: their own gap before the footer, now that no button follows them (owner, 2026-09-28). */
.faq { padding-bottom: var(--space-section); }
/* No seam above "Na jaką okazję?", "Jak to działa" and "Pytania" (owner, live 47dceb48, fbe0cd65 and 77689958, 2026-09-28:
   "symmetric"): each heading takes the seam's place (29px above it, plus its 1px), so all three stand equally far from
   what comes before them. The steps no longer follow the occasions at half the distance (that rule of 2026-09-27 is
   lifted by the same request). */
.occasions, .process, .faq { padding-top: calc(var(--space-section) - 30px); }
:is(.occasions, .process, .faq) .section-head::before { content: none; }

/* How it works: three numbered steps and the action. */
.steps { list-style: none; display: grid; gap: 20px; }
.step { position: relative; display: grid; grid-template-columns: 40px 1fr; align-content: start; column-gap: 14px;
  padding-top: 16px; }
/* the hairline over a step, a line of its own so it can draw itself as the step arrives (decision 113, below) */
.step::before { content: ""; position: absolute; top: 0; left: 0; right: 0; border-top: 1px solid var(--rule);
  transform-origin: left; }
.step__num { font-family: var(--font-display); font-weight: 200; font-size: 32px; line-height: 1; letter-spacing: 0;
  color: var(--on-night-soft); }
.step__title { font-family: var(--font-display); font-weight: 300; font-size: 23px; line-height: 1.25; letter-spacing: 0;
  text-wrap: balance; color: var(--on-night); }
.step__body p { margin-top: 6px; font-size: 17px; line-height: 1.6; color: var(--on-night-quiet); }

/* The quote form lives in a window over the page (owner, 2026-09-26): every "Poproś o wycenę" and every occasion tag
   opens it, a tag marking its occasion. A sheet over the whole screen on phones, a column in the middle of the screen
   from 700px. Since 2026-09-28 the whole window fits one phone screen (owner: no scrolling on a phone); on a screen
   shorter still it scrolls in itself and its close button stays at hand. */
.quote-dialog { width: 100vw; max-width: 100vw; height: 100dvh; max-height: 100dvh; margin: 0; padding: 0; border: 0;
  background: rgb(var(--night)); color: var(--on-night); overflow-y: auto; overscroll-behavior: contain; }
.quote-dialog::backdrop { background: rgb(var(--night)); }
.quote-dialog { scroll-padding-block: 24px; }   /* the phone's sheet covers the page: no blur to pay for */
/* A bar of no height, stuck to the window's top: the close button rides over the form as it scrolls. */
.quote-dialog__bar { position: sticky; top: 0; z-index: 2; display: flex; justify-content: flex-end; height: 0; }
/* A quiet disc with an ivory cross (owner, 2026-09-28, the calm window): the night's own tone inside a thin ivory ring,
   so it stays clear as it rides down over the fields; under the pointer the ring and the cross turn mustard. */
.quote-dialog__close { display: grid; place-items: center; width: 44px; height: 44px; margin: 10px 10px 0 0; padding: 0;
  border: 0; border-radius: 50%; background: rgb(var(--night)); box-shadow: inset 0 0 0 1px rgb(243 236 225 / .32);
  color: var(--on-night); cursor: pointer; transition: box-shadow .3s cubic-bezier(.2, .7, .2, 1), color .3s cubic-bezier(.2, .7, .2, 1); }
.quote-dialog__close:focus-visible { outline: 2px solid var(--mustard); outline-offset: 2px; }
.quote-dialog__close:hover { box-shadow: inset 0 0 0 1.5px var(--mustard); color: var(--mustard); }
.quote-dialog__body { min-height: 100%; padding: 11px var(--gutter) calc(12px + env(safe-area-inset-bottom)); }   /* fills the sheet, so a tap inside never reads as outside */
/* A calm head (owner, 2026-09-28, variant 3 "soft fields" of three shown, after the mustard head of 2026-09-27): the
   title and the promise in ivory on the night, clear of the close disc on the right. The promise is one sentence
   ("Wycena jest bezpłatna i do niczego nie zobowiązuje" left, owner). */
.quote__head { position: relative; margin: 0 0 16px; padding: 4px 52px 0 0; }
.quote__head .section-title { color: var(--on-night); font-size: 30px; line-height: 1.08; }
/* The owner's doodle of a clock stands under the close disc, in the column kept for it, beside the promise of an answer
   in 24 hours (owner, 2026-09-28); like the envelope on the send button it stays still. Neither adds height. */
.quote__art { position: absolute; right: 4px; bottom: 0; width: 40px; height: 40px; color: var(--on-night-soft);
  pointer-events: none; }
.quote__art path, .quote__send-art path { vector-effect: non-scaling-stroke; stroke-width: 1.5px; }
.quote__send-art { flex: none; width: 36px; height: 21px; }
.quote__send-art path { stroke-width: 1.6px; }
.quote__head .section-lead { margin-top: 8px; font-size: 15px; line-height: 1.45; color: var(--on-night-soft); }
/* The phone field is optional (owner, 2026-09-27), so the number to call stands under the promise; its tap area
   reaches past the line of text. */
.quote__call { margin-top: 4px; font-size: 15px; line-height: 1.4; color: var(--on-night-soft); }
.quote__call a { display: inline-block; margin: -10px 0; padding: 10px 0; color: var(--on-night); font-weight: 600;
  white-space: nowrap; text-decoration: underline; text-decoration-color: var(--mustard); text-decoration-thickness: 1.5px;
  text-underline-offset: 4px; }
/* The shop's path for a smaller meeting (owner, live 2026-09-28; a line of text before): «lub» between two hairlines,
   then the box button in mustard outline under the request. */
.quote__or { display: flex; align-items: center; gap: 12px; margin: 0; font-size: 13px; line-height: 1;
  color: var(--on-night-quiet); }
.quote__or::before, .quote__or::after { content: ""; flex: 1; height: 1px; background: var(--rule); }
.quote__boxy { color: var(--mustard); font-size: 17px; }   /* as tall and as round as the request above it */
/* Turnstile shows its box above the button only when Cloudflare wants the visitor's tick (interaction-only); a press of
   the button before the tick says so here, under the box. */
.quote__turnstile-ask { margin: 8px 0 0; font-size: 14px; line-height: 1.4; color: var(--on-night); }
.quote__boxy:hover { background: rgb(245 207 118 / .1); }
/* The form as soft fields (owner, 2026-09-28, variant 3 "soft fields" of three shown; before it the ruled sheet of the
   same day and the line with chips of 2026-09-27): each field a softly lit tile with its label small above the typed
   words, the short fields in pairs. The fields stay empty until typed in (owner): no sample words, and an empty date or
   time keeps its format out of sight. The occasion is a list, since chips are awkward on a phone (owner), and the
   phone has a row of its own under it. The hint of the field being filled shows in one line under the tiles (v2.js;
   each hint also stays tied to its field for screen readers). The tile being filled lights up with a mustard line
   along its foot and takes the error colour on a mistake; the message grows with its text. When one label of a pair
   runs to two lines, both labels still start at the top and the typed words of both sit on one line. */
.quote__form { display: block; }
.sheet { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px;
  --cell-x: 14px; --cell-top: 9px; --cell-bottom: 10px; --input-top: 2px; }
/* The tile's room belongs to its label and its field, so a tap anywhere on the tile lands in the field. */
.sheet__cell { grid-column: 1 / -1; display: flex; flex-direction: column; min-width: 0;
  margin: 0; padding: 0; border: 0; border-radius: 12px; background: var(--field-fill);
  transition: background-color .15s ease, box-shadow .15s ease; }
.sheet__cell--half { grid-column: auto; }
@media (hover: hover) { .sheet__cell:hover { background: rgb(255 255 255 / .09); } }
.sheet__cell:focus-within { background: rgb(255 255 255 / .1); box-shadow: inset 0 -2px 0 var(--mustard); }
.sheet__cell:has([aria-invalid="true"]) { box-shadow: inset 0 0 0 1.5px var(--error); }
.sheet__cell label { flex: 1 0 auto; display: block; padding: var(--cell-top) var(--cell-x) 0; font-size: 12.5px; font-weight: 500;
  line-height: 1.25; letter-spacing: .01em; color: var(--on-night-soft); transition: color .15s ease; }
.sheet__cell:focus-within > label { color: var(--mustard); }
.sheet__cell :is(input, textarea, select) { width: 100%; min-height: 0; margin: 0;
  padding: var(--input-top) var(--cell-x) var(--cell-bottom); border: 0; border-radius: 0; background: transparent;
  color: var(--on-night); font-size: 17px; line-height: 1.35; }
.sheet__cell :is(input, textarea, select):focus-visible { outline: none; }
/* A Windows contrast theme (forced colours) drops the backgrounds and shadows that mark the tiles and the focus, so the
   tiles carry transparent outlines: invisible here, drawn in the system colour there, the focused one 3px in Highlight;
   the close disc gets an edge too (audit 2026-09-30, decision 95). */
.sheet__cell { outline: 1px solid transparent; outline-offset: -1px; }
.sheet__cell:focus-within { outline: 3px solid transparent; outline-offset: 0; }
@media (forced-colors: active) {
  .sheet__cell:focus-within { outline-color: Highlight; }
  .quote-dialog__close { border: 1px solid CanvasText; }
  .cta-bar__art { color: inherit; }   /* the floating button's doodle takes its words' system colour, not mustard */
}
.sheet__cell textarea { resize: none; field-sizing: content; max-height: calc(4lh + var(--input-top) + var(--cell-bottom)); }
@supports not (field-sizing: content) {
  .sheet__cell textarea { min-height: calc(2lh + var(--input-top) + var(--cell-bottom)); } }
/* A date or an hour is as tall as a typed line (an empty one would shrink in Safari) and keeps its words on the left;
   the format of an empty one ("dd.mm.rrrr", "--:--") shows only while it is being filled (v2.js marks it empty). */
.sheet__cell input:is([type="date"], [type="time"]) { height: calc(1lh + var(--input-top) + var(--cell-bottom)); }
.sheet__cell input::-webkit-date-and-time-value { text-align: left; }
.sheet__cell input[data-empty]:not(:focus) { color: transparent; }
/* The list keeps the phone's own picker; a small chevron says it opens. */
.sheet__cell select { -webkit-appearance: none; appearance: none; padding-right: calc(var(--cell-x) + 24px); cursor: pointer;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5l5 5 5-5' fill='none' stroke='%23E3D9CB' stroke-width='1.6'/%3E%3C/svg%3E") no-repeat right var(--cell-x) center; }
.sheet__cell select option { background: #1e1a18; color: var(--on-night); }
/* The occasion list in the page's colours (owner, live 2026-09-28, option 1 of three shown): where the browser can style
   a list (a customizable select), it opens as a dark rounded panel with the chosen occasion in mustard; elsewhere the
   phone's own picker stays. The empty choice is not listed: the field is optional and starts empty. */
@supports (appearance: base-select) {
  .sheet__cell select, .sheet__cell select::picker(select) { appearance: base-select; }
  .sheet__cell select::picker-icon { display: none; }
  .sheet__cell select::picker(select) { margin-block: 6px; padding: 6px; border: 1px solid rgb(243 236 225 / .16);
    border-radius: 14px; background: #1a1411; box-shadow: 0 22px 48px rgb(0 0 0 / .55); }
  .sheet__cell select option { display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 10px 12px;
    border-radius: 10px; background: transparent; color: var(--on-night); font-size: 16px; line-height: 1.3; }
  .sheet__cell select option:hover, .sheet__cell select option:focus-visible { background: rgb(245 207 118 / .12); outline: none; }
  .sheet__cell select option:checked { color: var(--mustard); font-weight: 500; }
  .sheet__cell select option::checkmark { color: var(--mustard); }
  .sheet__cell select option[value=""] { display: none; }
}
/* An occasion card on the page picks its occasion in the list, and the list's tile glows once. */
.sheet__cell[data-field="occasion"] { transition: background-color .15s ease, box-shadow .9s ease; }
.sheet__cell[data-field="occasion"].is-picked { box-shadow: inset 0 0 0 1.5px var(--mustard), 0 0 0 5px rgb(245 207 118 / .3);
  transition-duration: .15s, .25s; }
.sheet__cell .field__error { margin: calc(4px - var(--cell-bottom)) var(--cell-x) var(--cell-bottom); font-size: 13px; }
.sheet__note { grid-column: 1 / -1; margin: 0; }
.sheet__hint { min-height: 1.4em; margin: 5px 0 7px; font-size: 13px; line-height: 1.4; color: var(--on-night-quiet); }
.field__optional { font-weight: 400; }
.field__note { padding: 12px 14px; border-radius: var(--radius); background: rgb(245 207 118 / .14); color: var(--on-night);
  font-size: 14px; line-height: 1.45; }
.field__note a, .form-status a, .quote__success a { font-weight: 500; text-decoration-color: var(--mustard); text-underline-offset: 3px; }
.field__error { display: flex; align-items: flex-start; gap: 8px; font-size: 14px; font-weight: 500; line-height: 1.4; color: var(--error); }
.field__error .icon { width: 16px; height: 16px; margin-top: 1px; stroke-width: 1.6; }
.field--trap { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }
.form-summary { padding: 16px 18px; border: 1.5px solid var(--error); border-radius: var(--radius); }
.form-summary:focus-visible { outline-offset: 2px; }
.form-summary__title { font-weight: 600; }
.form-summary__list { margin-top: 8px; list-style: none; display: grid; gap: 6px; }
.form-summary__list a { color: var(--error); font-weight: 500; text-underline-offset: 3px; }
.form-status { padding: 14px 16px; border: 1.5px solid var(--error); border-radius: var(--radius); font-size: 15px; line-height: 1.5; }
.quote__submit { display: grid; gap: 8px; }
.quote__submit .btn--block { min-height: 50px; border-radius: 12px; }
.quote__legal { max-width: 62ch; font-size: 12.5px; line-height: 1.4; color: var(--on-night-quiet); }   /* a readable line in the wide window (decision 95) */
.quote__legal a { color: var(--on-night); font-weight: 500; text-decoration-color: var(--mustard); text-underline-offset: 3px; white-space: nowrap; }
/* After sending (owner, 2026-09-29, variant "envelope" of two shown): the window's head steps aside (v2.js) and the thanks
   stands alone, the owner's envelope doodle over it, then the address the quote goes to. The thanks takes focus only to
   be announced; it is not a control, so it shows no ring. */
.quote__success { display: grid; gap: 14px; justify-items: start; padding: 12px 0 0; color: var(--on-night); }
.quote__success-art { width: 88px; height: auto; color: var(--mustard); }
.quote__success-art path { vector-effect: non-scaling-stroke; stroke-width: 1.6px; }
.quote__success-title { font-family: var(--font-display); font-weight: 200; font-size: 44px; line-height: 1.05;
  color: var(--mustard); }
.quote__success-title:focus { outline: none; }
.quote__success p:not(.preview-note) { font-size: 18px; line-height: 1.5; color: var(--on-night-soft); }
.quote__sent-email { color: var(--on-night); font-weight: 600; overflow-wrap: anywhere; }
/* On a phone the window fills the screen and needs no scrolling (owner, 2026-09-28): each measure below runs from a
   compact value on a screen 676px tall to the roomy one above at 926px, by the screen's height with the browser's
   bars shown (svh), so every phone in between gets a window that just fits; below 676px the spaces tighten once more,
   and below 608px (an iPhone SE in Safari, about 548px) the box button turns into one line. The bands sit 16px higher
   than on 2026-09-28, since the empty occasion list has its line again (decision 77). The line of hints keeps its room
   while the window is open, so the send button never moves under a finger (decision 77).
   Shorter still, the window scrolls in itself and its close button stays at hand. */
@supports (height: 100svh) {
  @media (max-width: 699.98px) {
    .quote-dialog { --fit: clamp(0px, 100svh - 676px, 250px); }
    .quote-dialog__close { --size: calc(40px + var(--fit) * .016); width: var(--size); height: var(--size);
      margin: calc(6px + var(--fit) * .016) calc(6px + var(--fit) * .016) 0 0; }
    .quote-dialog__body { padding-top: calc(6px + var(--fit) * .02); }
    .quote__head { margin-bottom: calc(8px + var(--fit) * .032); padding-top: calc(2px + var(--fit) * .008); }
    .quote__head .section-title { font-size: calc(24px + var(--fit) * .024); }
    .quote__head .section-lead { margin-top: calc(4px + var(--fit) * .016); font-size: calc(13px + var(--fit) * .008);
      line-height: 1.4; }
    .quote__call { margin-top: calc(2px + var(--fit) * .008); font-size: calc(14px + var(--fit) * .004); }
    .quote__call a { margin: -8px 0; padding: 8px 0; }
    .sheet { gap: calc(4px + var(--fit) * .016); --cell-x: calc(12px + var(--fit) * .008);
      --cell-top: calc(4px + var(--fit) * .02); --cell-bottom: calc(5px + var(--fit) * .02); --input-top: 1px; }
    .sheet__cell label { font-size: calc(12px + var(--fit) * .002); line-height: 1.2; }
    .sheet__cell :is(input, textarea, select) { font-size: calc(16px + var(--fit) * .004); line-height: 1.25; }
    /* Every hint keeps to one line (decision 77): 12px on every phone, at which the longest hint, the town's (312px),
       still fits the 316px line of a 360px phone. */
    .sheet__hint { min-height: 1.4em; margin: calc(2px + var(--fit) * .012) 0 calc(4px + var(--fit) * .012); font-size: 12px; }
    /* Narrower than 360px the town's hint takes two lines, so there the line keeps room for two (decision 78). */
    @media (max-width: 359.98px) { .sheet__hint { min-height: 2.8em; } }
    .quote__submit { gap: calc(6px + var(--fit) * .008); }
    .quote__submit .btn--block { min-height: calc(44px + var(--fit) * .024); }
    .quote__legal { font-size: 12px; line-height: 1.35; }
    /* Below 676px (an iPhone SE in Safari is about 548px): the spaces tighten once more, so the window still fits. */
    @media (max-height: 675.98px) {
      .quote-dialog__body { padding-top: 4px; padding-bottom: calc(5px + env(safe-area-inset-bottom)); }
      .quote__head { margin-bottom: 4px; }
      .quote__head .section-title { font-size: 21px; }
      .quote__head .section-lead { font-size: 13px; line-height: 1.3; }
      .quote__call { margin-top: 1px; font-size: 13px; line-height: 1.3; }
      .quote__submit { gap: 4px; }
      .sheet { gap: 3px; --cell-top: 2px; --cell-bottom: 3px; }
      .quote__legal { line-height: 1.3; }
      .quote__art { width: 34px; height: 34px; }
    }
    /* An iPhone SE in Safari: the box button becomes one line, «lub» and the doodle before the words, so the window
       keeps fitting. Its tap area (about 38px) runs under the send button, which stays on top, so a tap on the send
       button's lower edge still sends, and over the legal line's first pixels, so the link keeps 30px of its own
       (decision 77). */
    @media (max-height: 607.98px) {
      .quote__submit [data-submit] { position: relative; z-index: 2; }
      /* The rows close up by a pixel each: the town field's label takes two lines at half width since «i adres»
         (decision 67), and the occasion list has its line again (decision 77). */
      .quote__head { margin-bottom: 3px; }
      .sheet { gap: 2px; --cell-bottom: 2px; }
      .sheet__hint { margin: 1px 0 2px; }
      .quote__or { display: none; }
      .quote__submit .quote__boxy { position: relative; z-index: 1; min-height: 0; margin: -10px 0; padding: 10px 0; border: 0; justify-content: flex-start;
        gap: 8px; font-size: 14px; font-weight: 500; }
      .quote__boxy::before { content: "lub"; color: var(--on-night-quiet); font-weight: 400; }
      .quote__boxy .btn__art { width: 20px; }
      .quote__submit { gap: 3px; }
      .quote__boxy:hover { background: none; text-decoration: underline; }
    }
  }
}
.quote__success a { color: var(--on-night); text-decoration-color: var(--mustard); }
.quote__success :focus-visible { outline-color: var(--mustard); }
.preview-note { justify-self: start; padding: 4px 10px; border-radius: 4px; background: var(--mustard); color: var(--ink) !important;
  font-size: 13px; font-weight: 600; }

/* FAQ: native disclosure rows. */
.faq__item { border-bottom: 1px solid var(--rule); }
.faq__item summary { display: flex; align-items: center; justify-content: space-between; gap: 16px; min-height: 64px;
  padding: 16px 0; font-size: 18px; font-weight: 500; line-height: 1.35; color: var(--on-night); cursor: pointer; list-style: none; }
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary .icon { width: 20px; height: 20px; transition: transform .3s cubic-bezier(.2, .7, .2, 1); }
.faq__item[open] summary .icon { transform: rotate(45deg); }
.faq__answer { padding: 0 36px 20px 0; }
.faq__answer p { font-size: 17px; line-height: 1.6; color: var(--on-night-quiet); }

/* The final page (owner, 2026-09-28, variant 1 "curtain" of three shown, with the characters beside the thanks on a
   wide screen and the firm's lines kept compact): a mustard page that waits under the site and is uncovered from below
   as the questions go up, from 650px tall (decision 98: Safari on an iPhone 390x844 gives the page 650-699px; there
   the top of the page, empty space only, goes under the screen's edge); on a shorter screen it simply follows them.
   The owner's two characters stand on it, the girl left and the boy right (assets/js/farewell-characters.js brings
   them in and plays their loop), then the thanks for the visit and the firm's lines, the phone first among its links
   (decision 69). */
.site-footer { display: flex; flex-direction: column; gap: 24px; padding: 48px 0 calc(88px + env(safe-area-inset-bottom));
  background: var(--mustard); color: rgb(30 23 20 / .8); font-size: 14px; line-height: 1.5; text-align: center; }
@media (min-height: 650px) {
  /* In the page's last screen (v2.js marks it, from one screen before the end of the questions) the final page lies
     under the page, below every layer of it, the first screen's photo included: it shows only where the page has
     ended. Before that it keeps its place after the questions, so it never shows through the first screen's photo as
     that sinks into the night, and its characters are brought in only near the end. */
  .site-footer { min-height: 100svh; }
  .site-footer.is-near { position: sticky; bottom: 0; z-index: -1; }
}
.site-footer a { display: inline-flex; align-items: center; min-height: 44px; color: var(--ink); text-decoration: underline;
  text-decoration-color: rgb(30 23 20 / .45); text-decoration-thickness: 1px; text-underline-offset: 4px; }
.site-footer a:hover { text-decoration-color: var(--ink); text-decoration-thickness: 1.5px; }
.site-footer :focus-visible { outline-color: var(--ink); }
.site-footer ::selection { background: var(--ink); color: var(--mustard); }
/* The characters and the thanks sit a little below the middle of the free height, nearer the firm's lines (owner, live
   2026-09-28: «опусти персонажей и текст чуть ниже»): the top padding moves the centred group down by half its size. */
.site-footer__stage { flex: 1; display: flex; flex-direction: column; justify-content: center; padding-top: 80px; }
/* The characters' drawings arrive with their own colours for the night; here they take the ink and the mustard. */
.farewell-cast { display: flex; justify-content: center; align-items: flex-end; gap: clamp(12px, 5vw, 64px);
  height: min(55vw, 36svh, 420px); margin-bottom: 24px; }
.farewell-cast svg { height: 100%; width: auto; min-width: 0; max-width: 48%; }
.farewell-cast #girl-heart { order: -1; }
.site-footer .farewell-cast .paper { fill: var(--mustard); }
.site-footer .farewell-cast .ink { stroke: var(--ink); }
.site-footer .farewell-cast .ink-fill { fill: var(--ink); }
.site-footer__thanks { font-family: var(--font-display); font-weight: 200; font-size: min(44px, 11vw); line-height: 1.02;
  letter-spacing: -.01em; color: var(--ink); text-wrap: balance; }
.site-footer__thanks span { display: block; margin-top: 12px; font-family: var(--font-text); font-size: 18px; font-weight: 500;
  line-height: 1.4; letter-spacing: 0; }
/* The final page is the characters, the thanks and the firm (owner, live 2026-09-28: the big phone and address lines
   left it). The firm's block stays small and tight, centred: its details, then the phone, the address, Instagram and
   the privacy policy side by side, wrapping where they must. Each link's tap area reaches past its line, 25px tall,
   and the rows stand far enough apart that no area covers the next row's link (decision 77). */
.site-footer__wrap { display: grid; justify-items: center; gap: 6px; padding-top: 12px; border-top: 1px solid rgb(30 23 20 / .18);
  text-align: center; }
.site-footer__firm { font-size: 12.5px; line-height: 1.45; }
.site-footer__links { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px 18px; list-style: none;
  font-size: 12.5px; line-height: 1.4; }
.site-footer .site-footer__links a { position: relative; display: inline; min-height: 0; }
.site-footer__links a::after, .site-footer__cookies::after { content: ""; position: absolute; inset: -5px -6px; }
/* "Ustawienia cookies" opens the banner's settings (policy, point 8); it reads as one of the firm's links. */
.site-footer__cookies { position: relative; display: inline; padding: 0; border: 0; background: none; font: inherit; color: var(--ink);
  cursor: pointer; text-decoration: underline; text-decoration-color: rgb(30 23 20 / .45); text-decoration-thickness: 1px;
  text-underline-offset: 4px; }
.site-footer__cookies:hover { text-decoration-color: var(--ink); text-decoration-thickness: 1.5px; }

@media (min-width: 700px) {
  :root { --gutter: 40px; --space-section: 112px; }
  .section-title { font-size: 46px; }
  .section-head { margin-bottom: 44px; }
  .quote-dialog { width: min(calc(100vw - 2 * var(--gutter)), 680px); height: fit-content; max-height: min(calc(100dvh - 48px), 980px);
    margin: auto; border: 1px solid var(--rule); border-radius: 8px; }
  .quote-dialog::backdrop { background: rgb(var(--night) / .72); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
  html:has(.quote-dialog[open]) { overflow: hidden; }
  .quote-dialog__body { padding: 30px 44px 36px; }
  .quote__head { margin: 0 0 26px; padding: 0 56px 0 0; }
  .quote__art { right: 2px; width: 52px; height: 52px; }
  .quote__art path { stroke-width: 1.8px; }
  .quote__head .section-title { font-size: 44px; }
  .quote__head .section-lead { margin-top: 10px; font-size: 18px; }
  .quote__call { margin-top: 6px; font-size: 18px; }
  .sheet__cell :is(input, textarea, select) { font-size: 18px; }
  /* In pairs: name and e-mail, date and hour, guests and place, occasion and phone; the message across. */
  .sheet__cell:is([data-field="name"], [data-field="email"], [data-field="occasion"], [data-field="phone"]) { grid-column: auto; }
  .sheet__hint { margin-block: 10px 14px; font-size: 14px; }
}
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
  /* FAQ answers open smoothly where the platform can animate to "auto" (interpolate-size); elsewhere they just open. */
  :root { interpolate-size: allow-keywords; }
  .faq__item::details-content { block-size: 0; overflow-y: clip;
    transition: block-size .35s cubic-bezier(.2, .7, .2, 1), content-visibility .35s allow-discrete; }
  .faq__item[open]::details-content { block-size: auto; }
}

/* ---------- Cookie banner (CookieConsent v3, assets/js/consent.js; decisions 103-105) ----------
   The owner's "Ciasteczka?" (2026-10-01, the second of three shown): a small card of the floating button's night
   glass that never blocks the page, a thin display word, one sentence, "Nie, dziękuję" as a link and "Poproszę"
   filled in ivory beside it (the third of three shown, decision 104, in this order since decision 105; neither is
   mustard, which stays the quote's), and the settings as a link beside the policy. On a phone the card stands above
   the floating button, the screen's width less the gutter; from 700px it is 380px wide on the left, above the
   button, and from 1200px down beside it. The library's stylesheet loads after the page (consent.js), after this
   one: these rules give it the page's look, each led by "body" so it outweighs the library's rules of the same form,
   and with !important only where the library's own rules for narrow screens carry it. */
body #cc-main {
  --cc-font-family: var(--font-text);
  --cc-bg: #1A1614;
  --cc-primary-color: var(--on-night);
  --cc-secondary-color: var(--on-night-soft);
  --cc-btn-primary-bg: transparent;
  --cc-btn-primary-color: var(--on-night);
  --cc-btn-primary-border-color: rgb(243 236 225 / .55);
  --cc-btn-primary-hover-bg: rgb(243 236 225 / .08);
  --cc-btn-primary-hover-color: var(--on-night);
  --cc-btn-primary-hover-border-color: var(--on-night);
  --cc-btn-secondary-bg: transparent;
  --cc-btn-secondary-color: var(--on-night);
  --cc-btn-secondary-border-color: rgb(243 236 225 / .55);
  --cc-btn-secondary-hover-bg: rgb(243 236 225 / .08);
  --cc-btn-secondary-hover-color: var(--on-night);
  --cc-btn-secondary-hover-border-color: var(--on-night);
  --cc-btn-border-radius: 12px;
  --cc-modal-border-radius: 16px;
  --cc-modal-margin: 16px;
  --cc-separator-border-color: rgb(243 236 225 / .14);
  --cc-link-color: var(--on-night);
  --cc-footer-bg: transparent;
  --cc-footer-color: var(--on-night-soft);
  --cc-footer-border-color: transparent;
  --cc-overlay-bg: rgb(14 11 10 / .72);
  --cc-cookie-category-block-bg: rgb(255 255 255 / .04);
  --cc-cookie-category-block-border: rgb(243 236 225 / .14);
  --cc-cookie-category-block-hover-bg: rgb(255 255 255 / .07);
  --cc-cookie-category-block-hover-border: rgb(243 236 225 / .22);
  --cc-cookie-category-expanded-block-bg: transparent;
  --cc-cookie-category-expanded-block-hover-bg: rgb(255 255 255 / .04);
  --cc-section-category-border: rgb(243 236 225 / .14);
  --cc-toggle-on-bg: var(--mustard);
  --cc-toggle-off-bg: rgb(243 236 225 / .28);
  --cc-toggle-on-knob-bg: var(--ink);
  --cc-toggle-off-knob-bg: #1A1614;
  --cc-toggle-enabled-icon-color: var(--mustard);
  --cc-toggle-disabled-icon-color: rgb(243 236 225 / .7);
  --cc-toggle-readonly-bg: rgb(243 236 225 / .16);
  --cc-toggle-readonly-knob-bg: rgb(243 236 225 / .55);
  --cc-toggle-readonly-knob-icon-color: #1A1614;
  --cc-webkit-scrollbar-bg: rgb(243 236 225 / .2);
  --cc-webkit-scrollbar-hover-bg: rgb(243 236 225 / .35);
  --cc-z-index: 40;
}
/* The library builds its markup at once, its stylesheet comes later: until consent.js marks it in (html.cc-styled),
   the markup stays hidden, or the card and the settings would stand unstyled after the footer. */
html:not(.cc-styled) #cc-main { display: none; }
/* The floating button's glass (decision 101): the night at 70% over a 16px blur, so the page shows through the card
   (owner, 2026-10-01, decision 104). Over the lightest page possible, white, the 70% still holds the soft ivory of the
   description, the links and "Nie, dziękuję" at 5.4:1; the quieter tone would fall to 3.4:1, so no text here takes it. */
body #cc-main .cm { border: 1px solid rgb(243 236 225 / .14); box-shadow: 0 10px 26px rgb(0 0 0 / .38);
  background: rgb(var(--night) / .7); -webkit-backdrop-filter: blur(16px) saturate(1.2); backdrop-filter: blur(16px) saturate(1.2); }
body #cc-main .cm--box { left: var(--gutter); right: var(--gutter); margin: 0; bottom: calc(80px + env(safe-area-inset-bottom)); }
body #cc-main .cm__texts { padding: 16px 0 0 !important; }
body #cc-main .cm__title, body #cc-main .cm__desc { padding: 0 16px !important; }
body #cc-main .cm__title { font-family: var(--font-display); font-weight: 200; font-size: 34px; line-height: 1; letter-spacing: -.01em;
  color: var(--on-night); }
body #cc-main .cm__title + .cm__desc { margin-top: 8px; }
body #cc-main .cm__desc { padding-bottom: 0 !important; font-size: 15px; line-height: 1.45; color: var(--on-night-soft); }
body #cc-main .cm__btns { padding: 12px 16px 0 !important; border-top: 0 !important; }
/* One row, the refusal first (decision 105): "Poproszę" takes what "Nie, dziękuję" leaves. Where both do not fit, on a
   screen under about 270px wide (a phone with the page zoomed in, for one), "Poproszę" moves under the refusal to a
   line of its own, full width, instead of being squeezed; the refusal stays first, inside the card. */
body #cc-main .cm__btn-group { display: flex !important; flex-flow: row wrap !important; gap: 8px; }
body #cc-main .cm__btn + .cm__btn { margin: 0 !important; }
body #cc-main .cm__btn { min-height: 44px; padding: 0 12px; font-size: 16px; font-weight: 600; line-height: 1.2; }
/* The refusal stays on the first layer, one tap away, 44px tall and as readable as the description: quieter than the
   filled "Poproszę", never hidden (the EDPB taskforce, 2023: refusing must stay readable and must not hide in text). */
body #cc-main .cm .cm__btn[data-role="all"] { flex: 1 1 auto !important; background: var(--on-night); border-color: var(--on-night);
  color: var(--ink); }
body #cc-main .cm .cm__btn[data-role="all"]:hover { background: var(--on-night-soft); border-color: var(--on-night-soft); color: var(--ink); }
/* Its words line up with the description's left edge; the 8px in front of them still take taps. */
body #cc-main .cm .cm__btn[data-role="necessary"] { flex: 0 0 auto !important; margin-left: -8px !important; padding: 0 8px;
  border-color: transparent; background: transparent;
  color: var(--on-night-soft); font-size: 15px; font-weight: 500; text-decoration: underline;
  text-decoration-color: rgb(243 236 225 / .45); text-underline-offset: 4px; }
body #cc-main .cm .cm__btn[data-role="necessary"]:hover { border-color: transparent; background: transparent; color: var(--on-night);
  text-decoration-color: var(--on-night); }
body #cc-main .cm__footer { padding: 6px 0 10px; }
body #cc-main .cm__links { padding: 0 16px !important; }
body #cc-main .cm__link-group { justify-content: flex-start !important; flex-wrap: wrap; gap: 12px 18px; font-size: 13px; }
body #cc-main .cm__link-group > * + * { margin-left: 0; }
body #cc-main .cm__link-group > * { flex: none; }   /* where both do not fit, the policy goes to the next line whole */
/* Each link takes taps 6px below it and 8px to its sides (79×29 and 132×29), not above, where a tap that just misses
   "Poproszę" would land on them and leave the page. The library clips its links (overflow: hidden), so here they let
   the area out; between wrapped lines it leaves 6px free. */
body #cc-main .cm__link-group :is(a, button) { position: relative; overflow: visible; padding: 4px 0; border: 0; background: none; font: inherit;
  color: var(--on-night-soft); text-decoration: underline; text-decoration-color: rgb(243 236 225 / .4);
  text-underline-offset: 3px; cursor: pointer; }
body #cc-main .cm__link-group :is(a, button)::after { content: ""; position: absolute; inset: 0 -8px -6px; }
body #cc-main .cm__link-group :is(a, button):hover { color: var(--on-night); text-decoration-color: var(--on-night); }
/* The ring is for the controls; the library focuses its windows themselves when they open, and those get none. */
body #cc-main :is(button, a, input, [role="button"]):focus-visible { outline: 3px solid var(--mustard); outline-offset: 3px; }
body #cc-main :is(.cm, .pm):focus-visible { outline: none; }
body #cc-main .pm__title { font-family: var(--font-display); font-weight: 300; font-size: 25px; line-height: 1.25; }   /* DESIGN.md "title" */
/* A category's switch is drawn 50×23; what takes the tap is its invisible checkbox, grown here past the drawing to a
   62×43 rectangle (WCAG 2.5.8 asks at least 24×24; square corners, because a tap is tested against the rounded
   shape), and its focus ring is drawn on the switch it stands for. */
body #cc-main .pm .section__toggle { top: -10px; left: -6px; width: 62px; height: 43px; border-radius: 0; }
body #cc-main .pm .section__toggle:focus-visible { outline: none; }
body #cc-main .pm .section__toggle:focus-visible ~ .toggle__icon { outline: 3px solid var(--mustard); outline-offset: 3px; }
@media (min-width: 700px) {
  body #cc-main .cm--box { left: 24px; right: auto; width: 380px; }
}
/* Down beside the floating button only where both fit: its 360px stand in the middle, so the card's 24 + 380px and a
   16px gap need a screen 1200px wide. Narrower, on a tablet or a phone turned sideways too, the card stands above the
   button, as on a phone (review, 2026-10-01: at 700–1167px it covered the button). */
@media (min-width: 1200px) {
  body #cc-main .cm--box { bottom: 24px; }
}

/* 404 page. */
.not-found { padding-block: 88px 120px; border-top: 1px solid var(--rule); }
.not-found .btn { margin-top: 28px; }

/* Privacy policy page (spec 4, runbook step 11): the owner's approved text on the night under the 404 page's header,
   set for reading in one column of about 70 characters; headings in Heading Ivory, links underlined in mustard. The
   table of purposes stacks on a phone, each cell under its column's name. */
.policy { padding-block: 72px 96px; border-top: 1px solid var(--rule); }
.policy__text { max-width: calc(62ch + 2 * var(--gutter)); }
.policy__text > * + * { margin-top: 16px; }
.policy__text > h2 { margin-top: 48px; font-family: var(--font-sub); font-weight: 300; font-size: 25px; line-height: 1.25;
  color: var(--on-night); text-wrap: balance; }   /* DESIGN.md "title" */
.policy__text > h2 + * { margin-top: 12px; }
.policy__text p, .policy__text li, .policy__table td { font-size: 17px; line-height: 1.6; color: var(--on-night-soft); text-wrap: pretty; }
.policy__text ul { padding-left: 1.2em; }
.policy__text li + li { margin-top: 8px; }
.policy__text strong { font-weight: 600; color: var(--on-night); }
.policy__text a, .policy__cookies { color: var(--on-night); text-decoration: underline; text-decoration-color: var(--mustard);
  text-decoration-thickness: 1.5px; text-underline-offset: 4px; overflow-wrap: anywhere; }
.policy__table { width: 100%; border-collapse: collapse; }
.policy__table th { padding: 0 16px 10px 0; border-bottom: 1px solid var(--rule); text-align: left; font-size: 12.5px;
  font-weight: 500; letter-spacing: .01em; color: var(--on-night-quiet); }
.policy__table td { padding: 14px 16px 14px 0; border-bottom: 1px solid var(--rule); vertical-align: top; }
@media (max-width: 699.98px) {
  .policy__table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .policy__table tr { display: block; padding: 14px 0; border-bottom: 1px solid var(--rule); }
  .policy__table td { display: block; padding: 0; border: 0; }
  .policy__table td + td { margin-top: 8px; }
  .policy__table td::before { content: attr(data-label); display: block; font-size: 12.5px; font-weight: 500; color: var(--on-night-quiet); }
}
/* "Ustawienia cookies" opens the banner's settings (policy, point 8): a button that reads as the page's links. */
.policy__cookies { min-height: 44px; padding: 0; border: 0; background: none; font: inherit; cursor: pointer; }
.policy__footer { padding-block: 28px calc(28px + env(safe-area-inset-bottom)); border-top: 1px solid var(--rule);
  font-size: 13px; line-height: 1.45; color: var(--on-night-quiet); }
.policy__links { display: flex; flex-wrap: wrap; gap: 0 24px; margin-top: 4px; padding: 0; list-style: none; }
.policy__links a { display: inline-flex; align-items: center; min-height: 44px; color: var(--on-night); text-decoration: underline;
  text-decoration-color: var(--mustard); text-decoration-thickness: 1.5px; text-underline-offset: 4px; }

/* ---------- Sections arrive on their own clock, after marquet.nyc (owner, 2026-10-02, decision 113) ----------
   Owner: «Давай возьмем из рефернеса анимации проявления элементов страницы»; the first of three variants shown on «Jak
   to działa», with its knobs as they were. Before it each section came out of a light haze tied to the scroll (live
   2026-09-26, decisions up to 92). Now a block plays its arrival once, when it has come up far enough (v2.js marks it
   .is-revealed: a heading with its seam and lead at 30% of the screen from its foot, a block at 20%), then on its own
   clock, however fast the page moves: the words of a heading rise out of their own lines, the seam above it and the
   line over a step draw themselves from the left, and a block rises 68px into place while it comes in; since decision
   117 one clock for all of it, 1.6s for the words, the lines, a block's rise and its fade alike (it was 2s for the words
   and the fades, 1.5s for a block's rise), on marquet's long ease-out (outExpo; cubic-bezier(.14, 1, .34, 1) stays
   within 1% of it). Every answer to the pointer takes .3s on one curve, a photo pushing in .6s. Nothing is hidden until the page has marked itself .reveal-ready (script on, motion allowed),
   never on paper, and anything that takes keyboard focus arrives at once. The first screen, the services and the
   occasions keep their own motion (their blocks above), and the final page arrives by its curtain alone: from 650px
   tall it lies under the page and the page lifts off it, so an arrival of its words would play unseen beneath the page.
   */
:root { --arrive: cubic-bezier(.14, 1, .34, 1); }
.section-head { position: relative; }
.section-head::before { content: ""; position: absolute; top: -29px; left: 0; right: 0;
  border-top: 1px solid var(--rule); transform-origin: left; }   /* a border: it survives forced colours and paper */
/* Each word of a heading sits in its own line box, so it can rise out of it: the box clips above and below, a tenth
   of an em beyond the line, and never at the sides, where the hook of a «j» reaches past the word (review of
   decision 113). The services' names share it (decision 108). */
:is(.formats__name, .section-title, .about__slogan) .w { display: inline-block; overflow-x: visible; overflow-y: clip;
  padding-block: .1em; margin-block: -.1em; vertical-align: top; }
:is(.formats__name, .section-title, .about__slogan) .w > span { display: inline-block; }
@media screen {
  .reveal-ready [data-reveal] .w > span { transition: translate 1.6s var(--arrive); }
  .reveal-ready :is(.section-head, .step)[data-reveal]::before { transition: scale 1.6s var(--arrive); }
  .reveal-ready .section-head[data-reveal] .section-lead, .reveal-ready .step[data-reveal] > *,
  .reveal-ready :is(.about__text, .about__stat, .faq__item)[data-reveal] {
    transition: translate 1.6s var(--arrive), opacity 1.6s var(--arrive); }

  .reveal-ready [data-reveal]:not(.is-revealed) .w > span { translate: 0 105%; }
  .reveal-ready :is(.section-head, .step)[data-reveal]:not(.is-revealed)::before { scale: 0 1; }
  .reveal-ready .section-head[data-reveal]:not(.is-revealed) .section-lead,
  .reveal-ready .step[data-reveal]:not(.is-revealed) > *,
  .reveal-ready :is(.about__text, .about__stat, .faq__item)[data-reveal]:not(.is-revealed) { translate: 0 68px; opacity: 0; }
  /* Keyboard focus brings a block in with no glide (v2.js marks it), only on the parts that arrive (a question's
     icon keeps its turn), and the waiting state is set with no glide either, the moment the page marks itself ready
     (.reveal-setting, one frame). */
  .reveal-ready [data-reveal]:focus-within, .reveal-ready [data-reveal]:focus-within :is(.w > span, .section-lead),
  .reveal-ready .step[data-reveal]:focus-within > *, .reveal-ready [data-reveal]:focus-within::before { transition: none; }
  .reveal-setting [data-reveal], .reveal-setting [data-reveal] *, .reveal-setting [data-reveal]::before {
    transition: none !important; }
}
/* The services' text still comes out of the page's haze (decision 108, their block above). */
@keyframes arrive-haze { from { opacity: .2; transform: translateY(var(--rise, 16px)); filter: blur(var(--haze, 4px)); }
  to { opacity: 1; transform: none; filter: blur(0); } }

/* Print: a staged entrance never hides content on paper, and the night's white text turns to ink on white paper
   (the first screen keeps its white words on the photo). */
@media print {
  :root { --on-night: var(--ink); --on-night-soft: rgb(30 23 20 / .88); --on-night-quiet: rgb(30 23 20 / .74);
    --rule: rgb(30 23 20 / .14); --field-fill: transparent; --error: var(--red); }
  html { color-scheme: light; }
  body { background: #fff; }
  main > :not(.hero) { background: none; }
  .about { box-shadow: none; }
  .stat { height: auto; }
  .stat__photos { display: none; }
  .stat__facts { display: block; overflow: visible; mask-image: none; padding: 0; }
  .stat__fact { display: block; max-width: none; animation: none !important; transform: none; opacity: 1; }
  .stat__fact + .stat__fact { margin-top: .3em; }
  .ground { display: none; }
  .about__slogan, .stat__num, .section-title__accent, .formats__name { color: var(--ink); }
  .hero { --on-night: #fff; --on-night-soft: rgb(255 255 255 / .88); --on-night-quiet: rgb(255 255 255 / .74); }
  .site-header { position: static; background: none; }
  .site-header::after { display: none; }
  .site-header__logo { animation: none !important; }
  .section-head, .about__slogan, .about__text, .about__stat, .formats__item, .occasion, .step, .faq__item,
  .site-footer__words, .site-footer__wrap { opacity: 1 !important;
    transform: none !important; clip-path: none !important; filter: none !important; }
  .hero { animation: none !important; }
  .section-head, .about__slogan, .about__text, .about__stat, .formats__item, .occasion, .step, .faq__item,
  .site-footer__words, .site-footer__wrap, .occasion__photo { animation: none !important; }
  .formats__name .w > span, .formats__text, .formats__cta, .formats__photo, .formats__photo img {
    animation: none !important; translate: none !important; scale: none !important; clip-path: none !important; opacity: 1 !important; }
  .occasions__stage { height: auto !important; }
  .occasions__pin { position: static !important; height: auto !important; }
  .occasions__list { flex-wrap: wrap; width: auto !important; overflow: visible; translate: none !important; animation: none !important; }
  .occasions__item { width: 30%; }
  .occasions__bar { display: none !important; }
  .occasion__name { position: static !important; width: auto !important; height: auto !important; clip-path: none !important; white-space: normal !important; }
  .occasion__photo img { filter: none !important; }
  .quote-dialog, .cta-bar { display: none !important; }
  .hero { position: relative; z-index: auto; margin-bottom: 0 !important; }   /* still the frame of its photo and wordmark */
  .hero__photo { clip-path: none !important; animation: none !important; }
  .hero__wordmark img, .hero__caption, .hero__caption svg { animation: none !important; }
  .hero__curtain, .hero__backdrop, .hero__caption, .hero::before, .hero::after { display: none !important; }
  .site-footer, .site-footer.is-near { position: static; z-index: auto; min-height: 0; }
}

/* ---------- Other viewports (responsive phase) ---------- */

@media (min-width: 700px) {
  .site-header { padding-inline: max(var(--gutter), (100vw - var(--max)) / 2 + var(--gutter)); }
  .site-header__logo img { width: 116px; }
  .site-header__nav { gap: 32px; font-size: 15px; }
  .site-header__menu { font-size: 13px; }

  .about { --about-pad: 56px; }
  .about__slogan, .site-footer__thanks { font-size: 56px; }   /* the opening and the closing line, one size */
  .stat { height: min(58cqi, 663px); }
  .stat__fact { max-width: 6em; font-size: min(6.75cqi, 77.4px); }
  .stat__photo { --w: 14cqi; }
  .stat__photo:nth-child(3n) { --w: 19cqi; }
  .stat__photo:nth-child(6n + 1) { --x: 8%; --y: 6%; }
  .stat__photo:nth-child(6n + 2) { --x: 76%; --y: 57%; }
  .stat__photo:nth-child(6n + 3) { --x: 57%; --y: 1%; }
  .stat__photo:nth-child(6n + 4) { --x: 12%; --y: 60%; }
  .stat__photo:nth-child(6n + 5) { --x: 80%; --y: 4%; }
  .stat__photo:nth-child(6n + 6) { --x: 30%; --y: 74%; }
  .stat__photo:nth-child(7) { --y: 3%; }
  .stat__photo:nth-child(8) { --y: 60%; }
  .stat__photo:nth-child(9) { --y: 3%; }
  .stat__photo:nth-child(10) { --y: 62%; }   /* clear of the facts' middle line */
  .stat__photo:nth-child(11) { --y: 8%; }
  .stat__photo:nth-child(12) { --y: 72%; }


}

/* Desktops and low landscape screens: a larger circle a little lower, the wordmark wider across it (decision 106); where
   the circle is over 782px wide (2.2 radii over 860px) the wordmark keeps 1.1 of its width. */
@media (min-width: 1024px), (min-aspect-ratio: 1/1) and (max-height: 560px) and (min-width: 560px) {
  .hero { --hero-r: min(20vw, 30svh); --hero-y: 47%; --hero-k: .53; }
  .hero__wordmark { width: min(60vw, 100svh, max(860px, var(--hero-r) * 2.2)); }
}

@media (min-width: 1024px) {

  :root { --space-section: 128px; }
  .section-title { font-size: 52px; }
  .section-lead { font-size: 21px; }

  .about__slogan { font-size: 65px; }
  .about__text { font-size: 21px; }
  .about__stat { margin-top: 80px; }

  .steps { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 40px; }
  .step { grid-template-columns: 1fr; row-gap: 14px; }
  .step__num { font-size: 42px; }
  .step__title { font-size: 27px; }
  .site-menu { padding: 8svh max(var(--gutter), (100vw - var(--max)) / 2 + var(--gutter)) 5svh; }
  .site-menu__list a { font-size: clamp(48px, 9svh, 88px); }
  /* Two columns: the sections and the contact on the left, the still life standing on one line on the right. */
  .site-menu:popover-open { display: grid; }
  .site-menu { grid-template-columns: max-content minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) auto; column-gap: 64px; }
  .site-menu__list { grid-column: 1; grid-row: 1; align-self: start; }
  .site-menu__foot, .site-menu__foot-in { display: contents; }
  .site-menu__contact { grid-column: 1; grid-row: 2; }
  .site-menu__still { grid-column: 2; grid-row: 1 / -1; align-self: center; justify-self: end; width: min(100%, 540px);
    margin: 0; container-type: normal; align-items: flex-end; justify-content: space-between; }
  .site-menu__art { height: auto; max-height: none; }
  .site-menu__art--flower, .site-menu__art--glass { display: block; }
  .site-menu__art--flower { width: 24%; --sw: 1.95; }
  .site-menu__art--stand { width: 52%; --sw: .9; }
  .site-menu__art--glass { width: 15%; --sw: 3.1; }

  /* On a wide screen the two ways out stand in one row, «lub» between them (owner, live 2026-09-28). */
  .quote__submit { grid-template-columns: auto auto 1fr; align-items: center; column-gap: 18px; }
  .quote__submit .quote__boxy { justify-self: start; }
  .quote__submit .btn--block { width: auto; min-width: 0; }
  .quote__or::before, .quote__or::after { display: none; }
  .quote__submit .quote__legal { grid-column: 1 / -1; }

  .faq .wrap { display: grid; grid-template-columns: minmax(0, 8fr) minmax(0, 4fr); gap: 72px; align-items: start; }
  .faq .section-head { grid-column: 2; grid-row: 1; }
  .faq__list { grid-column: 1; grid-row: 1; }
  .faq .section-head { position: sticky; top: calc(var(--header-h) + var(--header-shade) + 8px); }

  /* The characters flank the thanks (owner): the girl at the left edge, the boy at the right, the words between. */
  .site-footer__stage { --cast-h: clamp(240px, 23vw, 340px); display: grid; grid-template-areas: "stage"; justify-content: stretch;
    align-content: center; align-items: center; padding-top: 120px; }
  .site-footer__stage > * { grid-area: stage; }
  .farewell-cast { height: var(--cast-h); margin: 0; justify-content: space-between; }
  .site-footer__words { justify-self: center; max-width: calc(100% - 1.6 * var(--cast-h) - 48px); }
  .site-footer__thanks { font-size: 65px; }
  .site-footer__links { gap: 10px 28px; }
}

/* Low landscape screens from 560px wide (a phone turned sideways, a short browser window): the first screen's words
   fit the height. Narrower near-square windows keep the phone layout. */
@media (min-aspect-ratio: 1/1) and (max-height: 560px) and (min-width: 560px) {
  /* The menu's five sections and two buttons would not fit under the bar here: the sections in two columns, the two
     buttons side by side under them (decision 77). */
  .site-menu { padding-block: 5svh 3svh; row-gap: 16px; }
  .site-menu__list { grid-template-columns: repeat(2, auto); justify-content: start; column-gap: 56px; }
  .site-menu__list .site-menu__cta, .site-menu__list .site-menu__cta + .site-menu__cta { grid-row: 4; margin-top: 2.4svh; }
}
/* A short phone held upright (an iPhone SE in Safari, about 548px): the menu's blocks close up so it fits (decision 77). */
@media (max-aspect-ratio: 1/1) and (max-height: 600px) {
  .site-menu { row-gap: 16px; }
}
