/* ==========================================================================
   Grafweb — Interaction Layer
   Loads AFTER styles.css. Overrides/extends the button, link and surface
   system defined there. Uses only tokens already defined in styles.css'
   :root (colours) — no new palette values are introduced. Shadow / tint
   colours are derived from those tokens via color-mix().

   Contents:
     1. Motion tokens
     2. Button system: base states (hover/active/focus/disabled/loading)
     3. Button variants (primary/dark/light sheen, ghost)
     4. Button sizes (sm/lg) + icon-only
     5. Links: .text-link, site-nav links, footer links
     6. Header scrolled state
     7. Small components: .tag, .menu-toggle, .dialog-close
     8. Surfaces: price cards, work/demo cards, browser & phone mockups
     9. Scroll-reveal (data-reveal) support for motion.js
    10. Reduced motion
   ========================================================================== */

/* ---------- 1. Motion tokens ---------- */
:root {
  --btn-ease: cubic-bezier(0.2, 0.7, 0.3, 1);
  --btn-fast: 150ms;
  --btn-base: 240ms;
  --btn-press: 90ms;
}

/* ---------- 2. Button system: base states ---------- */
.button {
  position: relative;
  isolation: isolate;
  transition:
    background var(--btn-fast) var(--btn-ease),
    color var(--btn-fast) var(--btn-ease),
    border-color var(--btn-fast) var(--btn-ease),
    box-shadow var(--btn-base) var(--btn-ease),
    transform var(--btn-fast) var(--btn-ease);
  box-shadow: 0 1px 1px color-mix(in srgb, var(--ink) 6%, transparent);
}

.button:hover:not(:disabled):not(.is-loading):not([aria-disabled="true"]) {
  transform: translateY(-2px);
}

.button:active:not(:disabled):not(.is-loading):not([aria-disabled="true"]) {
  transform: translateY(0) scale(0.985);
  transition-duration: var(--btn-press);
}

.button:focus-visible {
  box-shadow:
    0 1px 1px color-mix(in srgb, var(--ink) 6%, transparent),
    0 0 0 6px color-mix(in srgb, var(--blue) 16%, transparent);
}

/* Disabled: quiet, inert, no lift/press, no loading overlay */
.button:disabled,
.button[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  box-shadow: none;
}
.button:disabled:hover,
.button[aria-disabled="true"]:hover {
  transform: none;
}

/* Loading: hides label + icon via transparent text/stroke (keeps their
   layout width so the button never jumps), shows a centred CSS spinner. */
.button.is-loading,
.button[aria-busy="true"] {
  color: transparent;
  cursor: default;
  pointer-events: none;
}
.button.is-loading::after,
.button[aria-busy="true"]::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  animation: btn-spin 0.7s linear infinite;
}
.button-primary.is-loading::after,
.button-primary[aria-busy="true"]::after,
.button-dark.is-loading::after,
.button-dark[aria-busy="true"]::after {
  border: 2px solid rgba(255, 255, 255, 0.32);
  border-top-color: #fff;
}
.button-light.is-loading::after,
.button-light[aria-busy="true"]::after,
.button-ghost.is-loading::after,
.button-ghost[aria-busy="true"]::after {
  border: 2px solid color-mix(in srgb, var(--ink) 18%, transparent);
  border-top-color: var(--ink);
}
@keyframes btn-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Icon travel on hover/press */
.button svg {
  transition: transform var(--btn-fast) var(--btn-ease);
}
.button:hover:not(:disabled):not(.is-loading):not([aria-disabled="true"])
  svg {
  transform: translateX(3px);
}
.button:active:not(:disabled):not(.is-loading):not([aria-disabled="true"])
  svg {
  transform: translateX(1px);
}
.button.is-loading svg,
.button[aria-busy="true"] svg {
  visibility: hidden;
}

/* ---------- 3. Button variants ---------- */
.button-primary,
.button-dark {
  overflow: hidden;
}
.button-primary::before,
.button-dark::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    115deg,
    transparent 30%,
    rgba(255, 255, 255, 0.16) 46%,
    transparent 62%
  );
  transform: translateX(-120%);
  transition: transform 0.55s var(--btn-ease);
  pointer-events: none;
}
.button-primary:hover:not(:disabled):not(.is-loading):not(
    [aria-disabled="true"]
  )::before,
