/* css/bio-dive.css - Styles for the Bio artifact-dive experience
   The dive itself (reef wall, water, kelp, fish, every artifact) is a 3D
   world drawn behind the page by js/n64-dive.js; the page holds the
   controls (each artifact's button and caption), the recovered clues that
   unfold beneath them, and the instruments (depth gauge, specimen jar). */

/* ===== Bio Quote & Hero ===== */
.bio-quote {
    margin-top: 1.5rem;
    text-align: center;
    max-width: 500px;
    margin-left: auto;
    margin-right: auto;
}

.bio-quote p {
    font-style: italic;
    font-size: 1.15rem;
    color: rgba(255, 255, 255, 0.78);
    letter-spacing: 0.5px;
    line-height: 1.6;
    /* it crosses the sun's path on the water: a dark halo keeps it legible */
    text-shadow: 0 1px 2px rgba(3, 12, 22, 0.9), 0 0 12px rgba(3, 12, 22, 0.75);
}

.bio-quote cite {
    display: block;
    text-align: right;
    margin-top: 0.5rem;
    font-size: 0.9rem;
    color: rgba(255, 255, 255, 0.6);
    font-style: normal;
    text-shadow: 0 1px 2px rgba(3, 12, 22, 0.9), 0 0 10px rgba(3, 12, 22, 0.7);
}

/* A phone on its side: the quote runs in one line under the name, so the
   surface still fits between the clouds and Dive In */
@media (max-height: 540px) and (orientation: landscape) {
    .bio-quote {
        margin-top: 0.4rem;
        margin-bottom: 0;
        max-width: 640px;
    }

    .bio-quote p {
        margin: 0;
        font-size: 0.95rem;
        line-height: 1.4;
    }

    .bio-quote cite {
        margin-top: 0.15rem;
        font-size: 0.78rem;
    }
}

/* ===== Bio Event Sections ===== */
.bio-event-section {
    min-height: 80vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4rem;
    padding: 4rem 1.5rem;
    position: relative;
    z-index: 1;
}

