/* ===========================================================================
   Dieturi, arkusz główny motywu

   Port pliku app/globals.css z referencyjnej aplikacji. Tokeny, selektory i
   wszystkie wartości są identyczne, dzięki czemu szablony PHP używające tych
   samych nazw klas renderują się 1:1 z oryginałem.

   Trzy różnice względem źródła, wszystkie opisane niżej:
   1. usunięty `@import "tailwindcss"` i zastąpiony minimalnym resetem,
   2. ścieżki do fontów są względne (../fonts/...), bez PHP w CSS,
   3. na końcu pliku dodana sekcja zgodności z WordPressem.
   =========================================================================== */

/* ============================== minimalny reset ============================ */

/* W miejsce preflight z Tailwinda. Zeruje dokładnie to, na czym opiera się
   dalsza część arkusza: model pudełka, marginesy bloków, listy (także ol,
   używane w .steps-list), oraz natywny wygląd przycisku, bo .btn maluje tło
   i obramowanie samodzielnie. */

*, *::before, *::after { box-sizing: border-box; }
html { -moz-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; }
h1, h2, h3, h4, h5, h6, p, blockquote, figure, figcaption, ul, ol, dl, dd, pre, hr { margin: 0; }
ol { padding: 0; list-style: none; }
button, input, select, textarea, optgroup { margin: 0; font: inherit; color: inherit; letter-spacing: inherit; }
button, [type="button"], [type="submit"], [type="reset"] { -webkit-appearance: button; appearance: button; padding: 0; border: 0; background: transparent; cursor: pointer; }
img, video { height: auto; }
table { border-collapse: collapse; border-spacing: 0; }
hr { border: 0; border-top: 1px solid var(--line); }
b, strong { font-weight: bolder; }
code, kbd, samp, pre { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 1em; }
small { font-size: 80%; }
sub, sup { position: relative; font-size: 75%; line-height: 0; vertical-align: baseline; }
sub { bottom: -.25em; }
sup { top: -.5em; }

/* ============================== self hosted fonts ========================== */

/* Inter and Caveat ship with the repo (public/fonts) instead of being fetched at
   build time, so development renders exactly the same faces as production even
   when the Google Fonts download is unavailable. Two subsets each are enough for
   Polish copy: latin plus latin-ext, which carries ą ć ę ł ń ó ś ź ż. */

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

/* Metric adjusted fallbacks. font-display: swap means the first paint is drawn in
   whatever the stack falls through to, and Segoe UI is far narrower than Inter, so
   the balanced H1 used to re-break the moment the real face arrived. These two faces
   are the interim renderer instead: local Arial, rescaled so its average character
   advance and its vertical metrics match the webfont it stands in for. Nothing about
   them is hand tuned. They are byte for byte the blocks next/font generated for this
   pair before the switch to self hosting, recomputed here from the same capsize
   metrics the framework ships (node_modules/vinext/dist/build/google-fonts/,
   fallback-metrics.js applied to fallback-metrics-data.json): Inter 2048 upem,
   ascent 1984, descent -494, line gap 0, avg width 978 against Arial 2048 upem,
   avg width 913; Caveat 1000 upem, ascent 960, descent -300, avg width 343. */
@font-face {
  font-family: 'Inter Fallback';
  src: local('Arial');
  ascent-override: 90.44%;
  descent-override: 22.52%;
  line-gap-override: 0%;
  size-adjust: 107.12%;
}
@font-face {
  font-family: 'Caveat Fallback';
  src: local('Arial');
  ascent-override: 124.77%;
  descent-override: 38.99%;
  line-gap-override: 0%;
  size-adjust: 76.94%;
}

/* ============================== design tokens ============================== */

:root {
  --bg: #f1ebe3;
  --surface: #fbf8f3;
  --surface-tint: #fbebdd;
  --ink: #211e1a;
  --ink-soft: #3a342c;
  --muted: #6f6759;
  --accent: #e97832;
  --accent-deep: #c95e1d;
  --accent-line: rgba(233, 120, 50, .45);
  --line: rgba(33, 30, 26, .1);
  --light: #fffdfb;
  --light-muted: rgba(255, 253, 251, .64);
  /* form errors only. --accent-deep reads 3.5:1 on the page, too faint for small text, so
     errors take the same hue one step darker: 5.5:1 on --bg, 6.1:1 on --surface */
  --error: #9c4413;
  --photo-bg: #e9d5bd;
  --radius-card: 24px;
  --radius-canvas: 32px;
  /* two shells on one centre axis: the wide one carries header, hero, dark canvases, offer and footer */
  --shell: min(1320px, calc(100vw - 3rem));
  /* the inner shell — mid page sections step in symmetrically for a calmer reading width */
  --shell-narrow: min(1060px, calc(100vw - 3rem));
}

/* above full HD the layout is allowed to breathe wider, both shells scale together */
@media (min-width: 1920px) {
  :root {
    --shell: min(1560px, calc(100vw - 6rem));
    --shell-narrow: min(1240px, calc(100vw - 6rem));
  }
}

/* ================================== base =================================== */

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
/* 'Inter Fallback' sits directly behind the real face on purpose: it is the one the
   browser paints during the swap window, so it has to be reached before anything
   unadjusted. Segoe UI stays behind it rather than in front, as the fallback for
   systems that have no local Arial for the adjusted face to resolve against. */
body { margin: 0; overflow-x: hidden; background: var(--bg); color: var(--ink); font-family: 'Inter', 'Inter Fallback', "Segoe UI", system-ui, sans-serif; font-size: 16px; line-height: 1.65; -webkit-font-smoothing: antialiased; }
h1, h2, h3, p, blockquote, figure, ul { margin: 0; }
ul { padding: 0; list-style: none; }
h1, h2, h3, p, blockquote { text-wrap: pretty; }
a { color: inherit; text-decoration: none; }
img, svg { display: block; max-width: 100%; }
a, button { -webkit-tap-highlight-color: transparent; }
::selection { background: var(--surface-tint); color: var(--ink); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* the leading on both heading levels is set for the accent, not for Inter alone. Caveat
   is a script face: at the 1.26em the accent is set in, its extenders reach roughly a
   quarter em further above and below the baseline than Inter's do at 1em, and a wrapped
   accent stacks a Caveat descender directly over a Caveat ascender. Measured column by
   column at 375, where the type is tightest, 1.03/1.08 left the worst pair on the site
   ("prawdziwe" over "doświadczenie." in the about H2) 0.67px apart; 1.06/1.14 opens that
   to 2.67px and leaves nothing on any page under 2.6px. Leading is purely vertical, so
   this correction costs no re-break of its own: it only opens the gaps. */
h1 { max-width: 16ch; font-size: clamp(3.1rem, 4.8vw, 4.9rem); font-weight: 560; letter-spacing: -.03em; line-height: 1.06; text-wrap: balance; }
h2 { font-size: clamp(2.1rem, 3.1vw, 3.05rem); font-weight: 500; letter-spacing: -.015em; line-height: 1.14; text-wrap: balance; }
h3 { font-size: 1.2rem; font-weight: 620; letter-spacing: -.02em; line-height: 1.3; }
/* one rule for every orange accent on the site. The wordmark's hand used to come back
   in the H1 and nowhere else, which left the h2 and blockquote accents reading as a
   different voice in the same colour; they are the same gesture, so they are the same
   face. Caveat carries almost exactly Inter's cap height (72 against 73 per 100px) but
   a far smaller x-height (37 against 55), and every accent is a lowercase phrase, so it
   needs the size bump to read at the same optical weight. 1.16 was the floor, not the
   answer: the client still read it as small next to the Inter around it. 1.26 is the
   largest factor the H1s tolerate: 1.32 re-breaks the hero (three lines to four at 1280)
   and the /o-mnie H1 (two to three). Caveat is the narrower face of the two at this size,
   so widening the rule to h2 and blockquote re-flowed a few headings rather than
   overflowing any: the about H2 and the statement quote redistribute at 1280, and at 375
   the about H2 and the areas H2 each recover a line (four to three). Nothing wraps wider
   than its column at any width from 360 up.

   line-height: 0 is what keeps a heading's leading even. An inline box set 1.26em tall
   with line-height: 1 stands proud of the strut on both sides (10.3px above the baseline
   and 3.9px below it at the 1280 hero size), so whichever line happened to carry the
   accent was pushed a visibly wider gap from its neighbour than every other line, which
   is exactly the uneven hero the client reported. Zeroed, the accent's inline box
   collapses to a point well inside the strut and every line of a heading measures the
   same, accent or not. No glyph is touched: line-height never clipped ink, it only
   sized the box the ink sits in.

   The lift is a separate correction. Both faces sit on one baseline, and Caveat's ink
   mass lands lower there: rendering the same word in both at this size puts the Caveat
   centre .039em below the Inter one. top: -.04em hands that back, so the accent reads
   centred against the Inter beside it instead of hanging under it. It is relative, not
   a margin, so nothing about the line box moves. */
h1 em, h2 em, blockquote em { color: var(--accent); font-style: normal; font-family: 'Caveat', 'Caveat Fallback', cursive; font-weight: 600; font-size: 1.26em; line-height: 0; letter-spacing: 0; position: relative; top: -.04em; }

.skip-link { position: fixed; top: 1rem; left: 1rem; z-index: 100; padding: .75rem 1rem; border-radius: 999px; background: var(--ink); color: var(--light); font-size: .8rem; font-weight: 650; transform: translateY(-200%); transition: transform 180ms ease; }
.skip-link:focus { transform: translateY(0); }

/* ================================= layout ================================== */

/* max-width: none neutralizes Tailwind's built-in `container` utility caps (80/96rem),
   which otherwise silently narrow the shell and break header/content edge alignment */
.container { width: var(--shell); max-width: none; margin-inline: auto; }
/* modifier on .container: same centre, inset edges. Below ~1108px both shells resolve to 100vw - 3rem, so the rhythm folds away on small screens */
.container-narrow { width: var(--shell-narrow); margin-inline: auto; }
.section { padding-block: clamp(5rem, 8vw, 8rem); }
section[id] { scroll-margin-top: 120px; }

.section-head { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); gap: clamp(1.5rem, 4vw, 4rem); align-items: end; margin-bottom: clamp(2.5rem, 4vw, 3.5rem); }
.section-head-copy { display: flex; flex-direction: column; align-items: flex-start; gap: .9rem; }
.lead { max-width: 36em; color: var(--muted); font-size: 1.08rem; line-height: 1.65; }

