/* =====================================================
   863.no — Terminal / Vitals Monitor
   ===================================================== */

:root {
    color-scheme: dark;

    /* --- farge som RGB-tripler --- */
    --accent-rgb: 127 255 212;
    --warn-rgb: 255 209 102;
    --danger-rgb: 255 107 107;
    --blue-rgb: 45 108 255;
    --bg-rgb: 8 18 26;
    --fg-rgb: 232 247 240;

    --accent: rgb(var(--accent-rgb));
    --warn: rgb(var(--warn-rgb));
    --danger: rgb(var(--danger-rgb));
    --bg: rgb(var(--bg-rgb));
    --fg: rgb(var(--fg-rgb));

    /* --- strukturelle linjer og washes --- */
    --line-1: rgb(var(--accent-rgb) / 0.08);
    --line-2: rgb(var(--accent-rgb) / 0.125);
    --line-3: rgb(var(--accent-rgb) / 0.19);
    --line-4: rgb(var(--accent-rgb) / 0.25);
    --wash-1: rgb(var(--accent-rgb) / 0.025);
    --wash-2: rgb(var(--accent-rgb) / 0.04);

    /* Parameterfarger etter monitorkonvensjon. Gjelder kun tallene og
       etikettene — rammen rundt boksene er grønn uansett parameter. */
    --p-ecg-rgb: var(--accent-rgb);   /* grønn  — ECG / HR */
    --p-spo2-rgb: 127 212 255;        /* lys blå — SpO₂ / pleth */
    --p-abp-rgb: 255 107 107;         /* rød    — arterietrykk */
    --p-co2-rgb: var(--warn-rgb);     /* gul    — ETCO₂ */
    --p-temp-rgb: 238 248 255;        /* hvit   — temperatur */

    /* --- typografi --- */
    --mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
    --display: 'Space Grotesk', system-ui, -apple-system, Segoe UI, sans-serif;

    --fs-micro: 8px;
    --fs-nano: 9px;
    --fs-xs: 10px;
    --fs-sm: 11px;
    --fs-md: 12px;
    --fs-lg: 13px;
    --fs-base: 14px;
    --fs-body: 16px;
    --fs-body-lg: 18px;

    --track-1: 0.1em;
    --track-2: 0.15em;
    --track-3: 0.2em;

    /* --- spacing --- */
    --sp-1: 4px;
    --sp-2: 6px;
    --sp-3: 8px;
    --sp-4: 12px;
    --sp-5: 16px;
    --sp-6: 24px;
    --sp-7: 32px;
    --sp-8: 40px;
    --sp-9: 56px;
    --sp-10: 80px;
    --sp-11: 120px;

    /* --- radius --- */
    --r-xs: 2px;
    --r-sm: 3px;
    --r-md: 4px;
    --r-lg: 12px;

    /* --- motion --- */
    --dur-fast: 0.18s;
    --dur: 0.3s;
    --dur-slow: 0.45s;
    --dur-reveal: 0.7s;
    --ease-out: cubic-bezier(0.2, 0.7, 0.3, 1);
    --ease-crt: cubic-bezier(0.16, 1, 0.3, 1);

    /* --- CRT --- */
    --scanlines: 0.18;
    --vignette: 0.45;
}

* {
    box-sizing: border-box;
}

html {
    scroll-behavior: smooth;
}

html, body {
    margin: 0;
    padding: 0;
    background: var(--bg);
    color: var(--fg);
    font-family: var(--display);
}

body {
    overflow-x: hidden;
    min-height: 100vh;
    position: relative;
}

::selection {
    background: var(--line-4);
    color: #fff;
}

a {
    color: var(--accent);
}

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
    border-radius: var(--r-xs);
}

@keyframes blink {
    50% { opacity: 0; }
}

@keyframes fade-in {
    from { opacity: 0; transform: translateY(4px); }
    to { opacity: 1; transform: translateY(0); }
}

.cursor {
    display: inline-block;
    width: 0.55em;
    height: 1em;
    background: var(--accent);
    margin-left: 2px;
    vertical-align: text-bottom;
    animation: blink 1.05s steps(1) 300ms infinite;
}

.dim {
    opacity: 0.55;
}

.accent {
    color: var(--accent);
    text-shadow: 0 0 18px rgb(var(--accent-rgb) / 0.5);
}

/* hjørnebraketter — gjennomgående motiv, --bk styrer innrykk */
.brackets {
    position: relative;
}

.brackets::before,
.brackets::after {
    content: "";
    position: absolute;
    width: 10px;
    height: 10px;
    pointer-events: none;
    opacity: 0.5;
    z-index: 3;
}

.brackets::before {
    top: var(--bk, 3px);
    left: var(--bk, 3px);
    border-top: 1px solid var(--accent);
    border-left: 1px solid var(--accent);
}

.brackets::after {
    bottom: var(--bk, 3px);
    right: var(--bk, 3px);
    border-bottom: 1px solid var(--accent);
    border-right: 1px solid var(--accent);
}

/* =====================================================
   Scroll-reveal
   Skjuling er scoped til .js — uten JS er alt synlig.
   Kun opacity/transform, så teksten forblir i a11y-treet.
   ===================================================== */

.js [data-reveal],
.js [data-stagger] > * {
    opacity: 0;
    transform: translate3d(0, var(--reveal-y, 14px), 0);
    transition: opacity var(--dur-reveal) var(--ease-out),
                transform var(--dur-reveal) var(--ease-out);
}

.js [data-reveal].is-in,
.js [data-stagger].is-in > * {
    opacity: 1;
    transform: none;
}

/* failsafe: main.js lastet ikke innen 2s */
.js.no-reveal [data-reveal],
.js.no-reveal [data-stagger] > * {
    opacity: 1 !important;
    transform: none !important;
}

/* stagger — eksplisitt nth-child; sibling-index() er for nytt uten byggverktøy */
.js [data-stagger].is-in > *:nth-child(1) { transition-delay: 0ms; }
.js [data-stagger].is-in > *:nth-child(2) { transition-delay: 70ms; }
.js [data-stagger].is-in > *:nth-child(3) { transition-delay: 140ms; }
.js [data-stagger].is-in > *:nth-child(4) { transition-delay: 210ms; }
.js [data-stagger].is-in > *:nth-child(5) { transition-delay: 280ms; }
.js [data-stagger].is-in > *:nth-child(n+6) { transition-delay: 350ms; }

/* =====================================================
   Backdrop — orbs, helix, nodes, wash
   ===================================================== */

.backdrop,
.bggrid {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
}

.backdrop__wash {
    position: absolute;
    inset: 0;
    background:
        radial-gradient(ellipse 60% 50% at 20% 20%, rgb(var(--accent-rgb) / 0.0625), transparent 60%),
        radial-gradient(ellipse 50% 40% at 80% 70%, rgb(var(--blue-rgb) / 0.078), transparent 60%),
        radial-gradient(ellipse 40% 30% at 50% 100%, rgb(var(--accent-rgb) / 0.04), transparent 70%);
}

.backdrop__orbs {
    position: absolute;
    inset: 0;
    overflow: hidden;
}

/* Kun translate — scale() ville re-rasterisert 60–100px blur hver frame */
@keyframes orb-a {
    0%, 100% { transform: translate(-8vw, -4vh); }
    50%      { transform: translate(6vw, 8vh); }
}