.button-dark:hover:not(:disabled):not(.is-loading):not(
    [aria-disabled="true"]
  )::before {
  transform: translateX(120%);
}

.button-primary {
  box-shadow: 0 2px 5px -1px color-mix(in srgb, var(--blue) 40%, transparent);
}
.button-primary:hover:not(:disabled):not(.is-loading):not(
    [aria-disabled="true"]
  ) {
  box-shadow:
    0 6px 14px -6px color-mix(in srgb, var(--blue) 55%, transparent),
    0 18px 32px -18px color-mix(in srgb, var(--blue) 45%, transparent);
}
.button-primary:focus-visible {
  box-shadow:
    0 2px 5px -1px color-mix(in srgb, var(--blue) 40%, transparent),
    0 0 0 6px color-mix(in srgb, var(--blue) 22%, transparent);
}

.button-dark:hover:not(:disabled):not(.is-loading):not(
    [aria-disabled="true"]
  ) {
  box-shadow:
    0 6px 14px -6px color-mix(in srgb, var(--ink) 55%, transparent),
    0 18px 32px -18px color-mix(in srgb, var(--ink) 45%, transparent);
}

.button-light:hover:not(:disabled):not(.is-loading):not(
    [aria-disabled="true"]
  ) {
  border-color: color-mix(in srgb, var(--blue) 30%, var(--line));
  box-shadow: 0 10px 22px -16px color-mix(in srgb, var(--ink) 45%, transparent);
}

/* Ghost / tertiary — new variant, not present in styles.css */
.button-ghost {
  background: transparent;
  color: var(--ink);
  border-color: var(--line);
}
.button-ghost:hover:not(:disabled):not(.is-loading):not(
    [aria-disabled="true"]
  ) {
  background: color-mix(in srgb, var(--blue) 6%, transparent);
  border-color: color-mix(in srgb, var(--blue) 40%, var(--line));
  color: var(--blue);
}
.button-ghost:active:not(:disabled):not(.is-loading):not(
    [aria-disabled="true"]
  ) {
  background: color-mix(in srgb, var(--blue) 11%, transparent);
}

/* ---------- 4. Sizes + icon-only ---------- */
.button-sm {
  min-height: 44px; /* touch target floor, not visual floor */
  padding: 10px 16px;
  font-size: 12px;
  gap: 12px;
}
.button-sm svg {
  width: 15px;
  height: 15px;
}
.button-lg {
  min-height: 60px;
  padding: 17px 28px;
  font-size: 15px;
  gap: 26px;
}
.button-lg svg {
  width: 20px;
  height: 20px;
}

.button-icon {
  width: 44px;
  min-width: 44px;
  min-height: 44px;
  padding: 0;
  gap: 0;
  border-radius: 50%;
}
.button-icon svg {
  width: 20px;
  height: 20px;
}
.button-icon.button-lg {
  width: 52px;
  min-width: 52px;
  min-height: 52px;
}
.button-icon.button-lg svg {
  width: 22px;
  height: 22px;
}
.button-icon.is-loading::after,
.button-icon[aria-busy="true"]::after {
  width: 16px;
  height: 16px;
}

/* ---------- 5. Links ---------- */
.text-link {
  position: relative;
  transition: color var(--btn-fast) var(--btn-ease);
}
.text-link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -3px;
  height: 1px;
  background: currentColor;
  opacity: 0;
  transition: opacity var(--btn-fast) var(--btn-ease);
}
.text-link:hover::after,
.text-link:focus-visible::after {
  opacity: 1;
}
.text-link svg {
  transition: transform var(--btn-fast) var(--btn-ease);
}
.text-link:hover svg,
.text-link:focus-visible svg {
  transform: translateX(4px);
}

.site-nav > a:not(.button) {
  position: relative;
  transition: color var(--btn-fast) var(--btn-ease);
}
.site-nav > a:not(.button)::after {
  content: "";
  position: absolute;
  left: 6px;
  right: 6px;
  bottom: 2px;
  height: 2px;
  border-radius: 2px;
  background: var(--blue);
  opacity: 0;
  transition: opacity var(--btn-fast) var(--btn-ease);
}
.site-nav > a:not(.button):hover::after,
.site-nav > a:not(.button):focus-visible::after {
  opacity: 1;
}