/* stacked copy blocks share one rhythm: kicker, .9rem, heading, 1.1rem, prose */
.hero-copy, .about-copy, .contact-copy, .page-intro, .post-head { display: flex; flex-direction: column; align-items: flex-start; }
.hero-copy > * + *, .about-copy > * + *, .contact-copy > * + *, .page-intro > * + *, .post-head > * + * { margin-top: 1.1rem; }
.hero-copy > .kicker + h1, .about-copy > .kicker + h2, .contact-copy > .kicker + h2, .page-intro > .kicker + h1, .post-head > .kicker + h1 { margin-top: .9rem; }

/* ============================ shared components ============================ */

/* plain typographic kicker — no pill, no border, no dot, no icon */
.kicker { color: var(--muted); font-size: .74rem; font-weight: 650; letter-spacing: .12em; line-height: 1.4; text-transform: uppercase; }
/* the left aligned kickers earn a short accent rule; centred ones (trust, contact) and the
   statement label stay plain, and no section kicker carries a number any more — the only
   numerals left on the page are the process step indexes */
.kicker-rule { display: inline-flex; align-items: center; gap: .6rem; }
.kicker-rule::before { content: ""; flex: none; width: 28px; height: 2px; border-radius: 1px; background: var(--accent); }
.kicker-light { color: var(--light-muted); }

/* exactly two button styles: filled pill and outlined pill, one shared geometry, never a glyph.
   Round 16: both carry the accent instead of the ink. The filled pill is orange, the outlined
   pill is drawn in orange and fills orange on hover, and the two dark-canvas variants say the
   same thing on the ink slabs, so "primary" reads identically on every background the site has.
   Geometry is untouched: same min-height, padding, radius and weights as the ink pills had, the
   outlined pill's border-subtracted padding included. */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: .5rem; font-family: inherit; font-size: .85rem; font-weight: 650; letter-spacing: -.005em; transition: background 180ms ease, color 180ms ease, border-color 180ms ease; }