@keyframes orb-b {
    0%, 100% { transform: translate(10vw, 6vh); }
    50%      { transform: translate(-6vw, -10vh); }
}

@keyframes orb-c {
    0%, 100% { transform: translate(0, 0); }
    50%      { transform: translate(-12vw, 4vh); }
}

.orb {
    position: absolute;
    border-radius: 50%;
}

.orb--a {
    top: 10%;
    left: 10%;
    width: 44vw;
    height: 44vw;
    background: radial-gradient(circle, rgb(var(--accent-rgb) / 0.133) 0%, rgb(var(--accent-rgb) / 0.031) 35%, transparent 70%);
    filter: blur(60px);
    animation: orb-a 22s ease-in-out infinite;
}

.orb--b {
    top: 45%;
    right: 5%;
    width: 38vw;
    height: 38vw;
    background: radial-gradient(circle, rgb(var(--blue-rgb) / 0.125) 0%, rgb(var(--blue-rgb) / 0.031) 40%, transparent 70%);
    filter: blur(80px);
    animation: orb-b 28s ease-in-out infinite;
}

.orb--c {
    bottom: 5%;
    left: 30%;
    width: 50vw;
    height: 50vw;
    background: radial-gradient(circle, rgb(var(--accent-rgb) / 0.094) 0%, transparent 60%);
    filter: blur(100px);
    animation: orb-c 36s ease-in-out infinite;
}

.helix {
    position: absolute;
    top: -60px;
    right: -110px;
    color: var(--accent);
    opacity: 0.09;
    filter: blur(3px) drop-shadow(0 0 18px var(--accent));
    -webkit-mask-image: linear-gradient(to bottom, black, transparent 92%);
            mask-image: linear-gradient(to bottom, black, transparent 92%);
}

@keyframes float-dot {
    0%, 100% { transform: translateY(0); opacity: 0.3; }
    50%      { transform: translateY(-20px); opacity: 0.7; }
}

.nodes {
    position: absolute;
    bottom: -80px;
    left: -80px;
    color: var(--accent);
    opacity: 0.14;
    filter: blur(0.5px) drop-shadow(0 0 8px var(--accent));
}

.nodes__points circle {
    animation: float-dot 5s ease-in-out infinite;
}

/* =====================================================
   Background grid
   ===================================================== */

.bggrid {
    background-image:
        linear-gradient(rgb(var(--accent-rgb) / 0.024) 1px, transparent 1px),
        linear-gradient(90deg, rgb(var(--accent-rgb) / 0.024) 1px, transparent 1px);
    background-size: 44px 44px;
    -webkit-mask-image: radial-gradient(ellipse at center, black 0%, transparent 80%);
            mask-image: radial-gradient(ellipse at center, black 0%, transparent 80%);
}

/* =====================================================
   Top bar
   ===================================================== */

.topbar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 100;
    padding: var(--sp-5) var(--sp-7);
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-family: var(--mono);
    font-size: var(--fs-sm);
    color: var(--accent);
    background: linear-gradient(to bottom, rgb(var(--bg-rgb) / 0.95), rgb(var(--bg-rgb) / 0.7) 70%, transparent);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    border-bottom: 1px solid var(--line-1);
}

.topbar__meta {
    display: flex;
    align-items: center;
    gap: 14px;
}

.topbar__dot {
    width: var(--sp-3);
    height: var(--sp-3);
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 8px var(--accent);
}

.topbar__brand {
    font-weight: 700;
    letter-spacing: var(--track-1);
}

.topbar__sep {
    opacity: 0.4;
}

.topbar__subname {
    opacity: 0.55;
}

.topbar__nav {
    display: flex;
    gap: var(--sp-6);
    opacity: 0.7;
}

.topbar__nav a {
    color: var(--accent);
    text-decoration: none;
    transition: text-shadow var(--dur-fast) var(--ease-out);
}

.topbar__nav a:hover,
.topbar__nav a:focus-visible {
    text-shadow: 0 0 10px var(--accent);
}

.topbar__status {
    display: flex;
    gap: var(--sp-4);
    opacity: 0.5;
}

/* =====================================================
   Hero — inkl. boot-sekvens
   ===================================================== */

.hero {
    min-height: 100vh;
    padding: 100px var(--sp-7) 60px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    position: relative;
    z-index: 1;
}

.hero__inner {
    max-width: 1100px;
    margin: 0 auto;
    width: 100%;
}

@keyframes meta-in {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 0.55; transform: none; }
}

@keyframes line-in {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: none; }
}

@keyframes sub-in {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 0.7; transform: none; }
}

@keyframes soft-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@keyframes mfooter-in {
    from { opacity: 0; }
    to   { opacity: 0.5; }
}

@keyframes scroll-in {
    from { opacity: 0; }
    to   { opacity: 0.55; }
}

.hero__meta {
    display: flex;
    gap: var(--sp-7);
    font-family: var(--mono);
    font-size: var(--fs-xs);
    color: var(--accent);
    opacity: 0.55;
    margin-bottom: var(--sp-6);
    letter-spacing: var(--track-1);
    text-transform: uppercase;
    flex-wrap: wrap;
}

.hero__meta-live {
    opacity: 1;
}

.hero__title {
    font-family: var(--display);
    /* ned fra 120px: den tredje kurvekanalen trengte høyden mer */
    font-size: clamp(48px, 8vw, 104px);
    line-height: 1.02;
    letter-spacing: -0.04em;
    margin: 0;
    color: var(--fg);
    font-weight: 500;
    text-shadow: 0 0 40px rgb(var(--accent-rgb) / 0.145);
}

/* inline-block fordi transform ikke gjelder ikke-erstattede
   inline-elementer — linjene animeres hver for seg i boot-seksjonen */
.hero__title-line,
.hero__title-italic,
.hero__title-accent {
    display: inline-block;
}

.hero__title-italic {
    font-family: var(--mono);
    font-style: italic;
    font-weight: 400;
    font-size: 0.78em;
    opacity: 0.85;
    letter-spacing: -0.01em;
}

.hero__title-accent {
    color: var(--accent);
    text-shadow: 0 0 22px var(--accent), 0 0 6px var(--accent);
}

.hero__sub {
    margin: 28px 0 0;
    max-width: 560px;
    font-size: var(--fs-body);
    color: var(--fg);
    opacity: 0.7;
    line-height: 1.55;
    font-family: var(--display);
}

/* --- monitor panel --- */

/* CRT power-on: horisontal lysstrek som folder seg ut.
   scaleY beholder full layout-høyde → ingen reflow under. */
@keyframes monitor-on {
    0%   { transform: scaleY(0.006); opacity: 0; }
    26%  { transform: scaleY(0.006); opacity: 1; }
    100% { transform: scaleY(1); opacity: 1; }
}

@keyframes monitor-flash {
    0%, 22% { opacity: 0; }
    30%     { opacity: 0.5; }
    100%    { opacity: 0; }
}

