/* =================================================================
   The only CSS that had to be written for the WordPress port.

   app.css is byte-for-byte the file the React build ships. This file
   replaces what the Motion library did with inline styles: the hero
   entrance choreography and the crossfades between carousel slides.
   ~90 lines, no dependencies.
   ================================================================= */

/* ---- hero entrance (was: Motion variants) ---- */
@keyframes wtss-rise {
  from { opacity: 0; transform: translateY(24px); }
  to   { opacity: 1; transform: none; }
}

@keyframes wtss-word {
  from { opacity: 0; transform: translateY(18px); filter: blur(12px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}

@keyframes wtss-panel {
  from { opacity: 0; transform: translateY(30px) scale(0.97); filter: blur(14px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}

@keyframes wtss-pop {
  from { opacity: 0; transform: translateY(14px) scale(0.85); }
  to   { opacity: 1; transform: none; }
}

.enter    { animation: wtss-rise  0.7s var(--ease) both; animation-delay: var(--enter-delay, 0ms); }
.word-in  { animation: wtss-word  0.7s var(--ease) both; animation-delay: var(--enter-delay, 0ms); }
.panel-in { animation: wtss-panel 0.9s var(--ease) both; animation-delay: var(--enter-delay, 0ms); }
.pop      { animation: wtss-pop   0.55s var(--ease) both; animation-delay: var(--enter-delay, 0ms); }

/* ---- alert toast (was: AnimatePresence) ---- */
@keyframes wtss-toast-in {
  from { opacity: 0; transform: translateX(46px) scale(0.95); }
  to   { opacity: 1; transform: none; }
}

.panel-toast[hidden] { display: none; }
.panel-toast.is-in { animation: wtss-toast-in 0.5s var(--ease) both; }

/* ---- chain tour: all cards rendered, active one crossfades in ---- */
@keyframes wtss-card-in {
  from { opacity: 0; transform: translateY(26px); filter: blur(10px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}

.tourcard-slot { display: none; }
.tourcard-slot.is-active {
  display: block;
  animation: wtss-card-in 0.5s var(--ease) both;
}

/* ---- testimonials: one figure visible at a time ---- */
@keyframes wtss-quote-in {
  from { opacity: 0; transform: translateY(18px); filter: blur(6px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}

.testi__figure { display: none; }
.testi__figure.is-active {
  display: flex;
  animation: wtss-quote-in 0.55s var(--ease) both;
}

/* ---- WordPress admin bar clearance ---- */
body.admin-bar .nav { top: 32px; }
@media screen and (max-width: 782px) {
  body.admin-bar .nav { top: 46px; }
}

@media (prefers-reduced-motion: reduce) {
  .enter, .word-in, .panel-in, .pop,
  .panel-toast.is-in, .tourcard-slot.is-active, .testi__figure.is-active {
    animation: none;
  }
}

/* ---- Cookie consent ----
   Deliberately not a full-screen modal: it does not block the page, because a
   banner that traps the visitor until they choose reads as a cookie wall.
   Accept and Reject are the same size and weight — consent is not valid if
   refusing is harder than agreeing. */
.cc {
  position: fixed;
  left: 16px;
  right: 16px;
  bottom: 16px;
  z-index: 120;
  display: flex;
  justify-content: center;
  pointer-events: none;
}
.cc__card {
  pointer-events: auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px 26px;
  width: min(880px, 100%);
  padding: 20px 22px;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--r-lg, 18px);
  box-shadow: 0 24px 60px -24px rgba(8, 38, 56, 0.32);
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.26s var(--ease), transform 0.26s var(--ease);
}
.cc[data-consent-open] .cc__card {
  opacity: 1;
  transform: none;
}
.cc__text { flex: 1 1 340px; min-width: 0; }
.cc__title {
  margin: 0 0 4px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1rem;
  color: var(--ink);
}
.cc__body {
  margin: 0;
  font-size: 0.9rem;
  line-height: 1.55;
  color: var(--muted);
}
.cc__body a { color: var(--blue-700); font-weight: 600; text-decoration: underline; }
.cc__actions {
  display: flex;
  gap: 10px;
  flex: 0 0 auto;
}
/* Both choices carry identical weight — same size, same solid fill, same
   typography — differing only in hue so they stay distinguishable. CNIL and
   the Dutch AP read "as easy to refuse as to accept" as covering visual
   prominence, not just click count, and an outlined Reject beside a filled
   Accept is the pattern they have fined people for. */
.cc__actions .btn {
  flex: 1 1 auto;
  justify-content: center;
  min-width: 124px;
  box-shadow: none;
}
.cc__actions .btn--ghost {
  background: var(--navy);
  color: #fff;
}
.cc__actions .btn--ghost:hover {
  background: var(--navy-900);
  color: #fff;
  box-shadow: none;
  transform: translateY(-2px);
}

@media (max-width: 560px) {
  .cc { left: 10px; right: 10px; bottom: 10px; }
  .cc__card { padding: 18px; }
  .cc__actions { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .cc__card { transition: none; transform: none; }
}

/* ---- Active nav item ----
   The React build slides a shared-layout pill between links with Motion.
   There is no Motion here, so the current item gets the same 3px gradient
   underline, statically. .nav__link is already position:relative. */
.nav__link.is-current::after {
  content: '';
  position: absolute;
  left: 14px;
  right: 14px;
  bottom: 3px;
  height: 3px;
  border-radius: 2px;
  background: var(--grad-accent);
  pointer-events: none;
}

/* ---- Pagination and search ----
   WordPress constructs with no counterpart in the React build, which had one
   page of posts and no search at all. Styled from the same tokens as the rest
   of app.css so they read as part of the design rather than bolted on. */
.pagination {
  margin-top: 44px;
}
.pagination .screen-reader-text {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.pagination .nav-links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.pagination .page-numbers {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 42px;
  height: 42px;
  padding: 0 14px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: #fff;
  color: var(--navy-600);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.95rem;
  font-variant-numeric: tabular-nums;
  text-decoration: none;
  transition: border-color 0.18s var(--ease), color 0.18s var(--ease),
    transform 0.18s var(--ease);
}
.pagination a.page-numbers:hover {
  border-color: var(--blue);
  color: var(--blue-700);
  transform: translateY(-2px);
}
.pagination .page-numbers.current {
  background: var(--blue);
  border-color: var(--blue);
  color: #fff;
}
.pagination .page-numbers.dots {
  border-color: transparent;
  background: none;
  min-width: 24px;
  padding: 0;
}

.wp-search {
  margin: 0 0 40px;
}
.wp-search__form {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  max-width: 640px;
}
.wp-search__input {
  flex: 1 1 260px;
  min-width: 0;
  padding: 13px 16px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: #fff;
  font: inherit;
  font-size: 0.98rem;
  color: var(--ink);
  transition: border-color 0.18s var(--ease), box-shadow 0.18s var(--ease);
}
.wp-search__input::placeholder {
  color: var(--muted);
}
.wp-search__input:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 4px rgba(46, 144, 250, 0.14);
}

/* ---- [hidden] must actually hide ----
   The React build toggled elements by unmounting them, so it never needed
   this. Here the contact form and its success panel swap via the hidden
   attribute, and any author `display` rule — .contact__form is display:grid —
   outranks the user-agent [hidden] rule. Without this the form and the
   success message would both be on screen after submitting. */
[hidden] { display: none !important; }
