/* =============================================================================
   Linda-Jane Travia · Thermomix TM7 link page
   Design-system stylesheet — pure CSS, no build step, no framework.
   Works from any slug (e.g. mysite.com/linda/) because nothing is path-absolute.

   HOW TO EDIT (the spots you'll most likely want to change are flagged below):
     • PALETTE .................. see :root --color-* tokens
     • SLOPE / ANGLE ........... see :root --slope-angle  (0deg = perfectly flat)
     • BUTTON SIZING ........... see :root --btn-radius / --btn-min-h
     • TYPOGRAPHY .............. see :root --font-sans / --text-* tokens
   Each editable block carries an "EDIT:" comment. Search "EDIT:" to jump around.

   MOTION: only compositor-friendly properties are animated
   (transform / opacity / clip-path / filter). Respects prefers-reduced-motion.
   ============================================================================= */

/* =============================================================================
   1. DESIGN TOKENS  (:root custom properties)
   ============================================================================= */
:root {
  /* ---- PALETTE -------------------------------------------------------------
     EDIT: change these to re-skin the whole page.
     Thermomix fresh green is the hero colour; deep green anchors text/banners. */
  /* FRESH GEOMETRY skin — elegant Swiss minimal: near-black ink + two greens on
     white. Black anchors (banner, CTA, type); green is the disciplined accent.
     Restraint is the luxury — a narrow palette, generous white. */
  --color-ink:          #111512; /* near-black — banner field, primary CTA, type */
  --color-green:        #16a34a; /* refined fresh green (Thermomix), not neon    */
  --color-green-deep:   #0b6b30; /* forest green — contrast / hover              */
  --color-green-soft:   #eef7f1; /* whisper-green wash for icon chips            */
  --color-green-ring:   #1aa64d; /* avatar ring green                           */

  --color-bg:           #eceee9; /* soft paper field behind the card            */
  --color-surface:      #ffffff; /* white card surface                          */
  --color-surface-2:    #f4f6f2; /* faint inset (buttons, inputs)               */
  --color-text:         #111512; /* near-black primary text                     */
  --color-text-soft:    #6b726b; /* muted secondary text                        */
  --color-border:       #e6e9e3; /* hairline borders                           */

  --color-on-green:     #ffffff; /* text on a forest-green / ink fill            */
  --color-danger:       #c0392b; /* validation / error                         */
  --color-danger-soft:  #fbeae8; /* error background wash                       */
  --color-success:      #0b6b30; /* success text (forest green)                 */
  --color-success-soft: #eef7f1; /* success background wash                     */
  --color-focus:        #0a5cff; /* focus ring — high-contrast                  */

  /* ---- TYPOGRAPHY ----------------------------------------------------------
     EDIT: Inter is preloaded in the HTML; the stack falls back to system UI
     fonts automatically if the webfont is removed (fully offline-friendly). */
  --font-sans: "Inter", system-ui, -apple-system, "Segoe UI", Roboto,
               Helvetica, Arial, sans-serif;

  /* Fluid type scale (clamp keeps it readable from 320px up). EDIT freely. */
  --text-xs:   0.78rem;
  --text-sm:   0.875rem;
  --text-base: 1rem;
  --text-lg:   1.125rem;
  --text-name: clamp(1.5rem, 1.2rem + 1.6vw, 2rem);    /* profile name          */
  --text-h2:   clamp(1.25rem, 1.1rem + 0.8vw, 1.6rem); /* modal/section heads   */

  --weight-normal: 400;
  --weight-semi:   600;
  --weight-bold:   700;
  --weight-black:  800;

  /* ---- SPACING & RADIUS ----------------------------------------------------
     Intentional rhythm — not uniform padding everywhere. EDIT to taste. */
  --space-1: 0.375rem;
  --space-2: 0.625rem;
  --space-3: 0.9rem;
  --space-4: 1.25rem;
  --space-5: 1.75rem;
  --space-6: 2.5rem;
  --space-section: clamp(2rem, 1.5rem + 3vw, 3.5rem);

  --radius-card: 22px;
  --radius-sm:   10px;
  --radius-pill: 999px;

  /* ---- BUTTONS -------------------------------------------------------------
     EDIT: button geometry. Spec calls for ~14px radius + ~62px min-height. */
  --btn-radius: 14px;  /* EDIT: link-button corner radius                      */
  --btn-min-h:  62px;  /* EDIT: link-button minimum height                     */
  --btn-pad-x:  1rem;  /* horizontal padding inside link buttons               */

  /* ---- SLOPE / ANGLE -------------------------------------------------------
     EDIT: the signature sloped look is driven entirely by these two values.
     --slope-angle    controls how steep the angled banner + dividers are:
       4deg   = default subtle slant
       0deg   = perfectly flat (disables the signature angle everywhere)
       6-8deg = more dramatic editorial slant
     --slope-depth derives a pixel offset that keeps the polygon cuts and skew
     visually consistent regardless of width. Bump it if you raise the angle a
     lot. JS mirror of the angle lives in CONFIG.SLOPE_ANGLE. */
  --slope-angle: 4deg;  /* EDIT: signature slope. 0deg = flat.                 */
  /* Derived from the angle so a single knob controls everything: at 0deg this
     evaluates to 0 and the banner/modal cuts go perfectly flat. tan() of the
     angle scaled by the card width gives the polygon's vertical offset. */
  --slope-depth: calc(tan(var(--slope-angle)) * var(--maxw-card));

  /* ---- ELEVATION & MOTION --------------------------------------------------- */
  --shadow-card: 0 18px 50px -22px rgba(15, 122, 46, 0.35),
                 0 2px 8px -2px rgba(22, 38, 27, 0.08);
  --shadow-btn:  0 2px 6px -2px rgba(22, 38, 27, 0.12);
  --shadow-btn-hover: 0 10px 22px -10px rgba(15, 122, 46, 0.45);
  --shadow-float: 0 10px 30px -8px rgba(22, 38, 27, 0.35);

  --duration-fast:   150ms;
  --duration-normal: 280ms;
  --duration-slow:   520ms;
  --ease-out-expo:   cubic-bezier(0.16, 1, 0.3, 1);

  --maxw-card: 540px; /* mobile-first card width cap                           */
}