.monitor {
    margin-top: var(--sp-9);
    border: 1px solid var(--line-3);
    border-radius: var(--r-md);
    background: linear-gradient(180deg, var(--wash-2), rgb(var(--accent-rgb) / 0.01));
    padding: var(--sp-5) var(--sp-5) var(--sp-4);
    position: relative;
    transform-origin: 50% 50%;
    --fade: clamp(0, calc(1 - (var(--freeze, 0) - 0.18) * 1.6), 1);
    box-shadow:
        inset 0 1px 0 rgb(var(--accent-rgb) / 0.22),
        inset 0 0 80px rgb(var(--accent-rgb) / 0.06),
        inset 0 -46px 60px -46px rgb(0 0 0 / 0.55),
        0 1px 0 rgb(var(--accent-rgb) / 0.06),
        0 26px 60px -30px rgb(0 0 0 / 0.7),
        0 0 60px rgb(var(--accent-rgb) / 0.05);
}

/* pointer-reaktiv glød, under innholdet */
.monitor::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    border-radius: inherit;
    opacity: 0;
    transition: opacity var(--dur) var(--ease-out);
    background: radial-gradient(460px circle at var(--mx, 50%) var(--my, 50%),
                rgb(var(--accent-rgb) / 0.07), transparent 70%);
}

/* boot-bloom — flatt overlegg, ikke filter på .monitor
   (ville tvunget re-raster av EKG-ens feGaussianBlur hver frame) */
.monitor::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 2;
    pointer-events: none;
    border-radius: inherit;
    opacity: 0;
    background: linear-gradient(180deg, #eafff6, var(--accent));
    mix-blend-mode: screen;
}

.monitor > * {
    z-index: 1;
}

.monitor__corner {
    position: absolute;
    width: 14px;
    height: 14px;
}

.monitor__corner--tl { top: -1px; left: -1px; border-top: 2px solid var(--accent); border-left: 2px solid var(--accent); }
.monitor__corner--tr { top: -1px; right: -1px; border-top: 2px solid var(--accent); border-right: 2px solid var(--accent); }
.monitor__corner--bl { bottom: -1px; left: -1px; border-bottom: 2px solid var(--accent); border-left: 2px solid var(--accent); }
.monitor__corner--br { bottom: -1px; right: -1px; border-bottom: 2px solid var(--accent); border-right: 2px solid var(--accent); }

.vitals {
    position: relative;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
    gap: var(--sp-3);
    margin-bottom: var(--sp-4);
}

/* --v er boksens parameterfarge. Kun tekst og glød følger den;
   ramme, bakgrunn og kantlys er grønne for alle parametere.

   --vc er --v blandet mot terminalgrønt etter --freeze, som settes av
   fryse-modulen ved scroll. Når tallene blir binære, konvergerer
   fargekodingen mot kode. --vc-50 er samme blanding på 50% alpha,
   til glødene. */
.vital {
    --v: var(--p-ecg-rgb);
    --vc: color-mix(in oklab, rgb(var(--v)), var(--accent) calc(var(--freeze, 0) * 100%));
    --vc-50: color-mix(in oklab, rgb(var(--v) / 0.5), rgb(var(--accent-rgb) / 0.5) calc(var(--freeze, 0) * 100%));
    border: 1px solid var(--line-4);
    padding: var(--sp-3) 14px;
    min-width: 0;
    font-family: var(--mono);
    border-radius: var(--r-xs);
    position: relative;
    background: linear-gradient(180deg, rgb(var(--accent-rgb) / 0.05), rgb(var(--accent-rgb) / 0.01));
    box-shadow:
        inset 0 1px 0 rgb(var(--accent-rgb) / 0.14),
        0 8px 18px -14px rgb(0 0 0 / 0.8);
}

.vital--spo2 { --v: var(--p-spo2-rgb); }
.vital--abp  { --v: var(--p-abp-rgb); }
.vital--co2  { --v: var(--p-co2-rgb); }
.vital--temp { --v: var(--p-temp-rgb); }

.vital__label {
    font-size: var(--fs-nano);
    color: var(--vc);
    opacity: 0.7;
    letter-spacing: var(--track-2);
    text-transform: uppercase;
}

.vital__row {
    display: flex;
    align-items: baseline;
    gap: var(--sp-1);
}

.vital__value {
    font-size: 26px;
    color: var(--vc);
    font-weight: 600;
    text-shadow: 0 0 12px var(--vc-50), 0 0 4px var(--vc);
}

/* Nær-hvit lyser perseptuelt sterkere enn de andre hue-ene, så kjernen
   dempes til .8 — men den må være der. Uten kjerneglød blir glyfkantene
   knivskarpe ved siden av de andre parameterne. */
.vital--temp .vital__value {
    text-shadow: 0 0 13px var(--vc-50), 0 0 4px var(--vc-50);
}

/* ABP viser sys/dia stort og middeltrykk mindre, slik en invasiv
   trykkurve vises på monitor. Verdien er for lang til 26px. */
.vital--abp .vital__value {
    font-size: 20px;
}

/* samme farge, vekt og glød som sys/dia — kun mindre */
.vital__mean {
    font-size: var(--fs-md);
    color: var(--vc);
    font-weight: 600;
    text-shadow: 0 0 12px var(--vc-50), 0 0 4px var(--vc);
}

/* trendretning siden forrige måling — dekorativ, aria-hidden i markup */
.vital__trend {
    font-family: var(--mono);
    font-size: var(--fs-sm);
    color: var(--vc);
    opacity: 0.65;
    line-height: 1;
}

.vital__unit {
    font-size: var(--fs-xs);
    color: var(--vc);
    opacity: 0.6;
}

.vital__sub {
    font-size: var(--fs-nano);
    color: var(--vc);
    opacity: 0.55;
}

.ekg {
    position: relative;
    width: 100%;
    /* tre kanaler: ECG + pleth + ABP. Label-posisjonene under er i
       prosent av denne høyden, så de følger med om den endres. */
    height: 266px;
}

.ekg__svg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    color: var(--accent);
}

.ekg__label-l,
.ekg__label-r,
.ekg__label-pleth,
.ekg__label-abp {
    position: absolute;
    top: var(--sp-2);
    font-family: var(--mono);
    font-size: var(--fs-nano);
    color: var(--accent);
    opacity: calc(0.6 * var(--fade, 1));
    z-index: 2;
    /* Ved 12.5mm/s er syklusene halvert i bredde, så kurvene krysser
       etikettene. Halo i bakgrunnsfargen skjærer teksten fri av streken
       uten å legge en synlig plate over panelet. */
    text-shadow:
        0 0 3px rgb(var(--bg-rgb)),
        0 0 6px rgb(var(--bg-rgb)),
        0 0 10px rgb(var(--bg-rgb) / 0.8);
}

.ekg__label-l { left: var(--sp-3); letter-spacing: var(--track-1); }
.ekg__label-r { right: var(--sp-3); }

/* rett under kanalskillene på y=99 og y=175 av 266 i viewBox — prosent,
   ikke px, så labelene følger panelet hvis .ekg-høyden endres */
.ekg__label-pleth,
.ekg__label-abp {
    left: var(--sp-3);
    letter-spacing: var(--track-1);
    opacity: calc(0.5 * var(--fade, 1));
}

.ekg__label-pleth { top: 38.5%; }
.ekg__label-abp { top: 67%; }

/* kurvene følger sin parameterfarge — pleth ER SpO₂-kanalen */
.ekg__label-pleth,
.pleth__path {
    color: rgb(var(--p-spo2-rgb));
}

