/* ==========================================================================
   Ondervale design system — APP MOCKUP, "the living screenshot" (v1)
   --------------------------------------------------------------------------
   A believable in-browser mockup of the flagship booking system (Live-in-
   3-Days, €99 + €19/mo), drawn entirely in HTML/CSS/SVG — no images, no
   JS, no requests. One 8s keyframe loop makes it feel like a product
   video: a booking is typed in, confirmed, slides into the calendar, and
   a reminder toast appears. Then it breathes and starts over.

   DEPENDS ON tokens.css (load FIRST). Companion of components.css; pages
   that use the mockup link BOTH. Requires nothing else — the animation is
   pure CSS, so no-JS visitors see the full living loop too.

   THE CONTRACT (three frames, one markup):
   - ANIMATED (default)          → 8s loop, the "looping video" feel.
     Opt out per instance with data-static (forced by reduced-motion
     anyway, see §5).
   - REDUCED MOTION (or a browser
     without keyframes)          → static end-state frame: the confirmed
                                   booking seated in the calendar. The base
                                   styles below ARE that frame; the loop
                                   only paints over them while it runs.
   - INK SURFACES                → deeper window shadow via .hero--ink /
                                   .section--ink scope (same deal as .mock).

   NICHE SWAP — one mockup, many markets. The root carries the content
   tokens; a skin is ONE attribute:

       <div class="app-mockup" data-skin="tutor"> …

   No attribute (or data-skin="groomer") = the default groomer skin, and
   it INHERITS the page accent — so it always looks native to the page it
   sits on. The tutor/studio skins ship their own approved accent
   (teal / graphite) for standalone use. All copy inside arrives via
   ::before content: var(--am-*) — the whole mockup is decorative
   (aria-hidden at the usage site), so pseudo-content is a11y-safe.

   COLOR: every pair reuses AA-verified combinations — gray-900/600 on
   white & gray-50, accent on its soft tint, --accent-contrast on accent,
   deep-green #166534 (approved swatch) for the confirmation. No raw
   accent ever lands on an ink surface (the window itself is light).

   PERFORMANCE: animates opacity/transform (plus stroke-dashoffset for the
   check draw) — compositor-friendly, zero layout per frame, contain:
   content isolates it. ~8KB raw / ~2KB gzip. No external assets, so the
   page budget shape is unchanged.
   ========================================================================== */

/* ---------------------------------------------------------------------------
   1. TOKENS — everything a niche swap may touch. Nothing else.
   --------------------------------------------------------------------------- */
.app-mockup {
  /* colors: inherit the page skin by default */
  --am-accent:          var(--accent);
  --am-accent-contrast: var(--accent-contrast);
  --am-ok:              #166534;   /* approved "deep-green" swatch — 7.13:1 on white */

  /* identity */
  --am-biz: "Bella's Grooming";
  --am-url: "book.ondervale.app/bellas-grooming";

  /* the booking being made (form → confirm → calendar chip → toast) */
  --am-service: "Full groom · 75 min";
  --am-client:  "Buddy R.";
  --am-slot:    "Thu · 14:00";
  --am-confirm: "Buddy R. — Full groom, Thu 14:00";
  --am-toast:   "Buddy · tomorrow 9:00";
  --am-chip-n:  "Buddy";
  --am-chip-s:  "Full groom";

  /* the week already on the books (6 appointments, name + service) */
  --am-a1n: "Luna";  --am-a1s: "Bath & brush";
  --am-a2n: "Rex";   --am-a2s: "Full groom";
  --am-a3n: "Milo";  --am-a3s: "Nail trim";
  --am-a4n: "Coco";  --am-a4s: "Full groom";
  --am-a5n: "Rocky"; --am-a5s: "Bath & brush";
  --am-a6n: "Daisy"; --am-a6s: "Nail trim";

  /* motion */
  --am-loop: 8s;
}

/* Tutor skin — approved swatch "teal" (7.04:1 on white; tutors row). */
.app-mockup[data-skin="tutor"] {
  --am-accent: #0E6363;
  --am-accent-contrast: #ffffff;

  --am-biz: "Weber Tutoring";
  --am-url: "book.ondervale.app/weber-tutoring";

  --am-service: "Math lesson · 60 min";
  --am-client:  "Jonas K.";
  --am-slot:    "Thu · 16:00";
  --am-confirm: "Jonas K. — Math lesson, Thu 16:00";
  --am-toast:   "Jonas · tomorrow 16:00";
  --am-chip-n:  "Jonas";
  --am-chip-s:  "Math lesson";

  --am-a1n: "Emma";  --am-a1s: "Latin";
  --am-a2n: "Ben";   --am-a2s: "Math";
  --am-a3n: "Lena";  --am-a3s: "Physics";
  --am-a4n: "Paul";  --am-a4s: "Essay coaching";
  --am-a5n: "Sofia"; --am-a5s: "Math";
  --am-a6n: "Noah";  --am-a6s: "Spanish";
}