/* =============================================================================
   2. RESET / BASE
   ============================================================================= */
*,
*::before,
*::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100dvh;
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: 1.5;
  color: var(--color-text);
  /* Black field; the blurred cooking photo + scrim are painted by ::before/::after. */
  background: #05070a;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  padding: clamp(0.75rem, 0.5rem + 2vw, 2rem);
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* Atmospheric blurred cooking backdrop behind the floating white card. */
body::before {
  content: "";
  position: fixed;
  inset: -40px;                 /* overscan so blurred edges never show */
  z-index: -2;
  background: url('assets/img/bg-cooking.jpg') center / cover no-repeat;
  filter: blur(14px) brightness(0.92) saturate(1.15);
  transform: scale(1.1);
}
/* Scrim: black-dominant but lets the blurred ingredients read as a moody backdrop. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(120% 90% at 50% 32%, rgba(5,7,10,0.18) 0%, rgba(5,7,10,0.58) 70%, rgba(5,7,10,0.74) 100%);
}

img { display: block; max-width: 100%; }

a { color: var(--color-green-deep); }

h1, h2, p, ul { margin: 0; }
ul { list-style: none; padding: 0; }

/* Visible, consistent focus ring for keyboard users everywhere. */
:focus-visible {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
  border-radius: 6px;
}

/* =============================================================================
   3. CARD SURFACE  (main container — shared by index + book-demo)
   ============================================================================= */
.card {
  position: relative;
  width: 100%;
  max-width: var(--maxw-card);
  background: var(--color-surface);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  overflow: hidden;          /* clips the angled banner edge cleanly */
  padding-bottom: var(--space-5);
}

/* ----- Sloped header banner ---------------------------------------------------
   The angled bottom edge is cut with clip-path polygon. The slant magnitude is
   driven by --slope-depth (itself a function of --slope-angle). Set the angle
   to 0deg AND depth to 0 for a flat banner. */