.ekg__label-abp,
.abp__path {
    color: rgb(var(--p-abp-rgb));
}

/* =====================================================
   Binærfelt — monitoren pikseleres ved scroll

   To tekstlag i samme rutenett: ett med 1-ere der innholdet ligger,
   ett med 0-ere i bakgrunnen. Delt i to fordi ett enkelt tekstlag
   ikke kan ha to lysstyrker uten ~5000 spans.
   ===================================================== */

.binary {
    position: absolute;
    inset: 0;
    overflow: hidden;
    border-radius: inherit;
    pointer-events: none;
    /* feltet er flere tusen tegn som bygges om per steg — contain
       holder den layouten isolert fra resten av siden */
    contain: layout paint;
}

.monitor > .binary {
    z-index: 3;
}

.binary__layer {
    position: absolute;
    top: 0;
    left: 0;
    font-family: var(--mono);
    font-size: var(--fs-nano);
    line-height: 11px;
    letter-spacing: 0;
    white-space: pre;
    font-variant-ligatures: none;
    font-feature-settings: "liga" 0, "calt" 0;
}

/* Glødelaget: 1-erne på nytt, blurret, bak de skarpe lagene.
   Erstatter text-shadow, som ville kostet én blur per glyf — ~7000 av
   dem per steg. Her er det én raster og én blur-pass, og resultatet er
   en ekte bloom i stedet for en kontur rundt hvert tegn. */
.binary__glow {
    color: var(--accent);
    filter: blur(3.5px);
    opacity: 0.9;
}

/* Generell glød under 0-erne. De utgjør de fleste cellene, så det er
   dette laget som løfter feltets samlede luminans. Holdes lavt —
   for høyt flommer panelet og kontrasten mot 1-erne forsvinner. */
.binary__glow-bg {
    color: var(--accent);
    filter: blur(4px);
    opacity: 0.45;
}

/* 1-ere: der kurver og tekst faktisk ligger */
.binary__ink {
    color: var(--accent);
    opacity: 0.95;
}

/* 0-ere: tomrommet mellom dem. Må være tydelige nok til at feltet
   leser som en flate — for svakt ser det ut som spredte merker. */
.binary__bg {
    color: var(--accent);
    opacity: 0.34;
}

/* Innholdet viker for feltet. --fade er en multiplikator, ikke en
   opacity — flere av elementene har en basisverdi (footeren 0.5,
   etikettene 0.6/0.5) som ville blitt overskrevet ellers. */
.ekg__traces {
    opacity: clamp(0, calc(1 - var(--freeze, 0) * 1.45), 1);
}

.vitals {
    opacity: var(--fade, 1);
}

/* halo har opacity="0.55" som attributt — CSS vinner over det, så
   grunnverdien må ganges inn her for ikke å bli full styrke */
.ekg__head--dot,
.ekg__cursor {
    opacity: calc(1 - var(--freeze, 0));
}

.ekg__head--halo {
    opacity: calc(0.55 * (1 - var(--freeze, 0)));
}

.monitor__footer {
    position: relative;
    display: flex;
    justify-content: space-between;
    font-family: var(--mono);
    font-size: var(--fs-nano);
    color: var(--accent);
    opacity: calc(0.5 * var(--fade, 1));
    margin-top: var(--sp-3);
    letter-spacing: var(--track-1);
    flex-wrap: wrap;
    gap: var(--sp-2);
}

.hero__scroll {
    margin-top: var(--sp-9);
    display: flex;
    justify-content: center;
    flex-direction: column;
    align-items: center;
    gap: var(--sp-3);
    font-family: var(--mono);
    font-size: var(--fs-xs);
    color: var(--accent);
    opacity: 0.55;
    letter-spacing: var(--track-3);
}

@keyframes scroll-bob {
    0%, 100% { transform: translateY(0); opacity: 0.55; }
    50%      { transform: translateY(5px); opacity: 0.85; }
}

.hero__scroll-line {
    width: 1px;
    height: 36px;
    background: linear-gradient(to bottom, var(--accent), transparent);
    animation: scroll-bob 2.6s var(--ease-out) 1200ms infinite;
}

/* =====================================================
   Boot-sekvens — monitoren slår seg på

   Gated på .js av samme grunn som scroll-reveal: fill-mode
   backwards holder elementene på opacity 0 FØR animasjonen
   starter. Uten gate ville alt som fanger siden tidlig — print,
   PDF-eksport, skjermbildeverktøy, crawlere uten JS — fått en
   blank hero. .js settes av et inline-script i <head>, altså
   før første paint og uavhengig av om main.js laster.
   ===================================================== */

@keyframes vital-focus {
    from { opacity: 0; filter: blur(5px); }
    to   { opacity: 1; filter: none; }
}

.js .hero__meta {
    animation: meta-in 260ms var(--ease-out) backwards;
}

.js .hero__title-line,
.js .hero__title-italic,
.js .hero__title-accent {
    animation: line-in 320ms var(--ease-out) backwards;
}

/* LCP-elementet: 60ms delay, 320ms fade — under én frame å hente inn */
.js .hero__title-line { animation-delay: 60ms; }
.js .hero__title-italic { animation-delay: 140ms; }
.js .hero__title-accent { animation-delay: 220ms; }

.js .hero__sub {
    animation: sub-in 360ms var(--ease-out) 260ms backwards;
}

.js .monitor {
    animation: monitor-on 700ms var(--ease-crt) 380ms backwards;
}

.js .monitor::after {
    animation: monitor-flash 700ms linear 380ms backwards;
}

.js .monitor__corner {
    animation: corner-in 320ms var(--ease-out) backwards;
}

.js .monitor__corner--tl { animation-delay: 520ms; }
.js .monitor__corner--tr { animation-delay: 580ms; }
.js .monitor__corner--bl { animation-delay: 640ms; }
.js .monitor__corner--br { animation-delay: 700ms; }

.js .vital {
    animation: vital-focus 420ms var(--ease-out) backwards;
}

.js .vital:nth-child(1) { animation-delay: 640ms; }
.js .vital:nth-child(2) { animation-delay: 710ms; }
.js .vital:nth-child(3) { animation-delay: 780ms; }
.js .vital:nth-child(4) { animation-delay: 850ms; }
.js .vital:nth-child(5) { animation-delay: 920ms; }

.js .ekg {
    animation: soft-in 360ms var(--ease-out) 760ms backwards;
}

.js .monitor__footer {
    animation: mfooter-in 320ms var(--ease-out) 1040ms backwards;
}

.js .hero__scroll {
    animation: scroll-in 400ms var(--ease-out) 1200ms backwards;
}

/* Kill-switch: main.js lastet ikke innen 2s, eller siden skrives ut.
   Alt må stå i sluttilstand umiddelbart. */
.js.no-reveal .hero__meta,
.js.no-reveal .hero__title-line,
.js.no-reveal .hero__title-italic,
.js.no-reveal .hero__title-accent,
.js.no-reveal .hero__sub,
.js.no-reveal .monitor,
.js.no-reveal .monitor::after,
.js.no-reveal .monitor__corner,
.js.no-reveal .vital,
.js.no-reveal .ekg,
.js.no-reveal .monitor__footer,
.js.no-reveal .hero__scroll {
    animation: none !important;
}