.btn-solid { min-height: 48px; padding: .85rem 1.7rem; border-radius: 999px; background: var(--accent); color: #fff; }
.btn-solid:hover { background: var(--accent-deep); }
/* the filled pill on a dark canvas is now the same pill, deliberately: it used to invert to
   the light fill, which made the contact CTA read as a different primary from the hero's */
.btn-solid-light { background: var(--accent); color: #fff; }
.btn-solid-light:hover { background: var(--accent-deep); }
.btn-block { width: 100%; }
/* the 1px border is subtracted from the padding so an outlined pill measures exactly like a filled one side by side */
.btn-outline { min-height: 48px; padding: calc(.85rem - 1px) calc(1.7rem - 1px); border: 1px solid var(--accent); border-radius: 999px; background: transparent; color: var(--ink); }
.btn-outline:hover { background: var(--accent); color: #fff; }
.btn-outline-light { border-color: var(--accent); color: var(--light); }
.btn-outline-light:hover { border-color: var(--accent); background: var(--accent); color: #fff; }

/* the hand-drawn icon set: each glyph is a PNG alpha mask painted with currentColor,
   so it recolours from whatever context it sits in. Size always comes from that context. */
.icon { display: inline-block; flex: none; background-color: currentColor; mask: var(--icon) center / contain no-repeat; -webkit-mask: var(--icon) center / contain no-repeat; }

.circle-arrow { display: inline-flex; flex: none; width: 40px; height: 40px; align-items: center; justify-content: center; border: 1px solid var(--line); border-radius: 999px; color: var(--muted); transition: color 200ms ease, border-color 200ms ease; }
/* the mask is painted, not inherited as text colour, so the glyph needs its own background transition to follow the hover */
.circle-arrow .icon { width: 16px; height: 16px; transition: background-color 200ms ease; }

.check-list li, .price-features li, .area-list li { display: flex; align-items: flex-start; gap: .55rem; }
.check-icon { width: 16px; height: 16px; margin-top: .22rem; color: var(--accent-deep); }

/* ================================ photography ============================== */

/* the wrapper carries the box (radius, size); the photo is absolute so the box
   keeps stretching to its column exactly as the flat blocks used to */
.photo { position: relative; width: 100%; overflow: hidden; border-radius: var(--radius-card); background: var(--photo-bg); }
.photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center; }
/* both portraits sit high in frame — bias the crop towards the face */
.photo-hero img, .photo-about img { object-position: center 25%; }

/* ================================== header ================================= */

.site-header { position: fixed; top: 1rem; left: 50%; z-index: 50; width: var(--shell); transform: translateX(-50%); }
.header-inner { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: .55rem .75rem .55rem 1.6rem; border: 1px solid var(--line); border-radius: 999px; background: rgba(251, 248, 243, .9); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); }
.brand { display: inline-flex; align-items: baseline; }
/* the lift is optical, not layout: Caveat's ink mass sits low on its baseline, so in a
   row flex-centred against the nav and the CTA the wordmark measured 2.7px below the
   pill's centre while the nav read 1.0px below it. translateY(-.066em) is that 1.7px
   difference, written in em so the 1.7rem mark on small screens scales with it. */
.brand-mark { font-family: 'Caveat', 'Caveat Fallback', "Segoe Script", cursive; font-size: 1.9rem; font-weight: 600; letter-spacing: normal; line-height: 1; transform: translateY(-.066em); }
.nav { display: flex; margin-inline: auto; align-items: center; gap: clamp(1rem, 2.1vw, 2.1rem); font-size: .8rem; font-weight: 600; }
.nav a { transition: color 180ms ease; }
.nav a:hover { color: var(--accent-deep); }
.header-cta { min-height: 44px; padding: .7rem 1.35rem; font-size: .8rem; }
.label-short { display: none; }

/* ================================ mobile menu ============================== */

/* Below 820px the desktop nav is display: none, which left the CTA as the only control
   in the pill and no way at all to reach a subpage from the header. The menu fills that
   slot. It is off entirely up here: the breakpoint at the bottom of the file is the only
   place it is switched on, so nothing about the desktop header changes.
   No hamburger: the trigger is the same filled pill as the CTA it stands in for, with a
   word on it, because the site draws no glyph inside a button anywhere else either. */
.mobile-menu { display: none; }
/* the panel hangs off .site-header rather than off the trigger, so it measures the full
   width of the pill above it instead of the width of the button that opened it. .site-header
   is fixed, so it is already the containing block and nothing else needs a position. */
/* Opening and shutting is a fade with an 8px drop rather than a jump. The closed panel is
   transparent and lifted, not just absent: the script drops hidden first, lets the browser
   compute that state, and only then adds .is-open, so there is a frame to transition from.
   Shutting runs the same way in reverse and hidden goes back on after the fade, which is
   why display: none can no longer be the only thing standing between the two states. */
.mobile-panel { position: absolute; top: 100%; right: 0; left: 0; margin-top: .5rem; padding: 1rem; border: 1px solid var(--line); border-radius: var(--radius-card); background: var(--surface); opacity: 0; transform: translateY(-8px); transition: opacity 220ms cubic-bezier(.22, .61, .36, 1), transform 220ms cubic-bezier(.22, .61, .36, 1); }
.mobile-panel.is-open { opacity: 1; transform: none; }
/* nothing in a panel on its way out can be tapped: the fade lasts 220ms and a second tap
   inside that window would otherwise land on whichever link sits under the finger */
.mobile-panel:not(.is-open) { pointer-events: none; }
/* the panel closes by toggling the hidden attribute, which keeps the links out of the tab
   order and the accessibility tree; this restates the UA rule so no later display can win */
.mobile-panel[hidden] { display: none; }
.mobile-nav { display: flex; flex-direction: column; padding-bottom: .75rem; border-bottom: 1px solid var(--line); font-size: .95rem; font-weight: 600; }
.mobile-nav a { padding: .8rem 1rem; border-radius: 12px; transition: background 180ms ease, color 180ms ease; }
.mobile-nav a:hover { background: var(--bg); color: var(--accent-deep); }
.mobile-panel .btn { margin-top: .75rem; }
/* reduced motion: no glide at all. The panel is simply there the moment hidden comes off
   and gone the moment it goes back on, so the script never waits for a transitionend that
   would never fire. This sits here rather than in the block at the foot of the file so it
   cannot be read apart from the rules it undoes. */
@media (prefers-reduced-motion: reduce) {
  .mobile-panel { opacity: 1; transform: none; transition: none; }
  .mobile-panel:not(.is-open) { pointer-events: auto; }
}

/* =================================== hero ================================== */

.hero { padding: 7.5rem 0 clamp(2.5rem, 5vw, 4rem); }
/* subpage opening block: a fuller clearance under the fixed header than the hero canvas needs */
.page-top { padding: clamp(9rem, 11vw, 10rem) 0 clamp(2.5rem, 5vw, 4rem); }
.hero-canvas { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); gap: clamp(2.5rem, 5vw, 4.5rem); align-items: stretch; padding: clamp(2.5rem, 5vw, 4.5rem); border: 1px solid var(--line); border-radius: var(--radius-canvas); background: var(--surface); }
.hero-copy { justify-content: center; }
.hero-lead { max-width: 36em; color: var(--muted); font-size: 1.08rem; line-height: 1.65; }
.hero-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; margin-top: 2rem; }
.hero-visual { display: flex; }
.photo-hero { min-height: 520px; }

/* above the stacking breakpoint the canvas is a real header block, roughly four fifths
   of the viewport. svh keeps it stable while mobile browser chrome slides in and out;
   the clamp floor stops short viewports from crushing the copy, the cap stops very tall
   ones from turning it into a full screen splash. Below 820px the stack keeps its
   natural height — see the max-width: 820px block. */
@media (min-width: 821px) {
  .hero-canvas { min-height: 80vh; min-height: clamp(560px, 80svh, 960px); }
}

/* =============================== trust tiles =============================== */

/* no canvas here: the centered header and the grid sit straight on the page background */
.trust-head { display: flex; flex-direction: column; align-items: center; gap: .9rem; text-align: center; }
.trust-grid { display: grid; grid-template-columns: 1fr minmax(300px, 380px) 1fr; grid-template-rows: 1fr 1fr; gap: 1rem; align-items: stretch; margin-top: 2.5rem; }
/* the same light card as the area and price grids: a shade lighter than the page
   background and outlined with the shared hairline, but no hover, because a tile is
   not a link. space-between anchors the icon to the top and the copy to the bottom, so
   the tall desktop tiles carry their breathing space in the middle, not under the icon */
.trust-tile { display: flex; flex-direction: column; align-items: flex-start; justify-content: space-between; padding: 1.5rem 1.6rem; border: 1px solid var(--line); border-radius: 20px; background: var(--surface); }
/* the only dark icon badges on the page, deliberate and scoped to this section.
   the margin is the minimum gap; on stretched tiles space-between opens it further */
.trust-icon { display: inline-flex; flex: none; margin-bottom: 1.5rem; color: var(--accent-deep); }
.trust-icon .icon { width: 34px; height: 34px; }
.trust-tile p { color: var(--muted); font-size: 1rem; line-height: 1.55; }
.trust-tile strong { color: var(--ink); font-weight: 650; }
/* the photo comes first in the DOM (that is the small screen order); here it is lifted into the middle column */
.trust-photo { grid-column: 2; grid-row: 1 / -1; border-radius: 20px; }
.trust-tile:nth-of-type(1) { grid-column: 1; grid-row: 1; }
.trust-tile:nth-of-type(2) { grid-column: 1; grid-row: 2; }
.trust-tile:nth-of-type(3) { grid-column: 3; grid-row: 1; }
.trust-tile:nth-of-type(4) { grid-column: 3; grid-row: 2; }

/* only the three column layout: the centre photo sets the height of the whole block and the
   two 1fr rows split it, so each flanking tile lands around 262px. Scoped to a min-width so it
   never fights the fixed height the full width photo keeps in the stacked layout below. */
@media (min-width: 1121px) {
  .trust-photo { min-height: 540px; }
}

/* =============================== support areas ============================= */

/* Four equal categories, folding into two pairs and then one column on phones. */
.areas-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1rem; }
.area-card { display: flex; min-height: 215px; flex-direction: column; align-items: flex-start; gap: .8rem; padding: 1.75rem; border: 1px solid var(--line); border-radius: var(--radius-card); background: var(--surface); transition: border-color 200ms ease, background 200ms ease; }
.area-card:hover { border-color: var(--accent-line); background: var(--surface-tint); }
.area-icon { display: inline-flex; margin-bottom: .4rem; color: var(--accent-deep); }
.area-icon .icon { width: 32px; height: 32px; }
/* the same checked line as the about column and the price features, set at the smaller of the
   two scales. A plain vertical stack rather than the about block's two columns: a category
   card is read top to bottom. Grid stretch keeps each row level; the arrow's auto margin
   holds it on the bottom edge regardless of the number of conditions. */
.area-list { display: flex; flex-direction: column; gap: .5rem; width: 100%; }
.area-list li { color: var(--muted); font-size: .875rem; line-height: 1.5; overflow-wrap: anywhere; }
.area-card .circle-arrow { margin-top: auto; align-self: flex-end; }
.area-card:hover .circle-arrow { border-color: var(--accent-deep); color: var(--accent-deep); }
.areas-note { margin-top: 1.5rem; color: var(--muted); font-size: .85rem; }