.banner {
  position: relative;
  height: 132px;
  /* Saturated near-black field anchors identity; the green logo sits on it.
     One faint green sheen for depth — restraint over decoration. */
  background:
    radial-gradient(120% 160% at 82% -40%, rgba(22,163,74,0.22) 0%, transparent 55%),
    var(--color-ink);
  /* Angled cut: right edge lifts → signature slope. */
  clip-path: polygon(
    0 0,
    100% 0,
    100% calc(100% - var(--slope-depth)),
    0 100%
  );
}

/* Thermomix brand logo, centred near the top of the banner. */
.banner-logo {
  position: absolute;
  top: 20px;
  left: 50%;
  transform: translateX(-50%);
  height: 34px;
  width: auto;
  filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.45));
  z-index: 1;
}

/* ----- Angled section divider -------------------------------------------------
   A thin skewed bar used between sections. transform: skewY keeps it on the
   compositor. Angle = --slope-angle directly. */
.slope-divider {
  height: 2px;
  margin: var(--space-4) var(--space-5);
  background: linear-gradient(90deg, transparent, var(--color-green-ring), transparent);
  transform: skewY(calc(-1 * var(--slope-angle)));
  transform-origin: center;
}

.card-footer {
  margin-top: var(--space-4);
  padding: 0 var(--space-5);
  text-align: center;
  font-size: var(--text-sm);
  color: var(--color-text-soft);
}
.card-footer a { font-weight: var(--weight-semi); }

/* =============================================================================
   4. PROFILE  (avatar ring, name, handle, tagline)
   ============================================================================= */
.profile {
  position: relative;
  margin-top: -58px;        /* pull avatar up over the sloped banner */
  padding: 0 var(--space-5);
  text-align: center;
}

/* Avatar ring — layered conic gradient ring for depth (not a flat border). */
.avatar-ring {
  width: 124px;
  height: 124px;
  margin: 0 auto var(--space-3);
  border-radius: var(--radius-pill);
  padding: 4px;
  background: conic-gradient(
    from 210deg,
    var(--color-green),
    var(--color-green-deep),
    var(--color-green-ring),
    var(--color-green)
  );
  box-shadow: 0 8px 22px -10px rgba(15, 122, 46, 0.6);
}
.avatar-ring img {
  width: 116px;
  height: 116px;
  border-radius: var(--radius-pill);
  object-fit: cover;
  border: 4px solid var(--color-surface);
  background: var(--color-surface);
}

.profile-name {
  font-size: var(--text-name);
  font-weight: var(--weight-black);
  letter-spacing: -0.02em;
  color: var(--color-text);
}
.profile-handle {
  margin-top: 2px;
  font-size: var(--text-sm);
  font-weight: var(--weight-semi);
  color: var(--color-green-deep);
}
.profile-tagline {
  margin: var(--space-3) auto 0;
  max-width: 38ch;
  font-size: var(--text-base);
  color: var(--color-text-soft);
}

/* ----- Social icon row -------------------------------------------------------- */
.socials {
  display: flex;
  justify-content: center;
  gap: var(--space-3);
  margin-top: var(--space-4);
}
.social-link {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border-radius: var(--radius-pill);
  color: var(--color-green-deep);
  background: var(--color-green-soft);
  text-decoration: none;
  transition: transform var(--duration-fast) var(--ease-out-expo),
              background-color var(--duration-fast),
              color var(--duration-fast);
}
/* Respect the hidden attribute even though display is set above
   (app.js hides social icons whose URL is blank/placeholder). */
.social-link[hidden] { display: none !important; }
.social-link svg { width: 22px; height: 22px; }
.social-link:hover,
.social-link:focus-visible {
  transform: translateY(-3px);
  background: var(--color-green);
  color: var(--color-on-green);
}

/* =============================================================================
   5. LINK BUTTONS  (radius ~14px, min-height ~62px, hover lift + colour shift,
      leading icon/thumbnail slot)
   ============================================================================= */
.links {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: 0 var(--space-5);
}