@media print {
    .hero__meta,
    .hero__title-line,
    .hero__title-italic,
    .hero__title-accent,
    .hero__sub,
    .monitor,
    .monitor::after,
    .monitor__corner,
    .vital,
    .ekg,
    .monitor__footer,
    .hero__scroll,
    .hero__scroll-line,
    [data-reveal],
    [data-stagger] > * {
        animation: none !important;
        opacity: 1 !important;
        transform: none !important;
    }
    .crt { display: none !important; }
}

/* =====================================================
   Sections (Prosjekter, Om)
   ===================================================== */

.section {
    padding: var(--sp-11) 0;
    position: relative;
    z-index: 1;
}

/* hårlinje som fader ut i begge ender */
.section::before,
.footer::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 1px;
    background: linear-gradient(90deg, transparent,
        rgb(var(--accent-rgb) / 0.38) 20%,
        rgb(var(--accent-rgb) / 0.38) 80%, transparent);
}

/* målestokk-tick + glødesøm under skillet */
.section::after,
.footer::after {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 140px;
    z-index: 0;
    pointer-events: none;
    background:
        repeating-linear-gradient(90deg,
            rgb(var(--accent-rgb) / 0.28) 0 1px, transparent 1px 26px) top center / 100% 6px no-repeat,
        radial-gradient(60% 100% at 50% 0%, rgb(var(--accent-rgb) / 0.055), transparent 70%);
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 22%, #000 78%, transparent);
            mask-image: linear-gradient(90deg, transparent, #000 22%, #000 78%, transparent);
}

/* sømmen "lades" ut fra midten når seksjonen kommer i syne */
@keyframes seam-charge {
    from { transform: scaleX(0.15); opacity: 0; }
    to   { transform: scaleX(1); opacity: 1; }
}

.js [data-seam]::before {
    transform-origin: 50% 50%;
}

.js [data-seam].is-in::before {
    animation: seam-charge 0.9s var(--ease-out) backwards;
}

.section__inner {
    position: relative;
    z-index: 1;
    max-width: 1100px;
    margin: 0 auto;
    padding: 0 var(--sp-7);
}

.section__tag {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    font-family: var(--mono);
    font-size: var(--fs-sm);
    color: var(--accent);
    opacity: 0.75;
    margin-bottom: var(--sp-7);
    letter-spacing: var(--track-2);
    text-transform: uppercase;
    --reveal-y: 10px;
}

.section__tag-num {
    opacity: 0.5;
}

.section__tag-bar {
    width: var(--sp-7);
    height: 1px;
    background: var(--accent);
    opacity: 0.4;
}

/* --- projects --- */

.projects__header {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 60px;
    align-items: end;
    margin-bottom: var(--sp-9);
}

.projects__title {
    font-family: var(--display);
    font-size: clamp(40px, 6vw, 76px);
    font-weight: 500;
    margin: 0;
    color: var(--fg);
    letter-spacing: -0.03em;
    line-height: 1;
}

.projects__ls {
    --bk: -12px;
    /* fit-content så brakettene hugger terminal-teksten i stedet for
       å svaie ut til kanten av grid-cellen */
    width: fit-content;
    font-family: var(--mono);
    font-size: var(--fs-md);
    color: var(--accent);
    opacity: 0.7;
    line-height: 1.7;
}

.projects__ls > div:first-child {
    margin-bottom: var(--sp-1);
}

.projects__list {
    --reveal-y: 18px;
    /* hvor langt hover-feltet og skinnen blør ut i seksjonens gutter.
       Må holdes under .section__inner sin padding (32px / 18px mobil). */
    --row-bleed: 16px;
    border-bottom: 1px solid var(--line-2);
}

.project {
    border-top: 1px solid var(--line-2);
    padding: 28px 0;
    display: grid;
    grid-template-columns: 60px 1fr auto;
    gap: var(--sp-6);
    align-items: start;
    cursor: pointer;
    transition: background var(--dur) var(--ease-out);
    background: transparent;
    position: relative;
    color: inherit;
    text-decoration: none;
}

.project:focus-visible {
    outline-offset: -2px;
}

/* Flatt vask + pointer-glød i samme lag, med blødning ut i gutteren:
   raden er ~1036px bred, så en 420px sirkel kunne aldri nå både 01 og
   statuskolonnen. Ellipsen matcher radens format, og --row-bleed gjør
   at begge kantelementene ligger godt innenfor det opplyste feltet. */
.project::before {
    content: "";
    position: absolute;
    inset: 0 calc(-1 * var(--row-bleed));
    z-index: 0;
    pointer-events: none;
    opacity: 0;
    transition: opacity var(--dur) var(--ease-out);
    background:
        radial-gradient(760px 240px at var(--mx, 50%) var(--my, 50%),
            rgb(var(--accent-rgb) / 0.075), transparent 70%),
        linear-gradient(rgb(var(--accent-rgb) / 0.035), rgb(var(--accent-rgb) / 0.035));
}

.project:hover::before,
.project:focus-visible::before {
    opacity: 1;
}

/* accent-skinne som tegner seg nedover — ligger i gutteren, ikke på
   left: 0, der den skar rett gjennom .project__idx */
.project::after {
    content: "";
    position: absolute;
    left: calc(-1 * var(--row-bleed));
    top: -1px;
    bottom: 0;
    width: 2px;
    z-index: 0;
    pointer-events: none;
    background: linear-gradient(180deg, var(--accent), transparent);
    transform: scaleY(0);
    transform-origin: 0 0;
    transition: transform var(--dur-slow) var(--ease-out);
}

.project:hover::after,
.project:focus-visible::after {
    transform: scaleY(1);
}

.project > * {
    position: relative;
    z-index: 1;
}

.project__idx {
    font-family: var(--mono);
    font-size: var(--fs-sm);
    color: var(--accent);
    opacity: 0.55;
    padding-top: var(--sp-3);
    transition: opacity var(--dur) var(--ease-out), text-shadow var(--dur) var(--ease-out);
}

.project:hover .project__idx,
.project:focus-visible .project__idx {
    opacity: 1;
    text-shadow: 0 0 12px rgb(var(--accent-rgb) / 0.6);
}

.project__head {
    display: flex;
    align-items: baseline;
    gap: 14px;
    margin-bottom: var(--sp-2);
    flex-wrap: wrap;
}

.project__code {
    font-family: var(--mono);
    font-size: var(--fs-nano);
    color: var(--accent);
    opacity: 0.6;
    padding: 2px var(--sp-2);
    border: 1px solid var(--line-4);
    letter-spacing: var(--track-1);
    transition: opacity var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out);
}

.project:hover .project__code,
.project:focus-visible .project__code {
    opacity: 0.9;
    border-color: rgb(var(--accent-rgb) / 0.45);
}

.project__name {
    font-family: var(--display);
    font-size: 38px;
    font-weight: 600;
    letter-spacing: -0.02em;
    color: var(--fg);
    transition: text-shadow var(--dur) var(--ease-out);
}

.project:hover .project__name,
.project:focus-visible .project__name {
    text-shadow: 0 0 16px rgb(var(--accent-rgb) / 0.25);
}

.project__desc {
    font-size: var(--fs-base);
    color: var(--fg);
    opacity: 0.7;
    max-width: 540px;
    line-height: 1.55;
    margin: 0;
}

