/*
  Hidden and intermediate states, scoped to html.js (set by js-flag.js) and to prefers-reduced-motion: no-preference.
  Only transform, opacity, clip-path, fill and stroke are animated. A print block at the end cancels every hidden state.
*/
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }

  /* ---- The sheet appears: the page grid and the paper fade in once the fonts are in ---- */
  html.js body::before, html.js .stage .scene, html.js .stage .phase { opacity: 0; }
  html.js.ready body::before, html.js.ready .stage .scene { opacity: 1; transition: opacity 1.2s ease; }
  html.js.ready .stage .phase { opacity: 1; transition: opacity .8s ease .9s; }

  /* ---- Hero text: masked line rise for the title, soft rise for the rest, gated on fonts (html.ready) ---- */
  html.js .hero-in { opacity: 0; transform: translateY(12px); }
  html.js .hero-title .line-in { transform: translateY(115%); }
  html.js.ready .hero-in { opacity: 1; transform: none; transition: opacity .7s var(--ease), transform .7s var(--ease); }
  html.js.ready .hero-title .line-in { transform: none; transition: transform 1.1s var(--ease-out); }
  html.js.ready .eyebrow.hero-in { transition-delay: .1s; }
  html.js.ready .hero-title .line:nth-child(1) .line-in { transition-delay: .25s; }
  html.js.ready .hero-title .line:nth-child(2) .line-in { transition-delay: .4s; }
  html.js.ready .hero-lede { transition-delay: .6s; }
  html.js.ready .hero-actions { transition-delay: .75s; }

  /* ---- The stage ----
     Layers 0 (ground) and 2 (foundations) land on their own at load. The other layers start hidden; site.js writes
     opacity and transform straight onto each layer (a lift from 70 px below while it lands, then the parallax shift
     that makes the tilt read as depth) and onto the ghost outlines, which show where each layer will land.
     Inline styles, not custom properties: a property on the scene would restyle the whole drawing on every frame. */
  html.js .stage .layer[data-layer="1"], html.js .stage .layer[data-layer="3"], html.js .stage .layer[data-layer="4"],
  html.js .stage .layer[data-layer="5"], html.js .stage .layer[data-layer="6"], html.js .stage .layer[data-layer="7"] { opacity: 0; }
  html.js .stage .ghost { opacity: .6; }
  html.js .stage .sheet { will-change: transform; }
  html.js .stage .layer[data-layer="0"], html.js .scene-small .layer[data-layer="0"] { animation: land .9s var(--ease-out) backwards; }
  html.js .stage .layer[data-layer="2"], html.js .scene-small .layer[data-layer="2"] { animation: land .7s var(--ease-out) .5s backwards; }
  html.js .scene-small .layer:not([data-layer="0"]):not([data-layer="2"]) { animation: land .7s var(--ease-out) .9s backwards; }
  /* Light: day → dusk → night is a class change. The desk-lamp overlay fades over the sheet, the lamps fade to copper;
     the window panes swap their pattern in one frame, one layer at a time (site.js staggers the layer classes). */
  .scene::after { transition: opacity 1.8s ease, background .8s; }
  .iso .lamp { transition: fill 1.6s ease; }
  /* Phase readout */
  .phase span { transition: color .5s ease; }

  /* Build hint: a copper segment loops down the rail until the first scroll */
  .build-rail::after { animation: rail 1.6s ease-in-out infinite; }
  html.has-scrolled .build-hint { opacity: 0; transition: opacity .5s; }
  html.has-scrolled .build-rail::after { animation: none; }

  /* ---- Scroll reveals (.reveal → .is-in by IntersectionObserver) ---- */
  html.js .reveal { opacity: 0; transform: translateY(24px); transition: opacity .8s var(--ease), transform .8s var(--ease); }
  html.js .reveal.is-in { opacity: 1; transform: none; }
  html.js .reveal .line-in { transform: translateY(115%); transition: transform 1.1s var(--ease-out) .1s; }
  html.js .reveal.is-in .line-in { transform: none; }
  html.js .kicker::before, html.js .kicker::after { transform: scaleX(0); transition: transform .7s var(--ease) .25s; }
  html.js .reveal.is-in .kicker::before, html.js .reveal.is-in .kicker::after { transform: scaleX(1); }
  html.js .prose.reveal { transition-delay: .12s; }
  html.js .prose p:first-child::before { transform: scaleY(0); transition: transform .6s var(--ease) .5s; }
  html.js .prose.is-in p:first-child::before { transform: scaleY(1); }

  /* Service rows (each one is its own reveal trigger); the glyph pops up after the row */
  html.js .service.reveal { transition: opacity .7s var(--ease), transform .7s var(--ease), background-color .4s; }
  html.js .service.reveal:not(.is-in) { transform: translateY(18px); }
  html.js .service::before { background: var(--accent); transform: scaleX(0); transition: transform .6s var(--ease) .2s, background-color 1s ease 1.2s; }
  html.js .service.is-in::before { transform: scaleX(1); background: var(--rule); }
  html.js .service .icon { opacity: 0; transform: translateY(14px) scale(.9); }
  html.js .service.is-in .icon { opacity: 1; transform: none; transition: opacity .6s var(--ease) .3s, transform .7s var(--ease-out) .3s; }
  .service::after { transition: transform .4s var(--ease); }

  /* Process steps: numerals pop, the copper line is scrubbed by --proc (JS) */
  html.js .step .step-num { transform: scale(.6); opacity: 0; }
  html.js .step.is-in .step-num { transform: none; opacity: 1; transition: transform .6s var(--ease-out) .15s, opacity .4s ease .15s; }

  /* Contact sheet: the frame draws itself, the cell dividers follow, the entries wipe in */
  html.js .contact-sheet { border-color: transparent; }
  html.js .contact-sheet .rule { opacity: 1; transition: transform .8s var(--ease); }
  html.js .rule-t, html.js .rule-b { transform: scaleX(0); }
  html.js .rule-l, html.js .rule-r { transform: scaleY(0); }
  html.js .rule-b, html.js .rule-r { transition-delay: .25s; }
  html.js .contact-sheet.is-in .rule { transform: none; background: var(--rule); transition: transform .8s var(--ease), background-color 1s ease 1.2s; }
  html.js .cell { border-color: transparent; }
  html.js .cell::before { content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px; background: var(--rule); transform: scaleX(0); transform-origin: left; transition: transform .7s var(--ease) .25s; }
  html.js .cell::after { content: ""; position: absolute; top: 0; bottom: 0; right: -1px; width: 1px; background: var(--rule); transform: scaleY(0); transform-origin: top; transition: transform .7s var(--ease) .25s; }
  html.js .cell:last-child::before { display: none; }
  html.js .cell::after { display: none; }
  @media (min-width: 40rem) {
    html.js .cell:nth-child(odd)::after { display: block; }
    html.js .cell:nth-last-child(2)::before { display: none; }
  }
  html.js .contact-sheet.is-in .cell::before { transform: scaleX(1); }
  html.js .contact-sheet.is-in .cell::after { transform: scaleY(1); }
  /* The wipe ends 14 px outside the box: the links inside overhang it by up to 6 px and their focus ring by 5 px more */
  html.js .cell dt, html.js .cell dd { opacity: 0; clip-path: inset(-14px 100% -14px -14px); transition: opacity .7s var(--ease), clip-path .7s var(--ease); }
  html.js .contact-sheet.is-in .cell dt, html.js .contact-sheet.is-in .cell dd { opacity: 1; clip-path: inset(-14px); }
  /* Short stagger: the whole sheet (the phone number above all) is readable within a second */
  html.js .cell:nth-child(1) :is(dt, dd) { transition-delay: .15s; }
  html.js .cell:nth-child(2) :is(dt, dd) { transition-delay: .22s; }
  html.js .cell:nth-child(3) :is(dt, dd) { transition-delay: .29s; }
  html.js .cell:nth-child(4) :is(dt, dd) { transition-delay: .36s; }

  /* ---- Header: glass after 24 px, progress line ---- */
  .site-header { transition: background-color .35s, border-color .35s; }
  html.js .steps-fill { transform: scaleY(0); will-change: transform; }
  .site-nav a::after { transition: transform .3s var(--ease); }
  .brand-mark { transition: border-color .3s, color .3s; }

  /* ---- 404: the numeral fills with copper from the ground up ---- */
  html.js .code-fill { clip-path: inset(100% 0 0 0); animation: rise-fill 1.2s var(--ease) .6s both; }
  html:not(.js) .code-fill { animation: rise-fill 1.2s var(--ease) .6s both; }
}