/* ================================ statement ================================ */

.statement-canvas { display: flex; flex-direction: column; align-items: center; gap: 2rem; padding: clamp(4rem, 7vw, 6.5rem) clamp(1.5rem, 5vw, 4rem); border-radius: var(--radius-canvas); background: var(--ink); color: var(--light); text-align: center; }
/* same correction as the headings, on the one blockquote that carries an accent: at 375
   the quote stacks eight lines and 1.18 left the Caveat "Łączę fakty," 2px under the line
   above it. 1.22 restores the clearance the Inter-only pairs already had. */
.statement-quote { max-width: 880px; font-size: clamp(1.8rem, 3.8vw, 3.1rem); font-weight: 620; letter-spacing: -.03em; line-height: 1.22; }

/* ================================= process ================================= */

/* three bare columns straight on the page background: photo on top, step copy under it, no card and no border */
.process-steps { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.25rem; }
.photo-process { aspect-ratio: 4 / 3; }
/* the last numerals on the page, so they sit a touch larger and bolder than the kicker base */
.step-index { display: block; margin-top: 1.25rem; color: var(--accent-deep); font-size: .8rem; font-weight: 700; }
.process-step h3 { margin-top: .5rem; }
.process-step p { margin-top: .6rem; color: var(--muted); font-size: .95rem; line-height: 1.65; }

/* ================================== about ================================== */

.about-grid { display: grid; grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr); gap: clamp(2.5rem, 6vw, 5rem); align-items: stretch; }
.about-visual { display: flex; }
.photo-about { min-height: 560px; }
.about-copy { justify-content: center; }
.about-copy p:not(.kicker):not(.about-lead) { color: var(--muted); font-size: .95rem; line-height: 1.65; }
/* same lead-in pattern as the trust tiles: the opening phrase lifts out of the muted body */
.about-copy strong { color: var(--ink); font-weight: 650; }
.about-lead { max-width: 36em; color: var(--ink); font-size: 1.08rem; line-height: 1.65; }
.check-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .8rem 1.5rem; width: 100%; max-width: 34rem; margin-top: 1.75rem; }
.check-list li { font-size: .95rem; line-height: 1.5; }
.about-copy > .btn { margin-top: 1.9rem; }

/* ================================= pricing ================================= */

/* September 2026: the "not sure where to start" line sits under the offer heading, which
   leaves the lead on the right alone and bottom aligned like every other head. It keeps the
   lead's colour but not its 1.08rem: at that size it measured 537px in the 530px column and
   broke before its last two words; at 1rem it runs 497px and holds one line on desktop */
.section-head-note { font-size: 1rem; }
.section-head-note a { color: var(--ink); text-decoration: underline; text-underline-offset: .2em; }
.section-head-note a:hover { color: var(--accent-deep); }
.pricing-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1rem; }
.price-card { display: flex; flex-direction: column; padding: 1.75rem 1.6rem; border: 1px solid var(--line); border-radius: var(--radius-card); background: var(--surface); transition: border-color 200ms ease, background 200ms ease; }
.price-card:hover { border-color: var(--accent-line); background: var(--surface-tint); }
.price-card:hover .price-features { border-top-color: rgba(33, 30, 26, .14); }
.price-card.is-featured { border-color: var(--accent-line); background: var(--surface-tint); }
.price-card.is-featured .price-features { border-top-color: rgba(33, 30, 26, .14); }
.price-top { display: flex; min-height: 1.75rem; align-items: flex-start; justify-content: space-between; gap: .5rem; color: var(--muted); font-size: .74rem; font-weight: 650; letter-spacing: .12em; }
/* the only accent coloured pill on the page, and it carries information rather than decoration */
.price-badge { padding: .32rem .6rem; border-radius: 999px; background: var(--accent); color: #fff; font-size: .62rem; font-weight: 700; letter-spacing: .05em; line-height: 1.25; text-align: center; text-transform: uppercase; }
.price-card h3 { min-height: 3.25rem; margin-top: 1.4rem; }
.price-value { margin-top: 1rem; font-size: clamp(2.2rem, 2.6vw, 2.7rem); font-weight: 620; letter-spacing: -.02em; line-height: 1; }
.price-note { min-height: 2.4rem; margin-top: .6rem; color: var(--muted); font-size: .8rem; line-height: 1.5; }
/* September 2026: a step down from 1rem, so the description no longer outweighs the
   price above it; still a touch larger than the .85rem features, as the client suggested */
.price-description { margin-top: 1.1rem; color: var(--ink-soft); font-size: .9rem; line-height: 1.55; }
.price-features { flex: 1; display: flex; flex-direction: column; gap: .5rem; margin-top: 1.25rem; padding-top: 1.25rem; border-top: 1px solid var(--line); transition: border-color 200ms ease; }
.price-features li { color: var(--muted); font-size: .85rem; line-height: 1.5; }
.price-card .btn { margin-top: 1.6rem; }
.offer-note { margin-top: 1.5rem; color: var(--muted); font-size: .8rem; }

/* ================================= contact ================================= */

/* copy only, centred on one axis like the statement canvas */
.contact-canvas { padding: clamp(3.5rem, 7vw, 6rem) clamp(1.75rem, 5vw, 4rem); border-radius: var(--radius-canvas); background: var(--ink); color: var(--light); text-align: center; }
.contact-copy { align-items: center; justify-content: center; }
.contact-canvas h2 { max-width: 20ch; }
.contact-lead { max-width: 36em; color: var(--light-muted); font-size: 1.08rem; line-height: 1.65; }
.contact-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 1rem; margin-top: 2rem; }

/* ================================== footer ================================= */

.footer { padding-block: 4rem 2.5rem; }
/* four columns since the site grew: brand, page links, contact, socials */
.footer-grid { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, .7fr) minmax(0, .9fr) minmax(0, 1fr); gap: clamp(1.5rem, 3vw, 2.5rem); }
.footer-brand p { max-width: 17rem; margin-top: .9rem; color: var(--muted); font-size: .85rem; }
.footer-col { display: flex; flex-direction: column; align-items: flex-start; gap: .55rem; color: var(--muted); font-size: .85rem; }
.footer-label { margin-bottom: .35rem; color: var(--ink); font-size: .74rem; font-weight: 650; letter-spacing: .12em; text-transform: uppercase; }
.footer-col a { display: inline-flex; align-items: center; gap: .5rem; transition: color 180ms ease; }
.footer-col a:hover { color: var(--accent-deep); }
/* .footer-col a is already an inline-flex row with align-items: center, so the glyph centres on its line */
.footer-icon { width: 16px; height: 16px; color: var(--accent-deep); }
.footer-bottom { display: flex; justify-content: space-between; gap: .75rem; margin-top: 3rem; padding-top: 1.5rem; border-top: 1px solid var(--line); color: var(--muted); font-size: .74rem; }
.footer-bottom a { transition: color 180ms ease; }
.footer-bottom a:hover { color: var(--accent-deep); }

/* ================================ subpages ================================= */

/* every subpage opens with the same block: kicker, H1, lead. No canvas, the copy
   sits straight on the page background so the landing hero stays the only one */
.page-intro h1 { max-width: 18ch; }
.page-intro .lead { color: var(--muted); font-size: 1.08rem; }
/* the first content section after an intro block already has the intro padding above it */
/* on subpages every block after the intro shares one halved rhythm, so the visual gap
   between intro, content sections and the closing CTA band is identical (2 × 4rem) */
.page-top ~ .section { padding-block: clamp(2.5rem, 5vw, 4rem); }

/* the card recap of "Jak wygląda współpraca" on /oferta. It was one of twin sections until
   the /o-mnie subpage retired in September 2026, and keeps the recipe the pair shared: the
   light card of the area and price grids, three up on the same 1rem gap, same type inside,
   and whatever opens a card starting flush with its padding. */