.link-btn {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  min-height: var(--btn-min-h);          /* EDIT via --btn-min-h */
  padding: var(--space-2) var(--btn-pad-x);
  border: 1px solid var(--color-border);
  border-radius: var(--btn-radius);      /* EDIT via --btn-radius */
  background: var(--color-surface-2);    /* raised above the card for depth */
  color: var(--color-text);
  font: inherit;
  font-size: var(--text-lg);
  font-weight: var(--weight-semi);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  box-shadow: var(--shadow-btn);
  /* Animate only transform / box-shadow / colour — compositor friendly. */
  transition: transform var(--duration-fast) var(--ease-out-expo),
              box-shadow var(--duration-fast) var(--ease-out-expo),
              background-color var(--duration-fast),
              border-color var(--duration-fast),
              color var(--duration-fast);
}

/* Leading icon / thumbnail slot — accepts an inline SVG or an <img> thumbnail. */
.link-btn .thumb {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 12px;
  background: var(--color-green-soft);
  color: var(--color-green-deep);
  overflow: hidden;
  transition: background-color var(--duration-fast), color var(--duration-fast);
}
.link-btn .thumb svg { width: 22px; height: 22px; }
.link-btn .thumb img { width: 100%; height: 100%; object-fit: cover; }

.link-btn .label { flex: 1 1 auto; min-width: 0; }

.link-btn .chev {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  color: var(--color-text-soft);
  transition: transform var(--duration-fast) var(--ease-out-expo),
              color var(--duration-fast);
}
.link-btn .chev svg { width: 18px; height: 18px; }

/* Hover/focus: slight lift + colour shift (the designed states). */
.link-btn:hover,
.link-btn:focus-visible {
  transform: translateY(-2px);
  box-shadow: var(--shadow-btn-hover);
  border-color: var(--color-green);
  background: var(--color-green-soft);
}
.link-btn:hover .thumb,
.link-btn:focus-visible .thumb {
  background: var(--color-green);
  color: var(--color-on-green);
}
.link-btn:hover .chev,
.link-btn:focus-visible .chev {
  transform: translateX(3px);
  color: var(--color-green-deep);
}
.link-btn:active { transform: translateY(0); }

/* Primary CTA (Order your TM7) — solid near-black fill for unmistakable
   hierarchy; the green icon chip carries the brand. Black on a white field is
   the one bold moment. */
.link-btn.is-primary {
  background: var(--color-ink);
  border-color: transparent;
  color: #ffffff;
}
.link-btn.is-primary .thumb {
  background: var(--color-green);
  color: #ffffff;
}
.link-btn.is-primary .chev { color: rgba(255, 255, 255, 0.7); }
/* Darken (not lighten) on hover so white-on-green contrast never regresses. */
.link-btn.is-primary:hover,
.link-btn.is-primary:focus-visible {
  filter: brightness(0.92);
}

/* Internal back link (book-demo page) */
.back-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: var(--space-3) var(--space-5) 0;
  font-size: var(--text-sm);
  font-weight: var(--weight-semi);
  color: var(--color-green-deep);
  text-decoration: none;
  transition: transform var(--duration-fast) var(--ease-out-expo);
}
.back-link:hover,
.back-link:focus-visible { transform: translateX(-3px); }

/* =============================================================================
   6. MODAL / OVERLAY  (consultant form + reviews)
   ============================================================================= */
.modal {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: none;
  align-items: flex-end;       /* mobile: sheet rises from the bottom */
  justify-content: center;
  padding: 0;
  background: rgba(0, 0, 0, 0.68);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  opacity: 0;
  transition: opacity var(--duration-normal) var(--ease-out-expo);
}
.modal.is-open {
  display: flex;
  opacity: 1;
}

.modal-panel {
  position: relative;
  width: 100%;
  max-width: var(--maxw-card);
  max-height: 92dvh;
  overflow-y: auto;
  background: var(--color-surface);
  border-radius: var(--radius-card) var(--radius-card) 0 0;
  box-shadow: 0 -10px 40px -12px rgba(16, 38, 22, 0.5);
  transform: translateY(24px);
  transition: transform var(--duration-normal) var(--ease-out-expo);
}
.modal.is-open .modal-panel { transform: translateY(0); }