/* ===== Specimen Cluster (artifact + its tag) ===== */
.specimen-cluster {
    max-width: 680px;
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;

    /* the words surface as you reach them; the artifact is already there,
       resting on its ledge in the world behind the page */
    opacity: 0;
    transition: opacity 0.8s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Alternating sides of the wall for visual flow */
.specimen-cluster[data-direction="left"] {
    margin-right: auto;
    margin-left: 5%;
}

.specimen-cluster[data-direction="right"] {
    margin-left: auto;
    margin-right: 5%;
}

.specimen-cluster.revealed {
    opacity: 1;
}

/* Without the 3D world nothing would move the artifact, so the old drift
   stays only for that fallback (the world animates its own artifacts and
   their rock must never sway with them) */
.specimen-float {
    width: fit-content;
}

/* ===== Specimen Button ===== */
.specimen {
    position: relative;
    z-index: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    background: none;
    border: none;
    padding: 0.5rem 1.25rem 0.25rem;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.specimen:focus-visible {
    outline: 2px solid var(--hud-gold, #ffd36a);
    outline-offset: 8px;
}

/* ===== Specimen Caption (instrument voice, printed over rock and water) ===== */
.specimen-caption {
    margin-top: 1.3rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.28rem;
    font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
    text-shadow: 1px 1px 0 rgba(3, 12, 22, 0.95), 0 0 8px rgba(3, 12, 22, 0.9), 0 0 2px rgba(3, 12, 22, 0.9);
}

.specimen-no {
    font-size: 0.68rem;
    letter-spacing: 0.2em;
    color: rgba(206, 232, 255, 0.72);
}

.specimen-name {
    font-family: var(--hud-font, 'Lilita One', sans-serif);
    font-size: 1rem;
    font-weight: 400;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--hud-ink, #fff4d8);
    text-shadow: 2px 2px 0 var(--hud-shadow, #061220), 0 0 10px rgba(3, 12, 22, 0.85);
    transition: color 0.25s ease, transform 0.25s ease;
}

.specimen:hover .specimen-name,
.specimen:focus-visible .specimen-name {
    color: var(--hud-gold, #ffd36a);
    transform: translateY(-2px);
}

/* the "Press A" line: shown for whichever find is in reach
   (js/bio-specimens.js), gone while its clue is out or the octopus bolts */
.specimen-caption .press-prompt {
    margin-top: 0.3rem;
}

.specimen[aria-expanded="true"] .press-prompt,
.specimen.startled .press-prompt {
    opacity: 0;
}

/* while a prompt shows, its words are part of the thing it names:
   pressing them presses it (the find, the plaque, the line) */
html:not(.no-dive) .fp-near .specimen.in-reach:not([aria-expanded="true"]) .press-prompt,
html:not(.no-dive) .plaque-wrap.fp-near.in-reach .press-prompt,
html:not(.no-dive) .dive-line.fp-near.in-reach .press-prompt {
    pointer-events: auto;
    cursor: pointer;
}

/* ===== The dive world (js/n64-dive.js) =====
   One pixelated WebGL canvas behind the page draws the reef wall, the
   water, the fish and every artifact. Each artifact is anchored to the
   empty box inside its button: the button stays the control, the 3D
   object answers it. */
.n64-dive {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    z-index: 0;
    pointer-events: none;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    opacity: 0;
    transition: opacity 0.6s ease;
}

.n64-dive.n64-dive--on {
    opacity: 1;
}

html.nav-arriving:not(.nav-reveal) .n64-dive {
    opacity: 0;
}

.artifact-anchor {
    display: block;
    width: clamp(210px, 28vw, 270px);
    height: clamp(230px, 30vw, 290px);
}

.artifact-anchor--plaque {
    width: clamp(240px, 36vw, 320px);
    height: clamp(170px, 25vw, 220px);
}

/* drag to turn an artifact over; a click still examines it */
.specimen,
.floor-plaque {
    touch-action: pan-y;
}

.specimen.turning,
.floor-plaque.turning {
    cursor: grabbing;
}

/* the 3D world brings its own light shafts, snow, plankton and halocline */
html.dive-world .god-rays,
html.dive-world .marine-snow,
html.dive-world .bioluminescent-container,
html.dive-world .halocline-shimmer {
    display: none;
}

/* ===== Specimen Tag (the recovered clue) ===== */
.specimen-tag {
    display: none;
    width: 100%;
    margin-top: 1.6rem;
}

.specimen-tag.open {
    display: block;
    animation: tagUnfold 0.55s cubic-bezier(0.22, 1, 0.36, 1);
}

.specimen-tag.closing {
    animation: tagFold 0.28s ease-in forwards;
}

@keyframes tagUnfold {
    from {
        opacity: 0;
        transform: translateY(-18px) scale(0.96);
    }

    to {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
}

@keyframes tagFold {
    to {
        opacity: 0;
        transform: translateY(-10px) scale(0.97);
    }
}

/* The clue floats free in the water — no slab behind it. The inner is
   just a transparent stage that anchors the close key. */
.specimen-tag-inner {
    position: relative;
    text-align: left;
    padding-top: 0.3rem;
}

/* Return-specimen control: a square HUD key */
.tag-close {
    position: absolute;
    top: -0.5rem;
    right: -0.5rem;
    z-index: 2;
    width: 34px;
    height: 34px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--hud-font, 'Lilita One', sans-serif);
    font-size: 1.25rem;
    line-height: 1;
    color: var(--hud-ink, #fff4d8);
    cursor: pointer;
    background: var(--panel-bg, rgba(3, 12, 24, 0.88));
    border: 2px solid var(--panel-line, #d8b56a);
    border-radius: 0;
    box-shadow: 3px 3px 0 var(--hud-shadow, #061220);
    transition: transform 0.12s ease, box-shadow 0.12s ease, color 0.2s ease;
}

.tag-close:hover,
.tag-close:focus-visible {
    color: var(--hud-gold, #ffd36a);
    transform: translate(-1px, -1px);
    box-shadow: 4px 4px 0 var(--hud-shadow, #061220);
}

.tag-close:active {
    transform: translate(2px, 2px);
    box-shadow: 1px 1px 0 var(--hud-shadow, #061220);
}

/* ===== Recovered Clues =====
   Tags carry no labels — just the thing itself and whatever was written
   on it. Each piece DETACHES from the artifact and settles down through
   the water when the specimen is examined. */
.specimen-tag.open .specimen-tag-inner>figure {
    animation: clueDetach 1.1s cubic-bezier(0.25, 0.7, 0.3, 1) backwards;
}

.specimen-tag.open .specimen-tag-inner>figure:nth-of-type(2) {
    animation-delay: 0.22s;
}

.specimen-tag.open .specimen-tag-inner>figure:nth-of-type(3) {
    animation-delay: 0.44s;
}

/* Untied: drift down, swing once, settle */
@keyframes clueDetach {
    0% {
        opacity: 0;
        transform: translateY(-46px) rotate(3deg);
    }

    55% {
        opacity: 1;
        transform: translateY(8px) rotate(-1.5deg);
    }

    80% {
        transform: translateY(-3px) rotate(0.7deg);
    }

    100% {
        transform: translateY(0) rotate(0deg);
    }
}

/* A slip of paper, ink still holding */
.found-note {
    margin: 0.4rem 0 0.2rem;
}

.note-slip {
    margin-top: 0.55rem;
    max-width: 420px;
    padding: 1.15rem 1.4rem 1.25rem;
    background:
        linear-gradient(174deg, rgba(246, 238, 214, 0.94), rgba(210, 196, 160, 0.9));
    clip-path: polygon(0 6%, 3% 0, 97% 2%, 100% 10%, 99% 92%, 94% 100%, 55% 97%,
            8% 100%, 0 94%);
    transform: rotate(-1.6deg);
    box-shadow: 0 14px 26px rgba(0, 3, 10, 0.35);
}

.note-slip p {
    margin: 0;
    font-family: Georgia, 'Iowan Old Style', 'Times New Roman', serif;
    font-style: italic;
    font-size: 1.12rem;
    line-height: 1.55;
    color: rgba(52, 48, 38, 0.92);
}

/* Handwriting on the backs of photographs */
.note-ink {
    display: block;
    margin-top: 0.15rem;
    font-family: Georgia, 'Iowan Old Style', 'Times New Roman', serif;
    font-style: italic;
    font-size: 1.05rem;
    color: rgba(228, 238, 248, 0.92);
    text-shadow: 1px 1px 0 rgba(3, 12, 22, 0.9), 0 0 8px rgba(3, 12, 22, 0.8);
}

/* The dropped tablet's lock screen — the account outlived the shift.
   A square screen in a slate bezel. */
.nb-lock {
    margin: 0.4rem 0 0.2rem;
}

.nb-lock-screen {
    margin-top: 0.55rem;
    max-width: 440px;
    padding: 1.4rem 1.5rem 1.5rem;
    text-align: center;
    background: linear-gradient(180deg, rgba(8, 26, 44, 0.97), rgba(5, 17, 32, 0.98));
    border: 8px solid #2c384a;
    outline: 1px solid rgba(160, 184, 214, 0.35);
    outline-offset: -1px;
    border-radius: 0;
    box-shadow: 6px 6px 0 rgba(2, 8, 16, 0.55);
    position: relative;
    overflow: hidden;
}

/* faint screen glare */
.nb-lock-screen::before {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(112deg, rgba(200, 235, 255, 0.07), transparent 36%);
    pointer-events: none;
}

/* the account's avatar: a tiny 3D octopus */
.prop-stage--avatar {
    --stage-w: 64px;
    --stage-h: 54px;
    margin: 0 auto 0.7rem;
}

.nb-lock-screen p {
    margin: 0;
    font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
}

.nb-lock-user {
    font-size: 0.88rem;
    color: rgba(224, 241, 255, 0.92);
    letter-spacing: 0.04em;
    padding-bottom: 0.45rem;
    border-bottom: 1px solid rgba(159, 212, 255, 0.25);
    display: inline-block;
}

.nb-lock-pass {
    margin-top: 0.7rem !important;
    font-size: 0.8rem;
    color: rgba(159, 212, 255, 0.55);
    letter-spacing: 0.3em;
}

.nb-lock-caret {
    display: inline-block;
    width: 7px;
    height: 13px;
    margin-left: 4px;
    vertical-align: -2px;
    background: rgba(52, 224, 184, 0.9);
    animation: lockCaret 1.1s steps(1) infinite;
}

@keyframes lockCaret {
    50% {
        opacity: 0.12;
    }
}

.nb-lock-role {
    margin-top: 1.05rem !important;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: rgba(125, 240, 212, 0.75);
}

.nb-lock-status {
    margin-top: 0.45rem !important;
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: rgba(255, 180, 94, 0.8);
}

/* Recovered parchment: the diplomas are 3D scrolls that unroll once the
   twine is off (a prop stage sized to the parchment) */
.diploma {
    margin: 0.4rem 0 0.6rem;
}

.diploma-plate {
    margin-top: 0.55rem;
    max-width: 460px;
}

.diploma-plate .prop-stage {
    width: 100%;
    height: auto;
    aspect-ratio: 23 / 16;
}

/* ===== Recovered Slides (the dredge) =====
   Real photographs surface as silt-covered finds: wipe the sediment away
   (or take the button path) and the picture develops underneath. Each is
   mounted in a square gold dialog frame. */
.dredge-slide {
    margin: 1.7rem 0 0.3rem;
}

.slide-plate {
    position: relative;
    max-width: 430px;
    padding: 8px;
    background: var(--panel-bg, rgba(3, 12, 24, 0.88));
    border: 2px solid var(--panel-line, #d8b56a);
    outline: 1px solid var(--panel-line-dim, rgba(216, 181, 106, 0.38));
    outline-offset: 4px;
    border-radius: 0;
    box-shadow: 6px 6px 0 rgba(2, 8, 16, 0.55);
}

/* The photo stays hidden until its silt layer has been painted on top.
   (opacity: 1 overrides the site-wide img[loading="lazy"] fade-in, which
   waits for a .loaded class no script on this page ever adds — the silt
   canvas is this component's own reveal mechanism.) */
.slide-plate img,
.slide-plate img[loading="lazy"] {
    display: block;
    width: 100%;
    height: auto;
    border-radius: 0;
    visibility: hidden;
    opacity: 1;
}

.dredge-slide.silted .slide-plate img,
.dredge-slide.revealed .slide-plate img {
    visibility: visible;
}

.silt-canvas {
    position: absolute;
    inset: 8px;
    width: calc(100% - 16px);
    height: calc(100% - 16px);
    border-radius: 0;
    cursor: grab;
    touch-action: none;
    transition: opacity 0.9s ease;
}

.silt-canvas:active {
    cursor: grabbing;
}

.dredge-slide.revealed .silt-canvas {
    opacity: 0;
    pointer-events: none;
}

/* the silt's own prompt, in the same voice as every find's */
.silt-hint.press-prompt {
    position: absolute;
    left: 50%;
    top: 50%;
    opacity: 1;
    transform: translate(-50%, -50%);
    transition: opacity 0.4s ease;
}

.dredge-slide.wiping .silt-hint,
.dredge-slide.revealed .silt-hint {
    opacity: 0;
}

.slide-caption {
    margin-top: 0.85rem;
    color: #b9cbdc;
    font-size: 0.95rem;
    line-height: 1.5;
}

.slide-label {
    display: block;
    font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.66rem;
    font-weight: 600;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: rgba(176, 222, 255, 0.85);
    text-shadow: 1px 1px 0 rgba(3, 12, 22, 0.9), 0 0 6px rgba(3, 12, 22, 0.8);
    margin-bottom: 0.25rem;
}

.slide-reveal {
    margin-top: 0.5rem;
    padding: 0 0 2px;
    background: none;
    border: none;
    border-bottom: 1px dotted rgba(159, 212, 255, 0.5);
    font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.66rem;
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: rgba(176, 222, 255, 0.85);
    text-shadow: 1px 1px 0 rgba(3, 12, 22, 0.9);
    cursor: pointer;
    transition: color 0.3s ease, border-color 0.3s ease;
}

.slide-reveal:hover,
.slide-reveal:focus-visible {
    color: rgba(200, 232, 255, 0.95);
    border-bottom-style: solid;
}

.dredge-slide.revealed .slide-reveal {
    display: none;
}

/* the keyboard's way through the silt: there for focus, unseen otherwise */
.slide-reveal:not(:focus-visible) {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

/* ===== Golden Gate Diorama (inside the Bottled Fog tag) =====
   A 320×180 picture in a dialog frame: the real geography of the strait,
   low-poly, drawn by the prop stage. Sits clear of the close key. */
.gg-diorama {
    position: relative;
    width: 100%;
    max-width: 640px;
    aspect-ratio: 16 / 9;
    margin: 2.2rem auto 2.6rem;
    border: 2px solid var(--panel-line, #d8b56a);
    outline: 1px solid var(--panel-line-dim, rgba(216, 181, 106, 0.38));
    outline-offset: 4px;
    background: #dcd6cd;
    box-shadow: 6px 6px 0 rgba(2, 8, 16, 0.55);
    animation: ggZoom 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}

@keyframes ggZoom {
    from {
        opacity: 0;
        transform: scale(0.86);
    }

    to {
        opacity: 1;
        transform: scale(1);
    }
}

.gg-diorama .prop-stage {
    position: absolute;
    inset: 0;
    --stage-w: 100%;
    --stage-h: 100%;
}

.gg-label {
    position: absolute;
    left: 0;
    right: 0;
    bottom: -1.55rem;
    text-align: center;
    font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.64rem;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: rgba(220, 236, 255, 0.78);
    text-shadow: 1px 1px 0 rgba(6, 18, 32, 0.9);
}

/* ===== Specimen Jar (fixed collector beside the gauge) =====
   A 3D jar (prop "jar") that shows a glowing gem for every artifact
   pouched; the motes below are the record it reads. */
.specimen-jar {
    position: fixed;
    right: 1.2rem;
    bottom: 1.2rem;
    z-index: 100;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.4s ease;
}

body.has-scrolled .specimen-jar {
    opacity: 1;
}

.jar-visual {
    position: relative;
    width: 78px;
    height: 88px;
}

.prop-stage--jar {
    --stage-w: 100%;
    --stage-h: 100%;
}

.jar-motes {
    display: none;
}

/* without WebGL the jar falls back to a column of glowing motes */
html.no-props .jar-motes {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 4px;
    position: absolute;
    inset: 30% 18% 10%;
}

.jar-mote {
    width: 7px;
    height: 7px;
    background: var(--mote, #7df0d4);
    box-shadow: 0 0 8px var(--mote, #7df0d4);
}

.jar-count {
    font-family: var(--hud-font, 'Lilita One', sans-serif);
    font-size: 0.9rem;
    letter-spacing: 0.06em;
    font-variant-numeric: tabular-nums;
    color: var(--hud-ink, #fff4d8);
    text-shadow: 2px 2px 0 var(--hud-shadow, #061220);
    margin-top: -6px;
}

.specimen-jar.complete .jar-count {
    color: rgba(125, 240, 212, 0.95);
}

/* ===== Core Sample (clickable era strata on the depth meter) ===== */
.depth-fill {
    pointer-events: none;
}

.core-stratum {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    width: 22px;
    background: transparent;
    border: none;
    padding: 0;
    cursor: pointer;
    touch-action: manipulation;
}

.core-stratum::before {
    content: '';
    position: absolute;
    top: 1px;
    bottom: 1px;
    left: 50%;
    transform: translateX(-50%);
    width: 6px;
    background: var(--stratum-tint, rgba(0, 170, 255, 0.4));
    opacity: 0.55;
    transition: width 0.25s ease, opacity 0.25s ease, box-shadow 0.25s ease;
}

.core-stratum:hover::before,
.core-stratum:focus-visible::before,
.core-stratum.active::before {
    width: 10px;
    opacity: 0.95;
    box-shadow: 0 0 10px var(--stratum-tint, rgba(0, 170, 255, 0.5));
}

.core-stratum:focus-visible {
    outline: 1px solid var(--hud-gold, #ffd36a);
    outline-offset: 2px;
}

/* Era label surfaces beside the gauge (a square HUD tag) */
.core-stratum::after {
    content: attr(data-era);
    position: absolute;
    right: 26px;
    top: 50%;
    transform: translateY(-50%) translateX(8px);
    white-space: nowrap;
    font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.68rem;
    letter-spacing: 0.08em;
    color: rgba(224, 241, 255, 0.92);
    padding: 0.3rem 0.7rem;
    background: rgba(3, 12, 24, 0.9);
    border: 1px solid var(--panel-line-dim, rgba(216, 181, 106, 0.38));
    border-radius: 0;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.25s ease, transform 0.25s ease;
}

.core-stratum:hover::after,
.core-stratum:focus-visible::after {
    opacity: 1;
    transform: translateY(-50%) translateX(0);
}

/* ===== The Sea-Floor Plaque (deep-sea payoff) =====
   A stone slab on a pile of boulders at the lakebed, half-buried and still
   until every artifact is pouched; then the bed trembles and it shakes to
   be read. The 3D world plays all of it from the classes set here. */
.plaque-wrap {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.7rem;
    margin-bottom: 2.8rem;
    max-width: 620px;
    width: 100%;
}

.floor-plaque {
    background: none;
    border: none;
    padding: 0.4rem;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.floor-plaque:focus-visible {
    outline: 2px solid var(--hud-gold, #ffd36a);
    outline-offset: 8px;
}

/* The plaque says nothing until every find is pouched; then, trembling,
   it shows its prompt (its status stays for screen readers) */
.plaque-wrap.opened .press-prompt {
    opacity: 0;
}

/* The words on the plaque */
.plaque-note {
    display: none;
    width: 100%;
    margin-top: 0.6rem;
}

.plaque-note.open {
    display: block;
    animation: tagUnfold 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}

/* The words float in the dark, lit like the engraving itself */
.plaque-note-inner {
    text-align: center;
    padding: 0.6rem 0.5rem 0;
}

.plaque-note-inner h3 {
    margin: 0 0 0.9rem;
    font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.26em;
    text-transform: uppercase;
    color: rgba(125, 240, 212, 0.85);
    text-shadow: 0 0 14px rgba(125, 240, 212, 0.35), 1px 1px 0 rgba(3, 12, 22, 0.9);
}

.plaque-note-inner p {
    margin: 0 auto;
    max-width: 480px;
    font-size: 1.12rem;
    line-height: 1.85;
    color: rgba(226, 240, 252, 0.96);
    text-shadow: 0 2px 14px rgba(0, 8, 18, 0.8), 1px 1px 0 rgba(3, 12, 22, 0.9);
}

/* ===== Burst Ascent =====
   The rush of water past the mask on the ride back up: streaks race DOWN
   the screen while the dive controller rockets the scroll position to the
   surface. */
.ascent-rush {
    position: fixed;
    inset: 0;
    z-index: 150;
    pointer-events: none;
    overflow: hidden;
    animation: rushFade 2.4s ease forwards;
}

@keyframes rushFade {
    0% {
        opacity: 0;
    }

    10% {
        opacity: 1;
    }

    82% {
        opacity: 1;
    }

    100% {
        opacity: 0;
    }
}

.rush-streak {
    position: absolute;
    top: 0;
    width: 2.5px;
    height: 30vh;
    background: linear-gradient(180deg,
            transparent,
            rgba(190, 235, 255, 0.7),
            transparent);
    animation: streakDown 0.55s linear infinite;
}

@keyframes streakDown {
    from {
        transform: translateY(-40vh);
    }

    to {
        transform: translateY(140vh);
    }
}

.ascend-btn {
    margin-top: 1.5rem;
}

.ascend-btn::after {
    content: '↑';
}

/* ===== Halocline (Two Waters: where salt gives way to fresh) =====
   The world draws the boundary layer itself; the CSS sheet below is the
   fallback for a visit without WebGL. */
.halocline-band {
    min-height: 38vh;
    justify-content: center;
}

.halocline-shimmer {
    position: relative;
    width: min(680px, 86%);
    height: 76px;
}

.halocline-shimmer::before {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg,
            transparent 0%,
            rgba(140, 235, 205, 0.1) 36%,
            rgba(196, 248, 228, 0.24) 50%,
            rgba(120, 215, 190, 0.1) 64%,
            transparent 100%);
    filter: blur(7px);
}

.halocline-label {
    margin-top: 1.2rem;
    font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: rgba(200, 246, 228, 0.78);
    text-shadow: 1px 1px 0 rgba(3, 12, 22, 0.9), 0 0 8px rgba(3, 12, 22, 0.8);
    text-align: center;
}

/* ===== Two Waters zone tints (body[data-water] stamped by bio-dive.js) =====
   (for the DOM rays and snow, which only appear without the 3D world) */
.god-rays {
    transition: opacity 1.2s ease, filter 2.5s ease;
}

.marine-snow {
    transition: opacity 0.8s ease, filter 2.5s ease;
}

body[data-water="fresh"] .god-rays {
    filter: hue-rotate(55deg) saturate(1.05);
}

body[data-water="fresh"] .marine-snow {
    filter: sepia(0.55) hue-rotate(-12deg) saturate(1.2);
}

/* Fallback water column for the rare no-WebGL visit (the live scene drives
   the real freshwater shift in wave-background.js) */
body.bio-dive {
    background: #041410;
}

body.bio-dive .depth-background {
    background: linear-gradient(180deg,
            var(--surface-gradient-start) 0%,
            var(--surface-gradient-mid) 15%,
            var(--surface-gradient-end) 28%,
            #00b4c6 38%,
            #0f7f6e 52%,
            #0e6e58 68%,
            #07352a 84%,
            #041410 100%);
    background-size: 100% 500vh;
}

/* ===== Era Marker (on depth indicator) ===== */
.era-marker {
    font-size: 0.7rem;
    color: rgba(255, 255, 255, 0.6);
    text-align: center;
    white-space: nowrap;
    writing-mode: vertical-rl;
    text-orientation: mixed;
    transform: rotate(180deg);
    margin-top: 0.5rem;
    letter-spacing: 0.5px;
    transition: opacity 0.4s ease;
    min-height: 3rem;
}

/* ===== Pouching an artifact (the flight to the jar) ===== */
.pouch-flight {
    position: fixed;
    z-index: 140;
    pointer-events: none;
    will-change: transform, opacity;
}

.pouch-flight canvas {
    display: block;
    width: 100%;
    height: 100%;
    image-rendering: pixelated;
}

/* ===== Bottom Navigation ===== */
.bottom-nav-bubbles {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 2.5rem;
    padding: 3rem 1rem;
    position: relative;
    z-index: 1;
}

.bottom-nav-bubbles .dive-prop .prop-stage {
    --stage-w: 150px;
    --stage-h: 150px;
}

.bottom-nav-bubbles .dive-prop .hud-label {
    font-size: 1.1rem;
    margin-top: -0.5rem;
}

/* three props across a phone: they shrink to fit the screen, never past it */
@media (max-width: 600px) {
    .bottom-nav-bubbles {
        gap: 0.75rem;
        padding: 2rem 0.5rem;
    }

    .bottom-nav-bubbles .dive-prop .prop-stage {
        --stage-w: min(104px, 27vw);
        --stage-h: min(104px, 27vw);
    }

    .bottom-nav-bubbles .dive-prop .hud-label {
        font-size: 0.95rem;
        margin-top: -0.3rem;
    }
}

/* At the end of the dive the instruments have done their job: the gauge
   and the jar step aside so nothing sits on the way out
   (body.dive-end is set by js/bio-dive.js) */
body.dive-end .depth-indicator,
body.dive-end .specimen-jar {
    opacity: 0;
    pointer-events: none;
}

.bottom-nav-title {
    text-align: center;
    font-family: var(--hud-font, 'Lilita One', sans-serif);
    font-size: 0.95rem;
    letter-spacing: 0.12em;
    color: rgba(255, 244, 216, 0.75);
    text-shadow: 2px 2px 0 rgba(6, 18, 32, 0.9);
    text-transform: uppercase;
    margin-bottom: 0.5rem;
}

/* ===== Responsive ===== */
@media (max-width: 768px) {
    .bio-event-section {
        min-height: 60vh;
        gap: 3rem;
        padding: 2.5rem 1rem;
    }

    /* On mobile every artifact rests in the middle of the view */
    .specimen-cluster[data-direction="left"],
    .specimen-cluster[data-direction="right"] {
        margin-left: auto;
        margin-right: auto;
    }

    .artifact-anchor {
        width: clamp(170px, 50vw, 220px);
        height: clamp(190px, 54vw, 240px);
    }

    .artifact-anchor--plaque {
        width: clamp(220px, 64vw, 280px);
        height: clamp(150px, 44vw, 200px);
    }

    .tag-close {
        width: 32px;
        height: 32px;
    }

    .specimen-jar {
        right: 0.5rem;
        bottom: 0.6rem;
    }

    .jar-visual {
        width: 62px;
        height: 70px;
    }

    .jar-count {
        font-size: 0.78rem;
    }

    /* While a tag is open there's no room to share with the gauge —
       the instruments recede until the specimen is returned */
    body.specimen-open .depth-indicator {
        opacity: 0;
        pointer-events: none;
    }

    .slide-plate {
        max-width: 100%;
    }

    .gg-label {
        font-size: 0.64rem;
        letter-spacing: 0.08em;
        white-space: nowrap;
    }

    .halocline-band {
        min-height: 30vh;
    }

    /* the label and the plaque's words wrap clear of the depth gauge at
       the right edge */
    .halocline-label {
        padding: 0 3.25rem;
    }

    .plaque-note-inner {
        padding: 0.6rem 3.25rem 0;
    }
}

@media (max-width: 480px) {
    .bio-quote p {
        font-size: 1rem;
    }

    .specimen-name {
        font-size: 0.92rem;
    }
}

/* ===== Reduced Motion =====
   Tags and clues appear without theatre (the 3D world holds its own
   artifacts still and plays encounters straight to their end state). */
@media (prefers-reduced-motion: reduce) {

    .gg-diorama,
    .specimen-tag.open,
    .specimen-tag.closing,
    .plaque-note.open,
    .specimen-tag.open .specimen-tag-inner>figure,
    .nb-lock-caret {
        animation: none !important;
    }

    .silt-canvas,
    .god-rays,
    .marine-snow,
    .specimen-cluster,
    .n64-dive {
        transition: none !important;
    }
}

/* ===== The dive in first person (js/n64-dive.js) =====
   The sections only set the pace now: one stop per section, where it sits
   centred in the view. Each find's button rides its 3D object (the world
   lays it over the object's bounds every frame), its clue opens as a panel
   beside it — or across the top of an upright phone, the find settling low
   beneath it — the plaque and the signpost stand on the lakebed, and the
   halocline names itself as you sink through it. Without the 3D world
   (html.no-dive) the page falls back to the in-flow layout above. */
html:not(.no-dive) .bio-event-section {
    min-height: 100vh;
}

html:not(.no-dive) .specimen-cluster {
    opacity: 1;
    transition: none;
}

/* the layer a find's button rides in: a point at the view's corner; the
   world moves the button and fades the layer in as you reach it */
html:not(.no-dive) .specimen-float {
    position: fixed;
    left: 0;
    top: 0;
    width: 0;
    height: 0;
    z-index: 30;
    opacity: 0;
    pointer-events: none;
}

html:not(.no-dive) .specimen,
html:not(.no-dive) .floor-plaque {
    position: absolute;
    left: 0;
    top: 0;
    display: block;
    width: 240px;
    height: 260px;
    padding: 0;
    pointer-events: none;
}

html:not(.no-dive) .fp-near .specimen,
html:not(.no-dive) .plaque-wrap.fp-near .floor-plaque {
    pointer-events: auto;
}

html:not(.no-dive) .specimen .artifact-anchor,
html:not(.no-dive) .floor-plaque .artifact-anchor {
    width: 100%;
    height: 100%;
}

html:not(.no-dive) .specimen-caption,
html:not(.no-dive) .plaque-caption {
    position: absolute;
    top: calc(100% + 0.35rem);
    left: 50%;
    margin: 0;
    transform: translateX(-50%);
    white-space: nowrap;
    pointer-events: none;
}

/* the recovered clue: a panel beside the find (it floats free in the
   water, as ever — no slab; only the close key and the things themselves) */
html:not(.no-dive) .specimen-tag {
    position: fixed;
    top: 0;
    bottom: 0;
    width: min(460px, 40vw);
    margin: 0;
    z-index: 40;
    align-items: center;
    pointer-events: none;
}

html:not(.no-dive) .specimen-tag.open,
html:not(.no-dive) .specimen-tag.closing {
    display: flex;
}

html:not(.no-dive) .specimen-cluster[data-side="right"] .specimen-tag {
    left: 4vw;
}

/* a find on the left: the clue keeps clear of the depth gauge */
html:not(.no-dive) .specimen-cluster[data-side="left"] .specimen-tag {
    right: calc(4vw + 3.4rem);
}

html:not(.no-dive) .specimen-tag-inner {
    width: 100%;
    max-height: 86vh;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: none;
    padding: 0.9rem 0.9rem 1rem;
    box-sizing: border-box;
    pointer-events: auto;
}

html:not(.no-dive) .specimen-tag-inner::-webkit-scrollbar {
    display: none;
}

html:not(.no-dive) .tag-close {
    top: 0.2rem;
    right: 0.2rem;
}

/* the halocline names itself as you sink through it, like a place */
html:not(.no-dive) .halocline-label {
    position: fixed;
    left: 0;
    right: 0;
    top: 16vh;
    z-index: 20;
    margin: 0;
    padding: 0 4.5rem;
    opacity: 0;
    pointer-events: none;
    font-size: 0.78rem;
}

/* the lakebed: the plaque on its cairn, its words a panel above it */
html:not(.no-dive) .plaque-wrap {
    position: fixed;
    inset: 0;
    z-index: 30;
    display: block;
    max-width: none;
    margin: 0;
    opacity: 0;
    pointer-events: none;
}

html:not(.no-dive) .plaque-note {
    position: fixed;
    top: 9vh;
    left: 6vw;
    width: min(440px, 42vw);
    margin: 0;
    pointer-events: auto;
}

/* the signpost stands in the sand in the world; its planks stay the links */
html:not(.no-dive) .signpost.in-world {
    position: fixed;
    inset: 0;
    z-index: 30;
    width: auto;
    height: auto;
    margin: 0;
    pointer-events: none;
}

html:not(.no-dive) .signpost.in-world .prop-stage {
    visibility: hidden;
}

html:not(.no-dive) .signpost.in-world .plank-link {
    pointer-events: none;
}

html:not(.no-dive) .signpost.in-world.fp-near .plank-link {
    pointer-events: auto;
}

/* the line let down to the bed: a button rides it from the sand up the
   view (js/n64-dive.js), its prompt beside it */
.dive-line {
    display: none;
}

html.dive-world:not(.no-dive) .dive-line {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 30;
    margin: 0;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s ease;
}

html.dive-world:not(.no-dive) .dive-line.fp-near {
    opacity: 1;
}

.line-grab {
    position: absolute;
    left: 0;
    top: 0;
    width: 56px;
    height: 200px;
    padding: 0;
    background: none;
    border: none;
    cursor: pointer;
    pointer-events: none;
    -webkit-tap-highlight-color: transparent;
}

.dive-line.fp-near .line-grab {
    pointer-events: auto;
}

.line-grab:focus-visible {
    outline: 2px solid var(--hud-gold, #ffd36a);
    outline-offset: 4px;
}

.line-caption {
    position: absolute;
    top: var(--cap-y, 40%);
    left: calc(100% + 0.1rem);
    white-space: nowrap;
    pointer-events: none;
}

.dive-line[data-side="left"] .line-caption {
    left: auto;
    right: calc(100% + 0.1rem);
}

/* past the lakebed the way on rises over the scene, out of the dark */
html:not(.no-dive) .dive-exit {
    background: linear-gradient(180deg, rgba(3, 16, 12, 0) 0, rgba(3, 16, 12, 0.88) 9rem, #03100c 100%);
}

html:not(.no-dive) .dive-exit + .ocean-footer {
    position: relative;
    z-index: 1;
    background: #03100c;
}

/* an upright phone or tablet: the clue opens across the top of the view
   and the find settles low beneath it */
@media (max-width: 820px) and (orientation: portrait) {
    html:not(.no-dive) .bio-event-section {
        min-height: 88vh;
    }

    html:not(.no-dive) .specimen-tag,
    html:not(.no-dive) .specimen-cluster[data-side] .specimen-tag {
        left: 10px;
        right: 10px;
        top: 10px;
        bottom: auto;
        width: auto;
        align-items: flex-start;
    }

    html:not(.no-dive) .specimen-tag-inner {
        max-height: 56vh;
        padding: 0.6rem 0.6rem 0.8rem;
    }

    html:not(.no-dive) .plaque-note {
        top: 10px;
        left: 10px;
        right: 10px;
        width: auto;
    }

    html:not(.no-dive) .plaque-note-inner {
        padding: 0.6rem 0.5rem 0;
    }

    html:not(.no-dive) .halocline-label {
        top: 13vh;
        padding: 0 3.6rem 0 1.2rem;
        font-size: 0.7rem;
    }
}

/* a phone on its side: a narrower panel, nearly the view's height */
@media (max-height: 540px) and (orientation: landscape) {
    html:not(.no-dive) .specimen-tag {
        width: min(400px, 44vw);
    }

    html:not(.no-dive) .specimen-tag-inner {
        max-height: 90vh;
    }

    html:not(.no-dive) .plaque-note {
        top: 6vh;
        width: min(400px, 44vw);
    }
}

@media (prefers-reduced-motion: reduce) {
    html:not(.no-dive) .specimen-float,
    html:not(.no-dive) .plaque-wrap {
        transition: none;
    }
}

/* landed on the lakebed, an upright phone's gauge steps aside for the
   signpost (body.dive-landed is set by js/n64-dive.js) */
@media (max-width: 820px) and (orientation: portrait) {
    body.dive-landed .depth-indicator {
        opacity: 0;
        pointer-events: none;
    }
}

/* the dive's canvas needs no fade of its own: going under, the waterline
   climbing the lens is the transition (js/n64-dive.js) */
html:not(.no-dive) .n64-dive {
    transition: none;
}
