/* web-v2 base (BA-54 perf): page transitions, no flash on load, the prerendered first paint, accessibility fixes.
   Linked on every page by tools/prerender.mjs (post-build step); README → "Loading and the prerendered first paint". */

/* The raw design template is never shown (the runtime hides it too, but only once its deferred script runs). */
x-dc { display: none !important; }

/* Smooth page-to-page navigation: cross-document View Transitions (Chrome, Edge, Safari 18.2+; others just navigate). */
@view-transition { navigation: auto; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 220ms; animation-timing-function: cubic-bezier(.2, 0, 0, 1); }
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
  html { scroll-behavior: auto !important; }
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; scroll-behavior: auto !important; }
}

/* Prerendered first paint (html[data-pre]): the static snapshot (.dc-pre) shows until the runtime has rendered the same
   page into #dc-root, which meanwhile lays out invisibly (measurements stay right, nothing flashes). The swap script
   removes .dc-pre and data-pre in one frame. */
html[data-pre] #dc-root { position: absolute !important; top: 0; left: 0; right: 0; visibility: hidden !important; pointer-events: none !important; }
html:not([data-pre]) .dc-pre { display: none !important; }
html[data-pre].i18n-wait body { visibility: visible !important; } /* the snapshot is already translated */
@media (max-width: 767.98px) { .dc-pre-d { display: none !important; } }
@media (min-width: 768px) { .dc-pre-m { display: none !important; } }
/* The snapshot shows the final state at once: its entrance animations (fades from opacity 0, staggered delays) jump
   to their end, transitions never run — painted at once, its elements are the LCP; the live copy's animations ran
   while it was hidden and are finished at the swap. Its consent bar only for a visitor the live page will ask. */
.dc-pre, .dc-pre * { animation-duration: 0s !important; animation-delay: 0s !important; transition: none !important; }
html:not(.gm-ask) .dc-pre [data-pre-ask] { display: none !important; }

/* Accessibility (WCAG AA contrast ≥ 4.5:1 for normal text). The design's light greys measured 3.4–4.4:1 on white and
   #f7f7f7; these are the nearest darker greys that pass on both backgrounds. */