/* Studio skin (the "any business" neutral) — approved swatch "graphite". */
.app-mockup[data-skin="studio"] {
  --am-accent: #3F4A56;
  --am-accent-contrast: #ffffff;

  --am-biz: "Studio Meridian";
  --am-url: "book.ondervale.app/studio-meridian";

  --am-service: "Consultation · 45 min";
  --am-client:  "A. Habermann";
  --am-slot:    "Fri · 11:00";
  --am-confirm: "A. Habermann — Consultation, Fri 11:00";
  --am-toast:   "Consultation · tomorrow 11:00";
  --am-chip-n:  "A. H.";
  --am-chip-s:  "Consultation";

  --am-a1n: "Ricarda"; --am-a1s: "Kickoff";
  --am-a2n: "Tobias";  --am-a2s: "Review";
  --am-a3n: "Ines";    --am-a3s: "Consultation";
  --am-a4n: "Marek";   --am-a4s: "Kickoff";
  --am-a5n: "Selin";   --am-a5s: "Review";
  --am-a6n: "Jonas";   --am-a6s: "Consultation";
}

/* ---------------------------------------------------------------------------
   2. CHASSIS — the browser window. Sized in em off a fluid root so the
      whole UI scales with its column (never overflows at 360px).
   --------------------------------------------------------------------------- */
.app-mockup {
  font-size: clamp(9px, 0.55vw + 7.6px, 12px);   /* 360px → 9.6px · 1440px → 12px */
  line-height: 1.4;
  color: var(--gray-900);
  contain: content;                               /* isolate layout + paint */
  max-width: 34em;                                /* ~408px at full size */
}

.am-browser {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--color-surface-raised);
  border: 1px solid var(--gray-200);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;                               /* a window clips, like a window */
}
/* On ink bands the window floats like a real screenshot (same treatment
   as .hero--ink .mock — deeper shadow, hairline edge). */
.hero--ink .am-browser,
.section--ink .am-browser {
  border-color: var(--ink-border);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
}

/* Chrome bar: three dots + URL pill */
.am-chrome {
  display: flex;
  align-items: center;
  gap: 0.7em;
  padding: 0.6em 0.9em;
  background: var(--gray-100);
  border-bottom: 1px solid var(--gray-200);
}
.am-dots { display: inline-flex; gap: 0.35em; }
.am-dots i {
  width: 0.62em; height: 0.62em;
  border-radius: var(--radius-pill);
  background: var(--gray-300);
}
.am-url {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 0.28em 0.9em;
  background: var(--color-surface-raised);
  border: 1px solid var(--gray-200);
  border-radius: var(--radius-pill);
  font-size: 0.78em;
  color: var(--gray-600);
}
.am-url::before { content: var(--am-url); }

/* ---------------------------------------------------------------------------
   3. APP BODY — calendar side | booking panel side.
   --------------------------------------------------------------------------- */
.am-app {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
}

/* ---- 3a. Calendar side -------------------------------------------------- */
.am-side {
  display: flex;
  flex-direction: column;
  gap: 0.7em;
  padding: 0.9em;
  background: var(--gray-50);
  border-right: 1px solid var(--gray-200);
  min-width: 0;
}
.am-biz { display: flex; align-items: center; gap: 0.55em; }
.am-biz-avatar {
  flex: none;
  width: 2.1em; height: 2.1em;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--am-accent) 12%, #ffffff);
  color: var(--am-accent);
  border: 1px solid color-mix(in srgb, var(--am-accent) 24%, transparent);
}
.am-biz-avatar svg { width: 1.15em; height: 1.15em; }
.am-biz-name {
  font-weight: var(--weight-bold);
  font-size: 0.95em;
  line-height: 1.2;
}
.am-biz-name::before { content: var(--am-biz); }
.am-biz-sub {
  display: block;
  font-size: 0.72em;
  color: var(--gray-500);
}
.am-biz-sub::before { content: "This week"; }

/* Week grid: 5 day columns */
.am-cal {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 0.45em;
  flex: 1;
}
.am-day {
  display: flex;
  flex-direction: column;
  gap: 0.45em;
  min-width: 0;
}
.am-day-h {
  font-size: 0.66em;
  font-weight: var(--weight-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gray-600);                       /* gray-500 misses AA on gray-50 */
  text-align: center;
}
.am-day-body {
  display: flex;
  flex-direction: column;
  gap: 0.45em;
  background: var(--color-surface-raised);
  border: 1px solid var(--gray-200);
  border-radius: var(--radius-sm);
  padding: 0.4em 0.3em;
  flex: 1;
}