.steps-list { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1rem; }
.steps-list > * { display: flex; flex-direction: column; align-items: flex-start; padding: 1.6rem 1.7rem; border: 1px solid var(--line); border-radius: var(--radius-card); background: var(--surface); }
.steps-list > * > :first-child { margin-top: 0; }
.steps-list h3 { margin-top: .5rem; }
.steps-list p { margin-top: .6rem; color: var(--muted); font-size: .95rem; line-height: 1.65; }

/* ================================== blog =================================== */

.blog-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.25rem; }
/* the whole card is one link, laid out with the same rhythm as a process column */
.blog-card { display: flex; flex-direction: column; align-items: flex-start; }
.photo-cover { aspect-ratio: 4 / 3; }
/* the index thumbnails are square, which buys each one about a third more height in the
   same column; the article's own cover keeps the wider 4:3 frame it opens with */
.blog-card .photo-cover { aspect-ratio: 1 / 1; }
.blog-card h3 { margin-top: .5rem; transition: color 180ms ease; }
.blog-card:hover h3 { color: var(--accent-deep); }
.blog-card p { margin-top: .6rem; color: var(--muted); font-size: .95rem; line-height: 1.65; }

/* two editorial tiers on one axis: the cover runs the full 860px article block, the text
   column stays at a comfortable 74ch inside it. Both centred within the narrow container. */
.post-shell { width: 100%; max-width: min(860px, 100%); margin-inline: auto; }
.post-cover { margin-bottom: 2rem; }
.post-head, .prose, .post-footer { width: 100%; max-width: 74ch; margin-inline: auto; }
.post-head h1 { max-width: none; font-size: clamp(2.3rem, 3.6vw, 3.3rem); }

/* article typography: headings step down to body scale, prose stays muted */
.prose { margin-top: 2.5rem; }
.prose h2 { margin-top: 2.5rem; font-size: 1.5rem; font-weight: 600; letter-spacing: -.015em; line-height: 1.3; }
.prose p { margin-top: 1.1rem; color: var(--muted); font-size: 1rem; line-height: 1.75; }
.prose ul { display: flex; flex-direction: column; gap: .55rem; margin-top: 1.1rem; }
.prose li { display: flex; align-items: flex-start; gap: .65rem; color: var(--muted); font-size: 1rem; line-height: 1.7; }
.prose li::before { content: ""; flex: none; width: 6px; height: 6px; margin-top: .58rem; border-radius: 999px; background: var(--accent); }
.prose strong { color: var(--ink); font-weight: 650; }
.prose em { font-style: italic; }
.post-footer { display: flex; margin-top: 3rem; padding-top: 2rem; border-top: 1px solid var(--line); }

/* ============================== contact page =============================== */

.contact-layout { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); gap: clamp(2rem, 4vw, 3.5rem); align-items: start; }
.contact-form { display: flex; flex-direction: column; gap: 1.1rem; }
.form-field { display: flex; flex-direction: column; gap: .45rem; }
.form-field label { color: var(--ink); font-size: .8rem; font-weight: 650; }
.form-field input, .form-field select, .form-field textarea { width: 100%; padding: .8rem 1rem; border: 1px solid var(--line); border-radius: 14px; background: var(--surface); color: var(--ink); font-family: inherit; font-size: .95rem; line-height: 1.5; }
/* the native chevron sits hard against the right edge and is drawn in the platform's own
   grey, so the select gives up its UI and paints the glyph itself: the same 12px stroked
   chevron the rest of the page would draw, on the same 1.1rem inset the eye reads as the
   field's own gutter. The colour is baked because a data URI cannot see currentColor;
   #6f6759 is --muted written out. Everything else (fill, border, radius, type) is still
   the shared field rule above. */
.form-field select { appearance: none; -webkit-appearance: none; -moz-appearance: none; padding-right: 2.75rem; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none' stroke='%236f6759' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 4.75 6 8.25l3.5-3.5'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 1.1rem center; background-size: 12px 12px; }
/* vertical only, and with a ceiling: dragged past this the field used to keep going and
   push the whole two column layout apart */
.form-field textarea { min-height: 9rem; max-height: 24rem; resize: vertical; }
.form-field input::placeholder, .form-field textarea::placeholder { color: var(--muted); }
.contact-form .btn { align-self: flex-start; }
.form-note { color: var(--muted); font-size: .8rem; line-height: 1.55; }

/* September 2026: the form books a visit, so it carries a few more controls. Every one is
   built from the field recipe above (label type, fill, hairline, radius), not a look of its own */
.form-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.1rem; }
.form-optional { color: var(--muted); font-weight: 500; }
/* the date block closes whenever the topic needs no visit; hidden is restated so the grid
   display below can never win over it */
.form-booking { display: grid; gap: 1.1rem; min-width: 0; margin: 0; padding: 0; border: 0; }
.form-booking[hidden] { display: none; }
.form-choice { min-width: 0; margin: 0; padding: 0; border: 0; }
.form-choice legend { margin-bottom: .45rem; padding: 0; color: var(--ink); font-size: .8rem; font-weight: 650; }
.form-choice-options { display: flex; flex-wrap: wrap; gap: .6rem 1.75rem; }
/* podpowiedź pod pytaniem wyboru w ankiecie przed wizytą (wtyczka Dieturi Rezerwacje) */
.form-choice legend + .form-note { margin: -.15rem 0 .6rem; }

/* ankieta przed wizytą (strona ?ankieta= z wtyczki Dieturi Rezerwacje): jedna kolumna na
   środku, intro wyśrodkowane, wizyta w jednym wierszu nad pytaniami, pytania na jednej
   karcie rozdzielone hairline'ami. Pola dostają tło strony, żeby odcinać się od karty. */
.survey-intro { align-items: center; margin-inline: auto; text-align: center; }
.survey-intro h1, .survey-intro .lead { margin-inline: auto; }
.survey { max-width: 44rem; margin-inline: auto; }
.survey-visit { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: .35rem .6rem; margin-bottom: 1.5rem; padding: .9rem 1.25rem; border: 1px solid var(--line); border-radius: 18px; background: var(--surface-tint); color: var(--ink); font-size: .95rem; line-height: 1.5; }
.survey-visit .icon { width: 18px; height: 18px; color: var(--accent-deep); }
.survey-visit strong { font-weight: 650; }
.survey-visit span { color: var(--ink-soft); }
.survey-form { gap: 0; padding: clamp(1.5rem, 3.5vw, 2.5rem); border: 1px solid var(--line); border-radius: var(--radius-card); background: var(--surface); }
.survey-form .form-status { margin-bottom: 1.25rem; }
.survey-question { padding: 1.4rem 0; border-top: 1px solid var(--line); }
.survey-question:first-of-type { padding-top: 0; border-top: 0; }
.survey-form .form-field label, .survey-form .form-choice legend { font-size: .92rem; }
.survey-form .form-field textarea { min-height: 6rem; background: var(--bg); }
.survey-form .form-choice-options { gap: .55rem 1.5rem; }
.survey-form .form-consent { padding-top: 1.4rem; border-top: 1px solid var(--line); }
.survey-form .btn { margin-top: 1.25rem; }
.survey-form > .form-note { margin-top: .9rem; }
.survey .form-success { align-items: center; text-align: center; }
/* radios and the consent box stay native, tinted with the accent rather than redrawn */
.form-check { display: inline-flex; align-items: flex-start; gap: .6rem; color: var(--ink); font-size: .95rem; line-height: 1.5; cursor: pointer; }
.form-check input { flex: none; width: 18px; height: 18px; margin: .15rem 0 0; accent-color: var(--accent); }
.form-consent { display: flex; flex-direction: column; gap: .45rem; }
.form-consent .form-check { color: var(--muted); font-size: .8rem; line-height: 1.55; }
.form-consent .form-check input { margin-top: .05rem; }
.form-consent a { color: var(--ink); text-decoration: underline; text-underline-offset: .2em; }
.form-consent a:hover { color: var(--accent-deep); }
.form-error { color: var(--error); font-size: .8rem; font-weight: 600; line-height: 1.45; }
.form-field [aria-invalid="true"] { border-color: var(--error); }
/* the bot trap: out of sight and out of the tab order, but still part of the form */
.form-trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.contact-form[aria-busy="true"] .btn { opacity: .6; pointer-events: none; }
/* both blocks set their own display, which would otherwise outrank the hidden attribute */
.contact-form[hidden], .form-success[hidden] { display: none; }
/* what replaces the form once it is sent: the same card as the direct details beside it */
.form-success { display: flex; flex-direction: column; align-items: flex-start; gap: .75rem; padding: clamp(1.5rem, 3vw, 2rem); border: 1px solid var(--line); border-radius: var(--radius-card); background: var(--surface); }
.form-success .icon { width: 28px; height: 28px; color: var(--accent-deep); }
.form-success h2 { font-size: 1.2rem; font-weight: 620; letter-spacing: -.02em; line-height: 1.3; }
.form-success p { color: var(--muted); font-size: .95rem; }
.form-success .btn { margin-top: .5rem; }