:root { --gm-grey-868686: #6e6e6e; --gm-grey-747474: #6e6e6e; }
.testimonials-name.rekt, .number, .jf-tab-n, .pd-n, .nf-eyebrow, .v2-eyebrow, .pd-eyebrow, .sub-small-title { color: #6e6e6e; }
/* … but on the dark call-to-action band (#111) the design's own grey is the one that passes (5.2:1; the darker one 3.7:1) */
.cta .sub-small-title { color: #868686; }

/* Images shown in a box of another shape were stretched (Lighthouse image-aspect-ratio): the client logos of the
   testimonials (e.g. 1142×296 into 150×50) and the 32×32 arrows into 10×13. Shown whole, undistorted, in the same box. */
img[src*="_logo."], img[src*="breadcrumb-arrow."], img[src*="arrow-triangle."] { object-fit: contain; }

/* Process page, the looping illustrations (the video frame's chapter reel, the stage cards and result bar): they fade in
   and out every few seconds. Faded with filter: opacity() instead of opacity — the same picture, but contrast checkers
   no longer catch an element mid-fade ("contrast 1:1", "#e0e0e0 on #8b8b8d") and fail the page at random; at rest the
   text is white on near-black. None of these elements has a filter of its own. Reduced motion: the design's static
   state stays. */
@media (prefers-reduced-motion: no-preference) {
  @keyframes gm-jf-ch { 0% { filter: opacity(0); transform: translateY(16px) } 4%, 21% { filter: opacity(1); transform: none } 25%, 100% { filter: opacity(0); transform: translateY(-10px) } }
  .jf-reel > .jf-ch { animation-name: gm-jf-ch; }
  @keyframes gm-st-in { 0% { filter: opacity(0); transform: translateY(14px) } 5%, 92% { filter: opacity(1); transform: none } 98%, 100% { filter: opacity(0); transform: none } }
  .st .st-in { animation-name: gm-st-in; }
}

/* Project tiles with a light title over a dark picture (home): the tile itself is dark too, so the title stays readable
   while the picture loads or if it fails, and contrast checkers measure it against the colour it really sits on. Its own
   stacking context (isolation, nothing else changes) keeps axe from ordering the tile under the white section around it
   (the runtime's display:contents wrapper confused its layer order: "#f0f0f0 on #ffffff"). */
a:has(> .project-overlay .project-title.white) { background-color: #262626; isolation: isolate; }

/* ---------------------------------------------------------------------------------------------- BA-54 qa-ui (QA) */
/* UI-6: while the snapshot shows, nothing of the live copy may show through — an element with its own inline
   "visibility: visible" (the design's SiteHeader) beat the inherited hidden state and printed a second header. */
html[data-pre] #dc-root, html[data-pre] #dc-root * { visibility: hidden !important; }

/* UI-7: a visible keyboard focus everywhere (the hero's trust badges had a transparent outline, the process tabs none);
   light on the dark closing band. */
:where(a, button, [role=button], [role=tab], [tabindex]):focus-visible { outline: 2px solid #121217; outline-offset: 3px; }
.link_hero:focus-visible, .tab-link:focus-visible { outline: 2px solid #121217 !important; outline-offset: 3px !important; }
.cta :where(a, button, [role=button], [tabindex]):focus-visible { outline-color: #fff; }

/* UI-13: Služby "Přehled cen" — on narrow phones the price pill wraps under the name instead of leaving the card. */
@media (max-width: 420px) {
  .pc-item { flex-wrap: wrap !important; row-gap: 6px; }
}
/* … and a long name wraps inside its card at every width (the desktop cards are 218 px: "Marketingové kampaně →" ran
   16 px into the padding, its Japanese name 24 px out of the card) */
.pc-name { white-space: normal !important; min-width: 0; text-wrap: balance; }
:lang(ja) .pc-name { word-break: auto-phrase; }

/* UI-14: forms — 16 px fields on phones (iOS Safari zooms into smaller ones), a star after the label of a required
   field (no new words; hidden from screen readers, which announce "required" themselves), a consent box big enough to
   hit, a floated label that never touches the field above, and the period after the consent link kept with its words. */
@media (max-width: 767px) {
  form :is(input:not([type=checkbox]):not([type=radio]):not([type=submit]):not([type=button]), textarea, select) { font-size: 16px !important; }
}
.text-field-contact:required ~ .field-label::after, .w-checkbox:has(input:required) > .form-font::after { content: " *"; content: " *" / ""; }
.w-checkbox input[type=checkbox] { width: 20px; height: 20px; flex: none; margin-top: 0; accent-color: #121217; }
.text-field-contact.area ~ .field-label[style*="top: -16%"] { top: -8px !important; }
.w-checkbox > .form-font { text-wrap: pretty; }

/* UI-15: Japanese headings and card titles break between phrases (no one-character orphans); paragraphs avoid orphans. */
:lang(ja) :is(h1, h2, h3, h4, .display-14, .blog-card h3, [class*=title], [class*=subhead], .v2-sub) { word-break: auto-phrase; text-wrap: balance; }
:lang(ja) p { text-wrap: pretty; }

/* UI-22: Japanese glyphs from the system's Japanese UI fonts (Windows fell back to a thin Yu Gothic); Latin stays Manrope. */
html:lang(ja), :lang(ja) .gm-site { --gm-font-manrope: "Manrope", "Manrope Fallback", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic Medium", "Yu Gothic UI", Meiryo; }
:lang(ja) body, :lang(ja) .gm-site { font-family: Manrope, "Manrope Fallback", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic Medium", "Yu Gothic UI", Meiryo, sans-serif !important; }

/* UI-5: the process page's hero frame is an illustration now (no video, no control). */
.jf-vframe { cursor: default; }

/* UI-2: Kontakt, the live Cal.com booking calendar (patches/41-cal-embed.mjs, /_rt/cal.js) in the space of the design's
   picture of it: 570 px on desktop, 720 px on phones, reserved before it loads (no layout shift). The link to the
   booking page shows until the calendar is there. */
.gm-cal-box { max-width: 1040px; margin: clamp(36px, 4.4vw, 56px) auto 0; }
.gm-cal { position: relative; height: 570px; overflow: auto; border: var(--gm-border-card, 1px solid #e1e1e1); border-radius: var(--gm-radius-card, 10px); background: #fff; -webkit-overflow-scrolling: touch; }
.gm-cal-fallback { position: absolute; inset: 0; display: grid; place-items: center; align-content: center; gap: 12px; padding: 24px; text-align: center; }
.gm-cal.is-ready .gm-cal-fallback { display: none; }
.gm-cal-frame { position: relative; z-index: 1; width: 100%; min-height: 100%; }
@media (max-width: 767px) { .gm-cal-box { max-width: 351px; margin-top: 28px; } .gm-cal { height: 720px; } }

/* UI-8: the hero's pause button stays clickable while the consent bar is open (the bar covered it on /ja/, where its
   text runs to five lines): /_rt/forms.js lifts the button above the bar while they would overlap. */
.gmh-pp { transform: translateY(calc(-1 * var(--gm-pp-lift, 0px))); }

/* UI-17: the home hero's poster (the finished hub, the page's LCP) stays over the live stage while the module builds its
   first scene up from nothing (.gmh-hold, set and cleared by /assets/hero/gm-hero.js), then fades into the same frame. */
.gmh-host.gmh-on.gmh-hold .gmh-poster { opacity: 1; z-index: 1; pointer-events: none; }
/* the poster has transparent parts: the stage building up under it stays hidden until the hold ends */
.gmh-host.gmh-hold > :not(.gmh-poster):not(.gmh-pp) { visibility: hidden; }