.project__tags {
    display: flex;
    gap: var(--sp-3);
    margin-top: 14px;
    flex-wrap: wrap;
}

.project__tags span {
    font-family: var(--mono);
    font-size: var(--fs-xs);
    color: var(--accent);
    opacity: 0.7;
    padding: var(--sp-1) var(--sp-3);
    border: 1px solid rgb(var(--accent-rgb) / 0.145);
    border-radius: var(--r-xs);
    transition: opacity var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out);
}

.project:hover .project__tags span,
.project:focus-visible .project__tags span {
    opacity: 0.95;
    border-color: var(--line-4);
}

.project:hover .project__tags span:nth-child(2) { transition-delay: 30ms; }
.project:hover .project__tags span:nth-child(3) { transition-delay: 60ms; }
.project:hover .project__tags span:nth-child(4) { transition-delay: 90ms; }
.project:hover .project__tags span:nth-child(5) { transition-delay: 120ms; }
.project:hover .project__tags span:nth-child(n+6) { transition-delay: 150ms; }

.project__status-col {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--sp-3);
    padding-top: var(--sp-1);
}

.project__status {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    font-family: var(--mono);
    font-size: var(--fs-xs);
    letter-spacing: var(--track-1);
}

.project__status--live { color: var(--accent); }
.project__status--beta { color: var(--warn); }
.project__status--dev { color: var(--danger); }
.project__status--alpha { color: var(--danger); }

.project__led {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: currentColor;
    box-shadow: 0 0 8px currentColor;
    transition: box-shadow var(--dur) var(--ease-out);
}

.project:hover .project__led,
.project:focus-visible .project__led {
    box-shadow: 0 0 14px currentColor, 0 0 4px currentColor;
}

.project__open {
    font-family: var(--mono);
    font-size: var(--fs-sm);
    color: var(--accent);
    opacity: 0.5;
    transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}

.project:hover .project__open,
.project:focus-visible .project__open {
    opacity: 1;
    transform: translateX(4px);
}

/* =====================================================
   Om 863
   ===================================================== */

.om {
    display: grid;
    grid-template-columns: 1.4fr 1fr;
    gap: var(--sp-10);
    align-items: start;
}

.om__title {
    font-family: var(--display);
    font-size: clamp(40px, 6vw, 76px);
    font-weight: 500;
    margin: 0 0 var(--sp-8);
    color: var(--fg);
    letter-spacing: -0.03em;
    line-height: 1;
}

.om__title-accent {
    color: var(--accent);
    font-family: var(--mono);
    font-weight: 500;
}

.om__cmd {
    font-family: var(--mono);
    font-size: var(--fs-lg);
    color: var(--accent);
    opacity: 0.6;
    margin-bottom: var(--sp-5);
}

.om__body {
    font-family: var(--display);
    font-size: var(--fs-body-lg);
    line-height: 1.6;
    color: var(--fg);
    opacity: 0.85;
    border-left: 2px solid var(--accent);
    padding-left: 22px;
    max-width: 580px;
}

.om__body p {
    margin: 0 0 20px;
}

.om__body p:last-child {
    margin: 0;
    opacity: 0.7;
}

.om__meta {
    margin-top: 36px;
    font-family: var(--mono);
    font-size: var(--fs-sm);
    color: var(--accent);
    opacity: 0.55;
    line-height: 1.8;
}

.om__meta span.dim {
    opacity: 0.7;
}

/* --- pager --- */

.pager-sticky {
    position: sticky;
    top: 100px;
    transition-delay: 140ms;
}

.pager__caption {
    font-family: var(--mono);
    font-size: var(--fs-xs);
    color: var(--accent);
    opacity: 0.55;
    margin-bottom: var(--sp-3);
    letter-spacing: var(--track-1);
}

/* Personsøkeren er et wireframe-bur: ingen flater, bare kanter.
   Forflaten ligger i flyt og gir buret høyden sin; bakflaten og de
   fire stagene posisjoneres mot den. Rotasjonen settes av JS som
   --rx/--ry på .pager__box, så hele animasjonen er én transform. */

.pager {
    position: relative;
    max-width: 320px;
    padding: 14px 10px;
    perspective: 820px;
    perspective-origin: 50% 44%;
}

.pager__box {
    --depth: 64px;
    --wire-r: 4px;
    position: relative;
    transform-style: preserve-3d;
    transform: rotateX(var(--rx, 11deg)) rotateY(var(--ry, -26deg));
}

/* Vibrasjon når en ny melding lander. Utslaget ligger på translate,
   ikke transform: de to konkateneres av seg selv (translate → rotate →
   scale → transform), så rotasjonsløkka kan skrive --rx/--ry samtidig
   uten at de to slår hverandre ut.

   Amplituden faller 2px → 1px underveis, som en dempet svingning, og
   perioden er kort nok til å lese som brumming framfor risting. */
@keyframes pager-buzz {
    0%   { translate: 0 0; }
    10%  { translate: -2px 1px; }
    22%  { translate: 2px -1.5px; }
    34%  { translate: -2px -1px; }
    46%  { translate: 1.5px 1.5px; }
    58%  { translate: -1.5px 0.5px; }
    70%  { translate: 1px -1px; }
    82%  { translate: -1px 0.5px; }
    91%  { translate: 0.5px 0; }
    100% { translate: 0 0; }
}

.pager__box.is-buzz {
    animation: pager-buzz 340ms linear;
}

.pager__front,
.pager__back {
    border-radius: var(--wire-r);
}

.pager__front {
    position: relative;
    transform-style: preserve-3d;
    transform: translateZ(calc(var(--depth) / 2));
    border: 1px solid rgb(var(--accent-rgb) / 0.55);
    padding: var(--sp-5);
    background: linear-gradient(180deg,
                rgb(var(--accent-rgb) / 0.025), rgb(var(--bg-rgb) / 0.28));
    box-shadow:
        0 0 24px -8px rgb(var(--accent-rgb) / 0.22),
        0 0 0 0.5px rgb(var(--accent-rgb) / 0.28);
}

/* Bakflaten er stiplet og svakere — konvensjonen for skjulte kanter
   i en wireframe, og det eneste som skiller for fra bak når begge
   sees gjennom hverandre. */
.pager__back {
    position: absolute;
    inset: 0;
    transform: translateZ(calc(var(--depth) / -2));
    border: 1px solid rgb(var(--accent-rgb) / 0.15);
}

/* Stag langs Z: bredden er dybden, rotert 90° ut av planet.
   transform-origin i venstre kant gjør at linja starter nøyaktig i
   hjørnepunktet. Gradienten går mørk (bak) → lys (fram), altså samme
   dybdefall som mellom bak- og forflaten. */
.pager__strut {
    position: absolute;
    width: var(--depth);
    height: 1px;
    transform-origin: 0 0;
    transform: translateZ(calc(var(--depth) / -2)) rotateY(-90deg);
    background: linear-gradient(90deg,
                rgb(var(--accent-rgb) / 0.3), rgb(var(--accent-rgb) / 0.6));
    box-shadow: 0 0 6px rgb(var(--accent-rgb) / 0.18);
}