.footer-links a,
.footer-bottom a,
.footer-bottom > button {
  position: relative;
  transition: color var(--btn-fast) var(--btn-ease);
}
.footer-links a::after,
.footer-bottom a::after,
.footer-bottom > button::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 1px;
  background: currentColor;
  opacity: 0;
  transition: opacity var(--btn-fast) var(--btn-ease);
}
.footer-links a:hover::after,
.footer-links a:focus-visible::after,
.footer-bottom a:hover::after,
.footer-bottom a:focus-visible::after,
.footer-bottom > button:hover::after,
.footer-bottom > button:focus-visible::after {
  opacity: 1;
}

/* ---------- 6. Header scrolled state ---------- */
.site-header {
  transition:
    border-color var(--btn-base) var(--btn-ease),
    box-shadow var(--btn-base) var(--btn-ease),
    background var(--btn-base) var(--btn-ease);
}
.site-header.scrolled {
  box-shadow:
    0 1px 0 var(--line),
    0 16px 28px -22px color-mix(in srgb, var(--ink) 40%, transparent);
}

/* ---------- 7. Small components ---------- */
.tag {
  transition:
    color var(--btn-fast) var(--btn-ease),
    border-color var(--btn-fast) var(--btn-ease),
    background var(--btn-fast) var(--btn-ease);
}
.work-card:hover .tag,
.work-card:focus-within .tag {
  color: var(--blue);
  border-color: color-mix(in srgb, var(--blue) 45%, var(--line));
}

.menu-toggle {
  transition:
    background var(--btn-fast) var(--btn-ease),
    border-color var(--btn-fast) var(--btn-ease),
    transform var(--btn-fast) var(--btn-ease);
}
.menu-toggle:hover {
  background: var(--paper);
  border-color: color-mix(in srgb, var(--blue) 30%, var(--line));
}
.menu-toggle:active {
  transform: scale(0.94);
}

.dialog-close {
  width: 44px;
  height: 44px;
  transition:
    background var(--btn-fast) var(--btn-ease),
    box-shadow var(--btn-fast) var(--btn-ease),
    transform var(--btn-fast) var(--btn-ease);
}
.dialog-close:hover {
  background: var(--mist);
  box-shadow: 0 6px 14px -6px color-mix(in srgb, var(--ink) 35%, transparent);
}
.dialog-close:active {
  transform: scale(0.92);
}
.dialog-close svg {
  transition: transform var(--btn-fast) var(--btn-ease);
}
.dialog-close:hover svg {
  transform: rotate(90deg);
}

/* ---------- 8. Surfaces ---------- */
.price-card {
  transition:
    transform var(--btn-base) var(--btn-ease),
    box-shadow var(--btn-base) var(--btn-ease),
    border-color var(--btn-base) var(--btn-ease);
}
.price-card:hover {
  transform: translateY(-4px);
  border-color: color-mix(in srgb, var(--blue) 30%, var(--line));
  box-shadow: 0 24px 44px -30px color-mix(in srgb, var(--ink) 55%, transparent);
}
.price-card.featured:hover {
  box-shadow: 0 26px 48px -26px color-mix(in srgb, var(--blue) 50%, transparent);
}

.work-visual {
  transition: box-shadow var(--btn-base) var(--btn-ease);
}
.work-visual:hover,
.work-visual:focus-visible {
  box-shadow: 0 26px 50px -30px color-mix(in srgb, var(--ink) 60%, transparent);
}
.work-visual:active {
  transform: none; /* keep the resting rotate/position, only the preview reacts */
}
.work-preview {
  transition: transform var(--btn-base) var(--btn-ease);
}
.work-visual:hover .work-preview,
.work-visual:focus-visible .work-preview {
  transform: translateY(-8px) scale(1.012);
}
.work-visual:active .work-preview {
  transform: translateY(-4px) scale(1.004);
}
.work-open {
  transition:
    transform var(--btn-fast) var(--btn-ease),
    box-shadow var(--btn-fast) var(--btn-ease);
}
.work-visual:hover .work-open,
.work-visual:focus-visible .work-open {
  transform: translate(2px, -2px) scale(1.08);
  box-shadow: 0 8px 18px -6px color-mix(in srgb, var(--ink) 45%, transparent);
}
.work-visual:active .work-open {
  transform: scale(0.94);
}