/* the booking calendar: app/kontakt/booking-calendar.tsx, and the theme's
   assets/js/booking-calendar.js, which renders the same markup. It stands on the page
   background like every field above it rather than on a card of its own. A free day is the
   field recipe in miniature (surface fill, hairline, 12px corner) and anything that cannot be
   booked is bare muted type, so the few bookable days are what the eye finds first. Every
   state is read from the ARIA attribute the markup carries anyway, never from a parallel
   class, so the look cannot drift from what a screen reader is told. The cap keeps the tiles
   from swelling in the one column tablet layout; the desktop column is narrower than it. */
.booking-calendar { max-width: 34rem; }
.calendar-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.calendar-month { color: var(--ink); font-size: 1.05rem; font-weight: 620; letter-spacing: -.01em; line-height: 1.3; }
.calendar-nav { display: flex; gap: .5rem; }
/* the area cards draw .circle-arrow on a span; as a button it spells out its own fill and cursor */
.calendar-nav .circle-arrow { padding: 0; background: var(--surface); cursor: pointer; }
.calendar-nav .circle-arrow:hover { border-color: var(--accent-line); color: var(--accent-deep); }
/* aria-disabled rather than disabled: a disabled button would drop the focus it holds the
   moment the last month comes up */
.calendar-nav .circle-arrow[aria-disabled="true"] { border-color: var(--line); color: var(--muted); opacity: .4; cursor: default; }
/* one glyph, drawn pointing right; the previous month mirrors it */
.calendar-prev .icon { transform: scaleX(-1); }
/* a real table, for the grid semantics. border-spacing opens the gutter between the tiles and
   the negative margin hands the same 4px back on the outside, so the outer tiles line up with
   the fields above and below */
.calendar-grid { width: calc(100% + 8px); margin: calc(1rem - 4px) -4px -4px; border-collapse: separate; border-spacing: 4px; table-layout: fixed; }
/* the weekday row speaks in the kicker's voice; text-indent pays back the trailing letter
   spacing, so each label centres on its column */
.calendar-grid th { padding: 0 0 .2rem; color: var(--muted); font-size: .74rem; font-weight: 650; letter-spacing: .12em; line-height: 1.4; text-align: center; text-indent: .12em; text-transform: uppercase; }
.calendar-grid td { padding: 0; }
.calendar-day { position: relative; display: flex; width: 100%; aspect-ratio: 6 / 5; align-items: center; justify-content: center; padding: 0; border: 1px solid var(--line); border-radius: 12px; background: var(--surface); color: var(--ink); font-family: inherit; font-size: .95rem; font-weight: 560; font-variant-numeric: tabular-nums; line-height: 1; cursor: pointer; transition: background 180ms ease, border-color 180ms ease, color 180ms ease; }
.calendar-day:hover, .calendar-day:focus-visible { border-color: var(--accent-line); }
/* the shared 3px offset would reach across the gutter into the neighbouring tile */
.calendar-day:focus-visible, .calendar-hour:focus-visible { outline-offset: 1px; }
/* the arrow keys still walk onto these days, so focus shows on them, but nothing invites a click */
.calendar-day[aria-disabled="true"] { border-color: transparent; background: transparent; color: var(--muted); font-weight: 400; cursor: default; }
.calendar-day[aria-disabled="true"]:focus-visible { border-color: var(--accent-line); }
/* the chosen day takes the filled button's colours and its hover, a step heavier because
   white on the accent needs the weight to stay legible */