/* Sloped modal header — keeps the signature angle inside the overlay. */
.modal-head {
  position: relative;
  padding: var(--space-5) var(--space-5) calc(var(--space-5) + var(--slope-depth));
  background: var(--color-ink);
  color: var(--color-on-green);
  clip-path: polygon(
    0 0,
    100% 0,
    100% calc(100% - var(--slope-depth)),
    0 100%
  );
}
.modal-head h2 {
  font-size: var(--text-h2);
  font-weight: var(--weight-black);
  letter-spacing: -0.01em;
}
.modal-head p {
  margin-top: var(--space-1);
  font-size: var(--text-sm);
  color: rgba(255, 255, 255, 0.92);
}

.modal-close {
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  font-size: 1.6rem;
  line-height: 1;
  color: var(--color-on-green);
  background: rgba(255, 255, 255, 0.18);
  border: none;
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition: transform var(--duration-fast) var(--ease-out-expo),
              background-color var(--duration-fast);
}
.modal-close:hover,
.modal-close:focus-visible {
  transform: rotate(90deg);
  background: rgba(255, 255, 255, 0.3);
}

.modal-body {
  padding: var(--space-4) var(--space-5) var(--space-5);
  /* No negative pull — the sloped head is full-height on the left, so pulling
     content up would clip the first field's label. Start cleanly below it. */
  margin-top: 0;
}

/* =============================================================================
   7. FORM FIELDS  (shared by all forms: consultant, review, demo)
   ============================================================================= */
.field { margin-bottom: var(--space-3); }

/* Two-up field row (collapses to single column on small screens). */
.field-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}

.field label {
  display: block;
  margin-bottom: 6px;
  font-size: var(--text-sm);
  font-weight: var(--weight-semi);
  color: var(--color-text);
}

.field input,
.field textarea {
  width: 100%;
  padding: 0.85rem 0.9rem;
  font: inherit;
  font-size: var(--text-base);
  color: var(--color-text);
  /* Distinct from the dark modal panel so fields are clearly visible. */
  background: var(--color-surface-2);
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-sm);
  transition: border-color var(--duration-fast), box-shadow var(--duration-fast);
}
.field input::placeholder,
.field textarea::placeholder { color: var(--color-text-soft); opacity: 0.7; }
.field textarea { resize: vertical; min-height: 84px; }

.field input:focus-visible,
.field textarea:focus-visible {
  outline: none;
  border-color: var(--color-green);
  box-shadow: 0 0 0 3px rgba(40, 209, 70, 0.25);
}

/* Validation: native :user-invalid after interaction, plus JS-driven .is-invalid. */
.field input:user-invalid,
.field input.is-invalid,
.field textarea.is-invalid {
  border-color: var(--color-danger);
  box-shadow: 0 0 0 3px rgba(192, 57, 43, 0.18);
}

/* Visually-hidden but available to screen readers and keyboard focus
   (e.g. the QR text alternative). Becomes visible when focused. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.visually-hidden:focus-visible {
  position: static;
  width: auto;
  height: auto;
  margin: 0;
  overflow: visible;
  clip: auto;
  clip-path: none;
  white-space: normal;
  font-size: var(--text-xs);
  color: var(--color-green-deep);
}

/* Per-field validation message (linked to its input via aria-describedby).
   Conveys the error in text, not by colour alone. */
.field-error {
  margin: 6px 0 0;
  font-size: var(--text-xs);
  font-weight: var(--weight-semi);
  color: var(--color-danger);
}