@keyframes land { from { opacity: 0; transform: translateY(90px); } to { opacity: 1; transform: translateY(0); } }
@keyframes rail { 0% { transform: translateY(0); opacity: 0; } 15% { opacity: 1; } 85% { opacity: 1; } 100% { transform: translateY(24px); opacity: 0; } }
@keyframes rise-fill { from { clip-path: inset(100% 0 0 0); } to { clip-path: inset(0 0 0 0); } }

@media (prefers-reduced-motion: reduce) {
  .btn, .link-arrow .arrow, .service .icon { transition: none; }
  .btn:hover, .btn:active, .service:hover .icon { transform: none; }
  /* The complete house, whatever site.js wrote inline before the preference changed */
  .scene .layer { opacity: 1 !important; transform: none !important; }
  .scene .ghost { opacity: 0 !important; }
  .tilt { transform: none !important; }
  .steps-fill { transform: none !important; }
}

/* Print: every hidden state above is cancelled with the selector that set it (same specificity, later in the file), and its transition
   with it, so a cold print shows the whole page in its final state */
@media print {
  html.js body::before, html.js .stage .scene, html.js .stage .phase, html.js .hero-in, html.js.ready .hero-in, html.js .reveal, html.js .service .icon, html.js .step .step-num { opacity: 1; transform: none; transition: none; }
  html.js .hero-title .line-in, html.js.ready .hero-title .line-in, html.js .reveal .line-in, html.js .kicker::before, html.js .kicker::after,
  html.js .prose p:first-child::before, html.js .service.reveal, html.js .service.reveal:not(.is-in), html.js .service::before,
  html.js .rule-t, html.js .rule-b, html.js .rule-l, html.js .rule-r, html.js .cell::before, html.js .cell::after { transform: none; transition: none; }
  html.js .contact-sheet, html.js .cell { border-color: var(--rule); }
  html.js .contact-sheet .rule { opacity: 0; }
  html.js .cell dt, html.js .cell dd { opacity: 1; clip-path: none; transition: none; }
  /* !important: the inline opacity and transform written by site.js must not reach the paper */
  html.js .scene .layer, html.js .stage .layer[data-layer="0"], html.js .stage .layer[data-layer="2"], html.js .scene-small .layer { opacity: 1 !important; transform: none !important; animation: none !important; }
  .scene .ghost { opacity: 0 !important; }
  .tilt { transform: none !important; }
  .steps-fill { transform: none !important; }
  html.js .code-fill, html:not(.js) .code-fill { animation: none; clip-path: none; }
}