[aria-selected="true"] > .calendar-day { border-color: var(--accent); background: var(--accent); color: #fff; font-weight: 620; }
[aria-selected="true"] > .calendar-day:hover { border-color: var(--accent-deep); background: var(--accent-deep); }
/* today: the kicker's accent rule, shortened, under the numeral. It hangs from the tile's
   centre in em, so it keeps the same distance from the figure on the smaller phone tiles */
.calendar-day[aria-current="date"]::after { content: ""; position: absolute; top: calc(50% + .75em); right: 0; left: 0; width: 12px; height: 2px; margin-inline: auto; border-radius: 1px; background: var(--accent); }
[aria-selected="true"] > .calendar-day[aria-current="date"]::after { background: currentColor; }
.calendar-hours { display: flex; flex-direction: column; gap: .45rem; margin-top: 1.25rem; }
/* the flex display above would otherwise outrank the hidden attribute */
.calendar-hours[hidden] { display: none; }
.calendar-hours-label { color: var(--ink); font-size: .8rem; font-weight: 650; }
/* five across still fits the widest label in the 327px phone column, and the default ten
   hours fall into two even rows */
.calendar-hour-list { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: .5rem; }
/* the field recipe again, a notch tighter: 44px tall with a 12px corner, so it stays a
   rectangle and never reads as a pill or a third button */
.calendar-hour { padding: .6rem .25rem; border: 1px solid var(--line); border-radius: 12px; background: var(--surface); color: var(--ink); font-family: inherit; font-size: .95rem; font-weight: 500; font-variant-numeric: tabular-nums; line-height: 1.5; text-align: center; cursor: pointer; transition: background 180ms ease, border-color 180ms ease, color 180ms ease; }
.calendar-hour:hover, .calendar-hour:focus-visible { border-color: var(--accent-line); }
.calendar-hour[aria-pressed="true"] { border-color: var(--accent); background: var(--accent); color: #fff; font-weight: 620; }
.calendar-hour[aria-pressed="true"]:hover { border-color: var(--accent-deep); background: var(--accent-deep); }
/* a live region has to be in the page before its text arrives or the text is not read, so
   the summary is never hidden; only its spacing waits for something to say */
.calendar-summary { color: var(--ink); font-size: .85rem; font-weight: 600; line-height: 1.5; }
.calendar-summary:not(:empty) { margin-top: 1rem; }
/* inside the slot's fieldset the messages under the calendar keep the gap a field gives its
   own; a grid parent spaces them with its gap already, so the rule stays out of it */
.form-choice > .booking-calendar ~ .form-error { margin-top: .45rem; }

/* the direct details sit on a card, so the plain form on the page background keeps the focus */
.contact-info { display: flex; flex-direction: column; align-items: flex-start; gap: .75rem; padding: clamp(1.5rem, 3vw, 2rem); border: 1px solid var(--line); border-radius: var(--radius-card); background: var(--surface); color: var(--muted); font-size: .95rem; }
.contact-info h2 { margin-bottom: .35rem; font-size: 1.2rem; font-weight: 620; letter-spacing: -.02em; line-height: 1.3; }
.contact-info a { display: inline-flex; align-items: center; gap: .55rem; transition: color 180ms ease; }
.contact-info a:hover { color: var(--accent-deep); }
.contact-info .icon { width: 16px; height: 16px; color: var(--accent-deep); }
.contact-info .form-note { margin-top: .35rem; }

/* ============================== scroll reveal ============================== */

/* every rule here hangs off html.reveal, a class the inline script at the top of
   the body adds. No JS, no class, no hiding: crawlers and no-script visitors get
   the finished page, and because the class lands before the first section parses
   there is no flash of visible content collapsing into a hidden one either.

   Two entrances share the one attribute. Everything below the fold keeps the bare
   data-reveal: hidden up front, waiting for the observer in reveal.tsx to hand out
   the .is-in that plays the transition. Everything on the first screen is marked
   data-reveal="eager" and never hides at all, because hiding it would mean waiting
   for React to hydrate before it could come back — long enough on a cold dev server
   to read as a broken, empty canvas. Eager blocks instead auto-play the same
   movement straight from the stylesheet, so the first screen is already animating
   in while the bundle is still downloading. */
@keyframes reveal-in { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }
html.reveal [data-reveal="eager"] { animation: reveal-in .6s cubic-bezier(.22, .61, .36, 1) both; }
/* the second half of an above the fold pair (hero photo after hero copy, article
   head after its cover) trails the first, same idea as the grid cascade below */
html.reveal [data-reveal="eager"] + [data-reveal="eager"] { animation-delay: 120ms; }

/* the exclusion is wrapped in :where() so it adds no specificity: this rule still
   weighs exactly what the plain [data-reveal] version weighed, and the .is-in,
   :focus-within and reduced motion overrides below keep beating it on the same
   terms they always did. A bare :not() here would outrank the reduced motion rule
   and leave every lazy block stuck at opacity 0 for those visitors. */
html.reveal [data-reveal]:not(:where([data-reveal="eager"])) { opacity: 0; transform: translateY(18px); transition: opacity .6s ease, transform .6s cubic-bezier(.22, .61, .36, 1); }
html.reveal [data-reveal].is-in { opacity: 1; transform: none; }
/* keyboard safety net: a link tabbed to before its section scrolled into view */
html.reveal [data-reveal]:focus-within { opacity: 1; transform: none; }
/* the cards and the pills carry their own hover transition, and the shorthand
   above would drop it, so both restate theirs next to the entrance pair */
html.reveal .area-card[data-reveal], html.reveal .price-card[data-reveal] { transition: opacity .6s ease, transform .6s cubic-bezier(.22, .61, .36, 1), border-color 200ms ease, background 200ms ease; }
html.reveal .btn[data-reveal] { transition: opacity .6s ease, transform .6s cubic-bezier(.22, .61, .36, 1), background 180ms ease, color 180ms ease, border-color 180ms ease; }
/* grids cascade their children by 60ms, capped at six so no row ever trails */
html.reveal [data-reveal-stagger] > [data-reveal]:nth-child(2) { transition-delay: 60ms; }
html.reveal [data-reveal-stagger] > [data-reveal]:nth-child(3) { transition-delay: 120ms; }
html.reveal [data-reveal-stagger] > [data-reveal]:nth-child(4) { transition-delay: 180ms; }
html.reveal [data-reveal-stagger] > [data-reveal]:nth-child(5) { transition-delay: 240ms; }
html.reveal [data-reveal-stagger] > [data-reveal]:nth-child(6) { transition-delay: 300ms; }

/* =============================== breakpoints =============================== */

@media (max-width: 1120px) {
  .areas-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pricing-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* photo takes a full-width first row, the four tiles sit 2×2 below it */
  .trust-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: auto; }
  .trust-photo { grid-column: 1 / -1; grid-row: auto; height: 320px; }
  .trust-grid .trust-tile { grid-area: auto; }
  .hero-canvas { grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); gap: clamp(2rem, 4vw, 3rem); }
  .about-grid { gap: clamp(2rem, 4vw, 3rem); }
  .photo-about { min-height: 480px; }
  .price-card h3 { min-height: 0; }
  .price-note { min-height: 0; }
}

@media (max-width: 980px) {
  .section-head { grid-template-columns: 1fr; align-items: start; gap: 1.1rem; }
  .lead { max-width: 42em; }
  .contact-layout { grid-template-columns: 1fr; }
}

@media (max-width: 820px) {
  .nav { display: none; }
  /* the nav leaves the pill and the menu takes its place. The child combinator is the
     whole point: it hides the CTA sitting directly in the header row without touching
     the trigger, which carries .header-cta too so both pills measure the same. */
  .mobile-menu { display: block; }
  .header-inner > .header-cta { display: none; }
  h1 { max-width: none; }
  .hero { padding-top: 6.75rem; }
  .page-top { padding-top: 8rem; }
  .hero-canvas { grid-template-columns: 1fr; }
  .photo-hero { min-height: 0; height: 400px; }
  /* the three step columns stack, each photo keeps its 4/3 frame above its own copy */
  .process-steps, .blog-grid { grid-template-columns: 1fr; gap: 2.5rem; }
  .steps-list { grid-template-columns: 1fr; }
  .page-intro h1 { max-width: none; }
  .about-grid { grid-template-columns: 1fr; }
  .about-visual { width: 100%; max-width: 560px; }
  .photo-about { min-height: 0; height: 400px; }
  .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .footer-brand { grid-column: 1 / -1; }
}

@media (max-width: 580px) {
  .header-inner { padding: .5rem .5rem .5rem 1.15rem; }
  .header-cta { min-height: 42px; padding: .6rem 1.1rem; font-size: .78rem; }
  .brand-mark { font-size: 1.7rem; }
  .label-full { display: none; }
  .label-short { display: inline; }
  h1 { font-size: clamp(2.4rem, 8.8vw, 3.1rem); }
  .hero { padding-top: 5.75rem; }
  .page-top { padding-top: 7rem; }
  .hero-canvas { padding: 1.75rem 1.35rem 2rem; }
  .hero-actions { align-items: flex-start; flex-direction: column; }
  .photo-hero { height: 340px; }
  .trust-grid { grid-template-columns: 1fr; }
  .trust-photo { height: 260px; }
  .pricing-grid, .check-list { grid-template-columns: 1fr; }
  .areas-grid { grid-template-columns: 1fr; }
  .form-row { grid-template-columns: 1fr; }
  /* 3px gutters leave seven square tiles of about 44px in the 327px column */
  .calendar-grid { width: calc(100% + 6px); margin: calc(1rem - 3px) -3px -3px; border-spacing: 3px; }
  .calendar-day { aspect-ratio: 1; border-radius: 10px; }
  .calendar-hour-list { gap: .4rem; }
  .area-card { padding: 1.45rem; }
  .photo-about { height: 340px; }
  .statement-canvas, .contact-canvas { padding-inline: 1.35rem; }
  .contact-actions { flex-direction: column; }
  .footer-grid { grid-template-columns: 1fr; gap: 2rem; }
  .footer-brand { grid-column: auto; }
  .footer-bottom { align-items: flex-start; flex-direction: column; gap: .4rem; margin-top: 2.25rem; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
  /* the scroll entrance does not run at all here: every block is simply there,
     no fade, no offset, no delay. The observer bails out the same way, and the
     eager blocks drop their keyframes rather than playing them at 0.01ms. */
  html.reveal [data-reveal], html.reveal .area-card[data-reveal], html.reveal .price-card[data-reveal], html.reveal .btn[data-reveal] { opacity: 1; transform: none; transition: none; }
  html.reveal [data-reveal="eager"] { animation: none; opacity: 1; transform: none; }
  html.reveal [data-reveal-stagger] > [data-reveal] { transition-delay: 0s; }
}

/* ===========================================================================
   ZGODNOŚĆ Z WORDPRESSEM

   Wszystko poniżej tej linii jest dodatkiem motywu i nie istnieje w wersji
   referencyjnej. Nic tutaj nie nadpisuje reguł z góry pliku, sekcja tylko
   dokłada obsługę elementów, których statyczna aplikacja nie miała: paska
   administratora, bloków Gutenberga w treści wpisu i paginacji.
   =========================================================================== */

/* ------------------------------ pasek admina ------------------------------ */

/* nagłówek jest position: fixed, więc musi zejść o wysokość paska WordPressa */
body.admin-bar .site-header { top: calc(1rem + 32px); }
/* the offset may only apply when the link is focused, otherwise the hidden pill peeks from the top edge */
body.admin-bar .skip-link:focus { top: calc(1rem + 32px); }

@media screen and (max-width: 782px) {
  body.admin-bar .site-header { top: calc(1rem + 46px); }
  body.admin-bar .skip-link:focus { top: calc(1rem + 46px); }
}

/* --------------------------- pomocnicze klasy WP -------------------------- */

.screen-reader-text { position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); border: 0; white-space: nowrap; }
.screen-reader-text:focus { top: 1rem; left: 1rem; z-index: 100; width: auto; height: auto; margin: 0; padding: .75rem 1rem; clip: auto; clip-path: none; border-radius: 999px; background: var(--ink); color: var(--light); font-size: .8rem; font-weight: 650; }