/* Honeypot — visually hidden but reachable by bots. Do not remove. */
.hp-field {
  position: absolute !important;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Submit button */
.btn-submit {
  width: 100%;
  min-height: 54px;
  margin-top: var(--space-2);
  padding: 0 var(--space-4);
  font: inherit;
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  color: var(--color-on-green);
  /* Deep-green anchored gradient keeps white label >=4.5:1 across the button. */
  background: linear-gradient(135deg, #128a37 0%, var(--color-green-deep) 100%);
  border: none;
  border-radius: var(--btn-radius);
  cursor: pointer;
  box-shadow: var(--shadow-btn);
  transition: transform var(--duration-fast) var(--ease-out-expo),
              box-shadow var(--duration-fast) var(--ease-out-expo),
              filter var(--duration-fast);
}
.btn-submit:hover,
.btn-submit:focus-visible {
  transform: translateY(-2px);
  box-shadow: var(--shadow-btn-hover);
  /* Darken on hover so white-on-green contrast is preserved. */
  filter: brightness(0.92);
}
.btn-submit:active { transform: translateY(0); }
.btn-submit[disabled],
.btn-submit.is-loading {
  opacity: 0.7;
  cursor: progress;
  filter: none;
  transform: none;
}

/* ----- Form status / inline toast states (JS sets .is-success / .is-error) --- */
.form-status {
  margin-top: var(--space-3);
  padding: 0;
  font-size: var(--text-sm);
  font-weight: var(--weight-semi);
  text-align: center;
  min-height: 1.2em;
  color: var(--color-text-soft);
  border-radius: var(--radius-sm);
  transition: opacity var(--duration-fast);
}
.form-status.is-success {
  padding: 0.75rem 1rem;
  color: var(--color-success);
  background: var(--color-success-soft);
}
.form-status.is-error {
  padding: 0.75rem 1rem;
  color: var(--color-danger);
  background: var(--color-danger-soft);
}

/* Stand-alone toast (optional global notifications). Mirrors status styling. */
.toast {
  position: fixed;
  left: 50%;
  bottom: 1.25rem;
  z-index: 80;
  transform: translateX(-50%) translateY(12px);
  max-width: min(92vw, 420px);
  padding: 0.85rem 1.1rem;
  font-size: var(--text-sm);
  font-weight: var(--weight-semi);
  color: var(--color-on-green);
  background: var(--color-green-deep);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-float);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--duration-normal) var(--ease-out-expo),
              transform var(--duration-normal) var(--ease-out-expo);
}
.toast.is-visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
  pointer-events: auto;
}
.toast.is-error   { background: var(--color-danger); }
.toast.is-success { background: var(--color-green-deep); }

/* =============================================================================
   8. REVIEWS  (cards + star input)
   ============================================================================= */
.review-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}
.review-empty {
  text-align: center;
  color: var(--color-text-soft);
  font-size: var(--text-sm);
  padding: var(--space-4) 0;
}

.review-card {
  padding: var(--space-3) var(--space-4);
  background: var(--color-green-soft);
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--color-green);   /* accent edge for depth */
  border-radius: var(--radius-sm);
}
.review-card .r-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
}
.review-card .r-name {
  font-weight: var(--weight-bold);
  color: var(--color-text);
}
.review-card .r-date {
  font-size: var(--text-xs);
  color: var(--color-text-soft);
}
.review-card .r-stars {
  margin: 4px 0 6px;
  color: var(--color-green-deep);
  letter-spacing: 2px;
  font-size: var(--text-base);
}
.review-card .r-comment {
  font-size: var(--text-sm);
  color: var(--color-text);
  line-height: 1.55;
}

/* ----- Star rating input (CSS-only highlight via reverse-row + sibling hack) ---
   Markup lists 5★ first; we reverse it so hovering/checking a star lights up
   itself and every star to its left (which are later siblings in source). */
.star-input {
  display: inline-flex;
  flex-direction: row-reverse;
  justify-content: flex-end;
  gap: 2px;
  font-size: 1.9rem;
  line-height: 1;
}
.star-input input { position: absolute; opacity: 0; width: 0; height: 0; }
.star-input label {
  cursor: pointer;
  /* Muted grey for empty stars so the filled/empty distinction is perceivable
     (>=3:1 against white) instead of the near-invisible hairline border. */
  color: #9aa6a0;
  padding: 2px;
  margin: 0;
  transition: transform var(--duration-fast) var(--ease-out-expo),
              color var(--duration-fast);
}
.star-input label:hover,
.star-input label:hover ~ label,
.star-input input:checked ~ label {
  /* Deep green reads on both white and the green-soft card (>=5:1). */
  color: var(--color-green-deep);
}
.star-input label:hover { transform: scale(1.15); }
/* Keyboard focus ring on the active star label */
.star-input input:focus-visible + label {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
  border-radius: 6px;
}

