/* A white, fluid opening scene. The portfolio's themes resume after it. */
#top > .portal-intro,
.section-mode #top > .portal-intro {
  position: relative; isolation: isolate; min-height: 100svh; height: 100svh;
  padding: 0; overflow: hidden; background: var(--bg); color: var(--ink);
}
.section-mode #top > .portal-intro { position: absolute; }
#portal-canvas { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
#top > .portal-intro > * { margin: 0; }
.portal-copy { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 7vh; pointer-events: none; transition: opacity .7s, transform 1.2s cubic-bezier(.2,.7,.2,1); }
.portal-copy h1 { font: 600 clamp(4.5rem, 14.8vw, 19rem)/1 'Instrument Sans', sans-serif; letter-spacing: -.045em; white-space: nowrap; margin-left: -.05em; }
.portal-copy p { text-align: center; font-size: clamp(.9rem, 1.15vw, 1.3rem); line-height: 1.4; letter-spacing: -.025em; }
.portal-invite { position: absolute; left: 50%; top: 76%; transform: translateX(-50%); display: flex; align-items: center; gap: .8rem; border: 0; background: none; color: var(--ink); font: .75rem var(--font-body); cursor: pointer; padding: .7rem; z-index: 2; }
.portal-invite-ring { display: grid; place-items: center; width: 2.5rem; height: 2.5rem; border: 1px solid color-mix(in srgb, var(--ink) 40%, transparent); border-radius: 50%; font-size: 1rem; }
.portal-instructions { position: absolute; bottom: 5.6rem; left: 50%; transform: translateX(-50%); font: .6rem var(--font-mono); color: var(--ink-dim); white-space: nowrap; pointer-events: none; }
.portal-projects { position: absolute; bottom: 2.5rem; left: var(--frame-x); font: .75rem var(--font-body); color: var(--ink); z-index: 2; }
.portal-projects span { display: inline-block; margin-left: 1.8rem; }
.portal-touch-hint { display: none; }
.portal-intro.is-world .portal-copy { opacity: 0; transform: scale(1.12); }
.portal-intro.is-world .portal-invite, .portal-intro.is-world .portal-instructions, .portal-intro.is-world .portal-projects { visibility: hidden; }
html.portal-active body::before, html.portal-active body::after, html.portal-active .grain { opacity: 0; }
/* The fixed page gradients never belong over the cream introduction, renderer or not. */
body::before, body::after { transition: opacity .5s ease; }
html.section-mode:has(#intro.is-current) body::before, html.section-mode:has(#intro.is-current) body::after, html:not(.section-mode) body:not(.scrolled)::before { opacity: 0; }
/* The introduction arrives in order: name, line, invitation, hints. */
.portal-copy h1, .portal-copy p, .portal-invite, .portal-instructions, .portal-projects { animation: portal-rise 1.1s cubic-bezier(.2,.7,.2,1) backwards; }
.portal-copy p { animation-delay: .22s; }
.portal-invite { animation-delay: .5s; }
.portal-instructions { animation-delay: .65s; }
.portal-projects { animation-delay: .8s; }
@keyframes portal-rise { from { opacity: 0; translate: 0 22px; } }
html.portal-active .section-controls { background: color-mix(in srgb, var(--bg) 75%, transparent); border-radius: 3rem; padding: .3rem .6rem; }
html.portal-world .frame, html.portal-world .section-controls { visibility: hidden; }
html.portal-world, html.portal-world body { overflow: hidden; }
.portal-intro.is-world { touch-action: none; }
.portal-invite:focus-visible, .portal-projects:focus-visible { outline: 2px solid var(--accent); outline-offset: 5px; }
@media (max-width: 760px) {
  .portal-copy { gap: 5vh; }
  .portal-copy h1 { font-size: 15vw; }
  .portal-copy p { max-width: 85vw; font-size: .9rem; }
  .portal-invite { top: 68%; }
  .portal-instructions { bottom: 8rem; font-size: .5rem; }
  .portal-projects { bottom: 5.5rem; }
}
@media (hover: none) { .portal-desktop-hint { display: none; } .portal-touch-hint { display: inline; } }
@media (prefers-reduced-motion: reduce) { .portal-copy { transition: none; } .portal-copy h1, .portal-copy p, .portal-invite, .portal-instructions, .portal-projects { animation: none; } }
@media print { #top > .portal-intro { display: none; } }

.portal-invite[hidden] { display: none; }

.portal-hold-cursor { position:absolute; left:0;top:0;z-index:4;display:flex;align-items:center;gap:5px;pointer-events:none;color:#849099;font:600 10px var(--font-body);letter-spacing:2px;will-change:transform; }
.portal-hold-cursor i { font-style:normal;width:44px;height:44px;display:grid;place-items:center;border:1px solid #8490999a;border-radius:50%;background:conic-gradient(from -90deg,#84909950 var(--hold,0deg),transparent 0); }
html.portal-active:not(.portal-world):has(.portal-intro:hover) .cursor { opacity:0; }
@media (hover:none) { .portal-hold-cursor { display:none; } }
.portal-hold-cursor[hidden] { display:none; }

.portal-hold-meter { position:absolute;left:50%;top:calc(100% + 9px);width:68px;height:4px;transform:translateX(-50%);border-radius:4px;background:rgba(30,40,45,.2);box-shadow:0 0 0 1px rgba(255,255,255,.65);overflow:hidden;opacity:0; }
.portal-hold-meter b { display:block;width:100%;height:100%;background:#394c54;transform:scaleX(0);transform-origin:left; }
.portal-hold-cursor.is-holding { color:#394c54; }
.portal-hold-cursor.is-holding .portal-hold-meter { opacity:1; }
.portal-hold-cursor.is-holding .portal-hold-meter b { animation:portal-hold-fill 2s linear forwards; }
@keyframes portal-hold-fill { to { transform:scaleX(1); } }
@media (hover:none) { .portal-hold-cursor.is-holding { display:flex; } }

/* Touch gestures drive the same lens and particle field as the mouse. */
@media (pointer:coarse) {
  .section-mode #top > .portal-intro, .portal-intro.is-world { touch-action:none; }
  .portal-intro { -webkit-touch-callout:none; -webkit-user-select:none; user-select:none; }
  .portal-invite, .portal-projects { touch-action:manipulation; min-height:48px; }
  .portal-projects { display:flex;align-items:center; }
  .portal-hold-cursor.is-holding { margin-top:-64px; }
}
@media (max-width:760px) {
  .portal-instructions { bottom:calc(9.5rem + env(safe-area-inset-bottom));width:88%;white-space:normal;text-align:center;font-size:.65rem;line-height:1.6; }
  .portal-projects { bottom:calc(5.8rem + env(safe-area-inset-bottom)); }
  .portal-invite { top:auto;bottom:calc(12rem + env(safe-area-inset-bottom));white-space:nowrap; }
  .portal-copy { justify-content:flex-start;padding-top:max(26svh,8rem);gap:1.5rem; }
}
@media (max-height:550px) and (pointer:coarse) {
  .portal-copy { padding-top:24svh;gap:.6rem; }
  .portal-copy h1 { font-size:11vw; }
  .portal-invite { bottom:7rem; }
  .portal-instructions { bottom:5.5rem; }
  .portal-projects { bottom:4rem; }
}


/* Imported ink-field renderer owns the cursor, dispersal and exit control. */
html.portal-active .cursor { display:none; }
.portal-intro.is-world .portal-copy { transform:none; }
html:not(.portal-active) .mask-cursor, html:not(.portal-active) .mask-exit, html:not(.portal-active) .mask-exit-hint { display:none; }

/* The portal opens onto a conversation: the particle field dims behind it and the pointer comes back. */
#portal-canvas { transition: filter 1.4s ease; }
.portal-intro.is-world #portal-canvas { filter: brightness(.48) saturate(.85); }
html.portal-world, html.portal-world * { cursor: auto !important; }
html.portal-world button, html.portal-world a, html.portal-world [role="button"] { cursor: pointer !important; }
html.portal-world input, html.portal-world textarea { cursor: text !important; }
html.curio-open .cursor { display: none; }
.mask-loading { position:absolute !important; }
@media (pointer:coarse) {
  .mask-cursor--touch { margin-top:-56px; }
  .mask-exit.magnetic-close { top:max(16px,env(safe-area-inset-top));right:max(16px,env(safe-area-inset-right));width:48px;height:48px; }
}