.pager__strut--tl { top: var(--wire-r); left: 0; }
.pager__strut--tr { top: var(--wire-r); left: 100%; }
.pager__strut--bl { top: calc(100% - var(--wire-r)); left: 0; }
.pager__strut--br { top: calc(100% - var(--wire-r)); left: 100%; }

.pager::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    border-radius: inherit;
    opacity: 0;
    transition: opacity var(--dur) var(--ease-out);
    background: radial-gradient(300px circle at var(--mx, 50%) var(--my, 50%),
                rgb(var(--accent-rgb) / 0.06), transparent 70%);
}

.pager > * {
    position: relative;
    z-index: 1;
}

.pager__top {
    display: flex;
    justify-content: space-between;
    margin-bottom: var(--sp-4);
    font-family: var(--mono);
    font-size: var(--fs-micro);
    color: var(--accent);
    opacity: 0.5;
}

/* Skjermen er senket 12px inn i buret. Den er den eneste flaten med
   fyll — teksten må ha noe å lese mot når bakkantene skinner gjennom. */
.pager__lcd {
    background: rgb(6 16 13 / 0.72);
    border: 1px solid var(--line-4);
    border-radius: var(--r-sm);
    padding: var(--sp-5) 14px;
    min-height: 140px;
    position: relative;
    transform: translateZ(-12px);
    box-shadow:
        inset 0 0 40px rgb(var(--accent-rgb) / 0.082),
        0 0 18px -6px rgb(var(--accent-rgb) / 0.28);
    overflow: hidden;
}

.pager__scanlines {
    position: absolute;
    inset: 0;
    background-image: repeating-linear-gradient(to bottom, transparent 0, transparent 2px, var(--line-1) 2px, var(--line-1) 3px);
    pointer-events: none;
}

.pager__lcd-top {
    position: relative;
    font-family: var(--mono);
    font-size: var(--fs-nano);
    color: var(--accent);
    opacity: 0.6;
    margin-bottom: var(--sp-3);
    display: flex;
    justify-content: space-between;
}

.pager__msg {
    position: relative;
    font-family: var(--mono);
    font-size: var(--fs-body);
    font-weight: 700;
    color: var(--accent);
    text-shadow: 0 0 10px var(--accent), 0 0 4px var(--accent);
    line-height: 1.35;
    animation: fade-in 0.4s;
}

.pager__lcd-bottom {
    position: absolute;
    bottom: var(--sp-3);
    left: 14px;
    font-family: var(--mono);
    font-size: var(--fs-micro);
    color: var(--accent);
    opacity: 0.5;
}

/* Knappene løftes 6px ut av forflaten — motsatt vei av skjermen, så
   kortet får lag i begge retninger og ikke bare en senket boks. */
.pager__buttons {
    display: flex;
    justify-content: center;
    gap: var(--sp-3);
    margin-top: 14px;
    transform: translateZ(6px);
}

.pager__buttons span {
    background: transparent;
    border: 1px solid var(--line-3);
    color: var(--accent);
    opacity: 0.7;
    font-family: var(--mono);
    font-size: var(--fs-nano);
    padding: var(--sp-1) var(--sp-3);
    border-radius: var(--r-xs);
}

/* =====================================================
   Footer
   ===================================================== */

.footer {
    padding: var(--sp-8) var(--sp-7) var(--sp-7);
    font-family: var(--mono);
    font-size: var(--fs-sm);
    color: var(--accent);
    position: relative;
    z-index: 1;
}

.footer__grid {
    position: relative;
    z-index: 1;
    max-width: 1100px;
    margin: 0 auto;
    display: grid;
    grid-template-columns: 1.2fr 1fr 1fr;
    gap: var(--sp-7);
}

.footer__grid > div {
    opacity: 0.85;
}

.footer__label {
    margin-bottom: var(--sp-2);
    opacity: 0.6;
    letter-spacing: var(--track-1);
    text-transform: uppercase;
    font-size: var(--fs-xs);
}

.footer__val {
    opacity: 0.85;
}

.footer__mail {
    color: var(--accent);
    text-decoration: none;
    border-bottom: 1px dashed rgb(var(--accent-rgb) / 0.3);
    padding-bottom: 1px;
    transition: border-color var(--dur) var(--ease-out), text-shadow var(--dur) var(--ease-out);
}

.footer__mail:hover,
.footer__mail:focus-visible {
    border-bottom-color: var(--accent);
    text-shadow: 0 0 12px rgb(var(--accent-rgb) / 0.5);
}

.footer__cookie {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}

.footer__led {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 6px var(--accent);
}

.footer__bottom {
    position: relative;
    z-index: 1;
    max-width: 1100px;
    margin: var(--sp-7) auto 0;
    padding-top: var(--sp-5);
    border-top: 1px dashed var(--line-2);
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--sp-3);
    opacity: 0.5;
    font-size: var(--fs-xs);
}

/* =====================================================
   CRT overlay
   ===================================================== */

@keyframes crt-flicker {
    0%, 100% { opacity: 1; }
    45% { opacity: 1; }
    46% { opacity: 0.96; }
    47% { opacity: 1; }
    82% { opacity: 1; }
    83% { opacity: 0.93; }
    84% { opacity: 1; }
}

@keyframes scan-sweep {
    0%   { transform: translateY(-30vh); opacity: 0; }
    10%  { opacity: 0.6; }
    90%  { opacity: 0.6; }
    100% { transform: translateY(130vh); opacity: 0; }
}

.crt {
    position: fixed;
    pointer-events: none;
    inset: 0;
}

/* Statiske scanlines. scanline-drift (steps(2) hvert 0.2s) var sidens
   dyreste kontinuerlige kostnad — full-viewport repaint 5×/sek med
   mix-blend-mode: multiply — for et nær usynlig utbytte. */
.crt--scanlines {
    z-index: 9000;
    background-image: repeating-linear-gradient(to bottom,
        rgb(0 0 0 / var(--scanlines)) 0px,
        rgb(0 0 0 / var(--scanlines)) 1px,
        transparent 1px,
        transparent 3px);
    mix-blend-mode: multiply;
}

.crt--rgb {
    z-index: 9001;
    background-image: repeating-linear-gradient(to right,
        rgb(255 0 0 / 0.03) 0px,
        rgb(0 255 0 / 0.03) 1px,
        rgb(0 0 255 / 0.03) 2px,
        transparent 2px,
        transparent 3px);
    mix-blend-mode: screen;
}

.crt--sweep {
    left: 0;
    right: 0;
    height: 30vh;
    bottom: auto;
    inset: auto 0 auto 0;
    z-index: 9002;
    background: linear-gradient(to bottom, transparent 0%, rgb(var(--accent-rgb) / 0.028) 50%, transparent 100%);
    animation: scan-sweep 13s linear infinite;
}

.crt--vignette {
    z-index: 9003;
    background: radial-gradient(ellipse at center, transparent 50%, rgb(0 0 0 / var(--vignette)) 100%);
    animation: crt-flicker 6s infinite;
}

/* =====================================================
   Lave viewporter (laptop 900-960px høy)

   Heroen er ~1170px høy med begge kurvekanalene. Uten dette faller
   hele pleth-kanalen under folden på en 1440x900-skjerm, altså
   usynlig uten å scrolle. Strammer den vertikale rytmen så begge
   kurvene kommer over folden; bare scroll-hintet blir kuttet.
   ===================================================== */