/* =============================================================================
   9. FLOATING QR WIDGET  (fixed bottom-right desktop, collapsible mobile)
   ============================================================================= */
.qr-float {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 50;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 10px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 16px;
  box-shadow: var(--shadow-float);
  transition: transform var(--duration-normal) var(--ease-out-expo),
              opacity var(--duration-normal) var(--ease-out-expo);
}
.qr-float #qr-code { width: 116px; height: 116px; }
.qr-float #qr-code svg { width: 116px; height: 116px; display: block; }
.qr-caption {
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  letter-spacing: 0.12em;
  color: var(--color-green-deep);
}

/* Collapsed state (JS toggles data-collapsed on mobile) — slide off-screen. */
.qr-float[data-collapsed="true"] {
  transform: translateY(140%);
  opacity: 0;
  pointer-events: none;
}

/* Mobile toggle button — hidden on desktop, shown on small screens. */
.qr-toggle {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 51;
  width: 52px;
  height: 52px;
  display: none;                 /* hidden by default; shown < 768px */
  place-items: center;
  color: var(--color-on-green);
  background: linear-gradient(135deg, var(--color-green) 0%, var(--color-green-deep) 100%);
  border: none;
  border-radius: var(--radius-pill);
  cursor: pointer;
  box-shadow: var(--shadow-float);
  transition: transform var(--duration-fast) var(--ease-out-expo);
}
.qr-toggle svg { width: 24px; height: 24px; }
.qr-toggle:hover,
.qr-toggle:focus-visible { transform: scale(1.06); }

/* =============================================================================
   10. BOOK-A-DEMO  (embed + fallback form share card/form styling)
   ============================================================================= */
.demo-embed {
  padding: 0 var(--space-5) var(--space-4);
}
.demo-embed iframe {
  width: 100%;
  min-height: 640px;
  border: 0;
  border-radius: var(--radius-sm);
}
.demo-fallback {
  padding: 0 var(--space-5) var(--space-4);
}

/* =============================================================================
   11. MOTION  (fade-in on load — compositor-friendly only)
   ============================================================================= */
@keyframes fade-rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Elements flagged with [data-animate] fade + rise in. app.js sets a staggered
   animation-delay inline on each link button. */
[data-animate] {
  animation: fade-rise var(--duration-slow) var(--ease-out-expo) both;
}
/* The card itself eases in slightly slower for a deliberate entrance. */
.card[data-animate] {
  animation-duration: 640ms;
}

/* =============================================================================
   12. RESPONSIVE  (mobile-first; enhancements at >= 768px)
   ============================================================================= */
@media (min-width: 768px) {
  body { padding-top: clamp(2rem, 4vh, 4rem); }

  /* Two-up field rows expand on larger screens. */
  .field-row { grid-template-columns: 1fr 1fr; }

  /* Modal becomes a centered dialog rather than a bottom sheet. */
  .modal { align-items: center; padding: var(--space-4); }
  .modal-panel {
    border-radius: var(--radius-card);
    transform: translateY(0) scale(0.96);
  }
  .modal.is-open .modal-panel { transform: translateY(0) scale(1); }

  /* QR widget always visible on desktop; hide the mobile toggle and ignore
     any collapsed state carried over from a narrow viewport. */
  .qr-toggle { display: none !important; }
  .qr-float[data-collapsed="true"] {
    transform: none;
    opacity: 1;
    pointer-events: auto;
  }
}

/* Mobile: show the toggle, lift the QR above it. */
@media (max-width: 767px) {
  .qr-toggle { display: grid; }
  .qr-float { right: 0.75rem; bottom: 4.5rem; }
}

/* =============================================================================
   13. REDUCED MOTION  (respect user preference — disable all motion)
   ============================================================================= */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  [data-animate] { animation: none !important; opacity: 1 !important; transform: none !important; }
  .qr-float[data-collapsed="true"] { transform: none; }
}