/* motyw nie deklaruje wsparcia dla align-wide, ale zaimportowana treść może
   nieść te klasy z innej instalacji: sprowadzamy je do szerokości kolumny */
.prose .alignwide, .prose .alignfull { width: 100%; max-width: 100%; margin-left: 0; margin-right: 0; }
.prose .alignfull { border-radius: var(--radius-card); }
.prose .alignleft { float: left; margin: .4rem 1.5rem 1rem 0; max-width: 50%; }
.prose .alignright { float: right; margin: .4rem 0 1rem 1.5rem; max-width: 50%; }
.prose .aligncenter { margin-inline: auto; }
.prose::after { content: ""; display: block; clear: both; }

/* --------------------- bloki Gutenberga wewnątrz .prose ------------------- */

/* akapit i nagłówki: h2 ma już regułę wyżej, tutaj tylko pozostałe stopnie */
.prose h3 { margin-top: 2rem; font-size: 1.2rem; font-weight: 620; letter-spacing: -.02em; line-height: 1.3; }
.prose h4 { margin-top: 1.75rem; font-size: 1.05rem; font-weight: 650; letter-spacing: -.01em; line-height: 1.35; }
.prose h5, .prose h6 { margin-top: 1.5rem; font-size: .95rem; font-weight: 650; line-height: 1.4; }

.prose b { color: var(--ink); font-weight: 650; }
.prose i { font-style: italic; }
.prose a { color: var(--accent-deep); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .18em; transition: color 180ms ease; }
.prose a:hover { color: var(--accent); }

/* listy numerowane: kropka z reguły wyżej ustępuje licznikowi */
.prose ol { display: flex; flex-direction: column; gap: .55rem; margin-top: 1.1rem; counter-reset: dieturi-ol; }
.prose ol > li { counter-increment: dieturi-ol; }
.prose ol > li::before { content: counter(dieturi-ol) "."; width: auto; height: auto; margin-top: 0; border-radius: 0; background: none; color: var(--accent-deep); font-size: .95rem; font-weight: 700; line-height: 1.7; }
/* zagnieżdżona lista jest blokiem wewnątrz elementu listy, a nie kolejnym punktem.
   :has() zawęża zmianę wyłącznie do punktów, które faktycznie niosą podlistę,
   więc zwykły punkt renderuje się dokładnie tak jak w wersji referencyjnej */
.prose li > ul, .prose li > ol { width: 100%; margin-top: .55rem; padding-left: .25rem; }
.prose li:has(> ul), .prose li:has(> ol) { flex-wrap: wrap; }

/* obrazy, podpisy i osadzenia. Selektory celują w obrazy z treści wpisu i nigdy
   nie mogą trafić w .photo img, które trzyma kadr okładek */
.prose figure, .prose .wp-block-image, .prose .wp-block-embed, .prose .wp-block-gallery, .prose .wp-block-table { margin-top: 1.75rem; }
.prose > img, .prose figure img, .prose p img { max-width: 100%; height: auto; border-radius: var(--radius-card); }
.prose figcaption, .prose .wp-element-caption { margin-top: .7rem; color: var(--muted); font-size: .8rem; line-height: 1.55; text-align: left; }
.prose .wp-block-embed__wrapper iframe, .prose iframe { width: 100%; max-width: 100%; border-radius: var(--radius-card); }

/* cytat: ta sama typografia co statement, tylko w skali artykułu */
.prose blockquote, .prose .wp-block-quote { margin-top: 1.75rem; padding-left: 1.25rem; border-left: 2px solid var(--accent); color: var(--ink); font-size: 1.15rem; font-style: normal; line-height: 1.5; }
.prose blockquote p { color: var(--ink); font-size: 1.15rem; }
.prose blockquote cite, .prose .wp-block-quote cite { display: block; margin-top: .7rem; color: var(--muted); font-size: .8rem; font-style: normal; font-weight: 650; letter-spacing: .04em; text-transform: uppercase; }
.prose .wp-block-pullquote { margin-top: 2rem; padding: 1.75rem; border-left: 0; border-radius: var(--radius-card); background: var(--surface); text-align: center; }

/* kod, tabela, separator */
.prose pre, .prose .wp-block-code { margin-top: 1.5rem; padding: 1.1rem 1.25rem; overflow-x: auto; border-radius: 16px; background: var(--surface); color: var(--ink-soft); font-size: .85rem; line-height: 1.6; }
.prose code { padding: .1rem .35rem; border-radius: 6px; background: var(--surface); font-size: .9em; }
.prose pre code { padding: 0; background: none; }
.prose table { width: 100%; margin-top: 1.5rem; font-size: .9rem; }
.prose th, .prose td { padding: .6rem .75rem; border-bottom: 1px solid var(--line); text-align: left; }
.prose th { color: var(--ink); font-weight: 650; }
.prose td { color: var(--muted); }
.prose hr, .prose .wp-block-separator { margin-block: 2.25rem; border-top: 1px solid var(--line); }

/* przyciski Gutenberga dostają geometrię pigułek z reszty strony */
.prose .wp-block-buttons { display: flex; flex-wrap: wrap; gap: 1rem; margin-top: 1.75rem; }
.prose .wp-block-button__link { display: inline-flex; min-height: 48px; align-items: center; justify-content: center; padding: .85rem 1.7rem; border-radius: 999px; background: var(--accent); color: #fff; font-size: .85rem; font-weight: 650; text-decoration: none; transition: background 180ms ease; }
.prose .wp-block-button__link:hover { background: var(--accent-deep); color: #fff; }
.prose .is-style-outline .wp-block-button__link { padding: calc(.85rem - 1px) calc(1.7rem - 1px); border: 1px solid var(--accent); background: transparent; color: var(--ink); }
.prose .is-style-outline .wp-block-button__link:hover { background: var(--accent); color: #fff; }

/* --------------------------------- lista -------------------------------- */

/* paginacja archiwum, ta sama pigułka co przyciski, tylko mniejsza.
   the_posts_pagination() drukuje <nav class="navigation pagination"> z linkami
   w wewnętrznym .nav-links, więc układ siada na tym wewnętrznym pudełku */
.pagination { margin-top: 3rem; }
.pagination .nav-links { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: .5rem; }
.pagination .page-numbers { display: inline-flex; min-width: 40px; min-height: 40px; align-items: center; justify-content: center; padding: 0 .75rem; border: 1px solid var(--line); border-radius: 999px; color: var(--muted); font-size: .8rem; font-weight: 650; transition: border-color 200ms ease, color 200ms ease, background 200ms ease; }
.pagination .page-numbers:hover { border-color: var(--accent-line); color: var(--accent-deep); }
.pagination .page-numbers.current { border-color: var(--ink); background: var(--ink); color: var(--light); }
.pagination .page-numbers.dots { border-color: transparent; }

/* pojedynczy komunikat, np. pusty wynik wyszukiwania albo 404 */
.empty-note { margin-top: 1.5rem; color: var(--muted); font-size: 1.08rem; }

/* logo z Personalizacji, jeśli klientka ustawi własne zamiast napisu */
.custom-logo-link { display: inline-flex; align-items: center; }
.custom-logo { width: auto; max-height: 40px; }
.footer .custom-logo { max-height: 34px; }