/* Appointment chip: name + time row, service under. Token-fed. */
.am-apt {
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--am-accent) 10%, #ffffff);
  border: 1px solid color-mix(in srgb, var(--am-accent) 20%, transparent);
  padding: 0.35em 0.45em;
  font-size: 0.78em;
  line-height: 1.25;
  min-width: 0;
}
.am-apt-top {
  display: flex;
  justify-content: space-between;
  gap: 0.3em;
  font-weight: var(--weight-bold);
  color: var(--gray-900);
}
.am-apt-top .am-t {
  color: var(--gray-600);                       /* keeps AA on the accent tint */
  font-weight: var(--weight-medium);
  font-variant-numeric: tabular-nums;
  flex: 0 0 auto;
  white-space: nowrap;
}
.am-apt-svc {
  display: block;
  font-size: 0.82em;
  color: var(--gray-600);
  overflow: visible;
  white-space: normal;
  overflow-wrap: anywhere;
  line-height: 1.3;
}
.am-a1n::before { content: var(--am-a1n); } .am-a1s::before { content: var(--am-a1s); }
.am-a2n::before { content: var(--am-a2n); } .am-a2s::before { content: var(--am-a2s); }
.am-a3n::before { content: var(--am-a3n); } .am-a3s::before { content: var(--am-a3s); }
.am-a4n::before { content: var(--am-a4n); } .am-a4s::before { content: var(--am-a4s); }
.am-a5n::before { content: var(--am-a5n); } .am-a5s::before { content: var(--am-a5s); }
.am-a6n::before { content: var(--am-a6n); } .am-a6s::before { content: var(--am-a6s); }

/* Empty slot: dashed cell waiting for a booking. The one marked
   --target is the loop's landing zone. */
.am-slot {
  position: relative;
  border: 1px dashed var(--gray-300);
  border-radius: var(--radius-sm);
  padding: 0.35em 0.45em;
  font-size: 0.78em;
  color: var(--gray-500);
  min-height: 3.4em;
}
.am-slot-time { font-variant-numeric: tabular-nums; }

/* The booking that arrives: solid accent fill (contrast pair = AA by the
   swatch table). BASE STATE = SEATED (the static frame); the loop hides
   it until its cue. */
