/* varyAlive homepage — ported from Laura's design bundle (2026-08-04, Toby).
   Source: crew-uploads/1785863895421-f850360f.html (desktop) + ...75b65a5f.html (mobile).
   Palette: accent #7A4DD6 / deep #552FA8 / dark #1B1329 / bg #FBF8F4 / ink #1F1B18.
   The bundle carried ZERO @media rules (two fixed canvases). All breakpoints below
   are authored here, not in the design. */

/* ---------- Fonts ---------- */
@font-face { font-family:'Outfit'; font-style:normal; font-weight:400; font-display:swap; src:url("../assets/home/fonts/Outfit-400.woff2") format('woff2'); }
@font-face { font-family:'Outfit'; font-style:normal; font-weight:600; font-display:swap; src:url("../assets/home/fonts/Outfit-600.woff2") format('woff2'); }
@font-face { font-family:'Outfit'; font-style:normal; font-weight:700; font-display:swap; src:url("../assets/home/fonts/Outfit-700.woff2") format('woff2'); }
@font-face { font-family:'Outfit'; font-style:normal; font-weight:800; font-display:swap; src:url("../assets/home/fonts/Outfit-800.woff2") format('woff2'); }
@font-face { font-family:'Manrope'; font-style:normal; font-weight:400; font-display:swap; src:url("../assets/home/fonts/Manrope-400.woff2") format('woff2'); }
@font-face { font-family:'Manrope'; font-style:normal; font-weight:500; font-display:swap; src:url("../assets/home/fonts/Manrope-500.woff2") format('woff2'); }
@font-face { font-family:'Manrope'; font-style:normal; font-weight:600; font-display:swap; src:url("../assets/home/fonts/Manrope-600.woff2") format('woff2'); }
@font-face { font-family:'Manrope'; font-style:normal; font-weight:700; font-display:swap; src:url("../assets/home/fonts/Manrope-700.woff2") format('woff2'); }