.browser-mock,
.phone-mock {
  transition:
    transform var(--btn-base) var(--btn-ease),
    box-shadow var(--btn-base) var(--btn-ease);
}
.showcase:hover .browser-mock {
  transform: rotate(-1.2deg) translateY(-6px);
  box-shadow: 0 34px 60px -30px color-mix(in srgb, var(--ink) 55%, transparent);
}
.showcase:hover .phone-mock {
  transform: rotate(4deg) translateY(-8px);
  box-shadow: 0 26px 50px -22px color-mix(in srgb, var(--ink) 55%, transparent);
}

/* ---------- 9. Scroll reveal (paired with motion.js) ---------- */
/* Default: fully visible. If motion.js never runs (blocked, old browser,
   error), nothing below this line ever applies and content stays put. */
[data-reveal] {
  opacity: 1;
  transform: none;
}
/* motion.js adds "reveal-ready" to <html> only once it has confirmed
   IntersectionObserver support and that reduced motion is NOT requested. */
.reveal-ready [data-reveal] {
  opacity: 0;
  transform: translateY(24px);
  transition:
    opacity 0.6s var(--btn-ease),
    transform 0.6s var(--btn-ease);
  transition-delay: var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}
.reveal-ready [data-reveal].is-visible {
  opacity: 1;
  transform: none;
}

/* ---------- 10. Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  .button,
  .button::before,
  .button svg,
  .text-link,
  .text-link::after,
  .text-link svg,
  .site-nav > a:not(.button)::after,
  .footer-links a::after,
  .footer-bottom a::after,
  .footer-bottom > button::after,
  .site-header,
  .menu-toggle,
  .dialog-close,
  .dialog-close svg,
  .tag,
  .price-card,
  .work-visual,
  .work-preview,
  .work-open,
  .browser-mock,
  .phone-mock,
  [data-reveal] {
    transition: none !important;
    animation: none !important;
  }

  .button:hover:not(:disabled):not(.is-loading):not([aria-disabled="true"]),
  .button:active:not(:disabled):not(.is-loading):not([aria-disabled="true"]),
  .button:hover:not(:disabled):not(.is-loading):not([aria-disabled="true"])
    svg,
  .button:active:not(:disabled):not(.is-loading):not([aria-disabled="true"])
    svg,
  .button-primary::before,
  .button-dark::before,
  .menu-toggle:active,
  .dialog-close:active,
  .dialog-close:hover svg,
  .price-card:hover,
  .work-visual:hover .work-preview,
  .work-visual:active .work-preview,
  .work-visual:hover .work-open,
  .work-visual:active .work-open,
  .showcase:hover .browser-mock,
  .showcase:hover .phone-mock {
    transform: none !important;
  }

  .button.is-loading::after,
  .button[aria-busy="true"]::after {
    animation: none !important;
  }

  /* Belt-and-suspenders: even if motion.js already flagged the document as
     reveal-ready, content must stay visible once the user prefers less
     motion — this also covers a mid-session preference flip. */
  .reveal-ready [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
  }
}

/* ---------- 11. Touch-Ziele (Integrationsdurchgang) ---------- */
/* Textlinks und die Fusszeilen-Knöpfe sind bewusst klein gesetzt. Auf
   Touch-Geräten wird die Trefferfläche über ein Pseudoelement auf 44px
   gezogen, statt über Padding — so bleibt das Layout unverändert. */
@media (pointer: coarse) {
  .text-link,
  .footer-links a,
  .footer-bottom > button {
    position: relative;
  }
  .text-link::before,
  .footer-links a::before,
  .footer-bottom > button::before {
    content: "";
    position: absolute;
    inset: 50% 0 auto 0;
    height: 44px;
    transform: translateY(-50%);
    pointer-events: auto;
  }
}

/* ---------- 12. Druck (Integrationsdurchgang) ---------- */
/* Beim Drucken darf nichts unsichtbar bleiben, was nur wegen des
   Scroll-Reveals noch nicht eingeblendet wurde. */
@media print {
  .reveal-ready [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}