@media (min-width: 761px) and (max-height: 1040px) {
    .hero { padding-top: 84px; padding-bottom: var(--sp-8); }
    .hero__title { font-size: clamp(44px, 5.2vw, 72px); }
    .hero__sub { margin-top: 20px; }
    .monitor { margin-top: var(--sp-7); }
    /* SVG-en har preserveAspectRatio: none, så lavere høyde klemmer
       kurvene flate. Tittelen får heller vike — ABP mister formen
       under ~250px med tre kanaler. */
    .ekg { height: 250px; }
    .hero__scroll { margin-top: var(--sp-7); }
}

/* =====================================================
   Mobile
   ===================================================== */

@media (max-width: 760px) {
    .topbar { padding: var(--sp-4) var(--sp-5); gap: var(--sp-3); }
    .topbar__meta { gap: var(--sp-2); font-size: var(--fs-xs); }
    .topbar__subname,
    .topbar__sep { display: none; }
    .topbar__nav { gap: 14px; font-size: var(--fs-xs); }
    .topbar__status { display: none; }

    .hero { padding: 90px var(--sp-5) var(--sp-8); }
    .hero__meta { gap: var(--sp-3); font-size: var(--fs-nano); margin-bottom: 20px; }
    .hero__title {
        font-size: clamp(30px, 9vw, 56px);
        letter-spacing: -0.04em;
        overflow-wrap: anywhere;
    }
    .hero__sub { font-size: var(--fs-base); margin-top: 22px; }

    .monitor { padding: var(--sp-4); margin-top: 36px; }
    /* 880 viewBox-enheter presset ned i ~390px gjør at kurvetoppene
       kommer hver ~97px. De lange kanaldetaljene løper da rett inn i
       dem, så bare kanalnavnet blir stående. */
    .ekg__label-det { display: none; }

    /* "SWEEP 12.5mm/s" er ett tegn lengre enn 25mm/s og brakk fotlinja */
    .monitor__footer { font-size: var(--fs-micro); }

    /* 76px, ikke 84: ved 320px er det bare 260px å dele på, og 84px
       ga to kolonner slik at ABP falt ned på en andre rad. Antall
       bokser er uansett begrenset av spørringene lenger ned, så en
       lavere minstebredde påvirker bare den smaleste enden. */
    .vitals { grid-template-columns: repeat(auto-fit, minmax(76px, 1fr)); gap: var(--sp-2); }
    .vital { padding: var(--sp-2) var(--sp-3); }
    .vital__label { font-size: var(--fs-micro); letter-spacing: var(--track-1); }
    .vital__value { font-size: var(--fs-body); }
    .vital__unit { font-size: var(--fs-nano); }
    .vital__sub { font-size: var(--fs-micro); }
    /* "127/64 (85) mmHg" får ikke plass i én 84px-kolonne uten å krympe
       tallet under label-størrelse. Enheten flyttes derfor ned på
       sub-linja, så ABP-raden blir like høy som naboene. */
    .vital__row { flex-wrap: wrap; }
    .vital--abp .vital__value { font-size: var(--fs-base); }
    .vital__mean { font-size: var(--fs-micro); }
    .vital__trend { font-size: var(--fs-nano); }
    .vital--abp .vital__unit { display: none; }
    .vital--abp .vital__sub::before { content: "mmHg · "; }

    .section { padding: 72px 0; }
    .section__inner { padding: 0 var(--sp-5); }
    .section__tag { font-size: var(--fs-xs); margin-bottom: 22px; }

    .projects__header { grid-template-columns: 1fr; gap: var(--sp-5); margin-bottom: 36px; }
    .projects__title { font-size: clamp(34px, 9vw, 56px); }
    .projects__ls { --bk: -8px; }

    .projects__list { --row-bleed: 10px; }
    .project { grid-template-columns: 32px 1fr; gap: var(--sp-4); padding: 22px 0; }
    .project__name { font-size: 26px; }
    .project__desc { font-size: var(--fs-lg); }
    .project__status-col {
        grid-column: 1 / -1;
        flex-direction: row;
        align-items: center;
        justify-content: space-between;
        margin-top: var(--sp-3);
    }

    .om { grid-template-columns: 1fr; gap: 36px; }
    .om__title { font-size: clamp(34px, 9vw, 56px); }
    .om__body { font-size: 15px; padding-left: var(--sp-5); }
    .pager-sticky { position: relative; top: 0; }

    /* Full bredde gjør samme vinkel langt mer voldsom: perspektivet
       virker over ~390px i stedet for 300, og bakflaten svinger ut
       forbi skjermkanten. Dybde og utslag skaleres ned i stedet for
       å låses — driften i JS er den samme. */
    .pager {
        max-width: 100%;
        perspective: 1500px;
        padding: 12px 14px;
    }

    .pager__box {
        --depth: 40px;
        transform: rotateX(calc(var(--rx, 11deg) * 0.6)) rotateY(calc(var(--ry, -26deg) * 0.55));
    }

    .footer__grid { grid-template-columns: 1fr; gap: 20px; }
}

/* =====================================================
   Vitals som ikke får plass på én linje

   Fem bokser krever ~600px før ABP ("127/64 (85) ↓") har nok bredde.
   I stedet for å la dem brekke til en andre rad med en tom celle,
   skjules de som ville havnet der — én om gangen. Under 480px står
   HR, SpO₂ og ABP igjen, altså nøyaktig de tre som har hver sin
   kurvekanal under.
   ===================================================== */

@media (max-width: 599px) {
    .vital--temp { display: none; }
}

@media (max-width: 479px) {
    .vital--co2 { display: none; }
}

/* Under 400px har ABP-boksen ~96px, og "127/64 (85) ↓" trenger ~100.
   Trendpilen er det minst vesentlige, så den ryker først — ellers
   brekker den ned på egen linje og gjør boksen høyere enn naboene. */
@media (max-width: 399px) {
    .vital__trend { display: none; }
}

/* pointer-glød kun der det finnes en faktisk peker —
   ellers ville fallback 50% 50% gitt fastlåst glød på touch */
@media not all and (hover: hover) and (pointer: fine) {
    /* rene dekor-glød: ingen peker, ingen hensikt */
    .monitor::before,
    .pager::before { display: none; }

    /* prosjektradene beholder det flate vasket — ellers ville et tapp
       ikke gitt noen tilbakemelding i det hele tatt. Bare den
       markør-styrte radialen faller bort. */
    .project::before {
        background: linear-gradient(rgb(var(--accent-rgb) / 0.035), rgb(var(--accent-rgb) / 0.035));
    }
}

/* =====================================================
   Reduced motion
   ===================================================== */

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }

    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        /* Delay MÅ nulles: boot-sekvensen bruker fill-mode backwards, som
           holder elementet på opacity 0 gjennom hele forsinkelsen. Uten
           dette ville heroen stått tom i opptil 1,2s. */
        animation-delay: 0s !important;
        transition-delay: 0s !important;
    }

    /* effekter som skal helt bort, ikke bare fryses */
    .crt--sweep { display: none; }
    .cursor { animation: none; opacity: 1; }

    /* reveal: alltid synlig */
    .js [data-reveal],
    .js [data-stagger] > * {
        opacity: 1 !important;
        transform: none !important;
    }
}