/* ---------- Base ---------- */
*{ box-sizing:border-box; }
html,body{ margin:0; padding:0; }
body{ background:#FBF8F4; }
#va-home{ width:100% !important; max-width:100%; margin:0 auto; }
#va-home img{ max-width:100%; }
a{ -webkit-tap-highlight-color:transparent; }

/* ---------- Language toggle (DE/EN) ----------
   Ported from css/base.css:109-110 (this page doesn't load base.css). The wrap
   spans are plain/style-less, so this non-important display:none has nothing to
   override — no !important needed and no collision with the bundle's inline
   display:inline-flex on other elements. */
html[lang="de"] [lang="en"]{ display:none; }
html[lang="en"] [lang="de"]{ display:none; }

/* Nav DE/EN buttons. Active/inactive state lives here (was inline on the two
   buttons) so js/language-toggle.js toggling .active actually changes the look. */
.lang-btn{ border:1px solid transparent; background:none; color:rgb(107,100,94); font-family:Manrope,sans-serif; font-size:12px; font-weight:600; padding:4px 8px; border-radius:6px; cursor:pointer; }
.lang-btn.active{ background:rgb(251,248,244); color:rgb(31,27,24); font-weight:700; border-color:rgba(31,27,24,0.14); box-shadow:0 1px 2px rgba(31,27,24,0.12); }

/* Grid safety net. Grid items default to min-width:auto, so a track whose
   content (a fixed-px mock, a long German word) refuses to shrink can push the
   grid wider than its container and get clipped by a section's overflow:hidden.
   Cap every grid item to its track and let it shrink. No effect on the desktop
   layout (tracks are wider than their content there) — this only bites when a
   track is squeezed narrower than a fixed child, where it now shrinks instead
   of overflowing. Verified pixel-identical at 1440/1180/1024/900/768/640/390.
   (Toby, 2026-08-05) */
#va-home [style*="grid-template-columns"] > *{ min-width:0; max-width:100%; }

/* Reduced motion: freeze the mock loops on a representative frame.
   The mock layers are absolute siblings with no base opacity, so
   animation:none stacks every keyframe at once (both phone mocks render
   garbled). Pausing at a fixed delay keeps one coherent frame. (Nina, 2026-08-04) */
@media (prefers-reduced-motion: reduce){
  #va-home *{ animation-play-state:paused !important; animation-delay:-10s !important; }
}

/* ---------- Keyframes (from design bundle) ---------- */
@keyframes vaCardA { 0%, 2.44% { transform: translate(0,0) rotate(0deg); opacity: 1; } 4.57% { transform: translate(-20px,-3px) rotate(-1.5deg); opacity: 1; } 6.4% { transform: translate(-72px,-12px) rotate(-6deg); opacity: 0.9; } 9.76% { transform: translate(-268px,-34px) rotate(-16deg); opacity: 0; } 10.2%, 92% { transform: translate(-268px,-34px) rotate(-16deg); opacity: 0; } 92.5% { transform: translate(0,0) rotate(0deg); opacity: 0; } 94%, 100% { transform: translate(0,0) rotate(0deg); opacity: 1; } }
@keyframes vaCardB { 0% { transform: translateY(14px) scale(0.95); opacity: 0.75; } 6.1%, 10.98% { transform: translateY(0) scale(1); opacity: 1; } 13.11% { transform: translate(20px,-3px) rotate(1.5deg); opacity: 1; } 14.94% { transform: translate(72px,-12px) rotate(6deg); opacity: 0.9; } 18.29% { transform: translate(268px,-34px) rotate(16deg); opacity: 0; } 18.7%, 92% { transform: translate(268px,-34px) rotate(16deg); opacity: 0; } 92.5% { transform: translateY(14px) scale(0.95); opacity: 0; } 94%, 100% { transform: translateY(14px) scale(0.95); opacity: 0.75; } }
@keyframes vaMatch { 0%, 18.29% { opacity: 0; transform: scale(0.96); } 23.78%, 87% { opacity: 1; transform: scale(1); } 89%, 100% { opacity: 0; transform: scale(1); } }
@keyframes vaMScroll { 0%, 37.8% { transform: translateY(0); } 45.12%, 96% { transform: translateY(-104px); } 99%, 100% { transform: translateY(0); } }
@keyframes vaStamp { 0%, 18.29% { transform: scale(0.6) rotate(-4deg); opacity: 0; } 21.34% { transform: scale(1.1) rotate(-4deg); opacity: 1; } 23.17%, 100% { transform: scale(1) rotate(-4deg); opacity: 1; } }
@keyframes vaMatchRow { 0%, 22.56% { opacity: 0; transform: translateY(10px); } 25.61%, 100% { opacity: 1; transform: none; } }
@keyframes vaMatchSub { 0%, 18.29% { opacity: 0; transform: translateY(8px); } 21.34%, 100% { opacity: 1; transform: none; } }
@keyframes vaPickOn { 0%, 48.78% { opacity: 0; } 51.83%, 100% { opacity: 1; } }
@keyframes vaPickTap { 0%, 48.78% { transform: scale(1); } 50% { transform: scale(0.97); } 51.83%, 100% { transform: scale(1); } }
@keyframes vaNope { 0%, 2.44% { opacity: 0; transform: scale(0.6); } 4.57% { opacity: 1; transform: scale(1); } 8.23% { opacity: 1; transform: scale(1); } 9.76%, 100% { opacity: 0; transform: scale(0.94); } }
@keyframes vaLike { 0%, 10.98% { opacity: 0; transform: scale(0.6); } 13.11% { opacity: 1; transform: scale(1); } 16.77% { opacity: 1; transform: scale(1); } 18.29%, 100% { opacity: 0; transform: scale(0.94); } }
@keyframes vaPressHero { 0%, 57.32% { transform: scale(1); filter: none; } 58.5% { transform: scale(0.93); filter: brightness(1.15); } 60.06%, 100% { transform: scale(1); filter: none; } }
@keyframes vaSent { 0%, 60.98% { opacity: 0; transform: scale(0.94); } 65.85%, 78% { opacity: 1; transform: scale(1); } 80%, 100% { opacity: 0; transform: scale(1); } }
@keyframes vaSentBody { 0%, 63.41% { opacity: 0; transform: translateY(10px); } 67.07%, 74.4% { opacity: 1; transform: translateY(0); } 76.2%, 100% { opacity: 0; transform: translateY(-10px); } }
@keyframes vaSentTick { 0%, 63.41% { transform: scale(0.4); opacity: 0; } 67.07% { transform: scale(1.15); opacity: 1; } 68.9%, 74.4% { transform: scale(1); opacity: 1; } 76.2%, 100% { transform: scale(1); opacity: 0; } }
@keyframes vaLogo { 0%, 75.61% { opacity: 0; } 81.7%, 94% { opacity: 1; } 100% { opacity: 0; } }
@keyframes vaHeroEndIcon { 0%, 75.61% { transform: scale(0.7) rotate(-7deg); } 78.66% { transform: scale(1.06) rotate(2deg); } 80.5%, 100% { transform: scale(1) rotate(0deg); } }
@keyframes vaHeroEndRing { 0%, 77.4% { transform: scale(0.9); opacity: 0; } 78.66% { opacity: 0.5; } 83.5%, 100% { transform: scale(1.9); opacity: 0; } }
@keyframes vaHeroEndName { 0%, 78% { opacity: 0; transform: translateY(8px); } 80.5%, 100% { opacity: 1; transform: none; } }
@keyframes vaHeroEndCap { 0%, 79.3% { opacity: 0; transform: translateY(12px); } 81.7%, 100% { opacity: 1; transform: none; } }
@keyframes vaFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-9px); } }
@keyframes vaWrite { from { opacity: 0; transform: translateY(9px); filter: blur(4px); } to { opacity: 1; transform: none; filter: none; } }
@keyframes vaSA { 0%, 22.4% { opacity: 1; } 25%, 92.1% { opacity: 0; } 100% { opacity: 1; } }
@keyframes vaSB { 0%, 23.7% { opacity: 0; } 28.3%, 75.7% { opacity: 1; } 80.3%, 100% { opacity: 0; } }
@keyframes vaPress { 0%, 15.1% { transform: scale(1); filter: none; } 16.2% { transform: scale(0.96); filter: brightness(1.18); } 18.4%, 100% { transform: scale(1); filter: none; } }
@keyframes vaToast { 0%, 28.3% { opacity: 0; transform: translateY(-7px); } 32.9%, 43.4% { opacity: 1; transform: none; } 48%, 100% { opacity: 0; transform: translateY(-7px); } }
@keyframes vaScroll { 0%, 41.4% { transform: translateY(0); } 56.6%, 75.7% { transform: translateY(-24%); } 99%, 100% { transform: translateY(0); } }
@keyframes vaC1 { 0%, 45.4% { opacity: 0; transform: translateY(9px); } 50%, 75.7% { opacity: 1; transform: none; } 80.3%, 100% { opacity: 0; transform: translateY(9px); } }
@keyframes vaC2 { 0%, 52% { opacity: 0; transform: translateY(9px); } 56.6%, 75.7% { opacity: 1; transform: none; } 80.3%, 100% { opacity: 0; transform: translateY(9px); } }
@keyframes vaC3 { 0%, 58.6% { opacity: 0; transform: translateY(9px); } 63.2%, 75.7% { opacity: 1; transform: none; } 80.3%, 100% { opacity: 0; transform: translateY(9px); } }
@keyframes vaEndIcon { 0%, 71.7% { transform: scale(0.7) rotate(-7deg); } 77.6% { transform: scale(1.06) rotate(2deg); } 81.6%, 100% { transform: scale(1) rotate(0deg); } }
@keyframes vaEndRing { 0%, 76.3% { transform: scale(0.9); opacity: 0; } 77.6% { opacity: 0.5; } 85.5%, 100% { transform: scale(1.9); opacity: 0; } }
@keyframes vaEndName { 0%, 75.7% { opacity: 0; transform: translateY(8px); } 80.3%, 100% { opacity: 1; transform: none; } }
@keyframes vaEndCap { 0%, 78.3% { opacity: 0; transform: translateY(12px); } 82.9%, 100% { opacity: 1; transform: none; } }
@keyframes vaCount { 0%, 45.2% { transform: translateY(0); } 45.4%, 51.8% { transform: translateY(-13px); } 52%, 58.4% { transform: translateY(-26px); } 58.6%, 100% { transform: translateY(-39px); } }
@keyframes vaLoop { 0%, 71.7% { opacity: 0; } 76.3%, 92.1% { opacity: 1; } 100% { opacity: 0; } }
@keyframes vaSec { 0%, 6.45% { transform: translateY(0); } 6.7%, 13% { transform: translateY(-44px); } 13.3%, 100% { transform: translateY(-88px); } }
@keyframes vaBlink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0.2; } }
@keyframes vaSbFill { 0%, 25% { width: 89%; background: #34C759; } 31%, 58% { width: 52%; background: #FFC300; } 64%, 92% { width: 20%; background: #FF6B57; } 100% { width: 89%; background: #34C759; } }
@keyframes vaSbT1 { 0%, 27% { opacity: 1; } 31%, 96% { opacity: 0; } 100% { opacity: 1; } }
@keyframes vaSbT2 { 0%, 27% { opacity: 0; } 31%, 58% { opacity: 1; } 62%, 100% { opacity: 0; } }
@keyframes vaSbT3 { 0%, 60% { opacity: 0; } 64%, 92% { opacity: 1; } 96%, 100% { opacity: 0; } }
@keyframes vaRing { 0% { transform: scale(0.9); opacity: 0.45; } 100% { transform: scale(1.75); opacity: 0; } }
@keyframes vaNotifPulse { 0%, 100% { box-shadow: 0 10px 30px rgba(31,27,24,0.14), 0 0 0 0 var(--va-pulse); } 50% { box-shadow: 0 10px 30px rgba(31,27,24,0.14), 0 0 0 9px transparent; } }
@keyframes vaMarquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@keyframes vaDrift { 0%, 100% { transform: translate(0,0); } 50% { transform: translate(16px,-20px); } }
@keyframes vaTick { 0%, 24% { opacity: 0; transform: scale(0.7); } 34%, 100% { opacity: 1; transform: scale(1); } }

/* ---------- Responsive (authored — bundle had none) ----------
   Desktop canvas is 1440 with a 1120 centred content column via
   padding: calc(50% - 560px). Below ~1180 that padding is clamped;
   below ~820 the multi-column grids collapse to a single column. */

@media (max-width: 1180px){
  /* clamp the centred-column side padding so content keeps a gutter */
  #va-home [style*="calc(50% - 560px)"]{ padding-left:32px !important; padding-right:32px !important; }
}

@media (max-width: 900px){
  /* hero: text over phone. row-gap here (and on the two arms below): these
     three containers only set `column-gap: 72px` inline (never a `gap`
     shorthand, since desktop is a genuine two-column layout with no stacked
     rows), so a collapsed single column had zero space between stacked
     children beyond the child's own margin — which is exactly what breaks
     under the reveal rewrite noted above. Keyed on the same container
     selector as the collapse rule itself, so it can't be affected by that
     rewrite either.
     (Max ruling, 2026-08-06 — row-gap on the container, not child margin) */
  #va-home [style*="grid-template-columns: 1fr 480px"]{ grid-template-columns:1fr !important; row-gap:20px !important; }
  /* memory + rhythm two-up -> stack */
  #va-home [style*="grid-template-columns: 1fr 380px"]{ grid-template-columns:1fr !important; row-gap:20px !important; }
  #va-home [style*="grid-template-columns: 1fr 440px"]{ grid-template-columns:1fr !important; row-gap:20px !important; }
  /* four steps -> two */
  #va-home [style*="grid-template-columns: repeat(4, 1fr)"]{ grid-template-columns:1fr 1fr !important; row-gap:22px !important; }

  /* The three arms below key on the child's OWN style attribute
     ([style*="grid-area"]), which js/home.js:19-20 rewrites on reveal
     (writes .style.opacity, forcing a re-serialisation that can drop or
     rename the matched substring — same mechanism as the 640px Defect 1
     below). They still carry margin-top:24px, spacing the stacked mock
     from the copy above it, and are kept for that — not for placement,
     which is no longer reliable through them. Placement now comes from
     the container-keyed `> *` rule further down, which matches on the
     PARENT's attribute (never rewritten here — none of these three
     containers is [data-reveal]) and so can't be broken by the child
     rewrite.
     (Max ruling, 2026-08-06 — child-attribute arms demoted to
     margin-only; container-keyed `> *` rule is now the placement
     mechanism) */
  #va-home [style*="grid-template-columns: 1fr 480px"] > [style*="grid-area"]{ grid-area:auto !important; grid-column:1 !important; margin-top:24px !important; }
  #va-home [style*="grid-template-columns: 1fr 380px"] > [style*="grid-area"]{ grid-area:auto !important; grid-column:1 !important; margin-top:24px !important; }
  #va-home [style*="grid-template-columns: 1fr 440px"] > [style*="grid-area"]{ grid-area:auto !important; grid-column:1 !important; margin-top:24px !important; }

  /* Placement mechanism for the three stacking containers above. Keyed on
     the PARENT's grid-template-columns (a plain value, never a shorthand,
     never rewritten by the reveal observer) rather than on any CHILD
     style substring, so it keeps matching regardless of how WebKit vs.
     Chromium re-serialise the child's style attribute after
     js/home.js:19-20 sets .style.opacity. Same shape already proven on
     Laura's device by the grid safety net at :33.
     (Max ruling, 2026-08-06 — container-keyed child reset, survives the
     reveal-triggered style rewrite that broke the child-attribute arms
     above) */
  #va-home [style*="grid-template-columns: 1fr 480px"] > *,
  #va-home [style*="grid-template-columns: 1fr 380px"] > *,
  #va-home [style*="grid-template-columns: 1fr 440px"] > *
  { grid-row:auto !important; grid-column:1 !important; }
}

@media (max-width: 640px){
  #va-home [style*="calc(50% - 560px)"]{ padding-left:20px !important; padding-right:20px !important; }
  /* everything to one column on phones */
  #va-home [style*="grid-template-columns: repeat(4, 1fr)"]{ grid-template-columns:1fr !important; }
  #va-home [style*="grid-template-columns: repeat(3, 1fr)"]{ grid-template-columns:1fr !important; }
  #va-home [style*="grid-template-columns: repeat(2, 1fr)"]{ grid-template-columns:1fr !important; }
  #va-home [style*="grid-template-columns: 1fr 1fr"]{ grid-template-columns:1fr !important; }
  /* hero / Erinnerungsbuch / Freundschaften: same three collapse rules as the
     900px block above, duplicated rather than moved. On Laura's iOS Safari the
     900px block does not apply (640px does), so 1fr 380px/440px never collapsed
     there and the flexible column resolved to ~0. Mechanism unknown — this is a
     workaround, not a fix for the 900 block, which stays as-is.
     (Max ruling, 2026-08-06 — 900 block inert on iOS Safari, mechanism unknown;
     duplicated into 640 as a workaround) */
  #va-home [style*="grid-template-columns: 1fr 480px"]{ grid-template-columns:1fr !important; row-gap:20px !important; }
  #va-home [style*="grid-template-columns: 1fr 480px"] > [style*="grid-area"]{ grid-area:auto !important; grid-column:1 !important; margin-top:24px !important; }
  #va-home [style*="grid-template-columns: 1fr 380px"]{ grid-template-columns:1fr !important; row-gap:20px !important; }
  #va-home [style*="grid-template-columns: 1fr 380px"] > [style*="grid-area"]{ grid-area:auto !important; grid-column:1 !important; margin-top:24px !important; }
  #va-home [style*="grid-template-columns: 1fr 440px"]{ grid-template-columns:1fr !important; row-gap:20px !important; }
  #va-home [style*="grid-template-columns: 1fr 440px"] > [style*="grid-area"]{ grid-area:auto !important; grid-column:1 !important; margin-top:24px !important; }
  /* any explicit child placement (grid-column, incl. "span N") surviving a
     640px collapse forces the browser to add an implicit extra track sized to
     content — e.g. the Social Battery card (grid-column: span 2) inside the
     "Was noch?" repeat(3,1fr) grid measured 44px/290px instead of one 350px
     track. Reset generally across every grid that collapses at this
     breakpoint, not per-section.
     Superseded as the placement mechanism by the container-keyed `> *`
     blanket rule below (:239) — kept as belt-and-braces, matches on the
     CHILD's own style attribute and so is not reliable once js/home.js:19-20
     rewrites that attribute on reveal (see Defect 1 below).
     (Max ruling, 2026-08-06 — general child-placement reset; motivating case
     index.html:485. Browser-agnostic, independent of the 900-block workaround
     above.) */
  #va-home [style*="grid-template-columns: repeat(4, 1fr)"] > [style*="grid-column"],
  #va-home [style*="grid-template-columns: repeat(3, 1fr)"] > [style*="grid-column"],
  #va-home [style*="grid-template-columns: repeat(2, 1fr)"] > [style*="grid-column"],
  #va-home [style*="grid-template-columns: 1fr 1fr"] > [style*="grid-column"],
  #va-home [style*="grid-template-columns: 1fr 480px"] > [style*="grid-column"],
  #va-home [style*="grid-template-columns: 1fr 380px"] > [style*="grid-column"],
  #va-home [style*="grid-template-columns: 1fr 440px"] > [style*="grid-column"]
  { grid-column:1 !important; }
  /* same reset for a grid-area child specifically (grid-column alone doesn't
     clear grid-area). No inline grid-area child exists in these four patterns
     today — every current one sits in the three 1fr <px> grids above, which
     already carry a grid-area arm — but the general-reset intent above only
     holds if a re-exported design bundle emitting one here is also caught.
     No margin-top: unlike the 1fr <px> sections, these grids have no
     stacked-mock-under-copy relationship to space out. Belt-and-braces per
     the note above — the `> *` blanket rule at :239 is the mechanism that
     actually holds under the reveal rewrite. (Ravi gate MF-2, 2026-08-06) */
  #va-home [style*="grid-template-columns: repeat(4, 1fr)"] > [style*="grid-area"]{ grid-area:auto !important; grid-column:1 !important; }
  #va-home [style*="grid-template-columns: repeat(3, 1fr)"] > [style*="grid-area"]{ grid-area:auto !important; grid-column:1 !important; }
  #va-home [style*="grid-template-columns: repeat(2, 1fr)"] > [style*="grid-area"]{ grid-area:auto !important; grid-column:1 !important; }
  #va-home [style*="grid-template-columns: 1fr 1fr"] > [style*="grid-area"]{ grid-area:auto !important; grid-column:1 !important; }
  /* hero phone mock: below the copy, centred, no bleed.
     transform-origin is top center, so scale(1.05) on a 306px box paints
     ~15px BELOW the layout box (scaling only stretches the bottom edge
     downward from a fixed top). The old margin-bottom:8px was smaller than
     that overflow, so the mock always bled into the CTA block below it
     regardless of the new row-gap (row-gap separates layout boxes, not
     painted overflow). Raised past the ~15px bleed rather than dropping the
     scale — the scale is the deliberate "enlarged mock" effect, so widening
     its own clearance is the smaller change.
     (Max ruling, 2026-08-06 — margin raised past the transform overflow) */
  #va-home [style*="height: 306px"][style*="width: 220px"]{
    grid-column:1 !important; grid-row:auto !important;
    transform:scale(1.05) !important; transform-origin:top center !important;
    margin:28px auto 24px !important;
  }
  /* hero headline scales down */
  #va-home h1[style*="font-size: 68px"]{ font-size:44px !important; }
  #va-home h2[style*="font-size: 44px"]{ font-size:32px !important; }
  #va-home h2[style*="font-size: 40px"]{ font-size:30px !important; }
  /* memory + rhythm section headlines ("Euer Erinnerungsbuch", "Damit
     Freundschaften nicht einschlafen.") and the download-section h2 had no
     mobile size at all, unlike every other heading above. At 52px, the
     unbreakable compound word "Erinnerungsbuch" is wider than the mobile
     column and overflows its own box (invisible to a box-size overflow
     check — the text paints outside without enlarging it), then gets cut
     by the section's overflow:hidden. Scale down like the others. */
  #va-home h2[style*="font-size: 52px"]{ font-size:36px !important; }
  #va-home h2[style*="font-size: 48px"]{ font-size:34px !important; }

  /* Defect 1 (Laura 12:32): mock/notif card painted above the heading in the
     Erinnerungsbuch and Freundschaften sections, despite DOM order already
     being heading -> copy -> cards -> mock, and despite the grid-area reset
     above resolving correctly in Chromium. Root cause (Ravi gate,
     2026-08-06): js/home.js:19-20 sets `.style.opacity` on every
     [data-reveal] element — including all four inline grid-area children —
     which re-serialises the whole style attribute. WebKit expands the
     grid-area shorthand into longhands on that rewrite; Chromium keeps the
     shorthand. So on Laura's device the attribute contains
     grid-column-start (no substring "grid-area"), the `[style*="grid-area"]`
     arm above never matches for these two sections, and the row is never
     reset to auto — while the `[style*="grid-column"]` arm elsewhere in this
     block does match (grid-column-start contains "grid-column"), which is
     why the column collapses correctly but the row stays pinned. The row
     reset has to hang off the same longhand-matching arms instead of the
     shorthand. Hero is unaffected: its reset at `:165` above keys on
     height/width, not grid-area, so the serialiser rewrite doesn't touch it.
     STILL NOT ENOUGH: Laura's follow-up ("first it looks fine. but then it
     switches. and things go on top of their headline again.") showed the
     grid-area/grid-column/grid-row arms below are re-broken by the SAME
     rewrite that broke grid-area — the rewrite doesn't consistently land on
     one particular longhand set either. Kept for the margin-top:24px they
     still provide; placement now comes from the container-keyed `> *`
     blanket rule at :239, which matches on the PARENT's attribute and can't
     be touched by any rewrite of the child's.
     (Max ruling, 2026-08-06 — row reset keyed on grid-column/grid-row
     longhands, because [data-reveal]'s opacity rewrite expands grid-area to
     longhands on WebKit and the shorthand-keyed arm above stops matching;
     superseded as placement mechanism same day, see :239) */
  #va-home [style*="grid-template-columns: 1fr 380px"] > [style*="grid-column"],
  #va-home [style*="grid-template-columns: 1fr 380px"] > [style*="grid-row"],
  #va-home [style*="grid-template-columns: 1fr 440px"] > [style*="grid-column"],
  #va-home [style*="grid-template-columns: 1fr 440px"] > [style*="grid-row"]
  { grid-row:auto !important; grid-column:1 !important; }

  /* Placement mechanism for every grid that collapses at this breakpoint.
     Keyed on the PARENT's grid-template-columns — a plain value, never a
     shorthand, never touched by js/home.js:19-20's opacity rewrite on
     [data-reveal] children — instead of any CHILD style substring, which is
     exactly what the arms above tried and what kept breaking as the rewrite
     landed on a different longhand each time. Blanket (`> *`, not
     `> [style*="grid-area"]` etc.) because every grid is single-column here,
     unlike the 900px block where two containers deliberately stay two-up.
     Same shape already proven on Laura's device by the grid safety net at
     :33.
     (Max ruling, 2026-08-06 — container-keyed blanket child reset, replaces
     the child-attribute arms above as the placement mechanism) */
  #va-home [style*="grid-template-columns"] > *{ grid-row:auto !important; grid-column:1 !important; }

  /* Defect 2 (Laura 12:32): "the first look buttons are not centered under
     this" — the hero CTA links sat hard-left under a centred phone mock.
     Centring only the CTA would leave the headline left-aligned and look
     worse (Toby §7), so centre the whole hero text column: eyebrow pill,
     h1, copy, CTA block.
     (Max ruling, 2026-08-06 — centre hero text column at 640, not just CTA) */
  #va-home [style*="grid-template-columns: 1fr 480px"] > [style*="justify-self: start"]{ justify-self:center !important; }
  #va-home [style*="grid-template-columns: 1fr 480px"] > h1{ text-align:center !important; }
  #va-home [style*="grid-template-columns: 1fr 480px"] > p{ text-align:center !important; justify-self:center !important; }
  #va-home [style*="grid-template-columns: 1fr 480px"] > [style*="align-items: flex-start"]{ align-items:center !important; }

  /* Defect 3 (Laura 13:40): hard horizontal line partway down the mobile
     hero — photo and glow end at their fixed 460px/420px desktop heights,
     leaving flat cream below (the mock and everything under it) while the
     `:143` fade overlay keeps going, since IT has no fixed height (its
     `inset:0` already stretches it to the full hero, which is exactly why
     it doesn't show the same seam). Give both layers the same "stretch to
     the containing block" shape as the fade instead of a pixel height: set
     bottom to 0 (was `auto`) alongside the existing negative top/side
     offsets, drop the fixed height. An absolutely positioned box with both
     top and bottom set auto-sizes to the containing block's actual (post
     layout) height — unlike `height:100%`, which resolves to `auto` here
     because the hero wrapper's own height is content-driven (`auto`), not
     an explicit value, and percentage heights don't resolve against an
     auto-height containing block. Neither div carries `data-reveal` (only
     text/mock children do), so plain `height:`/`inset:` hooks are safe —
     nothing here is subject to the reveal-triggered style rewrite.
     No fade-gradient change needed: its stops are percentages of ITS OWN
     box, which already matched the hero's full height before this fix, so
     once photo/glow are stretched to match, they align with the same
     curve — checked visually (390 screenshot), not washed out.
     (Max ruling, 2026-08-06 — stretch via top+bottom inset instead of a
     fixed height, matching the fade layer's already-working mechanism) */
  #va-home [style*="height: 460px"]{ inset:-60px -40px 0 -40px !important; height:auto !important; }
  #va-home [style*="height: 420px"]{ inset:-80px -60px 0 -60px !important; height:auto !important; }
}

/* Long-word safety net: same rationale as the grid safety net above — an
   unbreakable word (German compounds) can be wider than its own box even
   after the box is correctly sized, since default overflow-wrap doesn't
   allow mid-word breaks. No effect where words already fit (all current
   desktop/tablet widths). (Tom, 2026-08-06) */
#va-home h1, #va-home h2, #va-home h3{ overflow-wrap:break-word; }