.am-chip-new {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.1em;
  padding: 0.3em 0.5em;
  border-radius: var(--radius-sm);
  background: var(--am-accent);
  color: var(--am-accent-contrast);
  line-height: 1.25;
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.am-chip-new .am-n { font-weight: var(--weight-bold); }
.am-chip-new .am-n::before { content: var(--am-chip-n); }
.am-chip-new .am-s {
  font-size: 0.9em;
  opacity: 0.92;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.am-chip-new .am-s::before { content: var(--am-chip-s); }

/* ---- 3b. Booking panel — form and confirmation stack in one cell ------- */
.am-panel {
  position: relative;
  min-height: 24em;
}
.am-form,
.am-confirm {
  position: absolute;
  inset: 1em 0.9em;
  display: flex;
  flex-direction: column;
  gap: 0.8em;
}
/* Base = the settled frame: confirmation in place, form hidden. */
.am-form { opacity: 0; }

.am-form-title {
  margin: 0;
  font-size: 0.95em;
  font-weight: var(--weight-bold);
}
.am-field {
  border: 1px solid var(--gray-200);
  border-radius: var(--radius-sm);
  padding: 0.5em 0.65em;
  background: var(--color-surface-raised);
}
.am-label {
  display: block;
  font-size: 0.68em;
  font-weight: var(--weight-bold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gray-500);
  margin-bottom: 0.15em;
}
.am-value {
  display: block;
  font-size: 0.88em;
  font-weight: var(--weight-medium);
  color: var(--gray-900);
  min-height: 1.25em;
  white-space: nowrap;
  overflow: hidden;
}
/* Values arrive via token + clip "typing" in the loop */
.am-v-service::before { content: var(--am-service); }
.am-v-client::before  { content: var(--am-client); }
.am-v-slot::before    { content: var(--am-slot); }

.am-btn {
  margin-top: 0.2em;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.65em 0.8em;
  border-radius: var(--radius-sm);
  background: var(--am-accent);
  color: var(--am-accent-contrast);
  font-size: 0.85em;
  font-weight: 600;
  box-shadow: var(--shadow-sm);
}

/* Confirmation card */
.am-confirm-card {
  border: 1px solid color-mix(in srgb, var(--am-ok) 26%, transparent);
  background: color-mix(in srgb, var(--am-ok) 7%, #ffffff);
  border-radius: var(--radius-md);
  padding: 0.8em;
  display: flex;
  gap: 0.7em;
  align-items: flex-start;
}
.am-check { width: 2.6em; height: 2.6em; flex: none; color: var(--am-ok); }
.am-confirm-title {
  display: block;
  margin: 0;
  font-size: 1em;
  font-weight: var(--weight-bold);
  color: var(--am-ok);
}
.am-confirm-detail { display: block; margin: 0; font-size: 0.85em; color: var(--gray-900); }
.am-confirm-detail::before { content: var(--am-confirm); }
.am-confirm-note {
  display: block;
  margin: 0.3em 0 0;
  font-size: 0.75em;
  color: var(--gray-600);
}
.am-confirm-note::before { content: "Reminder scheduled · client emailed automatically"; }
.am-panel-foot {
  margin-top: auto;
  font-size: 0.72em;
  color: var(--gray-500);
}

/* ---- 3c. Reminder toast --------------------------------------------------- */
.am-toast {
  position: absolute;
  top: 3.1em; right: 0.8em;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 0.55em;
  padding: 0.55em 0.8em 0.55em 0.55em;
  background: var(--color-surface-raised);
  border: 1px solid var(--gray-200);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  max-width: 15em;
  opacity: 0;                                   /* base = hidden (settled frame) */
}
.am-toast-icon {
  flex: none;
  width: 1.9em; height: 1.9em;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--am-accent) 12%, #ffffff);
  color: var(--am-accent);
}
.am-toast-icon svg { width: 1em; height: 1em; }
.am-toast strong { display: block; font-size: 0.8em; line-height: 1.25; }
.am-toast-text { display: block; font-size: 0.72em; color: var(--gray-600); }
.am-toast-text::before { content: var(--am-toast); }

/* ---------------------------------------------------------------------------
   3d. PLACEMENT — .am-duo puts the mockup beside a result/offer card:
       numbers left, living screenshot right; stacks under 880px (the same
       one exception .hero--split already owns).
   --------------------------------------------------------------------------- */
.am-duo {
  display: grid;
  gap: var(--space-8);
  align-items: center;
}
@media (min-width: 880px) {
  .am-duo { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}
.am-duo .app-mockup { margin-inline: auto; }

/* Caption under the window (page supplies the sentence — copy slot) */
.am-caption {
  margin: var(--space-3) 0 0;
  font-size: var(--text-small);
  color: var(--color-text-muted);
  text-align: center;
}
.hero--ink .am-caption,
.section--ink .am-caption { color: var(--color-on-ink-muted); }

/* ---------------------------------------------------------------------------
   4. THE LOOP — one 8s timeline, every actor on the same clock.
      (Timing sheet + rationale: docs/app-mockup/README.md)

        0.0s ─ 2.3s  form fills (service → client → slot, typed in)
        2.1s ─ 2.6s  button press
        2.9s ─ 3.2s  form ⇄ confirmation swap
        3.3s ─ 4.5s  check draws · booking slides into the empty slot
        4.6s ─ 6.4s  reminder toast in, holds, out
        7.0s ─ 7.4s  scene gently resets · 0.6s breathe → loop
   --------------------------------------------------------------------------- */

/* (a) panel swap */
@keyframes am-form-timeline {
  0%       { opacity: 1; transform: none; }
  34%      { opacity: 1; transform: none; }
  36.5%    { opacity: 0; transform: translateY(0.6em); }
  89%      { opacity: 0; transform: translateY(0.6em); }
  93%,100% { opacity: 1; transform: none; }
}
@keyframes am-confirm-timeline {
  0%       { opacity: 0; transform: translateY(0.6em); }
  36.5%    { opacity: 0; transform: translateY(0.6em); }
  40%      { opacity: 1; transform: none; }
  89%      { opacity: 1; transform: none; }
  93%,100% { opacity: 0; transform: translateY(0.6em); }
}

/* (b) typing — values clip in with steps() so they read as keystrokes */
@keyframes am-type-service {
  0%, 4%    { clip-path: inset(0 100% 0 0); }
  12%       { clip-path: inset(0 0 0 0); }
  88%       { clip-path: inset(0 0 0 0); }
  92%,100%  { clip-path: inset(0 100% 0 0); }
}
@keyframes am-type-client {
  0%, 13%   { clip-path: inset(0 100% 0 0); }
  21%       { clip-path: inset(0 0 0 0); }
  88%       { clip-path: inset(0 0 0 0); }
  92%,100%  { clip-path: inset(0 100% 0 0); }
}
@keyframes am-type-slot {
  0%, 22%   { clip-path: inset(0 100% 0 0); }
  29%       { clip-path: inset(0 0 0 0); }
  88%       { clip-path: inset(0 0 0 0); }
  92%,100%  { clip-path: inset(0 100% 0 0); }
}

/* (c) button press at ~2.1s */
@keyframes am-press {
  0%, 26%   { transform: none; }
  29%       { transform: scale(0.96); }
  32%,100%  { transform: none; }
}

/* (d) the booking lands: chip slides into the slot, slot outline firms up */
@keyframes am-chip-arrive {
  0%, 42%   { opacity: 0; transform: translateY(-0.9em) scale(0.94); }
  48%       { opacity: 1; transform: translateY(0.15em) scale(1); }
  50%       { transform: none; }
  88%       { opacity: 1; transform: none; }
  93%,100%  { opacity: 0; transform: translateY(-0.9em) scale(0.94); }
}
@keyframes am-slot-hold {
  0%, 42%   { border-color: var(--gray-300); border-style: dashed; }
  50%       { border-color: color-mix(in srgb, var(--am-accent) 34%, transparent); border-style: solid; }
  88%       { border-color: color-mix(in srgb, var(--am-accent) 34%, transparent); border-style: solid; }
  93%,100%  { border-color: var(--gray-300); border-style: dashed; }
}

/* (e) check draws itself (dasharray is set with the animation) */
@keyframes am-check-draw {
  0%, 41%   { stroke-dashoffset: 60; }
  54%, 88%  { stroke-dashoffset: 0; }
  93%,100%  { stroke-dashoffset: 60; }
}
@keyframes am-check-tick {
  0%, 45%   { stroke-dashoffset: 20; }
  56%, 88%  { stroke-dashoffset: 0; }
  93%,100%  { stroke-dashoffset: 20; }
}

/* (f) reminder toast */
@keyframes am-toast-timeline {
  0%, 58%   { opacity: 0; transform: translateX(1.2em); }
  63%       { opacity: 1; transform: none; }
  75%       { opacity: 1; transform: none; }
  80%,100%  { opacity: 0; transform: translateX(1.2em); }
}

/* Casting: every instance is alive unless it opts out with [data-static].
   No JS anywhere — this is the default state of the markup. */
.app-mockup:not([data-static]) .am-form         { animation: am-form-timeline  var(--am-loop) var(--ease-out) infinite; }
.app-mockup:not([data-static]) .am-confirm      { animation: am-confirm-timeline var(--am-loop) var(--ease-out) infinite; }
.app-mockup:not([data-static]) .am-v-service    { animation: am-type-service  var(--am-loop) steps(9, end) infinite; }
.app-mockup:not([data-static]) .am-v-client     { animation: am-type-client   var(--am-loop) steps(8, end) infinite; }
.app-mockup:not([data-static]) .am-v-slot       { animation: am-type-slot     var(--am-loop) steps(7, end) infinite; }
.app-mockup:not([data-static]) .am-btn          { animation: am-press         var(--am-loop) var(--ease-out) infinite; transform-origin: 50% 50%; }
.app-mockup:not([data-static]) .am-chip-new     { animation: am-chip-arrive   var(--am-loop) var(--ease-out) infinite; }
.app-mockup:not([data-static]) .am-slot--target { animation: am-slot-hold     var(--am-loop) ease infinite; }
.app-mockup:not([data-static]) .am-check-ring   { animation: am-check-draw    var(--am-loop) ease infinite; stroke-dasharray: 60; }
.app-mockup:not([data-static]) .am-check-tick   { animation: am-check-tick    var(--am-loop) ease infinite; stroke-dasharray: 20; }
.app-mockup:not([data-static]) .am-toast        { animation: am-toast-timeline var(--am-loop) var(--ease-out) infinite; }

/* ---------------------------------------------------------------------------
   5. MOTION SAFETY — the same deal as the rest of the system: off means OFF.
      Base styles above are already the settled end-state frame ("booking
      confirmed, seated in the calendar"), so pinning animations off yields
      a believable static product screenshot — nothing to polyfill.
   --------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .app-mockup *, .app-mockup *::before, .app-mockup *::after {
    animation: none !important;
  }
}

/* Small screens: the two panes stack (window stays a window); everything
   keeps scaling in em, so nothing reflows out of place. */
@media (max-width: 420px) {
  .am-app { grid-template-columns: 1fr; }
  .am-side { border-right: 0; border-bottom: 1px solid var(--gray-200); }
}
